From 666a3e5a6850264da5048b0a257a1bc591ce5780 Mon Sep 17 00:00:00 2001 From: Jean-Marie Verdun Date: Sat, 14 May 2016 10:05:56 +0200 Subject: [PATCH] Upgrade to SMESH7.7.1 --- src/3rdParty/salomesmesh/CMakeLists.txt | 22 +- .../salomesmesh/inc/Basics_OCCTVersion.hxx | 51 + src/3rdParty/salomesmesh/inc/Basics_Utils.hxx | 143 + .../salomesmesh/inc/DriverDAT_R_SMDS_Mesh.h | 31 +- .../salomesmesh/inc/DriverDAT_W_SMDS_Mesh.h | 31 +- src/3rdParty/salomesmesh/inc/DriverGMF.hxx | 46 + .../salomesmesh/inc/DriverGMF_Read.hxx | 64 + .../salomesmesh/inc/DriverGMF_Write.hxx | 93 + src/3rdParty/salomesmesh/inc/DriverMED.hxx | 46 + .../salomesmesh/inc/DriverMED_Family.h | 144 + .../inc/DriverMED_R_SMESHDS_Mesh.h | 64 + .../salomesmesh/inc/DriverMED_W_Field.h | 83 + .../inc/DriverMED_W_SMESHDS_Mesh.h | 93 + .../salomesmesh/inc/DriverSTL_R_SMDS_Mesh.h | 37 +- .../salomesmesh/inc/DriverSTL_W_SMDS_Mesh.h | 44 +- .../salomesmesh/inc/DriverUNV_R_SMDS_Mesh.h | 31 +- .../salomesmesh/inc/DriverUNV_W_SMDS_Mesh.h | 31 +- .../salomesmesh/inc/Driver_Document.h | 31 +- src/3rdParty/salomesmesh/inc/Driver_Mesh.h | 57 +- .../salomesmesh/inc/Driver_SMDS_Mesh.h | 31 +- .../salomesmesh/inc/Driver_SMESHDS_Mesh.h | 31 +- src/3rdParty/salomesmesh/inc/GEOMUtils.hxx | 346 + .../inc/Handle_SMESH_MeshVSLink.hxx | 167 +- .../salomesmesh/inc/MED_Algorithm.hxx | 156 + src/3rdParty/salomesmesh/inc/MED_Common.hxx | 184 + .../salomesmesh/inc/MED_CoordUtils.hxx | 56 + src/3rdParty/salomesmesh/inc/MED_Factory.hxx | 49 + src/3rdParty/salomesmesh/inc/MED_GaussDef.hxx | 69 + .../salomesmesh/inc/MED_GaussUtils.hxx | 365 + .../salomesmesh/inc/MED_SharedPtr.hxx | 95 + .../salomesmesh/inc/MED_SliceArray.hxx | 185 + .../salomesmesh/inc/MED_Structures.hxx | 1081 + .../salomesmesh/inc/MED_TStructures.hxx | 1215 ++ src/3rdParty/salomesmesh/inc/MED_TWrapper.hxx | 578 + .../salomesmesh/inc/MED_Utilities.hxx | 73 + .../salomesmesh/inc/MED_V2_2_Wrapper.hxx | 489 + src/3rdParty/salomesmesh/inc/MED_Vector.hxx | 152 + src/3rdParty/salomesmesh/inc/MED_Wrapper.hxx | 1052 + .../salomesmesh/inc/MED_WrapperBase.hxx | 46 + .../salomesmesh/inc/MED_WrapperFactory.hxx | 46 + .../salomesmesh/inc/NETGENPlugin_Defs.hxx | 33 +- .../inc/NETGENPlugin_Hypothesis.hxx | 79 +- .../inc/NETGENPlugin_Hypothesis_2D.hxx | 48 +- .../inc/NETGENPlugin_Hypothesis_2D_ONLY_i.hxx | 57 + .../inc/NETGENPlugin_Hypothesis_2D_i.hxx | 73 + .../inc/NETGENPlugin_Hypothesis_3D_i.hxx | 59 + .../inc/NETGENPlugin_Hypothesis_i.hxx | 151 + .../salomesmesh/inc/NETGENPlugin_Mesher.hxx | 252 +- .../inc/NETGENPlugin_NETGEN_2D.hxx | 50 +- .../inc/NETGENPlugin_NETGEN_2D3D.hxx | 51 +- .../inc/NETGENPlugin_NETGEN_2D3D_i.hxx | 59 + .../inc/NETGENPlugin_NETGEN_2D_ONLY.hxx | 69 +- .../inc/NETGENPlugin_NETGEN_2D_ONLY_i.hxx | 53 + .../inc/NETGENPlugin_NETGEN_2D_i.hxx | 59 + .../inc/NETGENPlugin_NETGEN_3D.hxx | 68 +- .../inc/NETGENPlugin_NETGEN_3D_i.hxx | 60 + .../inc/NETGENPlugin_SimpleHypothesis_2D.hxx | 58 +- .../NETGENPlugin_SimpleHypothesis_2D_i.hxx | 86 + .../inc/NETGENPlugin_SimpleHypothesis_3D.hxx | 38 +- .../NETGENPlugin_SimpleHypothesis_3D_i.hxx | 64 + src/3rdParty/salomesmesh/inc/ObjectPool.hxx | 174 + src/3rdParty/salomesmesh/inc/OpUtil.hxx | 34 + src/3rdParty/salomesmesh/inc/Rn.h | 38 +- src/3rdParty/salomesmesh/inc/SALOMEDS.hxx | 68 + .../salomesmesh/inc/SALOMEDS_Tool.hxx | 122 + .../salomesmesh/inc/SALOMEDS_defines.hxx | 40 + .../salomesmesh/inc/SALOME_Basics.hxx | 40 + src/3rdParty/salomesmesh/inc/SALOME_Utils.hxx | 40 + .../salomesmesh/inc/SMDSAbs_ElementType.hxx | 118 +- .../salomesmesh/inc/SMDS_BallElement.hxx | 60 + .../salomesmesh/inc/SMDS_Downward.hxx | 381 + .../salomesmesh/inc/SMDS_EdgePosition.hxx | 42 +- .../salomesmesh/inc/SMDS_ElemIterator.hxx | 39 +- .../salomesmesh/inc/SMDS_FaceOfEdges.hxx | 68 +- .../salomesmesh/inc/SMDS_FaceOfNodes.hxx | 52 +- .../salomesmesh/inc/SMDS_FacePosition.hxx | 50 +- .../salomesmesh/inc/SMDS_Iterator.hxx | 53 +- .../inc/SMDS_IteratorOfElements.hxx | 57 +- .../inc/SMDS_IteratorOnIterators.hxx | 67 + .../salomesmesh/inc/SMDS_LinearEdge.hxx | 68 + src/3rdParty/salomesmesh/inc/SMDS_Mesh.hxx | 783 +- .../salomesmesh/inc/SMDS_Mesh0DElement.hxx | 55 + .../salomesmesh/inc/SMDS_MeshCell.hxx | 83 + .../salomesmesh/inc/SMDS_MeshEdge.hxx | 67 +- .../salomesmesh/inc/SMDS_MeshElement.hxx | 131 +- .../inc/SMDS_MeshElementIDFactory.hxx | 54 +- .../salomesmesh/inc/SMDS_MeshFace.hxx | 38 +- .../salomesmesh/inc/SMDS_MeshGroup.hxx | 65 +- .../salomesmesh/inc/SMDS_MeshIDFactory.hxx | 50 +- .../salomesmesh/inc/SMDS_MeshInfo.hxx | 378 +- .../salomesmesh/inc/SMDS_MeshNode.hxx | 103 +- .../inc/SMDS_MeshNodeIDFactory.hxx | 65 + .../salomesmesh/inc/SMDS_MeshObject.hxx | 31 +- .../salomesmesh/inc/SMDS_MeshVolume.hxx | 40 +- .../inc/SMDS_PolygonalFaceOfNodes.hxx | 35 +- .../inc/SMDS_PolyhedralVolumeOfNodes.hxx | 34 +- .../salomesmesh/inc/SMDS_Position.hxx | 48 +- .../salomesmesh/inc/SMDS_QuadraticEdge.hxx | 39 +- .../inc/SMDS_QuadraticFaceOfNodes.hxx | 34 +- .../inc/SMDS_QuadraticVolumeOfNodes.hxx | 32 +- .../salomesmesh/inc/SMDS_SetIterator.hxx | 94 +- .../salomesmesh/inc/SMDS_SpacePosition.hxx | 45 +- .../salomesmesh/inc/SMDS_StdIterator.hxx | 80 + .../salomesmesh/inc/SMDS_TypeOfPosition.hxx | 41 +- .../salomesmesh/inc/SMDS_UnstructuredGrid.hxx | 125 + .../salomesmesh/inc/SMDS_VertexPosition.hxx | 38 +- .../salomesmesh/inc/SMDS_VolumeOfFaces.hxx | 56 +- .../salomesmesh/inc/SMDS_VolumeOfNodes.hxx | 109 +- .../salomesmesh/inc/SMDS_VolumeTool.hxx | 170 +- .../salomesmesh/inc/SMDS_VtkCellIterator.hxx | 74 + src/3rdParty/salomesmesh/inc/SMDS_VtkEdge.hxx | 59 + src/3rdParty/salomesmesh/inc/SMDS_VtkFace.hxx | 64 + .../salomesmesh/inc/SMDS_VtkVolume.hxx | 80 + .../salomesmesh/inc/SMESHDS_Command.hxx | 125 +- .../salomesmesh/inc/SMESHDS_CommandType.hxx | 45 +- .../inc/SMESHDS_DataMapOfShape.hxx | 51 +- .../salomesmesh/inc/SMESHDS_Document.hxx | 73 +- .../salomesmesh/inc/SMESHDS_Group.hxx | 41 +- .../salomesmesh/inc/SMESHDS_GroupBase.hxx | 49 +- .../salomesmesh/inc/SMESHDS_GroupOnFilter.hxx | 94 + .../salomesmesh/inc/SMESHDS_GroupOnGeom.hxx | 35 +- .../salomesmesh/inc/SMESHDS_Hypothesis.hxx | 52 +- src/3rdParty/salomesmesh/inc/SMESHDS_Mesh.hxx | 663 +- .../salomesmesh/inc/SMESHDS_Script.hxx | 115 +- .../salomesmesh/inc/SMESHDS_SubMesh.hxx | 75 +- .../inc/SMESHDS_TSubMeshHolder.hxx | 151 + src/3rdParty/salomesmesh/inc/SMESH_Algo.hxx | 293 +- src/3rdParty/salomesmesh/inc/SMESH_Block.hxx | 104 +- .../salomesmesh/inc/SMESH_Comment.hxx | 51 +- .../salomesmesh/inc/SMESH_ComputeError.hxx | 99 +- .../salomesmesh/inc/SMESH_Controls.hxx | 74 +- .../salomesmesh/inc/SMESH_ControlsDef.hxx | 584 +- .../salomesmesh/inc/SMESH_DriverDAT.hxx | 35 +- .../salomesmesh/inc/SMESH_DriverGMF.hxx | 40 + .../salomesmesh/inc/SMESH_DriverMED.hxx | 40 + .../salomesmesh/inc/SMESH_DriverSTL.hxx | 35 +- .../salomesmesh/inc/SMESH_DriverUNV.hxx | 35 +- src/3rdParty/salomesmesh/inc/SMESH_File.hxx | 124 + src/3rdParty/salomesmesh/inc/SMESH_Gen.hxx | 110 +- src/3rdParty/salomesmesh/inc/SMESH_Group.hxx | 39 +- .../salomesmesh/inc/SMESH_HypoFilter.hxx | 66 +- .../salomesmesh/inc/SMESH_Hypothesis.hxx | 73 +- src/3rdParty/salomesmesh/inc/SMESH_MAT2d.hxx | 238 + src/3rdParty/salomesmesh/inc/SMESH_Mesh.hxx | 314 +- .../salomesmesh/inc/SMESH_MeshAlgos.hxx | 200 + .../salomesmesh/inc/SMESH_MeshEditor.hxx | 599 +- .../salomesmesh/inc/SMESH_MeshVSLink.hxx | 320 +- .../salomesmesh/inc/SMESH_MeshVSLink.ixx | 120 +- .../salomesmesh/inc/SMESH_MesherHelper.hxx | 592 +- src/3rdParty/salomesmesh/inc/SMESH_Octree.hxx | 132 +- .../salomesmesh/inc/SMESH_OctreeNode.hxx | 135 +- .../salomesmesh/inc/SMESH_Pattern.hxx | 61 +- .../salomesmesh/inc/SMESH_ProxyMesh.hxx | 183 + .../salomesmesh/inc/SMESH_Quadtree.hxx | 73 + src/3rdParty/salomesmesh/inc/SMESH_SMDS.hxx | 33 +- src/3rdParty/salomesmesh/inc/SMESH_SMESH.hxx | 35 +- .../salomesmesh/inc/SMESH_SMESHDS.hxx | 33 +- .../salomesmesh/inc/SMESH_StdMeshers.hxx | 35 +- .../salomesmesh/inc/SMESH_TryCatch.hxx | 109 + .../salomesmesh/inc/SMESH_TypeDefs.hxx | 204 + src/3rdParty/salomesmesh/inc/SMESH_Utils.hxx | 40 + .../salomesmesh/inc/SMESH_subMesh.hxx | 194 +- .../inc/SMESH_subMeshEventListener.hxx | 72 +- src/3rdParty/salomesmesh/inc/SMESH_tree.hxx | 278 + .../salomesmesh/inc/StdMeshers_Adaptive1D.hxx | 90 + .../inc/StdMeshers_Arithmetic1D.hxx | 52 +- .../inc/StdMeshers_AutomaticLength.hxx | 40 +- .../inc/StdMeshers_CartesianParameters3D.hxx | 177 + .../inc/StdMeshers_Cartesian_3D.hxx | 64 + .../inc/StdMeshers_CompositeHexa_3D.hxx | 56 +- .../inc/StdMeshers_CompositeSegment_1D.hxx | 42 +- .../inc/StdMeshers_Deflection1D.hxx | 40 +- .../inc/StdMeshers_Distribution.hxx | 50 +- .../salomesmesh/inc/StdMeshers_FaceSide.hxx | 337 +- .../inc/StdMeshers_FixedPoints1D.hxx | 88 + .../inc/StdMeshers_Geometric1D.hxx | 67 + .../inc/StdMeshers_HexaFromSkin_3D.hxx | 54 + .../salomesmesh/inc/StdMeshers_Hexa_3D.hxx | 107 +- .../inc/StdMeshers_ImportSource.hxx | 100 + .../salomesmesh/inc/StdMeshers_Import_1D.hxx | 81 + .../inc/StdMeshers_Import_1D2D.hxx | 60 + .../inc/StdMeshers_LayerDistribution.hxx | 38 +- .../inc/StdMeshers_LayerDistribution2D.hxx | 53 + .../inc/StdMeshers_LengthFromEdges.hxx | 38 +- .../inc/StdMeshers_LocalLength.hxx | 40 +- .../salomesmesh/inc/StdMeshers_MEFISTO_2D.hxx | 55 +- .../inc/StdMeshers_MaxElementArea.hxx | 38 +- .../inc/StdMeshers_MaxElementVolume.hxx | 38 +- .../salomesmesh/inc/StdMeshers_MaxLength.hxx | 41 +- .../inc/StdMeshers_NotConformAllowed.hxx | 36 +- .../inc/StdMeshers_NumberOfLayers.hxx | 38 +- .../inc/StdMeshers_NumberOfLayers2D.hxx | 52 + .../inc/StdMeshers_NumberOfSegments.hxx | 94 +- .../salomesmesh/inc/StdMeshers_Penta_3D.hxx | 81 +- .../inc/StdMeshers_PolygonPerFace_2D.hxx | 47 + .../salomesmesh/inc/StdMeshers_Prism_3D.hxx | 385 +- .../inc/StdMeshers_ProjectionSource1D.hxx | 40 +- .../inc/StdMeshers_ProjectionSource2D.hxx | 42 +- .../inc/StdMeshers_ProjectionSource3D.hxx | 44 +- .../inc/StdMeshers_ProjectionUtils.hxx | 333 +- .../inc/StdMeshers_Projection_1D.hxx | 36 +- .../inc/StdMeshers_Projection_1D2D.hxx | 52 + .../inc/StdMeshers_Projection_2D.hxx | 44 +- .../inc/StdMeshers_Projection_3D.hxx | 40 +- .../inc/StdMeshers_Propagation.hxx | 67 +- .../StdMeshers_QuadFromMedialAxis_1D2D.hxx | 69 + .../inc/StdMeshers_QuadToTriaAdaptor.hxx | 94 +- .../inc/StdMeshers_QuadrangleParams.hxx | 91 + .../inc/StdMeshers_QuadranglePreference.hxx | 38 +- .../inc/StdMeshers_Quadrangle_2D.hxx | 304 +- .../inc/StdMeshers_QuadraticMesh.hxx | 36 +- .../inc/StdMeshers_RadialPrism_3D.hxx | 38 +- .../inc/StdMeshers_RadialQuadrangle_1D2D.hxx | 78 + .../salomesmesh/inc/StdMeshers_Regular_1D.hxx | 59 +- .../inc/StdMeshers_Reversible1D.hxx | 59 + .../inc/StdMeshers_SegmentAroundVertex_0D.hxx | 35 +- .../StdMeshers_SegmentLengthAroundVertex.hxx | 38 +- .../inc/StdMeshers_StartEndLength.hxx | 50 +- .../inc/StdMeshers_UseExisting_1D2D.hxx | 37 +- .../inc/StdMeshers_ViscousLayers.hxx | 131 + .../inc/StdMeshers_ViscousLayers2D.hxx | 78 + .../salomesmesh/inc/UNV164_Structure.hxx | 94 + .../salomesmesh/inc/UNV2411_Structure.hxx | 41 +- .../salomesmesh/inc/UNV2412_Structure.hxx | 43 +- .../salomesmesh/inc/UNV2417_Structure.hxx | 35 +- .../salomesmesh/inc/UNV2420_Structure.hxx | 119 + .../salomesmesh/inc/UNV_Utilities.hxx | 86 +- .../salomesmesh/inc/Utils_ExceptHandlers.hxx | 89 + src/3rdParty/salomesmesh/inc/Utils_Mutex.hxx | 62 + .../inc/Utils_SALOME_Exception.hxx | 85 + src/3rdParty/salomesmesh/inc/aptrte.h | 332 +- src/3rdParty/salomesmesh/inc/chrono.hxx | 75 + src/3rdParty/salomesmesh/inc/libmesh5.h | 155 + src/3rdParty/salomesmesh/inc/memoire.h | 43 + .../src/Controls/SMESHControls.cpp | 47 - .../src/Controls/SMESH_Controls.cpp | 2996 ++- .../src/Driver/Driver_Document.cpp | 31 +- .../salomesmesh/src/Driver/Driver_Mesh.cpp | 92 +- .../src/Driver/Driver_SMDS_Mesh.cpp | 31 +- .../src/Driver/Driver_SMESHDS_Mesh.cpp | 31 +- .../src/DriverDAT/DriverDAT_R_SMDS_Mesh.cpp | 105 +- .../src/DriverDAT/DriverDAT_W_SMDS_Mesh.cpp | 93 +- .../src/DriverSTL/Basics_Utils.cpp | 141 + .../src/DriverSTL/DriverSTL_R_SMDS_Mesh.cpp | 254 +- .../src/DriverSTL/DriverSTL_W_SMDS_Mesh.cpp | 618 +- .../salomesmesh/src/DriverSTL/SMESH_File.cpp | 336 + .../src/DriverUNV/DriverUNV_R_SMDS_Mesh.cpp | 676 +- .../src/DriverUNV/DriverUNV_W_SMDS_Mesh.cpp | 379 +- .../src/DriverUNV/UNV164_Structure.cpp | 83 + .../src/DriverUNV/UNV2411_Structure.cpp | 110 +- .../src/DriverUNV/UNV2412_Structure.cpp | 263 +- .../src/DriverUNV/UNV2417_Structure.cpp | 80 +- .../src/DriverUNV/UNV2420_Structure.cpp | 152 + .../src/DriverUNV/UNV_Utilities.cpp | 37 +- .../salomesmesh/src/MEFISTO2/aptrte.cpp | 229 +- .../NETGENPlugin/NETGENPlugin_Hypothesis.cpp | 256 +- .../NETGENPlugin_Hypothesis_2D.cpp | 128 +- .../src/NETGENPlugin/NETGENPlugin_Mesher.cpp | 4215 +++- .../NETGENPlugin/NETGENPlugin_NETGEN_2D.cpp | 143 +- .../NETGENPlugin/NETGENPlugin_NETGEN_2D3D.cpp | 95 +- .../NETGENPlugin_NETGEN_2D_ONLY.cpp | 817 +- .../NETGENPlugin/NETGENPlugin_NETGEN_3D.cpp | 968 +- .../NETGENPlugin_SimpleHypothesis_2D.cpp | 76 +- .../NETGENPlugin_SimpleHypothesis_3D.cpp | 32 +- .../salomesmesh/src/SMDS/SMDS_BallElement.cpp | 102 + .../salomesmesh/src/SMDS/SMDS_Downward.cpp | 2245 ++ .../src/SMDS/SMDS_EdgePosition.cpp | 56 +- .../salomesmesh/src/SMDS/SMDS_FaceOfEdges.cpp | 125 +- .../salomesmesh/src/SMDS/SMDS_FaceOfNodes.cpp | 76 +- .../src/SMDS/SMDS_FacePosition.cpp | 72 +- .../src/SMDS/SMDS_IteratorOfElements.cpp | 129 +- .../salomesmesh/src/SMDS/SMDS_LinearEdge.cpp | 160 + .../salomesmesh/src/SMDS/SMDS_MemoryLimit.cpp | 77 - .../salomesmesh/src/SMDS/SMDS_Mesh.cpp | 3561 +++- .../src/SMDS/SMDS_Mesh0DElement.cpp | 164 + .../salomesmesh/src/SMDS/SMDS_MeshCell.cpp | 476 + .../salomesmesh/src/SMDS/SMDS_MeshEdge.cpp | 161 +- .../salomesmesh/src/SMDS/SMDS_MeshElement.cpp | 236 +- .../src/SMDS/SMDS_MeshElementIDFactory.cpp | 172 +- .../salomesmesh/src/SMDS/SMDS_MeshFace.cpp | 38 +- .../salomesmesh/src/SMDS/SMDS_MeshGroup.cpp | 113 +- .../src/SMDS/SMDS_MeshIDFactory.cpp | 79 +- .../salomesmesh/src/SMDS/SMDS_MeshNode.cpp | 351 +- .../src/SMDS/SMDS_MeshNodeIDFactory.cpp | 149 + .../salomesmesh/src/SMDS/SMDS_MeshObject.cpp | 31 +- .../salomesmesh/src/SMDS/SMDS_MeshVolume.cpp | 37 +- .../src/SMDS/SMDS_PolygonalFaceOfNodes.cpp | 35 +- .../src/SMDS/SMDS_PolyhedralVolumeOfNodes.cpp | 32 +- .../salomesmesh/src/SMDS/SMDS_Position.cpp | 55 +- .../src/SMDS/SMDS_QuadraticEdge.cpp | 65 +- .../src/SMDS/SMDS_QuadraticFaceOfNodes.cpp | 66 +- .../src/SMDS/SMDS_QuadraticVolumeOfNodes.cpp | 48 +- .../src/SMDS/SMDS_SpacePosition.cpp | 55 +- .../src/SMDS/SMDS_UnstructuredGrid.cpp | 1168 + .../src/SMDS/SMDS_VertexPosition.cpp | 51 +- .../src/SMDS/SMDS_VolumeOfFaces.cpp | 116 +- .../src/SMDS/SMDS_VolumeOfNodes.cpp | 239 +- .../salomesmesh/src/SMDS/SMDS_VolumeTool.cpp | 1784 +- .../src/SMDS/SMDS_VtkCellIterator.cpp | 215 + .../salomesmesh/src/SMDS/SMDS_VtkEdge.cpp | 173 + .../salomesmesh/src/SMDS/SMDS_VtkFace.cpp | 348 + .../salomesmesh/src/SMDS/SMDS_VtkVolume.cpp | 724 + .../src/SMDS/Utils_SALOME_Exception.cpp | 122 + src/3rdParty/salomesmesh/src/SMDS/chrono.cpp | 87 + .../salomesmesh/src/SMDS/duplicate.cpp | 51 + .../salomesmesh/src/SMESH/DriverGMF.cpp | 66 + .../salomesmesh/src/SMESH/DriverGMF_Read.cpp | 486 + .../salomesmesh/src/SMESH/DriverGMF_Write.cpp | 426 + .../src/SMESH/DriverMED_Family.cpp | 549 + .../src/SMESH/DriverMED_R_SMESHDS_Mesh.cpp | 1299 ++ .../src/SMESH/DriverMED_W_Field.cpp | 430 + .../src/SMESH/DriverMED_W_SMESHDS_Mesh.cpp | 1007 + .../salomesmesh/src/SMESH/GEOMUtils.cpp | 1290 ++ .../salomesmesh/src/SMESH/MED_Algorithm.cpp | 374 + .../salomesmesh/src/SMESH/MED_CoordUtils.cpp | 159 + .../salomesmesh/src/SMESH/MED_Factory.cpp | 165 + .../salomesmesh/src/SMESH/MED_GaussDef.cpp | 570 + .../salomesmesh/src/SMESH/MED_GaussUtils.cpp | 2172 ++ .../salomesmesh/src/SMESH/MED_Structures.cpp | 865 + .../salomesmesh/src/SMESH/MED_Utilities.cpp | 113 + .../salomesmesh/src/SMESH/MED_Wrapper.cpp | 707 + .../salomesmesh/src/SMESH/SMESH_0D_Algo.cpp | 52 - .../salomesmesh/src/SMESH/SMESH_1D_Algo.cpp | 57 - .../salomesmesh/src/SMESH/SMESH_2D_Algo.cpp | 94 - .../salomesmesh/src/SMESH/SMESH_3D_Algo.cpp | 59 - .../salomesmesh/src/SMESH/SMESH_Algo.cpp | 982 +- .../salomesmesh/src/SMESH/SMESH_Block.cpp | 662 +- .../salomesmesh/src/SMESH/SMESH_Gen.cpp | 941 +- .../salomesmesh/src/SMESH/SMESH_Group.cpp | 80 +- .../src/SMESH/SMESH_HypoFilter.cpp | 129 +- .../src/SMESH/SMESH_Hypothesis.cpp | 74 +- .../salomesmesh/src/SMESH/SMESH_Mesh.cpp | 1835 +- .../salomesmesh/src/SMESH/SMESH_MeshAlgos.cpp | 1667 ++ .../src/SMESH/SMESH_MeshEditor.cpp | 17548 ++++++++++------ .../src/SMESH/SMESH_MeshVSLink.cpp | 684 +- .../src/SMESH/SMESH_MesherHelper.cpp | 5910 +++++- .../salomesmesh/src/SMESH/SMESH_Octree.cpp | 196 +- .../src/SMESH/SMESH_OctreeNode.cpp | 358 +- .../salomesmesh/src/SMESH/SMESH_Pattern.cpp | 675 +- .../salomesmesh/src/SMESH/SMESH_ProxyMesh.cpp | 595 + .../salomesmesh/src/SMESH/SMESH_TryCatch.cpp | 82 + .../salomesmesh/src/SMESH/SMESH_subMesh.cpp | 1680 +- .../src/SMESH/Utils_ExceptHandlers.cpp | 39 + src/3rdParty/salomesmesh/src/SMESH/libmesh.c | 1346 ++ .../src/SMESHDS/SMESHDS_Command.cpp | 507 +- .../src/SMESHDS/SMESHDS_Document.cpp | 136 +- .../salomesmesh/src/SMESHDS/SMESHDS_Group.cpp | 60 +- .../src/SMESHDS/SMESHDS_GroupBase.cpp | 39 +- .../src/SMESHDS/SMESHDS_GroupOnFilter.cpp | 415 + .../src/SMESHDS/SMESHDS_GroupOnGeom.cpp | 54 +- .../src/SMESHDS/SMESHDS_Hypothesis.cpp | 73 +- .../salomesmesh/src/SMESHDS/SMESHDS_Mesh.cpp | 1358 +- .../src/SMESHDS/SMESHDS_Script.cpp | 163 +- .../src/SMESHDS/SMESHDS_SubMesh.cpp | 403 +- .../src/StdMeshers/SMESH_MAT2d.cpp | 2023 ++ .../src/StdMeshers/SMESH_Quadtree.cpp | 76 + .../src/StdMeshers/StdMeshers_Adaptive1D.cpp | 1513 ++ .../StdMeshers/StdMeshers_Arithmetic1D.cpp | 81 +- .../StdMeshers/StdMeshers_AutomaticLength.cpp | 117 +- .../StdMeshers_CartesianParameters3D.cpp | 879 + .../StdMeshers/StdMeshers_Cartesian_3D.cpp | 3788 ++++ .../StdMeshers_CompositeHexa_3D.cpp | 707 +- .../StdMeshers_CompositeSegment_1D.cpp | 231 +- .../StdMeshers/StdMeshers_Deflection1D.cpp | 41 +- .../StdMeshers/StdMeshers_Distribution.cpp | 44 +- .../src/StdMeshers/StdMeshers_FaceSide.cpp | 1190 +- .../StdMeshers/StdMeshers_FixedPoints1D.cpp | 244 + .../src/StdMeshers/StdMeshers_Geometric1D.cpp | 204 + .../StdMeshers/StdMeshers_HexaFromSkin_3D.cpp | 1303 ++ .../src/StdMeshers/StdMeshers_Hexa_3D.cpp | 1499 +- .../StdMeshers/StdMeshers_ImportSource.cpp | 497 + .../src/StdMeshers/StdMeshers_Import_1D.cpp | 1100 + .../src/StdMeshers/StdMeshers_Import_1D2D.cpp | 920 + .../StdMeshers_LayerDistribution.cpp | 37 +- .../StdMeshers_LayerDistribution2D.cpp | 59 + .../StdMeshers/StdMeshers_LengthFromEdges.cpp | 42 +- .../src/StdMeshers/StdMeshers_LocalLength.cpp | 50 +- .../src/StdMeshers/StdMeshers_MEFISTO_2D.cpp | 295 +- .../StdMeshers/StdMeshers_MaxElementArea.cpp | 40 +- .../StdMeshers_MaxElementVolume.cpp | 40 +- .../src/StdMeshers/StdMeshers_MaxLength.cpp | 49 +- .../StdMeshers_NotConformAllowed.cpp | 34 +- .../StdMeshers/StdMeshers_NumberOfLayers.cpp | 39 +- .../StdMeshers_NumberOfLayers2D.cpp | 60 + .../StdMeshers_NumberOfSegments.cpp | 222 +- .../src/StdMeshers/StdMeshers_Penta_3D.cpp | 605 +- .../StdMeshers_PolygonPerFace_2D.cpp | 158 + .../src/StdMeshers/StdMeshers_Prism_3D.cpp | 4597 +++- .../StdMeshers_ProjectionSource1D.cpp | 45 +- .../StdMeshers_ProjectionSource2D.cpp | 80 +- .../StdMeshers_ProjectionSource3D.cpp | 56 +- .../StdMeshers/StdMeshers_ProjectionUtils.cpp | 1961 +- .../StdMeshers/StdMeshers_Projection_1D.cpp | 167 +- .../StdMeshers/StdMeshers_Projection_1D2D.cpp | 301 + .../StdMeshers/StdMeshers_Projection_2D.cpp | 1560 +- .../StdMeshers/StdMeshers_Projection_3D.cpp | 246 +- .../src/StdMeshers/StdMeshers_Propagation.cpp | 151 +- .../StdMeshers_QuadFromMedialAxis_1D2D.cpp | 2098 ++ .../StdMeshers_QuadToTriaAdaptor.cpp | 1724 +- .../StdMeshers_QuadrangleParams.cpp | 215 + .../StdMeshers_QuadranglePreference.cpp | 56 +- .../StdMeshers/StdMeshers_Quadrangle_2D.cpp | 5562 ++++- .../StdMeshers/StdMeshers_QuadraticMesh.cpp | 33 +- .../StdMeshers/StdMeshers_RadialPrism_3D.cpp | 336 +- .../StdMeshers_RadialQuadrangle_1D2D.cpp | 1347 ++ .../src/StdMeshers/StdMeshers_Regular_1D.cpp | 635 +- .../StdMeshers/StdMeshers_Reversible1D.cpp | 99 + .../StdMeshers_SegmentAroundVertex_0D.cpp | 50 +- .../StdMeshers_SegmentLengthAroundVertex.cpp | 39 +- .../StdMeshers/StdMeshers_StartEndLength.cpp | 82 +- .../StdMeshers_UseExisting_1D2D.cpp | 76 +- .../StdMeshers/StdMeshers_ViscousLayers.cpp | 7799 +++++++ .../StdMeshers/StdMeshers_ViscousLayers2D.cpp | 2775 +++ 413 files changed, 126728 insertions(+), 27766 deletions(-) create mode 100644 src/3rdParty/salomesmesh/inc/Basics_OCCTVersion.hxx create mode 100644 src/3rdParty/salomesmesh/inc/Basics_Utils.hxx create mode 100644 src/3rdParty/salomesmesh/inc/DriverGMF.hxx create mode 100644 src/3rdParty/salomesmesh/inc/DriverGMF_Read.hxx create mode 100644 src/3rdParty/salomesmesh/inc/DriverGMF_Write.hxx create mode 100644 src/3rdParty/salomesmesh/inc/DriverMED.hxx create mode 100644 src/3rdParty/salomesmesh/inc/DriverMED_Family.h create mode 100644 src/3rdParty/salomesmesh/inc/DriverMED_R_SMESHDS_Mesh.h create mode 100644 src/3rdParty/salomesmesh/inc/DriverMED_W_Field.h create mode 100644 src/3rdParty/salomesmesh/inc/DriverMED_W_SMESHDS_Mesh.h create mode 100644 src/3rdParty/salomesmesh/inc/GEOMUtils.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_Algorithm.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_Common.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_CoordUtils.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_Factory.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_GaussDef.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_GaussUtils.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_SharedPtr.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_SliceArray.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_Structures.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_TStructures.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_TWrapper.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_Utilities.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_V2_2_Wrapper.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_Vector.hxx create mode 100644 src/3rdParty/salomesmesh/inc/MED_Wrapper.hxx create mode 100755 src/3rdParty/salomesmesh/inc/MED_WrapperBase.hxx create mode 100755 src/3rdParty/salomesmesh/inc/MED_WrapperFactory.hxx create mode 100644 src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_2D_ONLY_i.hxx create mode 100644 src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_2D_i.hxx create mode 100644 src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_3D_i.hxx create mode 100644 src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_i.hxx create mode 100644 src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D3D_i.hxx create mode 100644 src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D_ONLY_i.hxx create mode 100644 src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D_i.hxx create mode 100644 src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_3D_i.hxx create mode 100644 src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_2D_i.hxx create mode 100644 src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_3D_i.hxx create mode 100644 src/3rdParty/salomesmesh/inc/ObjectPool.hxx create mode 100644 src/3rdParty/salomesmesh/inc/OpUtil.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SALOMEDS.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SALOMEDS_Tool.hxx create mode 100755 src/3rdParty/salomesmesh/inc/SALOMEDS_defines.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SALOME_Basics.hxx create mode 100755 src/3rdParty/salomesmesh/inc/SALOME_Utils.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMDS_BallElement.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMDS_Downward.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMDS_IteratorOnIterators.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMDS_LinearEdge.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMDS_Mesh0DElement.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMDS_MeshCell.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMDS_MeshNodeIDFactory.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMDS_StdIterator.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMDS_UnstructuredGrid.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMDS_VtkCellIterator.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMDS_VtkEdge.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMDS_VtkFace.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMDS_VtkVolume.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMESHDS_GroupOnFilter.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMESHDS_TSubMeshHolder.hxx create mode 100755 src/3rdParty/salomesmesh/inc/SMESH_DriverGMF.hxx create mode 100755 src/3rdParty/salomesmesh/inc/SMESH_DriverMED.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMESH_File.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMESH_MAT2d.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMESH_MeshAlgos.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMESH_ProxyMesh.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMESH_Quadtree.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMESH_TryCatch.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMESH_TypeDefs.hxx create mode 100755 src/3rdParty/salomesmesh/inc/SMESH_Utils.hxx create mode 100644 src/3rdParty/salomesmesh/inc/SMESH_tree.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_Adaptive1D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_CartesianParameters3D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_Cartesian_3D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_FixedPoints1D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_Geometric1D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_HexaFromSkin_3D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_ImportSource.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_Import_1D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_Import_1D2D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_LayerDistribution2D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_NumberOfLayers2D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_PolygonPerFace_2D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_Projection_1D2D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_QuadFromMedialAxis_1D2D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_QuadrangleParams.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_RadialQuadrangle_1D2D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_Reversible1D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_ViscousLayers.hxx create mode 100644 src/3rdParty/salomesmesh/inc/StdMeshers_ViscousLayers2D.hxx create mode 100644 src/3rdParty/salomesmesh/inc/UNV164_Structure.hxx create mode 100644 src/3rdParty/salomesmesh/inc/UNV2420_Structure.hxx create mode 100644 src/3rdParty/salomesmesh/inc/Utils_ExceptHandlers.hxx create mode 100644 src/3rdParty/salomesmesh/inc/Utils_Mutex.hxx create mode 100644 src/3rdParty/salomesmesh/inc/Utils_SALOME_Exception.hxx create mode 100644 src/3rdParty/salomesmesh/inc/chrono.hxx create mode 100644 src/3rdParty/salomesmesh/inc/libmesh5.h create mode 100644 src/3rdParty/salomesmesh/inc/memoire.h delete mode 100644 src/3rdParty/salomesmesh/src/Controls/SMESHControls.cpp create mode 100644 src/3rdParty/salomesmesh/src/DriverSTL/Basics_Utils.cpp create mode 100644 src/3rdParty/salomesmesh/src/DriverSTL/SMESH_File.cpp create mode 100644 src/3rdParty/salomesmesh/src/DriverUNV/UNV164_Structure.cpp create mode 100644 src/3rdParty/salomesmesh/src/DriverUNV/UNV2420_Structure.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMDS/SMDS_BallElement.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMDS/SMDS_Downward.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMDS/SMDS_LinearEdge.cpp delete mode 100644 src/3rdParty/salomesmesh/src/SMDS/SMDS_MemoryLimit.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMDS/SMDS_Mesh0DElement.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshCell.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshNodeIDFactory.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMDS/SMDS_UnstructuredGrid.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkCellIterator.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkEdge.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkFace.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkVolume.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMDS/Utils_SALOME_Exception.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMDS/chrono.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMDS/duplicate.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/DriverGMF.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/DriverGMF_Read.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/DriverGMF_Write.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/DriverMED_Family.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/DriverMED_R_SMESHDS_Mesh.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/DriverMED_W_Field.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/DriverMED_W_SMESHDS_Mesh.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/GEOMUtils.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/MED_Algorithm.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/MED_CoordUtils.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/MED_Factory.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/MED_GaussDef.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/MED_GaussUtils.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/MED_Structures.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/MED_Utilities.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/MED_Wrapper.cpp delete mode 100644 src/3rdParty/salomesmesh/src/SMESH/SMESH_0D_Algo.cpp delete mode 100644 src/3rdParty/salomesmesh/src/SMESH/SMESH_1D_Algo.cpp delete mode 100644 src/3rdParty/salomesmesh/src/SMESH/SMESH_2D_Algo.cpp delete mode 100644 src/3rdParty/salomesmesh/src/SMESH/SMESH_3D_Algo.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshAlgos.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/SMESH_ProxyMesh.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/SMESH_TryCatch.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/Utils_ExceptHandlers.cpp create mode 100644 src/3rdParty/salomesmesh/src/SMESH/libmesh.c create mode 100644 src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_GroupOnFilter.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/SMESH_MAT2d.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/SMESH_Quadtree.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Adaptive1D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_CartesianParameters3D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Cartesian_3D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_FixedPoints1D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Geometric1D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_HexaFromSkin_3D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ImportSource.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Import_1D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Import_1D2D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LayerDistribution2D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NumberOfLayers2D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_PolygonPerFace_2D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_1D2D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadFromMedialAxis_1D2D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadrangleParams.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialQuadrangle_1D2D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Reversible1D.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ViscousLayers.cpp create mode 100644 src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ViscousLayers2D.cpp diff --git a/src/3rdParty/salomesmesh/CMakeLists.txt b/src/3rdParty/salomesmesh/CMakeLists.txt index a07e1f2d5470..8fa2ac5e4bf1 100644 --- a/src/3rdParty/salomesmesh/CMakeLists.txt +++ b/src/3rdParty/salomesmesh/CMakeLists.txt @@ -17,7 +17,12 @@ if(CMAKE_COMPILER_IS_CLANGXX) endif() CMAKE_MINIMUM_REQUIRED(VERSION 2.6) - +find_package(VTK REQUIRED) +find_package(HDF5 REQUIRED) +find_package(OPENCASCADE) +find_package(MEDFile REQUIRED) +find_package(Boost COMPONENTS filesystem program_options regex signals system thread REQUIRED) +include(${VTK_USE_FILE}) include_directories( src/SMDS src/Driver @@ -34,6 +39,9 @@ include_directories( ${NGLIB_INCLUDE_DIR} ${NETGEN_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR} + ${VTK_INCLUDE_DIR} + ${HDF5_INCLUDE_DIR} + ${BOOST_INCLUDE_DIR} ) link_directories(${OCC_LIBRARY_DIR}) @@ -150,7 +158,7 @@ ENDIF(UNIX) ######### FILE(GLOB SMDS_source_files src/SMDS/*.cpp inc/SMDS*.hxx) ADD_LIBRARY(SMDS SHARED ${SMDS_source_files}) -TARGET_LINK_LIBRARIES(SMDS ${SMESH_LIBS}) +TARGET_LINK_LIBRARIES(SMDS ${SMESH_LIBS} ${HDF5_C_STATIC_LIBRARY} ${VTK_LIBRARIES}) SET_BIN_DIR(SMDS SMDS) if(WIN32) @@ -183,7 +191,7 @@ endif(WIN32) ############# FILE(GLOB DriverSTL_source_files src/DriverSTL/*.cpp inc/DriverSTL*.h*) ADD_LIBRARY(DriverSTL SHARED ${DriverSTL_source_files}) -TARGET_LINK_LIBRARIES(DriverSTL ${SMESH_LIBS} Driver SMDS) +TARGET_LINK_LIBRARIES(DriverSTL ${SMESH_LIBS} Driver SMDS ${Boost_LIBRARIES}) SET_BIN_DIR(DriverSTL DriverSTL) if(WIN32) @@ -244,7 +252,7 @@ endif(WIN32) ########### FILE(GLOB SMESHDS_source_files src/SMESHDS/*.cpp inc/SMESHDS_*.h*) ADD_LIBRARY(SMESHDS SHARED ${SMESHDS_source_files}) -TARGET_LINK_LIBRARIES(SMESHDS ${SMESH_LIBS} SMDS ) +TARGET_LINK_LIBRARIES(SMESHDS ${SMESH_LIBS} SMDS ${Boost_LIBRARIES} ) SET_BIN_DIR(SMESHDS SMESHDS) @@ -256,9 +264,9 @@ SET_BIN_DIR(SMESHDS SMESHDS) ######### # SMESH # ######### -FILE(GLOB SMESH_source_files src/SMESH/*.cpp src/Controls/*.cpp inc/SMESH_*.h*) +FILE(GLOB SMESH_source_files src/SMESH/*.c src/SMESH/*.cpp src/Controls/*.cpp inc/SMESH_*.h*) ADD_LIBRARY(SMESH SHARED ${SMESH_source_files}) -TARGET_LINK_LIBRARIES(SMESH SMDS SMESHDS Driver DriverSTL DriverDAT DriverUNV ${SMESH_LIBS}) +TARGET_LINK_LIBRARIES(SMESH SMDS SMESHDS Driver DriverSTL DriverDAT DriverUNV ${SMESH_LIBS} ${OPENCASCADE_LIBRARIES} ${OCC_LIBRARIES} ${OCC_DEBUG_LIBRARIES} ${OCC_OCAF_DEBUG_LIBRARIES} ${OCC_OCAF_LIBRARIES} ${MEDFILE_LIBRARIES}) SET_BIN_DIR(SMESH SMESH) if(WIN32) @@ -362,7 +370,7 @@ if (BUILD_FEM_NETGEN) ################ FILE(GLOB NETGENPlugin_source_files src/NETGENPlugin/*.cpp inc/NETGENPlugin_*.h* ) ADD_LIBRARY(NETGENPlugin SHARED ${NETGENPlugin_source_files}) -TARGET_LINK_LIBRARIES(NETGENPlugin SMDS SMESHDS SMESH StdMeshers ${SMESH_LIBS} ) +TARGET_LINK_LIBRARIES(NETGENPlugin SMDS SMESHDS SMESH StdMeshers ${SMESH_LIBS} ) SET_BIN_DIR(NETGENPlugin NETGENPlugin) if(WIN32) diff --git a/src/3rdParty/salomesmesh/inc/Basics_OCCTVersion.hxx b/src/3rdParty/salomesmesh/inc/Basics_OCCTVersion.hxx new file mode 100644 index 000000000000..2f9b49423e33 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/Basics_OCCTVersion.hxx @@ -0,0 +1,51 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : Basics_OCCTVersion.hxx +// Author : Julia DOROVSKIKH, Open CASCADE S.A.S (julia.dorovskikh@opencascade.com) + +#ifndef BASICS_OCCTVERSION_HXX +#define BASICS_OCCTVERSION_HXX + +#include + +// +// NOTE: Since version 6.7.0 OCC_VERSION_DEVELOPMENT macro in the Standard_Version.hxx +// points to the development status of the OCCT version: for example "dev", "alpha", +// "beta", "rc1", etc. +// OCC_VERSION_MAJOR, OCC_VERSION_MINOR and OCC_VERSION_MAINTENANCE macros +// specify actual (final) version number; for development version it is a future +// target version number (i.e. version number is incremented immediately after +// releasing of the stable version). +// + +#ifdef OCC_VERSION_SERVICEPACK +# define OCC_VERSION_LARGE (OCC_VERSION_MAJOR << 24 | OCC_VERSION_MINOR << 16 | OCC_VERSION_MAINTENANCE << 8 | OCC_VERSION_SERVICEPACK) +#else +# ifdef OCC_VERSION_DEVELOPMENT +# define OCC_VERSION_LARGE ((OCC_VERSION_MAJOR << 24 | OCC_VERSION_MINOR << 16 | OCC_VERSION_MAINTENANCE << 8)-1) +# else +# define OCC_VERSION_LARGE (OCC_VERSION_MAJOR << 24 | OCC_VERSION_MINOR << 16 | OCC_VERSION_MAINTENANCE << 8) +# endif +#endif + +#endif // BASICS_OCCTVERSION_HXX diff --git a/src/3rdParty/salomesmesh/inc/Basics_Utils.hxx b/src/3rdParty/salomesmesh/inc/Basics_Utils.hxx new file mode 100644 index 000000000000..dd97bb9a68a7 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/Basics_Utils.hxx @@ -0,0 +1,143 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SALOME Utils : general SALOME's definitions and tools +// File : Basics_DirUtils.hxx +// Autor : Alexander A. BORODIN +// Module : SALOME +// +#ifndef _Basics_UTILS_HXX_ +#define _Basics_UTILS_HXX_ + +#include "SALOME_Basics.hxx" +#include +#include + +#ifndef WIN32 +#include +#else +#include +#include +#pragma comment(lib,"winmm.lib") +#endif + + +namespace Kernel_Utils +{ + BASICS_EXPORT std::string GetHostname(); + + class BASICS_EXPORT Localizer + { + public: + Localizer(); + ~Localizer(); + private: + std::string myCurLocale; + }; + + //! GUID type + enum GUIDtype { + DefUserID = 1, //!< Default user attribute ID + ObjectdID //!< Global usage object identifier ID + }; + + //! Get predefined GUID + BASICS_EXPORT std::string GetGUID( GUIDtype ); +#ifndef WIN32 + BASICS_EXPORT void print_traceback(); +#else +#if (_MSC_VER >= 1400) // Visual Studio 2005 + BASICS_EXPORT int setenv(const char*, const char*, int); +#endif +#endif +} + + +// +// ============================================================= +// Helper macro for time analysis +// ============================================================= +// +#ifndef WIN32 +#define START_TIMING(name) static long name##tcount=0;static long name##cumul;long name##tt0; timeval name##tv; gettimeofday(&name##tv,0); \ + name##tt0=name##tv.tv_usec+name##tv.tv_sec*1000000; \ + if(name##tcount==0)std::cerr<<__FILE__<<":"<<__LINE__<<":"<<#name< +#include +#include + +template < class T > +std::string ToString(const T &arg) +{ + std::stringstream out; + out << arg; + return(out.str()); +} + +template < class T > +double ToDouble(const T &arg) { + std::stringstream out; + out << arg; + double value = atof(out.str().c_str()); + return value; +} + +// +// ============================================================= +// Simple Logger macros (no dependency with SALOME) +// ============================================================= +// +#if defined(_DEBUG_) || defined(_DEBUG) +#define STDLOG(msg) {std::cerr< + +namespace DriverGMF +{ + /*! + * \brief An object closing GMF mesh at destruction + */ + struct MeshCloser + { + int _gmfMeshID; + MeshCloser( const int gmfMeshID ): _gmfMeshID(gmfMeshID) {} + ~MeshCloser(); + }; + + bool isExtensionCorrect( const std::string& fileName ); +} + +#endif diff --git a/src/3rdParty/salomesmesh/inc/DriverGMF_Read.hxx b/src/3rdParty/salomesmesh/inc/DriverGMF_Read.hxx new file mode 100644 index 000000000000..49b2a975e2bf --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/DriverGMF_Read.hxx @@ -0,0 +1,64 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : DriverGMF_Read.hxx +// Created : Mon Sep 17 15:36:47 2012 +// Author : Edward AGAPOV (eap) + + +#ifndef __DriverGMF_Read_HXX__ +#define __DriverGMF_Read_HXX__ + +#include "SMESH_DriverGMF.hxx" + +#include "Driver_SMESHDS_Mesh.h" + +#include +#include + +/*! + * \brief Driver reading a mesh from the GMF file. The mesh to read is selected by + * an index (counted form 0) set via SetMeshId() + */ +class MESHDriverGMF_EXPORT DriverGMF_Read : public Driver_SMESHDS_Mesh +{ +public: + + DriverGMF_Read(); + ~DriverGMF_Read(); + + void SetMakeRequiredGroups( bool theMakeRequiredGroups ) + { + _makeRequiredGroups = theMakeRequiredGroups; + } + + virtual Status Perform(); + + private: + + Status storeBadNodeIds(const char* gmfKwd, int elemNb, int nb, ...); + + bool _makeRequiredGroups; + +}; + + +#endif diff --git a/src/3rdParty/salomesmesh/inc/DriverGMF_Write.hxx b/src/3rdParty/salomesmesh/inc/DriverGMF_Write.hxx new file mode 100644 index 000000000000..cb2e6f12adc1 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/DriverGMF_Write.hxx @@ -0,0 +1,93 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : DriverGMF_Write.hxx +// Created : Mon Sep 17 15:36:47 2012 +// Author : Edward AGAPOV (eap) + + +#ifndef __DriverGMF_Write_HXX__ +#define __DriverGMF_Write_HXX__ + +#include "SMESH_DriverGMF.hxx" + +#include "Driver_SMESHDS_Mesh.h" +#include "SMDSAbs_ElementType.hxx" +#include "SMDS_ElemIterator.hxx" + +#include + +/*! + * \brief Class for storing control points for writing GMF size maps + */ +class MESHDriverGMF_EXPORT Control_Pnt : public gp_Pnt +{ +public: + Control_Pnt(); + Control_Pnt(const gp_Pnt& aPnt, double theSize); + Control_Pnt(double x, double y, double z); + Control_Pnt(double x, double y, double z, double size); + + double Size() const { return size; }; + void SetSize( double theSize ) { size = theSize; }; + +private: + double size; +}; + +/*! + * \brief Driver Writing a mesh into a GMF file. + */ +class MESHDriverGMF_EXPORT DriverGMF_Write : public Driver_SMESHDS_Mesh +{ +public: + + DriverGMF_Write(); + ~DriverGMF_Write(); + + void SetExportRequiredGroups( bool toExport ) + { + _exportRequiredGroups = toExport; + } + + virtual Status Perform(); + + // Size Maps + Status PerformSizeMap( const std::vector& points ); + void SetSizeMapPrefix( std::string prefix ) + { + myVerticesFile = prefix + ".mesh"; + mySolFile = prefix + ".sol"; + }; + std::vector GetSizeMapFiles(); + + private: + + SMDS_ElemIteratorPtr elementIterator(SMDSAbs_ElementType type); + SMDS_ElemIteratorPtr elementIterator(SMDSAbs_EntityType type); + SMDS_ElemIteratorPtr elementIterator(SMDSAbs_GeometryType type); + + bool _exportRequiredGroups; + std::string myVerticesFile; + std::string mySolFile; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/DriverMED.hxx b/src/3rdParty/salomesmesh/inc/DriverMED.hxx new file mode 100644 index 000000000000..08c4d848d032 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/DriverMED.hxx @@ -0,0 +1,46 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// Declarations needed for usage of DriverMED + +#include "SMDSAbs_ElementType.hxx" +#include "SMESH_DriverMED.hxx" + +#include + +class DriverMED_Family; +typedef boost::shared_ptr DriverMED_FamilyPtr; + +namespace DriverMED +{ + // Implemetation is in DriverMED_W_Field.cxx + + /* + * Returns MED element geom type (MED::EGeometrieElement) by SMDS type + */ + MESHDRIVERMED_EXPORT int GetMedGeoType( SMDSAbs_EntityType smdsType ); + + /* + * Returns SMDS element geom type by MED type (MED::EGeometrieElement) + */ + MESHDRIVERMED_EXPORT SMDSAbs_EntityType GetSMDSType( int medType ); +} diff --git a/src/3rdParty/salomesmesh/inc/DriverMED_Family.h b/src/3rdParty/salomesmesh/inc/DriverMED_Family.h new file mode 100644 index 000000000000..0f77a01ed275 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/DriverMED_Family.h @@ -0,0 +1,144 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH DriverMED : tool to split groups on families +// File : DriverMED_Family.hxx +// Author : Julia DOROVSKIKH +// Module : SMESH +// +#ifndef _INCLUDE_DRIVERMED_FAMILY +#define _INCLUDE_DRIVERMED_FAMILY + +#include "SMESH_DriverMED.hxx" +#include "DriverMED.hxx" + +#include "SMDS_Mesh.hxx" +#include "SMESHDS_GroupBase.hxx" +#include "SMESHDS_SubMesh.hxx" +#include "MED_Common.hxx" + +#include +#include + +#define REST_NODES_FAMILY 1 +#define FIRST_NODE_FAMILY 2 + +#define REST_EDGES_FAMILY -1 +#define REST_FACES_FAMILY -2 +#define REST_VOLUMES_FAMILY -3 +#define REST_0DELEM_FAMILY -4 +#define REST_BALL_FAMILY -5 +#define FIRST_ELEM_FAMILY -6 + +typedef std::list DriverMED_FamilyPtrList; +typedef std::map SMESHDS_SubMeshPtrMap; +typedef std::list SMESHDS_GroupBasePtrList; +typedef std::set ElementsSet; + +class MESHDRIVERMED_EXPORT DriverMED_Family +{ + public: + + DriverMED_Family(); + + //! Methods for groups storing to MED + /*! + Split each group from list and each sub-mesh from list + on some parts (families) on the basis of the elements membership in other groups + from and other sub-meshes from . + Resulting families have no common elements. + */ + static + DriverMED_FamilyPtrList + MakeFamilies (SMESHDS_SubMeshIteratorPtr theSubMeshes, + const SMESHDS_GroupBasePtrList& theGroups, + const bool doGroupOfNodes, + const bool doGroupOfEdges, + const bool doGroupOfFaces, + const bool doGroupOfVolumes, + const bool doGroupOf0DElems, + const bool doGroupOfBalls); + + //! Create TFamilyInfo for this family + MED::PFamilyInfo + GetFamilyInfo (const MED::PWrapper& theWrapper, + const MED::PMeshInfo& theMeshInfo) const; + + //! Returns elements of this family + const ElementsSet& GetElements () const; + + //! Returns a family ID + int GetId () const; + + //! Sets a family ID + void SetId (const int theId); + + public: + + // Methods for groups reading from MED + + void AddElement(const SMDS_MeshElement* theElement); + + const MED::TStringSet& GetGroupNames() const; + void AddGroupName(std::string theGroupName); + + void SetType(const SMDSAbs_ElementType theType); + SMDSAbs_ElementType GetType(); + const std::set< SMDSAbs_ElementType >& GetTypes() const; + + bool MemberOf(std::string theGroupName) const; + + int GetGroupAttributVal() const; + void SetGroupAttributVal( int theValue); + + private: + //! Initialize the tool by SMESHDS_GroupBase + void Init (SMESHDS_GroupBase* group); + + //! Split on some parts (families) on the basis of the elements type. + static + DriverMED_FamilyPtrList + SplitByType(SMESHDS_SubMesh* theSubMesh, + const int theId); + + + /*! Remove from elements, common with , + Remove from elements, common with , + Create family from common elements, with combined groups list. + */ + void Split (DriverMED_FamilyPtr by, + DriverMED_FamilyPtr common); + + //! Check, if this family has empty list of elements + bool IsEmpty () const; + + + private: + int myId; + SMDSAbs_ElementType myType; + ElementsSet myElements; + MED::TStringSet myGroupNames; + int myGroupAttributVal; + std::set myTypes; // Issue 0020576 +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/DriverMED_R_SMESHDS_Mesh.h b/src/3rdParty/salomesmesh/inc/DriverMED_R_SMESHDS_Mesh.h new file mode 100644 index 000000000000..12b395105d74 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/DriverMED_R_SMESHDS_Mesh.h @@ -0,0 +1,64 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH DriverMED : driver to read and write 'med' files +// File : DriverMED_R_SMESHDS_Mesh.h +// Module : SMESH +// +#ifndef _INCLUDE_DRIVERMED_R_SMESHDS_MESH +#define _INCLUDE_DRIVERMED_R_SMESHDS_MESH + +#include "SMESH_DriverMED.hxx" + +#include "DriverMED.hxx" +#include "Driver_SMESHDS_Mesh.h" +#include "SMDSAbs_ElementType.hxx" + +#include +#include + +class SMESHDS_Mesh; +class SMESHDS_Group; +class SMESHDS_SubMesh; + +typedef std::pair< std::string, SMDSAbs_ElementType > TNameAndType; + +class MESHDRIVERMED_EXPORT DriverMED_R_SMESHDS_Mesh: public Driver_SMESHDS_Mesh +{ + public: + virtual Status Perform(); + + std::list< TNameAndType > GetGroupNamesAndTypes(); + void GetGroup(SMESHDS_Group* theGroup); + void CreateAllSubMeshes(); + void GetSubMesh(SMESHDS_SubMesh* theSubMesh, const int theId); + + std::list GetMeshNames(Status& theStatus); + void SetMeshName(std::string theMeshName); + + private: + std::string myMeshName; + std::map myFamilies; + +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/DriverMED_W_Field.h b/src/3rdParty/salomesmesh/inc/DriverMED_W_Field.h new file mode 100644 index 000000000000..a6512bad18b1 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/DriverMED_W_Field.h @@ -0,0 +1,83 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH DriverMED : driver to write a field to 'med' file +// Module : SMESH +// +#ifndef _INCLUDE_DriverMED_W_Field +#define _INCLUDE_DriverMED_W_Field + +#include "SMESH_DriverMED.hxx" + +#include "Driver_SMESHDS_Mesh.h" +#include "SMDSAbs_ElementType.hxx" +#include "SMDS_ElemIterator.hxx" + +#include +#include + +class MESHDRIVERMED_EXPORT DriverMED_W_Field: public Driver_SMESHDS_Mesh +{ + public: + + DriverMED_W_Field(); + + void AddODOnVertices(bool toAdd) { _addODOnVertices = toAdd; } + + bool Set(SMESHDS_Mesh * mesh, + const std::string & fieldName, + SMDSAbs_ElementType type, + const int nbComps, + const bool isIntData); + + void SetCompName(const int iComp, const char* name); + + void SetDtIt(const int dt, const int it); + + void AddValue( double val ); + void AddValue( int val ); + + /* + * Returns elements in the order they are written in MED file. Result can be NULL! + */ + SMDS_ElemIteratorPtr GetOrderedElems(); + + /* + * Add one field to the file + */ + virtual Status Perform(); + + private: + + std::string _fieldName; + SMDSAbs_ElementType _elemType; + std::vector< std::string > _compNames; + std::vector< double > _dblValues; + std::vector< int > _intValues; + int _dt, _it; + bool _addODOnVertices; + + std::vector< const SMDS_MeshElement* > _elemsByGeom[SMDSEntity_Last]; + std::vector< std::pair< SMDSAbs_EntityType, int > > _nbElemsByGeom; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/DriverMED_W_SMESHDS_Mesh.h b/src/3rdParty/salomesmesh/inc/DriverMED_W_SMESHDS_Mesh.h new file mode 100644 index 000000000000..873adf450284 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/DriverMED_W_SMESHDS_Mesh.h @@ -0,0 +1,93 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH DriverMED : driver to read and write 'med' files +// File : DriverMED_W_SMESHDS_Mesh.h +// Module : SMESH +// +#ifndef _INCLUDE_DRIVERMED_W_SMESHDS_MESH +#define _INCLUDE_DRIVERMED_W_SMESHDS_MESH + +#include "SMESH_DriverMED.hxx" + +#include "Driver_SMESHDS_Mesh.h" +#include "MED_Common.hxx" + +#include +#include +#include +#include + +class SMESHDS_Mesh; +class SMESHDS_GroupBase; +class SMESHDS_SubMesh; + +class MESHDRIVERMED_EXPORT DriverMED_W_SMESHDS_Mesh: public Driver_SMESHDS_Mesh +{ + public: + + DriverMED_W_SMESHDS_Mesh(); + + virtual void SetFile(const std::string& theFileName); + void SetFile(const std::string& theFileName, MED::EVersion theId); + void SetAutoDimension(bool toFindOutDimension) { myAutoDimension = toFindOutDimension; } + + static std::string GetVersionString(const MED::EVersion theVersion, int theNbDigits=2); + + void AddGroupOfNodes(); + void AddGroupOfEdges(); + void AddGroupOfFaces(); + void AddGroupOfVolumes(); + void AddGroupOf0DElems(); + void AddGroupOfBalls(); + + /*! functions to prepare adding one mesh + */ + void AddGroup(SMESHDS_GroupBase * theGroup); + void AddAllSubMeshes(); + void AddSubMesh(SMESHDS_SubMesh* theSubMesh, int theID); + void AddODOnVertices(bool toAdd) { myAddODOnVertices = toAdd; } + + static bool getNodesOfMissing0DOnVert(SMESHDS_Mesh* mesh, + std::vector& nodes); + + /*! add one mesh + */ + virtual Status Perform(); + + private: + + MED::EVersion myMedVersion; + std::list myGroups; + bool myAllSubMeshes; + std::vector mySubMeshes; + bool myDoGroupOfNodes; + bool myDoGroupOfEdges; + bool myDoGroupOfFaces; + bool myDoGroupOfVolumes; + bool myDoGroupOf0DElems; + bool myDoGroupOfBalls; + bool myAutoDimension; + bool myAddODOnVertices; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/DriverSTL_R_SMDS_Mesh.h b/src/3rdParty/salomesmesh/inc/DriverSTL_R_SMDS_Mesh.h index c541daf1bd3e..214f1404f226 100644 --- a/src/3rdParty/salomesmesh/inc/DriverSTL_R_SMDS_Mesh.h +++ b/src/3rdParty/salomesmesh/inc/DriverSTL_R_SMDS_Mesh.h @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #ifndef _INCLUDE_DRIVERSTL_R_SMDS_MESH #define _INCLUDE_DRIVERSTL_R_SMDS_MESH @@ -26,7 +27,7 @@ #include "Driver_SMDS_Mesh.h" -#include +class SMESH_File; class MESHDRIVERSTL_EXPORT DriverSTL_R_SMDS_Mesh: public Driver_SMDS_Mesh { @@ -37,8 +38,8 @@ class MESHDRIVERSTL_EXPORT DriverSTL_R_SMDS_Mesh: public Driver_SMDS_Mesh private: // PRIVATE METHODS - Status readAscii() const; - Status readBinary() const; + Status readAscii (SMESH_File& file) const; + Status readBinary(SMESH_File& file) const; private: // PRIVATE FIELDS diff --git a/src/3rdParty/salomesmesh/inc/DriverSTL_W_SMDS_Mesh.h b/src/3rdParty/salomesmesh/inc/DriverSTL_W_SMDS_Mesh.h index 04979d4fcd94..472610f0be47 100644 --- a/src/3rdParty/salomesmesh/inc/DriverSTL_W_SMDS_Mesh.h +++ b/src/3rdParty/salomesmesh/inc/DriverSTL_W_SMDS_Mesh.h @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH DriverSTL : driver to read and write 'stl' files // File : DriverSTL_W_SMDS_Mesh.h // Module : SMESH @@ -29,13 +30,19 @@ #include "SMESH_DriverSTL.hxx" #include "Driver_SMDS_Mesh.h" -#include +#include "SMDS_ElemIterator.hxx" + +#include +/*! + * \brief Writer of a mesh in STL (STereoLithography) file format. + */ class MESHDRIVERSTL_EXPORT DriverSTL_W_SMDS_Mesh: public Driver_SMDS_Mesh { public: DriverSTL_W_SMDS_Mesh(); + ~DriverSTL_W_SMDS_Mesh(); virtual Status Perform(); void SetIsAscii( const bool theIsAscii = false ); @@ -43,10 +50,15 @@ class MESHDRIVERSTL_EXPORT DriverSTL_W_SMDS_Mesh: public Driver_SMDS_Mesh // PRIVATE METHODS Status writeAscii () const; Status writeBinary () const; + void findVolumeTriangles(); + + SMDS_ElemIteratorPtr getFaces() const; private: // PRIVATE FIELDS bool myIsAscii; + int myNbVolumeTrias; + std::vector myVolumeFacets; // tmp faces }; #endif diff --git a/src/3rdParty/salomesmesh/inc/DriverUNV_R_SMDS_Mesh.h b/src/3rdParty/salomesmesh/inc/DriverUNV_R_SMDS_Mesh.h index d385dac32ab5..a50ee47f69be 100644 --- a/src/3rdParty/salomesmesh/inc/DriverUNV_R_SMDS_Mesh.h +++ b/src/3rdParty/salomesmesh/inc/DriverUNV_R_SMDS_Mesh.h @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #ifndef _INCLUDE_DRIVERUNV_R_SMDS_MESH #define _INCLUDE_DRIVERUNV_R_SMDS_MESH diff --git a/src/3rdParty/salomesmesh/inc/DriverUNV_W_SMDS_Mesh.h b/src/3rdParty/salomesmesh/inc/DriverUNV_W_SMDS_Mesh.h index 6a76da655c0e..d09d2d4058d2 100644 --- a/src/3rdParty/salomesmesh/inc/DriverUNV_W_SMDS_Mesh.h +++ b/src/3rdParty/salomesmesh/inc/DriverUNV_W_SMDS_Mesh.h @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #ifndef _INCLUDE_DRIVERUNV_W_SMDS_MESH #define _INCLUDE_DRIVERUNV_W_SMDS_MESH diff --git a/src/3rdParty/salomesmesh/inc/Driver_Document.h b/src/3rdParty/salomesmesh/inc/Driver_Document.h index d8779719d640..dc7cac68abff 100644 --- a/src/3rdParty/salomesmesh/inc/Driver_Document.h +++ b/src/3rdParty/salomesmesh/inc/Driver_Document.h @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #ifndef _INCLUDE_DRIVER_DOCUMENT #define _INCLUDE_DRIVER_DOCUMENT diff --git a/src/3rdParty/salomesmesh/inc/Driver_Mesh.h b/src/3rdParty/salomesmesh/inc/Driver_Mesh.h index 9840ed034635..cada40f96763 100644 --- a/src/3rdParty/salomesmesh/inc/Driver_Mesh.h +++ b/src/3rdParty/salomesmesh/inc/Driver_Mesh.h @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH Driver : implementaion of driver for reading and writing // File : Mesh_Reader.h // Module : SMESH @@ -26,10 +27,13 @@ #ifndef _INCLUDE_DRIVER_MESH #define _INCLUDE_DRIVER_MESH +#include "SMESH_ComputeError.hxx" + #include +#include -#ifdef WNT - #if defined MESHDRIVER_EXPORTS +#ifdef WIN32 + #if defined MESHDRIVER_EXPORTS || defined MeshDriver_EXPORTS #define MESHDRIVER_EXPORT __declspec( dllexport ) #else #define MESHDRIVER_EXPORT __declspec( dllimport ) @@ -50,17 +54,30 @@ class MESHDRIVER_EXPORT Driver_Mesh DRS_WARN_RENUMBER, // a file has overlapped ranges of element numbers, // so the numbers from the file are ignored DRS_WARN_SKIP_ELEM, // some elements were skipped due to incorrect file data + DRS_WARN_DESCENDING, // some elements were skipped due to descending connectivity DRS_FAIL // general failure (exception etc.) }; + void SetMeshId(int theMeshId); + virtual void SetFile(const std::string& theFileName); + virtual void SetMeshName(const std::string& theMeshName); + virtual std::string GetMeshName() const; + + virtual void SetOption(const std::string& optionName, + const std::string& optionValue) {} + virtual Status Perform() = 0; - void SetMeshId(int theMeshId); - void SetFile(const std::string& theFileName); + + virtual SMESH_ComputeErrorPtr GetError(); protected: std::string myFile; - int myMeshId; + std::string myMeshName; + int myMeshId; + Status addMessage(const std::string& msg, const bool isFatal=false); + std::vector< std::string > myErrorMessages; + Status myStatus; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/Driver_SMDS_Mesh.h b/src/3rdParty/salomesmesh/inc/Driver_SMDS_Mesh.h index 6391a009b994..090345714296 100644 --- a/src/3rdParty/salomesmesh/inc/Driver_SMDS_Mesh.h +++ b/src/3rdParty/salomesmesh/inc/Driver_SMDS_Mesh.h @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #ifndef _INCLUDE_DRIVER_SMDS_MESH #define _INCLUDE_DRIVER_SMDS_MESH diff --git a/src/3rdParty/salomesmesh/inc/Driver_SMESHDS_Mesh.h b/src/3rdParty/salomesmesh/inc/Driver_SMESHDS_Mesh.h index 4ea15e0ad12a..05a03baa9ede 100644 --- a/src/3rdParty/salomesmesh/inc/Driver_SMESHDS_Mesh.h +++ b/src/3rdParty/salomesmesh/inc/Driver_SMESHDS_Mesh.h @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #ifndef _INCLUDE_DRIVER_SMESHDS_MESH #define _INCLUDE_DRIVER_SMESHDS_MESH diff --git a/src/3rdParty/salomesmesh/inc/GEOMUtils.hxx b/src/3rdParty/salomesmesh/inc/GEOMUtils.hxx new file mode 100644 index 000000000000..8ffa25be2e10 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/GEOMUtils.hxx @@ -0,0 +1,346 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +#ifndef _GEOMUtils_HXX_ +#define _GEOMUtils_HXX_ + +#include +#include +#include + +#include + +#include + +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include + +class Bnd_Box; + +inline Standard_Boolean IsEqual (const TopoDS_Shape& S1, const TopoDS_Shape& S2) +{ + return S1.IsSame(S2); +} + +namespace GEOMUtils +{ + + typedef std::vector NodeLinks; + typedef std::map LevelInfo; + typedef std::vector LevelsList; + typedef std::map > TreeModel; + + /*! + * \brief Compute numerical functor for the shape. + * + * Resulting value can be used to sort out shapes according to some parameter. + * + * Returns a pair of two values (dist, functor) where + * - \a dist is a some value that is computed according to the center of mass of given shape; + * - \a functor is a numerical functor value + * + * The numerical functor is computed according to the shape's topological properties as follows: + * - orientation for vertices + * - length for edges and wires + * - area for faces and shells + * - volume for solids, compounds, compsolids + * + * If \a isOldSorting parameter is set to \c true, for all cases linear properties of the shape + * are used (to support backward compatibility in some methods). By default, this parameter is + * set to \c false. + */ + Standard_EXPORT std::pair ShapeToDouble (const TopoDS_Shape& theShape, + bool isOldSorting = false); + + /*! + * \brief Get Local Coordinate System, corresponding to the given shape. + * + * Origin of the LCS is situated at the shape's center of mass. + * Axes of the LCS are obtained from shape's location or, + * if the shape is a planar face, from position of its plane. + */ + Standard_EXPORT gp_Ax3 GetPosition (const TopoDS_Shape& theShape); + + /*! + * \brief Get vector, defined by the given edge. + * \param theShape The edge. + * \param doConsiderOrientation If True, take into account the edge orientation. + * \note It is recommended to use doConsiderOrientation=Standard_False, because + * the same edge can have different orientation depending on the way it was + * extracted from a shape. + */ + Standard_EXPORT gp_Vec GetVector (const TopoDS_Shape& theShape, + Standard_Boolean doConsiderOrientation); + + /*! + * \brief Sort shapes in the list by their coordinates. + * \param SL The list of shapes to sort. + */ + struct CompareShapes : public std::binary_function + { + CompareShapes (bool isOldSorting) + : myIsOldSorting(isOldSorting) {} + + bool operator() (const TopoDS_Shape& lhs, const TopoDS_Shape& rhs); + + typedef NCollection_DataMap > GEOMUtils_DataMapOfShapeDouble; + GEOMUtils_DataMapOfShapeDouble myMap; + bool myIsOldSorting; + }; + + /*! + * \brief Sort shapes by their centers of mass, using formula X*999 + Y*99 + Z*0.9 + */ + Standard_EXPORT void SortShapes (TopTools_ListOfShape& SL, + const Standard_Boolean isOldSorting = Standard_True); + + /*! + * \brief Convert TopoDS_COMPSOLID to TopoDS_COMPOUND. + * + * If the argument shape is not of type TopoDS_COMPSOLID, this method returns it as is. + * + * \param theCompsolid The compsolid to be converted. + * \retval TopoDS_Shape Returns the resulting compound. + */ + Standard_EXPORT TopoDS_Shape CompsolidToCompound (const TopoDS_Shape& theCompsolid); + + /*! + * \brief Recursively extract all shapes from compounds and compsolids of the given shape into theList. + * + * If theShape is not compound or compsolid, theList will contain only theShape itself. + * + * \param theShape The shape to be exploded. + * \param theList Output parameter. + */ + Standard_EXPORT void AddSimpleShapes (const TopoDS_Shape& theShape, + TopTools_ListOfShape& theList); + + /*! + * \brief Build a triangulation on \a theShape if it is absent. + * \param theShape The shape to check/build triangulation on. + * \retval bool Returns false if the shape has no faces, i.e. impossible to build triangulation. + */ + Standard_EXPORT bool CheckTriangulation (const TopoDS_Shape& theShape); + + /*! + * \brief Return type of shape for explode. In case of compound it will be a type of its first sub shape. + * \param theShape The shape to get type of. + * \retval TopAbs_ShapeEnum Return type of shape for explode. + */ + Standard_EXPORT TopAbs_ShapeEnum GetTypeOfSimplePart (const TopoDS_Shape& theShape); + + /*! + * \brief Find an edge of theShape, closest to thePoint. + * + * \param theShape The shape to explore. + * \param thePoint The point near the required edge. + * \retval TopoDS_Shape Returns the found edge or an empty shape if multiple edges found. + */ + Standard_EXPORT TopoDS_Shape GetEdgeNearPoint (const TopoDS_Shape& theShape, + const TopoDS_Vertex& thePoint); + + /*! + * \brief Compute precise bounding box of the shape based on the rough bounding box. + * + * \param theShape the shape. + * \param theBox rough bounding box on input; precise bounding box on output. + * \retval Standard_True in case of success; Standard_False otherwise. + */ + Standard_EXPORT Standard_Boolean PreciseBoundingBox(const TopoDS_Shape &theShape, Bnd_Box &theBox); + + /*! + * \brief Computes minumal distance between two shapes for singular cases + * (workaround for bugs 19899, 19908 and 19910 from Mantis). + * + * \param aSh1 the first shape + * \param aSh2 the second shape + * \param Ptmp1 the output result point on the first shape + * \param Ptmp2 the output result point on the second shape + * \retval negative value if it is not a singular case; actual distance for singular case. + */ + Standard_EXPORT Standard_Real GetMinDistanceSingular(const TopoDS_Shape& aSh1, + const TopoDS_Shape& aSh2, + gp_Pnt& Ptmp1, gp_Pnt& Ptmp2); + + /*! + * \brief Computes minumal distance between two shapes. + * + * \param theShape1 the first shape + * \param theShape2 the second shape + * \param thePnt1 the output result point on the first shape + * \param thePnt2 the output result point on the second shape + * \retval negative value in case of failure; otherwise the real distance. + */ + Standard_EXPORT Standard_Real GetMinDistance(const TopoDS_Shape& theShape1, + const TopoDS_Shape& theShape2, + gp_Pnt& thePnt1, gp_Pnt& thePnt2); + + /*! + * \brief Returns the point clicked in 3D view. + * + * \param x The X coordinate in the view. + * \param y The Y coordinate in the view. + * \param theView View where the given point takes place. + * \retval gp_Pnt Returns the point clicked in 3D view + */ + Standard_EXPORT gp_Pnt ConvertClickToPoint( int x, int y, Handle(V3d_View) theView ); + + /*! + * \brief Convert dependency tree data to the string representation + * + * \param tree dependency tree data + * \param dependencyStr output string + */ + Standard_EXPORT void ConvertTreeToString( const TreeModel& tree, + std::string& dependencyStr ); + + /*! + * \brief Restore dependency tree data from the string representation + * + * \param dependencyStr string representation of tree data + * \param tree output dependency tree data + */ + Standard_EXPORT void ConvertStringToTree( const std::string& dependencyStr, + TreeModel& tree ); + + /*! + * \brief Check shape + * + * \param shape input shape object + * \param checkGeometry when set to \c true, causes check of underlying geometry + * in addition to the topology + * \return \c true if shape is valid or \c false otherwise + */ + Standard_EXPORT bool CheckShape( TopoDS_Shape& shape, bool checkGeometry = false ); + + /*! + * \brief Limit shape tolerance to the given value + * + * \param shape shape being fixed + * \param type topology type which tolerance is to be limited; TopAbs_SHAPE means + * all types of topology + * \param tolerance expected tolerance value (1e-7 by default) + * \param checkGeometry check geometry validity of result + * \return \c true if resulting shape is valid + * + * \note Resulting tolerance of the shape is not mandatory equal to requested value + * as it might be changed by fixshape operation in order to get valid shape where possible + * \note By default, result only checked for topology validity; check of geometry can be done by + * passing \c true to \a checkGeometry parameter + */ + Standard_EXPORT bool FixShapeTolerance( TopoDS_Shape& shape, + TopAbs_ShapeEnum type, + Standard_Real tolerance = Precision::Confusion(), + bool checkGeometry = false ); + + /*! + * \brief Limit shape tolerance to the given value + * This is overloaded function, it behaves exactly as previous one + */ + Standard_EXPORT bool FixShapeTolerance( TopoDS_Shape& shape, + Standard_Real tolerance = Precision::Confusion(), + bool checkGeometry = false ); + + /*! + * \brief Limit shape tolerance to the given value + * This is overloaded function, it behaves exactly as previous one + */ + Standard_EXPORT bool FixShapeTolerance( TopoDS_Shape& shape, + bool checkGeometry ); + + /*! + * \brief Fix curves of the given shape + * + * The function checks each curve of the input shape in the following way: + * - compute deviation of the curve from the underlying surface in a set of points + * computed with the certain discretization step value + * - find maximum tolerance between computed deviation values + * - limit tolerance of the curve with the computed maximum value + * + * \param shape shape being fixed + * \return \c true if resulting shape is valid + */ + Standard_EXPORT bool FixShapeCurves( TopoDS_Shape& shape ); + + /*! + * \brief Write shape to the BREP file + * + * \param source shape + * \return \c true if file was written or \c false otherwise + */ + Standard_EXPORT bool Write( const TopoDS_Shape& shape, + const char* fileName ); + + /*! + * \brief Extract single SOLID from COMPSOLID or COMPOUND. + * + * If the argument shape is a COMPUND or COMPSOLID and there's + * only single simple-shape type inside, this sub-shape is returned as a result; + * otherwise, the shape is not changed. + * + * \param shape compound or compsolid being processed. + * \retval TopoDS_Shape resulting shape + */ + Standard_EXPORT TopoDS_Shape ReduceCompound( const TopoDS_Shape& shape ); + + /*! + * \brief Generate triangulation for the shape. + * + * \param shape shape being meshed + * \param deflection deflection coefficient to be used + * \param forced if \c true, causes generation of mesh regardless it is already present in the shape + */ + Standard_EXPORT void MeshShape( const TopoDS_Shape shape, + double deflection, bool forced = true ); + + /*! + * \brief Get default deflection coefficient used for triangulation + * \return default deflection value + */ + Standard_EXPORT double DefaultDeflection(); + + /** + * \brief Check if the shape is not a closed wire or edge. + * + * This function is used for pipe creation algorithm to test if + * the pipe path is not closed. It returns false if theShape is a wire or + * an edge with coincident end vertices. Otherwise it returns true. + * + * \param theShape the shape to be tested. + * \return true if theShape is not a closed wire or edge. + */ + Standard_EXPORT bool IsOpenPath(const TopoDS_Shape &theShape); + +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/Handle_SMESH_MeshVSLink.hxx b/src/3rdParty/salomesmesh/inc/Handle_SMESH_MeshVSLink.hxx index dc29a000809f..57e005857bb7 100644 --- a/src/3rdParty/salomesmesh/inc/Handle_SMESH_MeshVSLink.hxx +++ b/src/3rdParty/salomesmesh/inc/Handle_SMESH_MeshVSLink.hxx @@ -1,83 +1,84 @@ -// SMESH SMESH_MeshVSLink : Connection of SMESH with MeshVS from OCC -// -// 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 : SMESH_MeshVSLink.cxx -// Created : Mon Dec 1 09:00:00 2008 -// Author : Sioutis Fotios -// Module : SMESH - -#ifndef _Handle_SMESH_MeshVSLink_HeaderFile -#define _Handle_SMESH_MeshVSLink_HeaderFile - -#ifndef _Standard_Macro_HeaderFile -#include -#endif -#ifndef _Standard_HeaderFile -#include -#endif -#ifndef _Standard_Version_HeaderFile -#include -#endif - -#if OCC_VERSION_HEX < 0x070000 -#ifndef _Handle_MeshVS_DataSource3D_HeaderFile -#include -#endif - -class Standard_Transient; -class Handle_Standard_Type; -class Handle(MeshVS_DataSource3D); -class SMESH_MeshVSLink; - -Standard_EXPORT Handle_Standard_Type& STANDARD_TYPE(SMESH_MeshVSLink); - -class Handle(SMESH_MeshVSLink) : public Handle(MeshVS_DataSource3D) { - public: - Handle(SMESH_MeshVSLink)():Handle(MeshVS_DataSource3D)() {} - Handle(SMESH_MeshVSLink)(const Handle(SMESH_MeshVSLink)& aHandle) : Handle(MeshVS_DataSource3D)(aHandle) - { - } - - Handle(SMESH_MeshVSLink)(const SMESH_MeshVSLink* anItem) : Handle(MeshVS_DataSource3D)((MeshVS_DataSource3D *)anItem) - { - } - - Handle(SMESH_MeshVSLink)& operator=(const Handle(SMESH_MeshVSLink)& aHandle) - { - Assign(aHandle.Access()); - return *this; - } - - Handle(SMESH_MeshVSLink)& operator=(const SMESH_MeshVSLink* anItem) - { - Assign((Standard_Transient *)anItem); - return *this; - } - - SMESH_MeshVSLink* operator->() const - { - return (SMESH_MeshVSLink *)ControlAccess(); - } - - Standard_EXPORT static const Handle(SMESH_MeshVSLink) DownCast(const Handle(Standard_Transient)& AnObject); -}; -#endif // OCC_VERSION_HEX < 0x070000 -#endif +// SMESH SMESH_MeshVSLink : Connection of SMESH with MeshVS from OCC +// +// 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 : SMESH_MeshVSLink.cxx +// Created : Mon Dec 1 09:00:00 2008 +// Author : Sioutis Fotios +// Module : SMESH + +#ifndef _Handle_SMESH_MeshVSLink_HeaderFile +#define _Handle_SMESH_MeshVSLink_HeaderFile + +#ifndef _Standard_Macro_HeaderFile +#include +#endif +#ifndef _Standard_HeaderFile +#include +#endif +#ifndef _Standard_Version_HeaderFile +#include +#endif + +#if OCC_VERSION_HEX < 0x070000 +#ifndef _Handle_MeshVS_DataSource3D_HeaderFile +//#include +#include +#endif + +class Standard_Transient; +class Handle_Standard_Type; +class Handle(MeshVS_DataSource3D); +class SMESH_MeshVSLink; + +Standard_EXPORT Handle_Standard_Type& STANDARD_TYPE(SMESH_MeshVSLink); + +class Handle(SMESH_MeshVSLink) : public Handle(MeshVS_DataSource3D) { + public: + Handle(SMESH_MeshVSLink)():Handle(MeshVS_DataSource3D)() {} + Handle(SMESH_MeshVSLink)(const Handle(SMESH_MeshVSLink)& aHandle) : Handle(MeshVS_DataSource3D)(aHandle) + { + } + + Handle(SMESH_MeshVSLink)(const SMESH_MeshVSLink* anItem) : Handle(MeshVS_DataSource3D)((MeshVS_DataSource3D *)anItem) + { + } + + Handle(SMESH_MeshVSLink)& operator=(const Handle(SMESH_MeshVSLink)& aHandle) + { + Assign(aHandle.Access()); + return *this; + } + + Handle(SMESH_MeshVSLink)& operator=(const SMESH_MeshVSLink* anItem) + { + Assign((Standard_Transient *)anItem); + return *this; + } + + SMESH_MeshVSLink* operator->() const + { + return (SMESH_MeshVSLink *)ControlAccess(); + } + + Standard_EXPORT static const Handle(SMESH_MeshVSLink) DownCast(const Handle(Standard_Transient)& AnObject); +}; +#endif // OCC_VERSION_HEX < 0x070000 +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_Algorithm.hxx b/src/3rdParty/salomesmesh/inc/MED_Algorithm.hxx new file mode 100644 index 000000000000..4c2dcc8c0b0a --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_Algorithm.hxx @@ -0,0 +1,156 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// +#ifndef MED_Algorithm_HeaderFile +#define MED_Algorithm_HeaderFile + +#include "MED_WrapperBase.hxx" +#include "MED_Structures.hxx" + +#include + +namespace MED +{ + //--------------------------------------------------------------- + typedef std::map TGeom2ElemInfo; + typedef std::map TEntity2TGeom2ElemInfo; + + //! Get set of TElemInfo by its geometrical type and corresponding MED ENTITY + MEDWRAPPER_EXPORT + TEntity2TGeom2ElemInfo + GetEntity2TGeom2ElemInfo(const PWrapper& theWrapper, + const PMeshInfo& theMeshInfo, + const MED::TEntityInfo& theEntityInfo); + + + //--------------------------------------------------------------- + typedef std::set TFamilyInfoSet; + + //! Read set of MED FAMILIES for defined MED file + MEDWRAPPER_EXPORT + TFamilyInfoSet + GetFamilyInfoSet(const PWrapper& theWrapper, + const PMeshInfo& theMeshInfo); + + + //--------------------------------------------------------------- + typedef boost::tuple TFamilyTSize; + + bool + operator<(const TFamilyTSize& theLeft, const TFamilyTSize& theRight); + typedef std::set TFamilyTSizeSet; + + + //--------------------------------------------------------------- + typedef std::map TEntity2FamilySet; + + //! Split set of MED FAMILIES by corresponding MED ENTITY + MEDWRAPPER_EXPORT + TEntity2FamilySet + GetEntity2FamilySet(const PWrapper& theWrapper, + const TEntity2TGeom2ElemInfo& theEntity2TGeom2ElemInfo, + const TFamilyInfoSet& theFamilyInfoSet); + + + //--------------------------------------------------------------- + typedef std::map TGroupInfo; + + //! Split the input set of MED FAMILIES by corresponding MED GROUPS + MEDWRAPPER_EXPORT + TGroupInfo + GetGroupInfo(const TFamilyInfoSet& theFamilyInfoSet); + + + //--------------------------------------------------------------- + typedef std::set TTimeStampInfoSet; + typedef std::map TFieldInfo2TimeStampInfoSet; + + //! Read set of MED TIMESTAMPS groupped by corresponding MED FIELDS + MEDWRAPPER_EXPORT + TFieldInfo2TimeStampInfoSet + GetFieldInfo2TimeStampInfoSet(const PWrapper& theWrapper, + const PMeshInfo& theMeshInfo, + const MED::TEntityInfo& theEntityInfo); + + + //--------------------------------------------------------------- + typedef std::map TEntite2TFieldInfo2TimeStampInfoSet; + + //! Split the input set of MED TIMESTAMPS by corresponding MED FIELDS and MED ENTITIES + MEDWRAPPER_EXPORT + TEntite2TFieldInfo2TimeStampInfoSet + GetEntite2TFieldInfo2TimeStampInfoSet(const TFieldInfo2TimeStampInfoSet& theFieldInfo2TimeStampInfoSet); + + + //--------------------------------------------------------------- + typedef std::map TKey2Gauss; + + //! Read set of MED GAUSS + MEDWRAPPER_EXPORT + TKey2Gauss + GetKey2Gauss(const PWrapper& theWrapper, + TErr* theErr = NULL, + EModeSwitch theMode = eFULL_INTERLACE); + + + //--------------------------------------------------------------- + //! Get MED PROFILE by its name + MEDWRAPPER_EXPORT + PProfileInfo + GetProfileInfo(const PWrapper& theWrapper, + const std::string& theProfileName, + TErr* theErr = NULL, + EModeProfil theMode = eCOMPACT); + + + //--------------------------------------------------------------- + typedef std::map TKey2Profile; + typedef boost::tuple TMKey2Profile; + + //! Read set of MED PROFILES + MEDWRAPPER_EXPORT + TMKey2Profile + GetMKey2Profile(const PWrapper& theWrapper, + TErr* theErr = NULL, + EModeProfil theMode = eCOMPACT); + + //--------------------------------------------------------------- + //! Get Entity for Grille by family id. + MEDWRAPPER_EXPORT + EEntiteMaillage + GetEntityByFamilyId(PGrilleInfo& theInfo, + TInt theId); + + typedef std::map TFamilyID2NbCells; + + //! Get Number of cells for theId family, for Grille + MEDWRAPPER_EXPORT + TFamilyID2NbCells + GetFamilyID2NbCells(PGrilleInfo& theInfo); + + //! Convert eNOEUD_ELEMENT to eMAILLE + MEDWRAPPER_EXPORT + EEntiteMaillage + ConvertEntity(const EEntiteMaillage& aEntity); + +} + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_Common.hxx b/src/3rdParty/salomesmesh/inc/MED_Common.hxx new file mode 100644 index 000000000000..3f80849ba3c4 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_Common.hxx @@ -0,0 +1,184 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +#ifndef MED_Common_HeaderFile +#define MED_Common_HeaderFile + +#include "MED_WrapperBase.hxx" + +#include +#include +#include + +#include + +#include + +#include "MED_Vector.hxx" +#include "MED_SharedPtr.hxx" +#include "MED_SliceArray.hxx" + +#ifdef WIN32 +#pragma warning(disable:4099) +#endif + +namespace MED{ + + enum EVersion {eVUnknown = -1, eV2_1, eV2_2}; + + typedef enum {eFAUX, eVRAI} EBooleen ; + typedef double TFloat; +#if defined(HAVE_F77INT64) + typedef long TInt; +#else + typedef int TInt; +#endif + typedef hid_t TIdt; + typedef herr_t TErr; + + typedef enum {eFULL_INTERLACE, eNO_INTERLACE} EModeSwitch; + + typedef enum {eFLOAT64=6, eINT=24, eLONG=26 } ETypeChamp; + + typedef enum {eNON_STRUCTURE, eSTRUCTURE} EMaillage; + + typedef enum {eCART, eCYL, eSPHER} ERepere; + + typedef enum {eNOD, eDESC} EConnectivite ; + + typedef enum {ePOINT1=1, eSEG2=102, eSEG3=103, eTRIA3=203, + eQUAD4=204, eTRIA6=206, eTRIA7=207, eQUAD8=208, eQUAD9=209,eTETRA4=304, + ePYRA5=305, ePENTA6=306, eHEXA8=308, eOCTA12=312, eTETRA10=310, + ePYRA13=313, ePENTA15=315, eHEXA20=320, eHEXA27=327, + ePOLYGONE=400, ePOLYGON2=420, ePOLYEDRE=500, eNONE=0, + eBALL=1101 /*no such a type in med.h, it's just a trick*/, + eAllGeoType=-1 } EGeometrieElement; + + typedef enum {eMAILLE, eFACE, eARETE, eNOEUD, eNOEUD_ELEMENT, eSTRUCT_ELEMENT} EEntiteMaillage; + + typedef enum {eNO_PFLMOD, eGLOBAL, eCOMPACT} EModeProfil; + + typedef enum {eGRILLE_CARTESIENNE, eGRILLE_POLAIRE, eGRILLE_STANDARD} EGrilleType; + + typedef enum {eCOOR, eCONN, eNOM, eNUM, eFAM, eCOOR_IND1, eCOOR_IND2, eCOOR_IND3} ETable; + + typedef TVector TFloatVector; + typedef TVector TStringVector; + typedef TVector TIntVector; + typedef std::set TStringSet; + + typedef std::map TGeom2Size; + typedef std::map TEntityInfo; + + typedef std::set TGeomSet; + typedef std::map TEntity2GeomSet; + + MEDWRAPPER_EXPORT + const TEntity2GeomSet& + GetEntity2GeomSet(); + + template + TInt MEDWRAPPER_EXPORT + GetDESCLength(); + + template + TInt MEDWRAPPER_EXPORT + GetIDENTLength(); + + template + TInt MEDWRAPPER_EXPORT + GetNOMLength(); + + template + TInt MEDWRAPPER_EXPORT + GetLNOMLength(); + + template + TInt MEDWRAPPER_EXPORT + GetPNOMLength(); + + template + void MEDWRAPPER_EXPORT + GetVersionRelease(TInt& majeur, TInt& mineur, TInt& release); + + template + MEDWRAPPER_EXPORT + TInt + GetNbConn(EGeometrieElement typmai, + EEntiteMaillage typent, + TInt mdim); + + MEDWRAPPER_EXPORT + TInt + GetNbNodes(EGeometrieElement typmai); + + struct TNameInfo; + typedef SharedPtr PNameInfo; + + struct TMeshInfo; + typedef SharedPtr PMeshInfo; + + struct TFamilyInfo; + typedef SharedPtr PFamilyInfo; + + struct TElemInfo; + typedef SharedPtr PElemInfo; + + struct TNodeInfo; + typedef SharedPtr PNodeInfo; + + struct TPolygoneInfo; + typedef SharedPtr PPolygoneInfo; + + struct TPolyedreInfo; + typedef SharedPtr PPolyedreInfo; + + struct TCellInfo; + typedef SharedPtr PCellInfo; + + struct TBallInfo; + typedef SharedPtr PBallInfo; + + struct TFieldInfo; + typedef SharedPtr PFieldInfo; + + struct TTimeStampInfo; + typedef SharedPtr PTimeStampInfo; + + struct TProfileInfo; + typedef SharedPtr PProfileInfo; + + struct TGaussInfo; + typedef SharedPtr PGaussInfo; + + class TGrilleInfo; + typedef SharedPtr PGrilleInfo; + + struct TTimeStampValueBase; + typedef SharedPtr PTimeStampValueBase; + + struct TWrapper; + typedef SharedPtr PWrapper; +} + + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_CoordUtils.hxx b/src/3rdParty/salomesmesh/inc/MED_CoordUtils.hxx new file mode 100644 index 000000000000..01c8446b0220 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_CoordUtils.hxx @@ -0,0 +1,56 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// +#ifndef MED_CoordUtils_HeaderFile +#define MED_CoordUtils_HeaderFile + +#include "MED_WrapperBase.hxx" + +#include "MED_Structures.hxx" + +namespace MED +{ + typedef TFloat (*TGetCoord)(const TCCoordSlice& theCoordSlice); + + + //--------------------------------------------------------------- + class MEDWRAPPER_EXPORT TCoordHelper + { + TGetCoord* myGetCoord; + + public: + TCoordHelper(TGetCoord* theGetCoord); + + TFloat + GetCoord(TCCoordSlice& theCoordSlice, + TInt theCoordId); + }; + typedef SharedPtr PCoordHelper; + + + //--------------------------------------------------------------- + MEDWRAPPER_EXPORT + PCoordHelper + GetCoordHelper(PNodeInfo theNodeInfo); + +} + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_Factory.hxx b/src/3rdParty/salomesmesh/inc/MED_Factory.hxx new file mode 100644 index 000000000000..930d17a0da7c --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_Factory.hxx @@ -0,0 +1,49 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +#ifndef MED_Factory_HeaderFile +#define MED_Factory_HeaderFile + +#include "MED_WrapperFactory.hxx" +#include "MED_Wrapper.hxx" + +namespace MED +{ + MEDWRAPPER_FACTORY_EXPORT + EVersion + GetVersionId(const std::string& theFileName, + bool theDoPreCheckInSeparateProcess = false); + + MEDWRAPPER_FACTORY_EXPORT + bool getMEDVersion( const std::string&, int&, int&, int& ); + + MEDWRAPPER_FACTORY_EXPORT + PWrapper + CrWrapper(const std::string& theFileName, + bool theDoPreCheckInSeparateProcess = false); + + MEDWRAPPER_FACTORY_EXPORT + PWrapper + CrWrapper(const std::string& theFileName, EVersion theId); +} + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_GaussDef.hxx b/src/3rdParty/salomesmesh/inc/MED_GaussDef.hxx new file mode 100644 index 000000000000..b5ef03d798c7 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_GaussDef.hxx @@ -0,0 +1,69 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 : MED_GaussDef.hxx +// Author : Edward AGAPOV (eap) +// +#ifndef MED_GaussDef_HeaderFile +#define MED_GaussDef_HeaderFile + +#include "MED_WrapperBase.hxx" + +//#include "MED_GaussUtils.hxx" <<<---- avoid dependence on boost +#include + +namespace MED +{ + class TShapeFun; + typedef std::vector TDoubleVector; + /*! + * \brief Description of family of integration points + */ + struct TGaussDef + { + int myType; //!< element geometry (EGeometrieElement or med_geometrie_element) + TDoubleVector myRefCoords; //!< description of reference points + TDoubleVector myCoords; //!< coordinates of Gauss points + TDoubleVector myWeights; //!< weights, len(weights)== + + /*! + * \brief Creates definition of gauss points family + * \param geomType - element geometry (EGeometrieElement or med_geometrie_element) + * \param nbPoints - nb gauss point + * \param variant - [1-3] to choose the variant of definition + * + * Throws in case of invalid parameters + * variant == 1 refers to "Fonctions de forme et points d'integration + * des elements finis" v7.4 by J. PELLET, X. DESROCHES, 15/09/05 + * variant == 2 refers to the same doc v6.4 by J.P. LEFEBVRE, X. DESROCHES, 03/07/03 + * variant == 3 refers to the same doc v6.4, second variant for 2D elements + */ + MEDWRAPPER_EXPORT TGaussDef(const int geomType, const int nbPoints, const int variant=1); + + MEDWRAPPER_EXPORT int dim() const { return myType/100; } + MEDWRAPPER_EXPORT int nbPoints() const { return myWeights.capacity(); } + + private: + void add(const double x, const double weight); + void add(const double x, const double y, const double weight); + void add(const double x, const double y, const double z, const double weight); + void setRefCoords(const TShapeFun& aShapeFun); + }; +} + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_GaussUtils.hxx b/src/3rdParty/salomesmesh/inc/MED_GaussUtils.hxx new file mode 100644 index 000000000000..d2bafc497cb3 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_GaussUtils.hxx @@ -0,0 +1,365 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// +#ifndef MED_GaussUtils_HeaderFile +#define MED_GaussUtils_HeaderFile + +#include "MED_WrapperBase.hxx" + +#include "MED_Structures.hxx" + +namespace MED +{ + //--------------------------------------------------------------- + typedef TVector TCCoordSliceArr; + typedef TVector TCoordSliceArr; + + //! Define a helper class to handle Gauss Points coordinates + class MEDWRAPPER_EXPORT TGaussCoord: + virtual TModeSwitchInfo + { + TInt myNbElem; + TInt myNbGauss; + TInt myDim; + + TInt myGaussStep; + + TNodeCoord myGaussCoord; + + public: + + TGaussCoord(); + + //! To init the class + void + Init(TInt theNbElem, + TInt theNbGauss, + TInt theDim, + EModeSwitch theMode = eFULL_INTERLACE); + + TInt + GetNbElem() const; + + TInt + GetNbGauss() const; + + TInt + GetDim() const; + + unsigned char* + GetValuePtr(); + + //! Get slice of the coordinate that corresponds to defined cell (const version) + TCCoordSliceArr + GetCoordSliceArr(TInt theElemId) const; + + //! Get slice of the coordinate that corresponds to defined cell + TCoordSliceArr + GetCoordSliceArr(TInt theElemId); + }; + typedef SharedPtr PGaussCoord; + + + //--------------------------------------------------------------- + //! To calculate Gauss Points coordinates + MEDWRAPPER_EXPORT + bool + GetGaussCoord3D(const TGaussInfo& theGaussInfo, + const TCellInfo& theCellInfo, + const TNodeInfo& theNodeInfo, + TGaussCoord& theGaussCoord, + const TElemNum& theElemNum = TElemNum(), + EModeSwitch theMode = eFULL_INTERLACE); + + + //--------------------------------------------------------------- + //! To calculate Gauss Points coordinates for defined TCellInfo as its bary center + MEDWRAPPER_EXPORT + bool + GetBaryCenter(const TCellInfo& theCellInfo, + const TNodeInfo& theNodeInfo, + TGaussCoord& theGaussCoord, + const TElemNum& theElemNum = TElemNum(), + EModeSwitch theMode = eFULL_INTERLACE); + + //! To calculate Gauss Points coordinates for defined TPolygoneInfo as its bary center + MEDWRAPPER_EXPORT + bool + GetBaryCenter(const TPolygoneInfo& thePolygoneInfo, + const TNodeInfo& theNodeInfo, + TGaussCoord& theGaussCoord, + const TElemNum& theElemNum = TElemNum(), + EModeSwitch theMode = eFULL_INTERLACE); + + //! To calculate Gauss Points coordinates for defined TPolyedreInfo as its bary center + MEDWRAPPER_EXPORT + bool + GetBaryCenter(const TPolyedreInfo& thePolyedreInfo, + const TNodeInfo& theNodeInfo, + TGaussCoord& theGaussCoord, + const TElemNum& theElemNum = TElemNum(), + EModeSwitch theMode = eFULL_INTERLACE); + + //--------------------------------------------------------------- + //! Shape function definitions + //--------------------------------------------------------------- + struct MEDWRAPPER_EXPORT TShapeFun + { + class TFun; + + TFloatVector myRefCoord; + TInt myDim; + TInt myNbRef; + + TShapeFun(TInt theDim = 0, TInt theNbRef = 0); + + TInt GetNbRef() const { return myNbRef; } + + TCCoordSlice GetCoord(TInt theRefId) const; + + TCoordSlice GetCoord(TInt theRefId); + + void GetFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + virtual + void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const = 0; + virtual + bool IsSatisfy(const TCCoordSliceArr& theRefCoord) const; + + bool Eval(const TCellInfo& theCellInfo, + const TNodeInfo& theNodeInfo, + const TElemNum& theElemNum, + const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TGaussCoord& theGaussCoord, + EModeSwitch theMode); + }; + //--------------------------------------------------------------- + struct TSeg2a: TShapeFun { + TSeg2a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TSeg3a: TShapeFun { + TSeg3a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TTria3a: TShapeFun { + TTria3a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TTria6a: TShapeFun { + TTria6a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TTria3b: TShapeFun { + TTria3b(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TTria6b: TShapeFun { + TTria6b(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TQuad4a: TShapeFun { + TQuad4a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TQuad8a: TShapeFun { + TQuad8a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TQuad9a: TShapeFun { + TQuad9a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TQuad4b: TShapeFun { + TQuad4b(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TQuad8b: TShapeFun { + TQuad8b(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TQuad9b: TShapeFun { + TQuad9b(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TTetra4a: TShapeFun { + TTetra4a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TTetra10a: TShapeFun { + TTetra10a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TTetra4b: TShapeFun { + TTetra4b(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TTetra10b: TShapeFun { + TTetra10b(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct THexa8a: TShapeFun { + THexa8a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct THexa20a: TShapeFun { + THexa20a(TInt theDim = 3, TInt theNbRef = 20); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct THexa27a: THexa20a { + THexa27a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct THexa8b: TShapeFun { + THexa8b(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct THexa20b: TShapeFun { + THexa20b(TInt theDim = 3, TInt theNbRef = 20); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TPenta6a: TShapeFun { + TPenta6a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TPenta6b: TShapeFun { + TPenta6b(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TPenta15a: TShapeFun { + TPenta15a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TPenta15b: TShapeFun { + TPenta15b(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TPyra5a: TShapeFun { + TPyra5a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TPyra5b: TShapeFun { + TPyra5b(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TPyra13a: TShapeFun { + TPyra13a(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + struct TPyra13b: TShapeFun { + TPyra13b(); + virtual void InitFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const; + }; + //--------------------------------------------------------------- + +} + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_SharedPtr.hxx b/src/3rdParty/salomesmesh/inc/MED_SharedPtr.hxx new file mode 100644 index 000000000000..7477805f16e6 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_SharedPtr.hxx @@ -0,0 +1,95 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// +#ifndef MED_SharedPtr_HeaderFile +#define MED_SharedPtr_HeaderFile + +#include + +namespace MED +{ + + //! To extend the boost::shared_ptr to support such features automatic dynamic cast + /*! + All entities of the MEDWrapper package are handled as pointer. + This class was introduced to provide correct and flexible memory management + for all of the MEDWrapper objects. + */ + template class SharedPtr: public boost::shared_ptr + { + public: + //! Default constructor + SharedPtr() {} + + //! Construct the class by any type of a pointer + template + explicit SharedPtr(Y * p): + boost::shared_ptr(p) + {} + + //! Construct the class by any specialisation of the class + template + SharedPtr(SharedPtr const & r): + boost::shared_ptr(boost::dynamic_pointer_cast(r)) + {} + + //! Copy-constructor + template + SharedPtr& + operator=(SharedPtr const & r) + { + SharedPtr(r).swap(*this); + return *this; + } + + //! Introduce a flexible way to reset the wrapped pointer + template + SharedPtr& + operator()(Y * p) // Y must be complete + { + return operator=(SharedPtr(p)); + } + + //! Introduce a flexible way to reset the wrapped pointer + template + SharedPtr& + operator()(SharedPtr const & r) // Y must be complete + { + return operator=(SharedPtr(r)); + } + + //! To provide a flexible way to use reference to the wrapped pointer (const version) + operator const T& () const + { + return *(this->get()); + } + + //! To provide a flexible way to use reference to the wrapped pointer + operator T& () + { + return *(this->get()); + } + }; + +} + + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_SliceArray.hxx b/src/3rdParty/salomesmesh/inc/MED_SliceArray.hxx new file mode 100644 index 000000000000..9eb9241460b7 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_SliceArray.hxx @@ -0,0 +1,185 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// +#ifndef MED_SliceArray_HeaderFile +#define MED_SliceArray_HeaderFile + +#ifdef WIN32 // for correctly compiling "valarray" in modules, which are includes this file + #undef max + #undef min +#endif + +#include +#include + +//#if defined(_DEBUG_) +# define MED_TCSLICE_CHECK_RANGE +//#endif + +namespace MED +{ + //--------------------------------------------------------------- + //! This class intends to provide an uniform way to handle multy-dimention data (const version) + /*! + It just contains pointer to real sequence and implement proper calcultion of its indexes. + This class deal with constant pointer to the sources data and provide const method to + read the them (data). + */ + template + class TCSlice + { + const TValueType* myCValuePtr; //!< Reference to source multy-dimension data + size_t mySourceSize; //!< Size of the source multy-dimension data + std::slice mySlice; //!< Defines algorithm of index calculation + + protected: + void + check_id(size_t theId) const + { + long int anId = -1; + if(theId < mySlice.size()){ + anId = mySlice.start() + theId*mySlice.stride(); + if(anId < (long int)mySourceSize) + return; + } + throw std::out_of_range("TCSlice::check_id"); + } + + //! Calculate internal index to get proper element from the source multy-dimension data + size_t + calculate_id(size_t theId) const + { + return mySlice.start() + theId*mySlice.stride(); + } + + size_t + get_id(size_t theId) const + { +#ifdef MED_TCSLICE_CHECK_RANGE + check_id(theId); +#endif + return calculate_id(theId); + } + + size_t + get_id_at(size_t theId) const + { + check_id(theId); + return calculate_id(theId); + } + + public: + typedef TValueType value_type; + + //! Construct the class from bare pointer + TCSlice(const value_type* theValuePtr, + size_t theSourceSize, + const std::slice& theSlice): + myCValuePtr(theValuePtr), + mySourceSize(theSourceSize), + mySlice(theSlice) + {} + + //! Construct the class from corresponding container + TCSlice(const TVector& theContainer, + const std::slice& theSlice): + myCValuePtr(&theContainer[0]), + mySourceSize(theContainer.size()), + mySlice(theSlice) + {} + + //! Default constructor (dangerous) + TCSlice(): + myCValuePtr(NULL) + {} + + //! Get element by its number (const version) + const value_type& + operator[](size_t theId) const + { + return *(myCValuePtr + get_id(theId)); + } + + const value_type& + at(size_t theId) const + { + return *(myCValuePtr + get_id_at(theId)); + } + + //! Get range of the order numbers + size_t + size() const + { + return mySlice.size(); + } + }; + + + //--------------------------------------------------------------- + //! This class extend TCSlice functionality for non-constant case + template + class TSlice: public TCSlice + { + TValueType* myValuePtr; + + public: + typedef TValueType value_type; + typedef TCSlice TSupperClass; + + //! Construct the class from bare pointer + TSlice(value_type* theValuePtr, + size_t theSourceSize, + const std::slice& theSlice): + TSupperClass(theValuePtr, theSourceSize, theSlice), + myValuePtr(theValuePtr) + {} + + //! Construct the class from corresponding container + TSlice(TVector& theContainer, + const std::slice& theSlice): + TSupperClass(theContainer, theSlice), + myValuePtr(&theContainer[0]) + {} + + //! Default constructor (dangerous) + TSlice(): + myValuePtr(NULL) + {} + + //! Get element by its number + value_type& + operator[](size_t theId) + { + return *(myValuePtr + this->get_id(theId)); + } + + value_type& + at(size_t theId) + { + return *(myValuePtr + this->get_id_at(theId)); + } + }; + +} + +#undef MED_TCSLICE_CHECK_RANGE + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_Structures.hxx b/src/3rdParty/salomesmesh/inc/MED_Structures.hxx new file mode 100644 index 000000000000..0f1d1a21a84b --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_Structures.hxx @@ -0,0 +1,1081 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +#ifndef MED_Structures_HeaderFile +#define MED_Structures_HeaderFile + +#include "MED_Common.hxx" +#include "MED_Utilities.hxx" + +#ifdef WIN32 +#pragma warning(disable:4251) +#endif + +namespace MED +{ + + //--------------------------------------------------------------- + //! Defines a type for managing sequence of strings + typedef TVector TString; + typedef SharedPtr PString; + + //! Extract a substring from the sequence of the strings + MEDWRAPPER_EXPORT + std::string + GetString(TInt theId, TInt theStep, + const TString& theString); + + //! Set a substring in the sequence of the strings + MEDWRAPPER_EXPORT + void + SetString(TInt theId, TInt theStep, + TString& theString, + const std::string& theValue); + + //! Set a substring in the sequence of the strings + MEDWRAPPER_EXPORT + void + SetString(TInt theId, TInt theStep, + TString& theString, + const TString& theValue); + + //--------------------------------------------------------------- + //! Define a parent class for all MEDWrapper classes + struct MEDWRAPPER_EXPORT TBase + { + virtual ~TBase() {} + }; + + + //--------------------------------------------------------------- + //! Define a parent class for all named MED entities + struct MEDWRAPPER_EXPORT TNameInfo: virtual TBase + { + TString myName; //!< Keeps its name + virtual std::string GetName() const = 0; //!< Gets its name + virtual void SetName(const std::string& theValue) = 0; //!< Set a new name + virtual void SetName(const TString& theValue) = 0; //!< Set a new name + }; + + + //--------------------------------------------------------------- + //! Define a parent class for all MED entities that contains a sequence of numbers + /*! + It defines through corresponding enumeration (EModeSwitch) how the sequence + should be interpreted in C or Fortran mode (eFULL_INTERLACE or eNON_INTERLACE). + */ + struct MEDWRAPPER_EXPORT TModeSwitchInfo: virtual TBase + { + //! To construct instance of the class by default + TModeSwitchInfo(): + myModeSwitch(eFULL_INTERLACE) + {} + + //! To construct instance of the class + TModeSwitchInfo(EModeSwitch theModeSwitch): + myModeSwitch(theModeSwitch) + {} + + EModeSwitch myModeSwitch; //!< Keeps the + EModeSwitch GetModeSwitch() const { return myModeSwitch;} + }; + + + //--------------------------------------------------------------- + //! Define a base class which represents MED Mesh entity + struct MEDWRAPPER_EXPORT TMeshInfo: virtual TNameInfo + { + TInt myDim; //!< Dimension of the mesh (0, 1, 2 or 3) + TInt GetDim() const { return myDim;} //!< Gets dimension of the mesh + + TInt mySpaceDim; + TInt GetSpaceDim() const { return mySpaceDim; } + + EMaillage myType; //!< Type of the mesh + EMaillage GetType() const { return myType;} //!< Gets type of the mesh + + TString myDesc; //!< Description of the mesh + virtual std::string GetDesc() const = 0; //!< Get description for the mesh + virtual void SetDesc(const std::string& theValue) = 0; //!< Sets description for the mesh + + + }; + + + //--------------------------------------------------------------- + typedef TVector TIntVector; + typedef TSlice TIntVecSlice; + typedef TCSlice TCIntVecSlice; + + typedef TIntVector TFamAttr; + + //! Define a base class which represents MED Family entity + struct MEDWRAPPER_EXPORT TFamilyInfo: virtual TNameInfo + { + PMeshInfo myMeshInfo; //!< A reference to correspondig MED Mesh + //! Get a reference to corresponding MED Mesh + const PMeshInfo& GetMeshInfo() const { return myMeshInfo;} + + TInt myId; //!< An unique index of the MED FAMILY + TInt GetId() const { return myId;} //!< Gets number of the MED FAMILY + void SetId(TInt theId) { myId = theId;} //! Define number of the MED FAMILY + + TInt myNbGroup; //!< Defines number MED Groups connected to + //! Gets number of MED GROUPS the MED FAMILY is bound to + TInt GetNbGroup() const { return myNbGroup;} + + //! Contains sequence of the names for the MED Groups connected to + TString myGroupNames; + //! Gets name of a bound MED GROUP by its number + virtual std::string GetGroupName(TInt theId) const = 0; + //! Sets name of the defined MED GROUP by its number + virtual void SetGroupName(TInt theId, const std::string& theValue) = 0; + + TInt myNbAttr; //!< Defines number of the MED Family attributes + //! Gets number of attached attributes for the MED FAMILY + TInt GetNbAttr() const { return myNbAttr;} + + //! Defines sequence of the indexes of the MED Family attributes + TFamAttr myAttrId; + //! Get MED FAMILY attribute by its number + TInt GetAttrId(TInt theId) const; + //! Set MED FAMILY attribute by its number + void SetAttrId(TInt theId, TInt theVal); + + //! Defines sequence of the values of the MED Family attributes + TFamAttr myAttrVal; + //! Get MED FAMILY attribute by its number + TInt GetAttrVal(TInt theId) const; + //! Set MED FAMILY attribute by its number + void SetAttrVal(TInt theId, TInt theVal); + + //! Defines sequence of the names of the MED Family attributes + TString myAttrDesc; + //! Get value of the MED FAMILY attribute by its number + virtual std::string GetAttrDesc(TInt theId) const = 0; + //! Set value of the MED FAMILY attribute by its number + virtual void SetAttrDesc(TInt theId, const std::string& theValue) = 0; + }; + + + //--------------------------------------------------------------- + typedef TIntVector TElemNum; + typedef SharedPtr PElemNum; + + //! Define a parent class for all MED entities that describes mesh entites such as nodes and cells. + struct MEDWRAPPER_EXPORT TElemInfo: virtual TBase + { + PMeshInfo myMeshInfo; //!< A reference to correspondig MED Mesh + //! Get a reference to corresponding MED Mesh + const PMeshInfo& GetMeshInfo() const { return myMeshInfo;} + + TInt myNbElem; // TFloatVector; + typedef TSlice TFloatVecSlice; + typedef TCSlice TCFloatVecSlice; + + typedef TFloatVector TNodeCoord; + typedef SharedPtr PNodeCoord; + + typedef TFloatVecSlice TCoordSlice; + typedef TCFloatVecSlice TCCoordSlice; + + //! Define a base class which represents MED Nodes entity + struct MEDWRAPPER_EXPORT TNodeInfo: + virtual TElemInfo, + virtual TModeSwitchInfo + { + PNodeCoord myCoord; //!< Contains all nodal coordinates + + //! Gives coordinates for mesh node by its number (const version) + TCCoordSlice GetCoordSlice(TInt theId) const; + //! Gives coordinates for mesh node by its number + TCoordSlice GetCoordSlice(TInt theId); + + ERepere mySystem; //!< Defines, which coordinate system is used + //! Get which coordinate system is used for the node describing + ERepere GetSystem() const { return mySystem;} + //! Set coordinate system to be used for the node describing + void SetSystem(ERepere theSystem) { mySystem = theSystem;} + + TString myCoordNames; //!< Contains names for the coordinate dimensions + //! Get name of the coordinate dimension by its order number + virtual std::string GetCoordName(TInt theId) const = 0; + //! Set name of the coordinate dimension by its order number + virtual void SetCoordName(TInt theId, const std::string& theValue) = 0; + + TString myCoordUnits; //!< Contains units for the coordinate dimensions + //! Get name of unit for the coordinate dimension by its order number + virtual std::string GetCoordUnit(TInt theId) const = 0; + //! Set name of unit for the coordinate dimension by its order number + virtual void SetCoordUnit(TInt theId, const std::string& theValue) = 0; + }; + + + //--------------------------------------------------------------- + typedef TIntVecSlice TConnSlice; + typedef TCIntVecSlice TCConnSlice; + + //! Define a base class which represents MED Cells entity + struct MEDWRAPPER_EXPORT TCellInfo: + virtual TElemInfo, + virtual TModeSwitchInfo + { + EEntiteMaillage myEntity; //!< Defines the MED Entity where the mesh cells belongs to + //! Let known what MED ENTITY the cells belong to + EEntiteMaillage GetEntity() const { return myEntity;} + + EGeometrieElement myGeom; //!< Defines the MED Geometric type of the instance + //! Let known what MED geometrical type the cells belong to + EGeometrieElement GetGeom() const { return myGeom;} + + EConnectivite myConnMode; //!< Defines connectivity mode + //! Let known in what connectivity the cells are writen + EConnectivite GetConnMode() const { return myConnMode;} + + virtual TInt GetConnDim() const = 0; //!< Gives step in the connectivity sequence + + PElemNum myConn; //!< Defines sequence which describe connectivity for each of mesh cell + + //! Gives connectivities for mesh cell by its number (const version) + TCConnSlice GetConnSlice(TInt theElemId) const; + //! Gives connectivities for mesh cell by its number + TConnSlice GetConnSlice(TInt theElemId); + }; + + //--------------------------------------------------------------- + //! Define a base class which represents MED Polygon entity + struct MEDWRAPPER_EXPORT TPolygoneInfo: + virtual TElemInfo + { + //! Defines the MED Entity where the polygons belongs to + EEntiteMaillage myEntity; // MED_FACE|MED_MAILLE + //! Let known what MED ENTITY the MED Polygons belong to + EEntiteMaillage GetEntity() const { return myEntity;} + + //! Defines the MED Geometric type of the instance + EGeometrieElement myGeom; // ePOLYGONE + //! Let known what MED geometrical type the MED Polygons belong to + EGeometrieElement GetGeom() const { return ePOLYGONE;} + + //! Defines connectivity mode + EConnectivite myConnMode; // eNOD|eDESC(eDESC not used) + //! Let known in what connectivity the cells are writen + EConnectivite GetConnMode() const { return myConnMode;} + + PElemNum myConn; //!< Table de connectivities + PElemNum myIndex; //!< Table de indexes + + //! Gives number of the connectivities for the defined polygon + TInt GetNbConn(TInt theElemId) const; + + //! Gives connectivities for polygon by its number (const version) + TCConnSlice GetConnSlice(TInt theElemId) const; + //! Gives connectivities for polygon by its number + TConnSlice GetConnSlice(TInt theElemId); + }; + + //--------------------------------------------------------------- + //! Define a class representing MED_BALL structure element. + // + // This could be a generic class for any structure element + // holding any number of contant and variable attributes + // but it's too hard to implement + // + struct MEDWRAPPER_EXPORT TBallInfo: + virtual TCellInfo + { + TFloatVector myDiameters; + }; + + //--------------------------------------------------------------- + typedef TVector TCConnSliceArr; + typedef TVector TConnSliceArr; + + //! Define a base class which represents MED Polyedre entity + struct MEDWRAPPER_EXPORT TPolyedreInfo: + virtual TElemInfo + { + //! Defines the MED Entity where the polyedres belongs to + EEntiteMaillage myEntity; // MED_FACE|MED_MAILLE + //! Let known what MED ENTITY the MED Polyedres belong to + EEntiteMaillage GetEntity() const { return myEntity;} + + //! Defines the MED Geometric type of the instance + EGeometrieElement myGeom; // ePOLYEDRE + //! Let known what MED geometrical type the MED Polyedres belong to + EGeometrieElement GetGeom() const { return ePOLYEDRE;} + + //! Defines connectivity mode + EConnectivite myConnMode; // eNOD|eDESC(eDESC not used) + //! Let known in what connectivity the cells are writen + EConnectivite GetConnMode() const { return myConnMode;} + + PElemNum myConn; //!< Table de connectivities + PElemNum myFaces; //!< Table de faces indexes + PElemNum myIndex; //!< Table de indexes + + //! Gives number of the faces for the defined polyedre (const version) + TInt GetNbFaces(TInt theElemId) const; + //! Gives number of the nodes for the defined polyedre + TInt GetNbNodes(TInt theElemId) const; + + //! Gives sequence of the face connectivities for polyedre by its number (const version) + TCConnSliceArr GetConnSliceArr(TInt theElemId) const; + //! Gives sequence of the face connectivities for polyedre by its number + TConnSliceArr GetConnSliceArr(TInt theElemId); + }; + + //--------------------------------------------------------------- + //! Define a base class which represents MED Field entity + struct MEDWRAPPER_EXPORT TFieldInfo: + virtual TNameInfo + { + PMeshInfo myMeshInfo; //!< A reference to correspondig MED Mesh + //! Get a reference to corresponding MED Mesh + const PMeshInfo& GetMeshInfo() const { return myMeshInfo;} + + ETypeChamp myType; //!< Defines type of the MED Field + //! Let known what type of the MED FIELD is used + ETypeChamp GetType() const { return myType;} + + TInt myNbComp; //!< Defines number of components stored in the field + //! Get number of components for the MED FIELD + TInt GetNbComp() const { return myNbComp;} + + EBooleen myIsLocal; //!< Defines if the MED Field is local + //! Let known is the MED FIELD is local or not + EBooleen GetIsLocal() const { return myIsLocal;} + + TInt myNbRef; //!< Defines number of refereces of the field + //! Let known number of references for the MED FIELD + TInt GetNbRef() const { return myNbRef;} + + TString myCompNames; //!< Contains names for each of MED Field components + //! Get name of the component by its order number + virtual std::string GetCompName(TInt theId) const = 0; + //! Set name for the component by its order number + virtual void SetCompName(TInt theId, const std::string& theValue) = 0; + + TString myUnitNames; //!< Contains units for each of MED Field components + //! Get unit of the component by its order number + virtual std::string GetUnitName(TInt theId) const = 0; + //! Set unit for the component by its order number + virtual void SetUnitName(TInt theId, const std::string& theValue) = 0; + + }; + + + //--------------------------------------------------------------- + //! Get dimension of the Gauss coordinates for the defined type of mesh cell + MEDWRAPPER_EXPORT + TInt + GetDimGaussCoord(EGeometrieElement theGeom); + + //! Get number of referenced nodes for the defined type of mesh cell + MEDWRAPPER_EXPORT + TInt + GetNbRefCoord(EGeometrieElement theGeom); + + typedef TFloatVector TWeight; + + //! The class represents MED Gauss entity + struct MEDWRAPPER_EXPORT TGaussInfo: + virtual TNameInfo, + virtual TModeSwitchInfo + { + typedef boost::tuple TKey; + typedef boost::tuple TInfo; + struct MEDWRAPPER_EXPORT TLess + { + bool + operator()(const TKey& theLeft, const TKey& theRight) const; + + bool + operator()(const TGaussInfo& theLeft, const TGaussInfo& theRight) const; + }; + + //! Defines, which geometrical type the MED Gauss entity belongs to + EGeometrieElement myGeom; + //! Let known what MED geometrical type the MED GAUSS entity belong to + EGeometrieElement GetGeom() const { return myGeom;} + + //! Contains coordinates for the refereced nodes + TNodeCoord myRefCoord; + + //! Gives coordinates for the referenced node by its number + TCCoordSlice GetRefCoordSlice(TInt theId) const; + //! Gives coordinates for the referenced node by its number + TCoordSlice GetRefCoordSlice(TInt theId); + + //! Contains coordinates for the Gauss points + TNodeCoord myGaussCoord; + + //! Gives coordinates for the Gauss points by its number + TCCoordSlice GetGaussCoordSlice(TInt theId) const; + //! Gives coordinates for the Gauss points by its number + TCoordSlice GetGaussCoordSlice(TInt theId); + + //! Contains wheights for the Gauss points + TWeight myWeight; + + //! Gives number of the referenced nodes + TInt GetNbRef() const { return GetNbRefCoord(GetGeom());} + + //! Gives dimension of the referenced nodes + TInt GetDim() const { return GetDimGaussCoord(GetGeom());} + + //! Gives number of the Gauss Points + TInt GetNbGauss() const { return (TInt)(myGaussCoord.size()/GetDim());} + }; + + + //--------------------------------------------------------------- + typedef std::map TGeom2Gauss; + typedef std::map TGeom2NbGauss; + + //! Define a base class which represents MED TimeStamp + struct MEDWRAPPER_EXPORT TTimeStampInfo: + virtual TBase + { + PFieldInfo myFieldInfo; //!< A reference to correspondig MED Field + //! Get a reference to corresponding MED Field + const PFieldInfo& GetFieldInfo() const { return myFieldInfo;} + + //! Defines the MED Entity where the MED TimeStamp belongs to + EEntiteMaillage myEntity; + //! Let known to what MED Entity the MED TimeStamp belong to + EEntiteMaillage GetEntity() const { return myEntity;} + + //! Keeps map of number of cells per geometric type where the MED TimeStamp belongs to + TGeom2Size myGeom2Size; + //! Get map of number of cells per geometric type where the MED TimeStamp belongs to + const TGeom2Size& GetGeom2Size() const { return myGeom2Size;} + + TGeom2NbGauss myGeom2NbGauss; //!< Keeps number of the Gauss Points for the MED TimeStamp + TInt GetNbGauss(EGeometrieElement theGeom) const; //!< Gives number of the Gauss Points for the MED TimeStamp + + TInt myNumDt; //!< Keeps number in time for the MED TimeStamp + TInt GetNumDt() const { return myNumDt;} //!< Defines number in time for the MED TimeStamp + + TInt myNumOrd; //!< Keeps number for the MED TimeStamp + TInt GetNumOrd() const { return myNumOrd;} //!< Defines number for the MED TimeStamp + + TFloat myDt; //!< Keeps time for the MED TimeStamp + TFloat GetDt() const { return myDt;} //!< Defines time for the MED TimeStamp + + //! Keeps map of MED Gauss entityes per geometric type + TGeom2Gauss myGeom2Gauss; + //! Gets a map of MED Gauss entityes per geometric type + const TGeom2Gauss& GetGeom2Gauss() const { return myGeom2Gauss;} + + TString myUnitDt; //!< Defines unit for the time for the MED TimeStamp + //! Get unit of time for the MED TimeStamp + virtual std::string GetUnitDt() const = 0; + //! Set unit of time for the MED TimeStamp + virtual void SetUnitDt(const std::string& theValue) = 0; + }; + + + //--------------------------------------------------------------- + //! The class represents MED Profile entity + struct MEDWRAPPER_EXPORT TProfileInfo: + virtual TNameInfo + { + typedef std::string TKey; + typedef boost::tuple TInfo; + + EModeProfil myMode; //!< Keeps mode for the MED Profile + //! Let known what mode of MED Profile is used + EModeProfil GetMode() const { return myMode;} + //! Set mode for the MED Profile + void SetMode(EModeProfil theMode) { myMode = theMode;} + + PElemNum myElemNum; //!< Keeps sequence of cell by its number which belong to the profile + //! Get number of mesh elelemts by its order number + TInt GetElemNum(TInt theId) const; + //! Set number of mesh elelemts by its order number + void SetElemNum(TInt theId, TInt theVal); + + //! Let known is the MED Profile defined + bool IsPresent() const { return GetName() != "";} + + //! Let known size of the MED Profile + TInt GetSize() const { return (TInt)myElemNum->size();} + }; + + + //--------------------------------------------------------------- + //! The class is a helper one. It provide safe and flexible way to get access to values for a MED TimeStamp + struct MEDWRAPPER_EXPORT TMeshValueBase: + virtual TModeSwitchInfo + { + TInt myNbElem; + TInt myNbComp; + TInt myNbGauss; + TInt myStep; + + TMeshValueBase(); + + //! Initialize the class + void + Allocate(TInt theNbElem, + TInt theNbGauss, + TInt theNbComp, + EModeSwitch theMode = eFULL_INTERLACE); + + //! Returns size of the value container + size_t + GetSize() const; + + //! Returns MED interpetation of the value size + size_t + GetNbVal() const; + + //! Returns number of Gauss Points bounded with the value + size_t + GetNbGauss() const; + + //! Returns step inside of the data array + size_t + GetStep() const; + + //! Returns bare pointer on the internal value representation + virtual + unsigned char* + GetValuePtr() = 0; + }; + + //--------------------------------------------------------------- + //! The class is a helper one. It provide safe and flexible way to get access to values for a MED TimeStamp + template + struct TTMeshValue: + virtual TMeshValueBase + { + typedef TValueType TValue; + typedef typename TValueType::value_type TElement; + + typedef TSlice TValueSlice; + typedef TCSlice TCValueSlice; + + typedef TVector TCValueSliceArr; + typedef TVector TValueSliceArr; + + TValue myValue; + + //! Initialize the class + void + Allocate(TInt theNbElem, + TInt theNbGauss, + TInt theNbComp, + EModeSwitch theMode = eFULL_INTERLACE) + { + TMeshValueBase::Allocate(theNbElem, theNbGauss, theNbComp, theMode); + myValue.resize(theNbElem * this->GetStep()); + } + + //! Returns bare pointer on the internal value representation + virtual + unsigned char* + GetValuePtr() + { + return (unsigned char*)&myValue[0]; + } + + //! Returns bare pointer on the internal value representation + virtual + TElement* + GetPointer() + { + return &myValue[0]; + } + + //! Returns bare pointer on the internal value representation + virtual + const TElement* + GetPointer() const + { + return &myValue[0]; + } + + //! Iteration through Gauss Points by their components + TCValueSliceArr + GetGaussValueSliceArr(TInt theElemId) const + { + TCValueSliceArr aValueSliceArr(myNbGauss); + if(GetModeSwitch() == eFULL_INTERLACE){ + TInt anId = theElemId * myStep; + for(TInt aGaussId = 0; aGaussId < myNbGauss; aGaussId++){ + aValueSliceArr[aGaussId] = + TCValueSlice(myValue, std::slice(anId, myNbComp, 1)); + anId += myNbComp; + } + } + else{ + for(TInt aGaussId = 0; aGaussId < myNbGauss; aGaussId++){ + aValueSliceArr[aGaussId] = + TCValueSlice(myValue, std::slice(theElemId, myNbComp, myStep)); + } + } + return aValueSliceArr; + } + + //! Iteration through Gauss Points by their components + TValueSliceArr + GetGaussValueSliceArr(TInt theElemId) + { + TValueSliceArr aValueSliceArr(myNbGauss); + if(GetModeSwitch() == eFULL_INTERLACE){ + TInt anId = theElemId*myStep; + for(TInt aGaussId = 0; aGaussId < myNbGauss; aGaussId++){ + aValueSliceArr[aGaussId] = + TValueSlice(myValue, std::slice(anId, myNbComp, 1)); + anId += myNbComp; + } + } + else{ + for(TInt aGaussId = 0; aGaussId < myNbGauss; aGaussId++){ + aValueSliceArr[aGaussId] = + TValueSlice(myValue, std::slice(theElemId, myNbComp, myStep)); + } + } + return aValueSliceArr; + } + + //! Iteration through components by corresponding Gauss Points + TCValueSliceArr + GetCompValueSliceArr(TInt theElemId) const + { + TCValueSliceArr aValueSliceArr(myNbComp); + if(GetModeSwitch() == eFULL_INTERLACE){ + TInt anId = theElemId*myStep; + for(TInt aCompId = 0; aCompId < myNbComp; aCompId++){ + aValueSliceArr[aCompId] = + TCValueSlice(myValue, std::slice(anId, myNbGauss, myNbComp)); + anId += 1; + } + } + else{ + for(TInt aCompId = 0; aCompId < myNbComp; aCompId++){ + aValueSliceArr[aCompId] = + TCValueSlice(myValue, std::slice(theElemId, myNbGauss, myStep)); + } + } + return aValueSliceArr; + } + + //! Iteration through components by corresponding Gauss Points + TValueSliceArr + GetCompValueSliceArr(TInt theElemId) + { + if(GetModeSwitch() == eFULL_INTERLACE){ + TValueSliceArr aValueSliceArr(myNbComp); + TInt anId = theElemId*myStep; + for(TInt aCompId = 0; aCompId < myNbComp; aCompId++){ + aValueSliceArr[aCompId] = + TValueSlice(myValue, std::slice(anId, myNbGauss, myNbComp)); + anId += 1; + } + return aValueSliceArr; + } + else{ + TValueSliceArr aValueSliceArr(myNbGauss); + for(TInt aGaussId = 0; aGaussId < myNbGauss; aGaussId++){ + aValueSliceArr[aGaussId] = + TValueSlice(myValue,std::slice(theElemId, myNbComp, myStep)); + } + return aValueSliceArr; + } + } + }; + + typedef TTMeshValue TFloatMeshValue; + typedef TTMeshValue TIntMeshValue; + + //--------------------------------------------------------------- + // Backward compatibility declarations + typedef TFloatVector TValue; + typedef TSlice TValueSlice; + typedef TCSlice TCValueSlice; + + typedef TVector TCValueSliceArr; + typedef TVector TValueSliceArr; + + typedef TFloatMeshValue TMeshValue; + typedef std::map TGeom2Value; + + //--------------------------------------------------------------- + typedef std::map TGeom2Profile; + typedef std::set TGeom; + + //! The class is a base class for MED TimeStamp values holder + struct MEDWRAPPER_EXPORT TTimeStampValueBase: + virtual TModeSwitchInfo + { + //! A reference to correspondig MED TimeStamp + PTimeStampInfo myTimeStampInfo; + //!< Get a reference to correspondig MED TimeStamp + const PTimeStampInfo& GetTimeStampInfo() const { return myTimeStampInfo;} + + //! Keeps set of MED EGeometrieElement which contains values for the timestamp + TGeomSet myGeomSet; + const TGeomSet& GetGeomSet() const { return myGeomSet;} + + //! Keeps map of MED Profiles per geometric type + TGeom2Profile myGeom2Profile; + //! Gets a map of MED Profiles per geometric type + const TGeom2Profile& GetGeom2Profile() const { return myGeom2Profile;} + + //! Gets type of the champ + virtual + ETypeChamp + GetTypeChamp() const = 0; + + //! Allocates values for the given geometry + virtual + void + AllocateValue(EGeometrieElement theGeom, + TInt theNbElem, + TInt theNbGauss, + TInt theNbComp, + EModeSwitch theMode = eFULL_INTERLACE) = 0; + + virtual + size_t + GetValueSize(EGeometrieElement theGeom) const = 0; + + virtual + size_t + GetNbVal(EGeometrieElement theGeom) const = 0; + + virtual + size_t + GetNbGauss(EGeometrieElement theGeom) const = 0; + + virtual + unsigned char* + GetValuePtr(EGeometrieElement theGeom) = 0; + }; + + + //--------------------------------------------------------------- + //! The class implements a container for MED TimeStamp values + template + struct TTimeStampValue: + virtual TTimeStampValueBase + { + typedef TMeshValueType TTMeshValue; + typedef SharedPtr PTMeshValue; + typedef typename TMeshValueType::TElement TElement; + typedef std::map TTGeom2Value; + + ETypeChamp myTypeChamp; //second; + } + + //! Gets MED TimeStamp values for the given geometric type + PTMeshValue& + GetMeshValuePtr(EGeometrieElement theGeom) + { + myGeomSet.insert(theGeom); + if(myGeom2Value.find(theGeom) == myGeom2Value.end()){ + myGeom2Value[theGeom] = PTMeshValue(new TTMeshValue()); + return myGeom2Value[theGeom]; + } + return myGeom2Value[theGeom]; + } + + //! Gets MED TimeStamp values for the given geometric type (const version) + const TTMeshValue& + GetMeshValue(EGeometrieElement theGeom) const + { + return *(this->GetMeshValuePtr(theGeom)); + } + + //! Gets MED TimeStamp values for the given geometric type + TTMeshValue& + GetMeshValue(EGeometrieElement theGeom) + { + return *(this->GetMeshValuePtr(theGeom)); + } + }; + + + //--------------------------------------------------------------- + typedef TTimeStampValue TFloatTimeStampValue; + typedef SharedPtr PFloatTimeStampValue; + + PFloatTimeStampValue MEDWRAPPER_EXPORT + CastToFloatTimeStampValue(const PTimeStampValueBase& theTimeStampValue); + + typedef TTimeStampValue TIntTimeStampValue; + typedef SharedPtr PIntTimeStampValue; + + PIntTimeStampValue MEDWRAPPER_EXPORT + CastToIntTimeStampValue(const PTimeStampValueBase& theTimeStampValue); + + + //--------------------------------------------------------------- + template + void + CopyTimeStampValue(SharedPtr > theTimeStampValueFrom, + SharedPtr > theTimeStampValueTo) + { + typedef TTimeStampValue TimeStampValueTypeFrom; + typedef TTimeStampValue TimeStampValueTypeTo; + typedef typename TMeshValueTypeTo::TElement TElementTo; + + typename TimeStampValueTypeFrom::TTGeom2Value& aGeom2Value = theTimeStampValueFrom->myGeom2Value; + typename TimeStampValueTypeFrom::TTGeom2Value::const_iterator anIter = aGeom2Value.begin(); + for(; anIter != aGeom2Value.end(); anIter++){ + const EGeometrieElement& aGeom = anIter->first; + const typename TimeStampValueTypeFrom::TTMeshValue& aMeshValue = *anIter->second; + typename TimeStampValueTypeTo::TTMeshValue& aMeshValue2 = theTimeStampValueTo->GetMeshValue(aGeom); + aMeshValue2.Allocate(aMeshValue.myNbElem, + aMeshValue.myNbGauss, + aMeshValue.myNbComp, + aMeshValue.myModeSwitch); + const typename TimeStampValueTypeFrom::TTMeshValue::TValue& aValue = aMeshValue.myValue; + typename TimeStampValueTypeTo::TTMeshValue::TValue& aValue2 = aMeshValue2.myValue; + TInt aSize = aValue.size(); + for(TInt anId = 0; anId < aSize; anId++) + aValue2[anId] = TElementTo(aValue[anId]); + } + } + + template + void + CopyTimeStampValue(SharedPtr > theTimeStampValueFrom, + SharedPtr > theTimeStampValueTo) + { + typedef TTimeStampValue TimeStampValueType; + typename TimeStampValueType::TTGeom2Value& aGeom2Value = theTimeStampValueFrom->myGeom2Value; + typename TimeStampValueType::TTGeom2Value::const_iterator anIter = aGeom2Value.begin(); + for(; anIter != aGeom2Value.end(); anIter++){ + const EGeometrieElement& aGeom = anIter->first; + const typename TimeStampValueType::TTMeshValue& aMeshValue = *anIter->second; + typename TimeStampValueType::TTMeshValue& aMeshValue2 = theTimeStampValueTo->GetMeshValue(aGeom); + aMeshValue2 = aMeshValue; + } + } + + //--------------------------------------------------------------- + inline + void + CopyTimeStampValueBase(const PTimeStampValueBase& theValueFrom, + const PTimeStampValueBase& theValueTo) + { + if(theValueFrom->GetTypeChamp() == theValueTo->GetTypeChamp()){ + if(theValueFrom->GetTypeChamp() == eFLOAT64) + CopyTimeStampValue(theValueFrom, theValueTo); + else if(theValueFrom->GetTypeChamp() == eINT) + CopyTimeStampValue(theValueFrom, theValueTo); + }else{ + if(theValueFrom->GetTypeChamp() == eFLOAT64 && theValueTo->GetTypeChamp() == eINT) + CopyTimeStampValue(theValueFrom, theValueTo); + else if(theValueFrom->GetTypeChamp() == eINT && theValueTo->GetTypeChamp() == eFLOAT64) + CopyTimeStampValue(theValueFrom, theValueTo); + } + } + + + //--------------------------------------------------------------- + // Backward compatibility declarations + typedef TFloatTimeStampValue TTimeStampVal; + typedef PFloatTimeStampValue PTimeStampVal; + + //--------------------------------------------------------------- + typedef std::map TIndexes; + typedef std::map TNames; + + //! Define a base class which represents MED Grille (structured mesh) + struct MEDWRAPPER_EXPORT TGrilleInfo: + virtual TModeSwitchInfo + { + + PMeshInfo myMeshInfo; + const PMeshInfo& GetMeshInfo() const { return myMeshInfo;} + + TNodeCoord myCoord; //!< Contains all nodal coordinates, now used only for eGRILLE_STANDARD + //! Gives coordinates for mesh nodes (const version) + const TNodeCoord& GetNodeCoord() const; + TNodeCoord& GetNodeCoord(); + //! Gives coordinates for mesh node by its number, array index from 0 + TNodeCoord GetCoord(TInt theId); + //! Gives ids of nodes for mesh cell or sub-cell by its number, array index from 0 + TIntVector GetConn(TInt theId, const bool isSub=false); + + EGrilleType myGrilleType; //!< Defines grille type (eGRILLE_CARTESIENNE,eGRILLE_POLAIRE,eGRILLE_STANDARD) + //!Gets grille type (const version) + const EGrilleType& GetGrilleType() const; + //!Gets grille type + EGrilleType GetGrilleType(); + //!Sets grille type + void SetGrilleType(EGrilleType theGrilleType); + + + + TString myCoordNames; //!< Contains names for the coordinate dimensions + //! Get name of the coordinate dimension by its order number + virtual std::string GetCoordName(TInt theId) const = 0 ; + //! Set name of the coordinate dimension by its order number + virtual void SetCoordName(TInt theId, const std::string& theValue) = 0; + + TString myCoordUnits; //!< Contains units for the coordinate dimensions + //! Get name of unit for the coordinate dimension by its order number + virtual std::string GetCoordUnit(TInt theId) const = 0; + //! Set name of unit for the coordinate dimension by its order number + virtual void SetCoordUnit(TInt theId, const std::string& theValue) = 0; + + + //! Map of index of axes and Table of indexes for certain axe, now used for eGRILLE_CARTESIENNE and eGRILLE_POLAIRE + TIndexes myIndixes; + //!Gets a map of Tables (const version) + const TIndexes& GetMapOfIndexes() const ; + //!Gets a map of Tables + TIndexes& GetMapOfIndexes(); + //!Gets a Table of indexes for certain axe(const version) + const TFloatVector& GetIndexes(TInt theAxisNumber) const; + //!Gets a Table of indexes for certain axe + TFloatVector& GetIndexes(TInt theAxisNumber); + //!Gets a number of indices per axe + TInt GetNbIndexes(TInt theAxisNumber); + + TInt GetNbNodes();//! Return count of all points + TInt GetNbCells();//! Return count of all cells + TInt GetNbSubCells();//! Return count of all entities of + EGeometrieElement GetGeom();//! Return geometry of cells (calculated from mesh dimension) + EGeometrieElement GetSubGeom();//! Return geometry of subcells (calculated from mesh dimension) + EEntiteMaillage GetEntity();//! Return entity (eMAILLE) + EEntiteMaillage GetSubEntity();//! Return sub entity + + /*! + *Vector of grille structure (Example: {3,4,5}, 3 nodes in X axe, 4 nodes in Y axe, ...) + */ + TIntVector myGrilleStructure; + //!Gets grille structure(const version) + const TIntVector& GetGrilleStructure() const; + //!Gets grille structure + TIntVector GetGrilleStructure(); + //!Sets the grille structure of theAxis axe to theNb. + void SetGrilleStructure(TInt theAxis,TInt theNb); + + /*! + *Defines sequence MED Family indexes for corresponding mesh entites + */ + TElemNum myFamNum; + //! Get number of a MED FAMILY by order number of the mesh element + TInt GetFamNum(TInt theId) const; + //! Set number of a MED FAMILY for the mesh element with the order number + void SetFamNum(TInt theId, TInt theVal); + + /*! + *Defines sequence MED Family indexes for sub entites + */ + TElemNum myFamSubNum; + //! Get number of a MED FAMILY by order number of sub element + TInt GetFamSubNum(TInt theId) const; + //! Set number of a MED FAMILY for theId-th sub element + void SetFamSubNum(TInt theId, TInt theVal); + + /*! + *Defines sequence MED Family indexes for corresponding mesh nodes + */ + TElemNum myFamNumNode; + //! Get number of a MED FAMILY by order number of the mesh node + TInt GetFamNumNode(TInt theId) const; + //! Set number of a MED FAMILY for the mesh node with the order number + void SetFamNumNode(TInt theId, TInt theVal); + + }; + + +} + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_TStructures.hxx b/src/3rdParty/salomesmesh/inc/MED_TStructures.hxx new file mode 100644 index 000000000000..9b8fba09a198 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_TStructures.hxx @@ -0,0 +1,1215 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// +#ifndef MED_TStructures_HeaderFile +#define MED_TStructures_HeaderFile + +#include "MED_Structures.hxx" + +#ifdef WIN32 +#pragma warning(disable:4250) +#endif + +namespace MED +{ + //--------------------------------------------------------------- + //! To provide a common way to handle values of MEDWrapper types as native MED types + template + struct TValueHolder + { + TValue& myValue; + TRepresentation myRepresentation; + + TValueHolder(TValue& theValue): + myValue(theValue), + myRepresentation(TRepresentation(theValue)) + {} + + ~TValueHolder() + { + myValue = TValue(myRepresentation); + } + + TRepresentation* + operator& () + { + return &myRepresentation; + } + + operator TRepresentation () const + { + return myRepresentation; + } + + const TValue& + operator() () const + { + return myValue; + } + }; + + //! To customize TValueHolder common template definition for TVector + template + struct TValueHolder, TRepresentation> + { + typedef TVector TValue; + TValue& myValue; + TRepresentation* myRepresentation; + + TValueHolder(TValue& theValue): + myValue(theValue) + { + if(theValue.empty()) + myRepresentation = (TRepresentation*)NULL; + else + myRepresentation = (TRepresentation*)&theValue[0]; + } + + TRepresentation* + operator& () + { + return myRepresentation; + } + }; + + //--------------------------------------------------------------- + template + struct TTNameInfo: virtual TNameInfo + { + TTNameInfo(const std::string& theValue) + { + myName.resize(GetNOMLength()+1); + SetName(theValue); + } + + virtual + std::string + GetName() const + { + return GetString(0, GetNOMLength(), myName); + } + + virtual + void + SetName(const std::string& theValue) + { + SetString(0, GetNOMLength(), myName, theValue); + } + + virtual + void + SetName(const TString& theValue) + { + SetString(0, GetNOMLength(), myName, theValue); + } + }; + + + //--------------------------------------------------------------- + template + struct TTMeshInfo: + virtual TMeshInfo, + virtual TTNameInfo + { + typedef TTNameInfo TNameInfoBase; + + TTMeshInfo(const PMeshInfo& theInfo): + TNameInfoBase(theInfo->GetName()) + { + myDim = theInfo->GetDim(); + mySpaceDim = theInfo->GetSpaceDim(); + myType = theInfo->GetType(); + + myDesc.resize(GetDESCLength()+1); + SetDesc(theInfo->GetDesc()); + } + + TTMeshInfo(TInt theDim, TInt theSpaceDim, + const std::string& theValue, + EMaillage theType, + const std::string& theDesc): + TNameInfoBase(theValue) + { + myDim = theDim; + mySpaceDim = theSpaceDim; + myType = theType; + + myDesc.resize(GetDESCLength()+1); + SetDesc(theDesc); + } + + virtual + std::string + GetDesc() const + { + return GetString(0, GetDESCLength(), myDesc); + } + + virtual + void + SetDesc(const std::string& theValue) + { + SetString(0, GetDESCLength(), myDesc, theValue); + } + }; + + + //--------------------------------------------------------------- + template + struct TTFamilyInfo: + virtual TFamilyInfo, + virtual TTNameInfo + { + typedef TTNameInfo TNameInfoBase; + + TTFamilyInfo(const PMeshInfo& theMeshInfo, const PFamilyInfo& theInfo): + TNameInfoBase(theInfo->GetName()) + { + myMeshInfo = theMeshInfo; + + myId = theInfo->GetId(); + + myNbGroup = theInfo->GetNbGroup(); + myGroupNames.resize(myNbGroup*GetLNOMLength()+1); + if(myNbGroup){ + for(TInt anId = 0; anId < myNbGroup; anId++){ + SetGroupName(anId,theInfo->GetGroupName(anId)); + } + } + + myNbAttr = theInfo->GetNbAttr(); + myAttrId.resize(myNbAttr); + myAttrVal.resize(myNbAttr); + myAttrDesc.resize(myNbAttr*GetDESCLength()+1); + if(myNbAttr){ + for(TInt anId = 0; anId < myNbAttr; anId++){ + SetAttrDesc(anId,theInfo->GetAttrDesc(anId)); + myAttrVal[anId] = theInfo->GetAttrVal(anId); + myAttrId[anId] = theInfo->GetAttrId(anId); + } + } + } + + TTFamilyInfo(const PMeshInfo& theMeshInfo, + TInt theNbGroup, + TInt theNbAttr, + TInt theId, + const std::string& theValue): + TNameInfoBase(theValue) + { + myMeshInfo = theMeshInfo; + + myId = theId; + + myNbGroup = theNbGroup; + myGroupNames.resize(theNbGroup*GetLNOMLength()+1); + + myNbAttr = theNbAttr; + myAttrId.resize(theNbAttr); + myAttrVal.resize(theNbAttr); + myAttrDesc.resize(theNbAttr*GetDESCLength()+1); + } + + TTFamilyInfo(const PMeshInfo& theMeshInfo, + const std::string& theValue, + TInt theId, + const TStringSet& theGroupNames, + const TStringVector& theAttrDescs, + const TIntVector& theAttrIds, + const TIntVector& theAttrVals): + TNameInfoBase(theValue) + { + myMeshInfo = theMeshInfo; + + myId = theId; + + myNbGroup = (TInt)theGroupNames.size(); + myGroupNames.resize(myNbGroup*GetLNOMLength()+1); + if(myNbGroup){ + TStringSet::const_iterator anIter = theGroupNames.begin(); + for(TInt anId = 0; anIter != theGroupNames.end(); anIter++, anId++){ + const std::string& aVal = *anIter; + SetGroupName(anId,aVal); + } + } + + myNbAttr = (TInt)theAttrDescs.size(); + myAttrId.resize(myNbAttr); + myAttrVal.resize(myNbAttr); + myAttrDesc.resize(myNbAttr*GetDESCLength()+1); + if(myNbAttr){ + for(TInt anId = 0, anEnd = (TInt)theAttrDescs.size(); anId < anEnd; anId++){ + SetAttrDesc(anId,theAttrDescs[anId]); + myAttrVal[anId] = theAttrVals[anId]; + myAttrId[anId] = theAttrIds[anId]; + } + } + } + + virtual + std::string + GetGroupName(TInt theId) const + { + return GetString(theId, GetLNOMLength(), myGroupNames); + } + + virtual + void + SetGroupName(TInt theId, const std::string& theValue) + { + SetString(theId, GetLNOMLength(), myGroupNames, theValue); + } + + virtual + std::string + GetAttrDesc(TInt theId) const + { + return GetString(theId, GetDESCLength(), myAttrDesc); + } + + virtual + void + SetAttrDesc(TInt theId, const std::string& theValue) + { + SetString(theId, GetDESCLength(), myAttrDesc, theValue); + } + }; + + + //--------------------------------------------------------------- + template + struct TTElemInfo: virtual TElemInfo + { + TTElemInfo(const PMeshInfo& theMeshInfo, const PElemInfo& theInfo) + { + myMeshInfo = theMeshInfo; + + myNbElem = theInfo->GetNbElem(); + myFamNum.reset(new TElemNum(myNbElem)); + myIsFamNum = eFAUX; // is set to eVRAI in SetFamNum() + + myIsElemNum = theInfo->IsElemNum(); + if(theInfo->IsElemNum()) + myElemNum.reset(new TElemNum(myNbElem)); + else + myElemNum.reset(new TElemNum()); + + myIsElemNames = theInfo->IsElemNames(); + if(theInfo->IsElemNames()) + myElemNames.reset(new TString(myNbElem*GetPNOMLength() + 1)); + else + myElemNames.reset(new TString()); + + if(theInfo->GetNbElem()){ + for(TInt anId = 0; anId < myNbElem; anId++){ + SetFamNum(anId, theInfo->GetFamNum(anId)); + } + if(theInfo->IsElemNum() == eVRAI){ + for(TInt anId = 0; anId < myNbElem; anId++){ + SetElemNum(anId, theInfo->GetElemNum(anId)); + } + } + if(theInfo->IsElemNames() == eVRAI){ + for(TInt anId = 0; anId < myNbElem; anId++){ + SetElemName(anId,theInfo->GetElemName(anId)); + } + } + } + } + + TTElemInfo(const PMeshInfo& theMeshInfo, + TInt theNbElem, + EBooleen theIsElemNum, + EBooleen theIsElemNames) + { + myMeshInfo = theMeshInfo; + + myNbElem = theNbElem; + myFamNum.reset(new TElemNum(theNbElem)); + myIsFamNum = eFAUX; // is set to eVRAI in SetFamNum() + + myIsElemNum = theIsElemNum; + if(theIsElemNum) + myElemNum.reset(new TElemNum(theNbElem)); + else + myElemNum.reset(new TElemNum()); + + myIsElemNames = theIsElemNames; + if(theIsElemNames) + myElemNames.reset(new TString(theNbElem*GetPNOMLength() + 1)); + else + myElemNames.reset(new TString()); + } + + TTElemInfo(const PMeshInfo& theMeshInfo, + TInt theNbElem, + const TIntVector& theFamilyNums, + const TIntVector& theElemNums, + const TStringVector& theElemNames) + { + myMeshInfo = theMeshInfo; + + myNbElem = theNbElem; + myFamNum.reset(new TElemNum(theNbElem)); + myIsFamNum = eFAUX; // is set to eVRAI in SetFamNum() + + myIsElemNum = theElemNums.size()? eVRAI: eFAUX; + if(myIsElemNum) + myElemNum.reset(new TElemNum(theNbElem)); + else + myElemNum.reset(new TElemNum()); + + myIsElemNames = theElemNames.size()? eVRAI: eFAUX; + if(myIsElemNames) + myElemNames.reset(new TString(theNbElem*GetPNOMLength() + 1)); + else + myElemNames.reset(new TString()); + + if(theNbElem){ + + if(theFamilyNums.size()) + *myFamNum = theFamilyNums; + + if(myIsElemNum) + *myElemNum = theElemNums; + + if(myIsElemNames){ + for(TInt anId = 0; anId < theNbElem; anId++){ + const std::string& aVal = theElemNames[anId]; + SetElemName(anId,aVal); + } + } + } + } + + virtual + std::string + GetElemName(TInt theId) const + { + return GetString(theId,GetPNOMLength(), *myElemNames); + } + + virtual + void + SetElemName(TInt theId, const std::string& theValue) + { + SetString(theId,GetPNOMLength(), *myElemNames, theValue); + } + }; + + + //--------------------------------------------------------------- + template + struct TTNodeInfo: + virtual TNodeInfo, + virtual TTElemInfo + { + typedef TTElemInfo TElemInfoBase; + + TTNodeInfo(const PMeshInfo& theMeshInfo, const PNodeInfo& theInfo): + TNodeInfo(theInfo), + TElemInfoBase(theMeshInfo, theInfo) + { + myModeSwitch = theInfo->GetModeSwitch(); + + mySystem = theInfo->GetSystem(); + + myCoord.reset(new TNodeCoord(*theInfo->myCoord)); + + TInt aSpaceDim = theMeshInfo->GetSpaceDim(); + + myCoordNames.resize(aSpaceDim*GetPNOMLength()+1); + for(TInt anId = 0; anId < aSpaceDim; anId++) + SetCoordName(anId,theInfo->GetCoordName(anId)); + + myCoordUnits.resize(aSpaceDim*GetPNOMLength()+1); + for(TInt anId = 0; anId < aSpaceDim; anId++) + SetCoordUnit(anId,theInfo->GetCoordUnit(anId)); + } + + TTNodeInfo(const PMeshInfo& theMeshInfo, + TInt theNbElem, + EModeSwitch theMode, + ERepere theSystem, + EBooleen theIsElemNum, + EBooleen theIsElemNames): + TModeSwitchInfo(theMode), + TElemInfoBase(theMeshInfo, + theNbElem, + theIsElemNum, + theIsElemNames) + { + mySystem = theSystem; + + myCoord.reset(new TNodeCoord(theNbElem * theMeshInfo->mySpaceDim)); + + myCoordUnits.resize(theMeshInfo->mySpaceDim*GetPNOMLength()+1); + + myCoordNames.resize(theMeshInfo->mySpaceDim*GetPNOMLength()+1); + } + + + TTNodeInfo(const PMeshInfo& theMeshInfo, + const TFloatVector& theNodeCoords, + EModeSwitch theMode, + ERepere theSystem, + const TStringVector& theCoordNames, + const TStringVector& theCoordUnits, + const TIntVector& theFamilyNums, + const TIntVector& theElemNums, + const TStringVector& theElemNames): + TModeSwitchInfo(theMode), + TElemInfoBase(theMeshInfo, + (TInt)theNodeCoords.size()/theMeshInfo->GetDim(), + theFamilyNums, + theElemNums, + theElemNames) + { + mySystem = theSystem; + + myCoord.reset(new TNodeCoord(theNodeCoords)); + + TInt aSpaceDim = theMeshInfo->GetSpaceDim(); + + myCoordNames.resize(aSpaceDim*GetPNOMLength()+1); + if(!theCoordNames.empty()) + for(TInt anId = 0; anId < aSpaceDim; anId++) + SetCoordName(anId,theCoordNames[anId]); + + myCoordUnits.resize(aSpaceDim*GetPNOMLength() + 1); + if(!theCoordUnits.empty()) + for(TInt anId = 0; anId < aSpaceDim; anId++) + SetCoordUnit(anId, theCoordUnits[anId]); + } + + virtual + std::string + GetCoordName(TInt theId) const + { + return GetString(theId,GetPNOMLength(),myCoordNames); + } + + virtual + void + SetCoordName(TInt theId, const std::string& theValue) + { + SetString(theId,GetPNOMLength(),myCoordNames,theValue); + } + + virtual + std::string + GetCoordUnit(TInt theId) const + { + return GetString(theId,GetPNOMLength(),myCoordUnits); + } + + virtual + void + SetCoordUnit(TInt theId, const std::string& theValue) + { + SetString(theId,GetPNOMLength(),myCoordUnits,theValue); + } + }; + + //--------------------------------------------------------------- + template + struct TTPolygoneInfo: + virtual TPolygoneInfo, + virtual TTElemInfo + { + typedef TTElemInfo TElemInfoBase; + + TTPolygoneInfo(const PMeshInfo& theMeshInfo, const PPolygoneInfo& theInfo): + TElemInfoBase(theMeshInfo,theInfo) + { + myEntity = theInfo->GetEntity(); + myGeom = theInfo->GetGeom(); + + myIndex.reset(new TElemNum(*theInfo->myIndex)); + myConn.reset(new TElemNum(*theInfo->myConn)); + + myConnMode = theInfo->GetConnMode(); + } + + TTPolygoneInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TInt theNbElem, + TInt theConnSize, + EConnectivite theConnMode, + EBooleen theIsElemNum, + EBooleen theIsElemNames): + TElemInfoBase(theMeshInfo, + theNbElem, + theIsElemNum, + theIsElemNames) + { + myEntity = theEntity; + myGeom = theGeom; + + myIndex.reset(new TElemNum(theNbElem + 1)); + myConn.reset(new TElemNum(theConnSize)); + + myConnMode = theConnMode; + } + + TTPolygoneInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + const TIntVector& theIndexes, + const TIntVector& theConnectivities, + EConnectivite theConnMode, + const TIntVector& theFamilyNums, + const TIntVector& theElemNums, + const TStringVector& theElemNames): + TElemInfoBase(theMeshInfo, + (TInt)theIndexes.size() - 1, + theFamilyNums, + theElemNums, + theElemNames) + { + myEntity = theEntity; + myGeom = theGeom; + + myIndex.reset(new TElemNum(theIndexes)); + myConn.reset(new TElemNum(theConnectivities)); + + myConnMode = theConnMode; + } + }; + + //--------------------------------------------------------------- + template + struct TTPolyedreInfo: + virtual TPolyedreInfo, + virtual TTElemInfo + { + typedef TTElemInfo TElemInfoBase; + + TTPolyedreInfo(const PMeshInfo& theMeshInfo, const PPolyedreInfo& theInfo): + TElemInfoBase(theMeshInfo,theInfo) + { + myEntity = theInfo->GetEntity(); + myGeom = theInfo->GetGeom(); + + myIndex.reset(new TElemNum(*theInfo->myIndex)); + myFaces.reset(new TElemNum(*theInfo->myFaces)); + myConn.reset(new TElemNum(*theInfo->myConn)); + + myConnMode = theInfo->GetConnMode(); + } + + TTPolyedreInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TInt theNbElem, + TInt theNbFaces, + TInt theConnSize, + EConnectivite theConnMode, + EBooleen theIsElemNum, + EBooleen theIsElemNames): + TElemInfoBase(theMeshInfo, + theNbElem, + theIsElemNum, + theIsElemNames) + { + myEntity = theEntity; + myGeom = theGeom; + + myIndex.reset(new TElemNum(theNbElem + 1)); + myFaces.reset(new TElemNum(theNbFaces)); + myConn.reset(new TElemNum(theConnSize)); + + myConnMode = theConnMode; + } + + TTPolyedreInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + const TIntVector& theIndexes, + const TIntVector& theFaces, + const TIntVector& theConnectivities, + EConnectivite theConnMode, + const TIntVector& theFamilyNums, + const TIntVector& theElemNums, + const TStringVector& theElemNames): + TElemInfoBase(theMeshInfo, + (TInt)theIndexes.size()-1, + theFamilyNums, + theElemNums, + theElemNames) + { + myEntity = theEntity; + myGeom = theGeom; + + myIndex.reset(new TElemNum(theIndexes)); + myFaces.reset(new TElemNum(theFaces)); + myConn.reset(new TElemNum(theConnectivities)); + + myConnMode = theConnMode; + } + }; + + //--------------------------------------------------------------- + template + struct TTCellInfo: + virtual TCellInfo, + virtual TTElemInfo + { + typedef TTElemInfo TElemInfoBase; + + TTCellInfo(const PMeshInfo& theMeshInfo, const PCellInfo& theInfo): + TElemInfoBase(theMeshInfo,theInfo) + { + myEntity = theInfo->GetEntity(); + myGeom = theInfo->GetGeom(); + myConnMode = theInfo->GetConnMode(); + + TInt aConnDim = GetNbNodes(myGeom); + TInt aNbConn = GetNbConn(myGeom, myEntity, myMeshInfo->myDim); + myConn.reset(new TElemNum(myNbElem * aNbConn)); + for(TInt anElemId = 0; anElemId < myNbElem; anElemId++){ + TConnSlice aConnSlice = GetConnSlice(anElemId); + TCConnSlice aConnSlice2 = theInfo->GetConnSlice(anElemId); + for(TInt anConnId = 0; anConnId < aConnDim; anConnId++){ + aConnSlice[anConnId] = aConnSlice2[anConnId]; + } + } + } + + TTCellInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TInt theNbElem, + EConnectivite theConnMode, + EBooleen theIsElemNum, + EBooleen theIsElemNames, + EModeSwitch theMode): + TModeSwitchInfo(theMode), + TElemInfoBase(theMeshInfo, + theNbElem, + theIsElemNum, + theIsElemNames) + { + myEntity = theEntity; + myGeom = theGeom; + + myConnMode = theConnMode; + TInt aNbConn = GetNbConn(theGeom, myEntity, theMeshInfo->myDim); + myConn.reset(new TElemNum(theNbElem * aNbConn)); + } + + TTCellInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + const TIntVector& theConnectivities, + EConnectivite theConnMode, + const TIntVector& theFamilyNums, + const TIntVector& theElemNums, + const TStringVector& theElemNames, + EModeSwitch theMode): + TModeSwitchInfo(theMode), + TElemInfoBase(theMeshInfo, + (TInt)theConnectivities.size() / GetNbNodes(theGeom), + theFamilyNums, + theElemNums, + theElemNames) + { + myEntity = theEntity; + myGeom = theGeom; + + myConnMode = theConnMode; + TInt aConnDim = GetNbNodes(myGeom); + TInt aNbConn = GetNbConn(myGeom, myEntity, myMeshInfo->myDim); + myConn.reset(new TElemNum(myNbElem * aNbConn)); + for(TInt anElemId = 0; anElemId < myNbElem; anElemId++){ + TConnSlice aConnSlice = GetConnSlice(anElemId); + for(TInt anConnId = 0; anConnId < aConnDim; anConnId++){ + aConnSlice[anConnId] = theConnectivities[anElemId*aConnDim + anConnId]; + } + } + } + + virtual + TInt + GetConnDim() const + { + return GetNbConn(myGeom, myEntity, myMeshInfo->myDim); + } + + }; + + //--------------------------------------------------------------- + template + struct TTBallInfo: + virtual TBallInfo, + virtual TTCellInfo + { + typedef TTCellInfo TCellInfoBase; + + TTBallInfo(const PMeshInfo& theMeshInfo, const PBallInfo& theInfo): + TCellInfoBase::TElemInfoBase(theMeshInfo, theInfo), + TCellInfoBase(theMeshInfo,theInfo) + { + myDiameters = theInfo->myDiameters; + } + + TTBallInfo(const PMeshInfo& theMeshInfo, + TInt theNbElem, + EBooleen theIsElemNum ): + TCellInfoBase::TElemInfoBase(theMeshInfo, + theNbElem, + theIsElemNum, + /*theIsElemNames=*/eFAUX), + TCellInfoBase(theMeshInfo, + eSTRUCT_ELEMENT, + eBALL, + theNbElem, + /*EConnectivite=*/eNOD, + theIsElemNum, + /*theIsElemNames=*/eFAUX, + eFULL_INTERLACE) + { + myDiameters.resize( theNbElem ); + } + + TTBallInfo(const PMeshInfo& theMeshInfo, + const TIntVector& theNodes, + TFloatVector& theDiameters, + const TIntVector& theFamilyNums, + const TIntVector& theElemNums): + TCellInfoBase::TElemInfoBase(theMeshInfo, + (TInt)std::max(theNodes.size(),theDiameters.size() ), + theFamilyNums, + theElemNums, + TStringVector()), + TCellInfoBase(theMeshInfo, + eSTRUCT_ELEMENT, + eBALL, + theNodes, + /*EConnectivite=*/eNOD, + theFamilyNums, + theElemNums, + TStringVector(), + eFULL_INTERLACE) + { + myDiameters.swap( theDiameters ); + } + }; + + //--------------------------------------------------------------- + template + struct TTFieldInfo: + virtual TFieldInfo, + virtual TTNameInfo + { + typedef TTNameInfo TNameInfoBase; + + TTFieldInfo(const PMeshInfo& theMeshInfo, const PFieldInfo& theInfo): + TNameInfoBase(theInfo->GetName()) + { + myMeshInfo = theMeshInfo; + + myNbComp = theInfo->GetNbComp(); + myCompNames.resize(myNbComp*GetPNOMLength()+1); + for(TInt anId = 0; anId < myNbComp; anId++){ + SetCompName(anId,theInfo->GetCompName(anId)); + } + + myUnitNames.resize(myNbComp*GetPNOMLength()+1); + for(TInt anId = 0; anId < myNbComp; anId++){ + SetUnitName(anId,theInfo->GetUnitName(anId)); + } + + myType = theInfo->GetType(); + + myIsLocal = theInfo->GetIsLocal(); + myNbRef = theInfo->GetNbRef(); + } + + TTFieldInfo(const PMeshInfo& theMeshInfo, + TInt theNbComp, + ETypeChamp theType, + const std::string& theValue, + EBooleen theIsLocal, + TInt theNbRef): + TNameInfoBase(theValue) + { + myMeshInfo = theMeshInfo; + + myNbComp = theNbComp; + myCompNames.resize(theNbComp*GetPNOMLength()+1); + myUnitNames.resize(theNbComp*GetPNOMLength()+1); + + myType = theType; + + myIsLocal = theIsLocal; + myNbRef = theNbRef; + } + + virtual + std::string + GetCompName(TInt theId) const + { + return GetString(theId,GetPNOMLength(),myCompNames); + } + + virtual + void + SetCompName(TInt theId, const std::string& theValue) + { + SetString(theId,GetPNOMLength(),myCompNames,theValue); + } + + virtual + std::string + GetUnitName(TInt theId) const + { + return GetString(theId,GetPNOMLength(),myUnitNames); + } + + virtual + void + SetUnitName(TInt theId, const std::string& theValue) + { + SetString(theId,GetPNOMLength(),myUnitNames,theValue); + } + }; + + + //--------------------------------------------------------------- + template + struct TTGaussInfo: + virtual TGaussInfo, + virtual TTNameInfo + { + typedef TTNameInfo TNameInfoBase; + + TTGaussInfo(const TGaussInfo::TInfo& theInfo, + EModeSwitch theMode): + TModeSwitchInfo(theMode), + TNameInfoBase(boost::get<1>(boost::get<0>(theInfo))) + { + const TGaussInfo::TKey& aKey = boost::get<0>(theInfo); + + myGeom = boost::get<0>(aKey); + myRefCoord.resize(GetNbRef()*GetDim()); + + TInt aNbGauss = boost::get<1>(theInfo); + myGaussCoord.resize(aNbGauss*GetDim()); + myWeight.resize(aNbGauss); + } + }; + + + //--------------------------------------------------------------- + template + struct TTTimeStampInfo: virtual TTimeStampInfo + { + TTTimeStampInfo(const PFieldInfo& theFieldInfo, const PTimeStampInfo& theInfo) + { + myFieldInfo = theFieldInfo; + + myEntity = theInfo->GetEntity(); + myGeom2Size = theInfo->GetGeom2Size(); + + myNumDt = theInfo->GetNumDt(); + myNumOrd = theInfo->GetNumOrd(); + myDt = theInfo->GetDt(); + + myUnitDt.resize(GetPNOMLength()+1); + SetUnitDt(theInfo->GetUnitDt()); + + myGeom2NbGauss = theInfo->myGeom2NbGauss; + myGeom2Gauss = theInfo->GetGeom2Gauss(); + } + + TTTimeStampInfo(const PFieldInfo& theFieldInfo, + EEntiteMaillage theEntity, + const TGeom2Size& theGeom2Size, + const TGeom2NbGauss& theGeom2NbGauss, + TInt theNumDt, + TInt theNumOrd, + TFloat theDt, + const std::string& theUnitDt, + const TGeom2Gauss& theGeom2Gauss) + { + myFieldInfo = theFieldInfo; + + myEntity = theEntity; + myGeom2Size = theGeom2Size; + + myNumDt = theNumDt; + myNumOrd = theNumDt; + myDt = theDt; + + myUnitDt.resize(GetPNOMLength()+1); + SetUnitDt(theUnitDt); + + myGeom2NbGauss = theGeom2NbGauss; + myGeom2Gauss = theGeom2Gauss; + } + + virtual + std::string + GetUnitDt() const + { + return GetString(0,GetPNOMLength(),myUnitDt); + } + + virtual + void + SetUnitDt(const std::string& theValue) + { + SetString(0,GetPNOMLength(),myUnitDt,theValue); + } + }; + + + //--------------------------------------------------------------- + template + struct TTProfileInfo: + virtual TProfileInfo, + virtual TTNameInfo + { + typedef TTNameInfo TNameInfoBase; + + TTProfileInfo(const TProfileInfo::TInfo& theInfo, + EModeProfil theMode): + TNameInfoBase(boost::get<0>(theInfo)) + { + TInt aSize = boost::get<1>(theInfo); + myElemNum.reset(new TElemNum(aSize)); + myMode = aSize > 0? theMode: eNO_PFLMOD; + } + }; + + + //--------------------------------------------------------------- + template + struct TTTimeStampValue: virtual TTimeStampValue + { + TTTimeStampValue(const PTimeStampInfo& theTimeStampInfo, + const PTimeStampValueBase& theInfo, + ETypeChamp theTypeChamp) + { + typedef TTimeStampValue TCompatible; + if(TCompatible* aCompatible = dynamic_cast(theInfo.get())){ + this->myTimeStampInfo = theTimeStampInfo; + this->myTypeChamp = theTypeChamp; + this->myGeom2Profile = aCompatible->GetGeom2Profile(); + this->myGeom2Value = aCompatible->myGeom2Value; + this->myGeomSet = aCompatible->GetGeomSet(); + }else + EXCEPTION(std::runtime_error,"TTTimeStampValue::TTTimeStampValue - use incompatible arguments!"); + } + + TTTimeStampValue(const PTimeStampInfo& theTimeStampInfo, + ETypeChamp theTypeChamp, + const TGeom2Profile& theGeom2Profile, + EModeSwitch theMode): + TModeSwitchInfo(theMode) + { + this->myTimeStampInfo = theTimeStampInfo; + + this->myTypeChamp = theTypeChamp; + + this->myGeom2Profile = theGeom2Profile; + + TInt aNbComp = theTimeStampInfo->myFieldInfo->myNbComp; + + const TGeom2Size& aGeom2Size = theTimeStampInfo->GetGeom2Size(); + TGeom2Size::const_iterator anIter = aGeom2Size.begin(); + for(; anIter != aGeom2Size.end(); anIter++){ + const EGeometrieElement& aGeom = anIter->first; + TInt aNbElem = anIter->second; + + MED::PProfileInfo aProfileInfo; + MED::TGeom2Profile::const_iterator anIter = theGeom2Profile.find(aGeom); + if(anIter != theGeom2Profile.end()) + aProfileInfo = anIter->second; + + if(aProfileInfo && aProfileInfo->IsPresent()) + aNbElem = aProfileInfo->GetSize(); + + TInt aNbGauss = theTimeStampInfo->GetNbGauss(aGeom); + + this->GetMeshValue(aGeom).Allocate(aNbElem,aNbGauss,aNbComp); + } + } + + virtual + size_t + GetValueSize(EGeometrieElement theGeom) const + { + return this->GetMeshValue(theGeom).GetSize(); + } + + virtual + size_t + GetNbVal(EGeometrieElement theGeom) const + { + return this->GetMeshValue(theGeom).GetNbVal(); + } + + virtual + size_t + GetNbGauss(EGeometrieElement theGeom) const + { + return this->GetMeshValue(theGeom).GetNbGauss(); + } + + virtual + void + AllocateValue(EGeometrieElement theGeom, + TInt theNbElem, + TInt theNbGauss, + TInt theNbComp, + EModeSwitch theMode = eFULL_INTERLACE) + { + this->GetMeshValue(theGeom).Allocate(theNbElem,theNbGauss,theNbComp,theMode); + } + + virtual + unsigned char* + GetValuePtr(EGeometrieElement theGeom) + { + return this->GetMeshValue(theGeom).GetValuePtr(); + } + }; + + //--------------------------------------------------------------- + template + struct TTGrilleInfo: + virtual TGrilleInfo + { + TTGrilleInfo(const PMeshInfo& theMeshInfo, + const PGrilleInfo& theInfo) + { + myMeshInfo = theMeshInfo; + + myCoord = theInfo->GetNodeCoord(); + + myGrilleType = theInfo->GetGrilleType(); + + myCoordNames = theInfo->myCoordNames; + + myCoordUnits = theInfo->myCoordUnits; + + myIndixes = theInfo->GetMapOfIndexes(); + + myGrilleStructure = theInfo->GetGrilleStructure(); + + myGrilleType = theInfo->GetGrilleType(); + + myFamNumNode.resize(theInfo->GetNbNodes()); + myFamNumNode = theInfo->myFamNumNode; + + myFamNum = theInfo->myFamNum; + } + + TTGrilleInfo(const PMeshInfo& theMeshInfo, + const EGrilleType& type, + const TInt nnoeuds) + { + myMeshInfo = theMeshInfo; + TInt aSpaceDim = theMeshInfo->GetSpaceDim(); + if(type == eGRILLE_STANDARD){ + myCoord.resize(aSpaceDim*nnoeuds); + myCoordNames.resize(aSpaceDim*GetPNOMLength()+1); + myCoordUnits.resize(aSpaceDim*GetPNOMLength()+1); + } else { //if(type == eGRILLE_CARTESIENNE){ + myCoordNames.resize(aSpaceDim*GetPNOMLength()+aSpaceDim); + myCoordUnits.resize(aSpaceDim*GetPNOMLength()+aSpaceDim); + } + myGrilleStructure.resize(aSpaceDim); + myFamNumNode.resize(nnoeuds); + } + + TTGrilleInfo(const PMeshInfo& theMeshInfo, + const EGrilleType& type) + { + myMeshInfo = theMeshInfo; + TInt aSpaceDim = theMeshInfo->GetSpaceDim(); + if(type == eGRILLE_STANDARD){ + myCoordNames.resize(aSpaceDim*GetPNOMLength()+1); + myCoordUnits.resize(aSpaceDim*GetPNOMLength()+1); + } else {// if(type == eGRILLE_CARTESIENNE){ + myCoordNames.resize(aSpaceDim*GetPNOMLength()+aSpaceDim); + myCoordUnits.resize(aSpaceDim*GetPNOMLength()+aSpaceDim); + } + myGrilleStructure.resize(aSpaceDim); + } + + TTGrilleInfo(const PMeshInfo& theMeshInfo, + const EGrilleType& type, + const MED::TIntVector& nbNodeVec) + { + myMeshInfo = theMeshInfo; + + TInt aSpaceDim = theMeshInfo->GetSpaceDim(); + if(type == eGRILLE_STANDARD){ + myCoordNames.resize(aSpaceDim*GetPNOMLength()+1); + myCoordUnits.resize(aSpaceDim*GetPNOMLength()+1); + } else {// if(type == eGRILLE_CARTESIENNE){ + myCoordNames.resize(aSpaceDim*GetPNOMLength()+aSpaceDim); + myCoordUnits.resize(aSpaceDim*GetPNOMLength()+aSpaceDim); + } + + if(type != eGRILLE_STANDARD) + for(unsigned int aAxe=0;aAxe(),myCoordNames); + } + + virtual + void + SetCoordName(TInt theId, const std::string& theValue) + { + SetString(theId,GetPNOMLength(),myCoordNames,theValue); + } + + virtual + std::string + GetCoordUnit(TInt theId) const + { + return GetString(theId,GetPNOMLength(),myCoordUnits); + } + + virtual + void + SetCoordUnit(TInt theId, const std::string& theValue) + { + SetString(theId,GetPNOMLength(),myCoordUnits,theValue); + } + + }; +} + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_TWrapper.hxx b/src/3rdParty/salomesmesh/inc/MED_TWrapper.hxx new file mode 100644 index 000000000000..637a403933f7 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_TWrapper.hxx @@ -0,0 +1,578 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// +#ifndef MED_TWrapper_HeaderFile +#define MED_TWrapper_HeaderFile + +#include "MED_TStructures.hxx" +#include "MED_Wrapper.hxx" + +namespace MED +{ + + template + class TTWrapper: public TWrapper + { + public: + //---------------------------------------------------------------------------- + //! Gets version of the MED library used for the MED file + virtual + EVersion + GetVersion() + { + return eVersion; + } + + //---------------------------------------------------------------------------- + virtual + PMeshInfo + CrMeshInfo(TInt theDim = 0, TInt theSpaceDim = 0, + const std::string& theValue = "", + EMaillage theType = eNON_STRUCTURE, + const std::string& theDesc = "") + { + return PMeshInfo(new TTMeshInfo + (theDim, + theSpaceDim, + theValue, + theType, + theDesc)); + } + + virtual + PMeshInfo + CrMeshInfo(const PMeshInfo& theInfo) + { + return PMeshInfo(new TTMeshInfo(theInfo)); + } + + + //---------------------------------------------------------------------------- + virtual + PFamilyInfo + CrFamilyInfo(const PMeshInfo& theMeshInfo, + TInt theNbGroup = 0, + TInt theNbAttr = 0, + TInt theId = 0, + const std::string& theValue = "") + { + return PFamilyInfo(new TTFamilyInfo + (theMeshInfo, + theNbGroup, + theNbAttr, + theId, + theValue)); + } + + virtual + PFamilyInfo + CrFamilyInfo(const PMeshInfo& theMeshInfo, + const std::string& theValue, + TInt theId, + const MED::TStringSet& theGroupNames, + const MED::TStringVector& theAttrDescs = MED::TStringVector(), + const MED::TIntVector& theAttrIds = MED::TIntVector(), + const MED::TIntVector& theAttrVals = MED::TIntVector()) + { + return PFamilyInfo(new TTFamilyInfo + (theMeshInfo, + theValue, + theId, + theGroupNames, + theAttrDescs, + theAttrIds, + theAttrVals)); + } + + virtual + PFamilyInfo + CrFamilyInfo(const PMeshInfo& theMeshInfo, + const PFamilyInfo& theInfo) + { + return PFamilyInfo(new TTFamilyInfo + (theMeshInfo, + theInfo)); + } + + //---------------------------------------------------------------------------- + virtual + PElemInfo + CrElemInfo(const PMeshInfo& theMeshInfo, + TInt theNbElem, + EBooleen theIsElemNum = eVRAI, + EBooleen theIsElemNames = eVRAI) + { + return PElemInfo(new TTElemInfo + (theMeshInfo, + theNbElem, + theIsElemNum, + theIsElemNames)); + } + + virtual + PElemInfo + CrElemInfo(const PMeshInfo& theMeshInfo, + TInt theNbElem, + const TIntVector& theFamNum, + const TIntVector& aElemNum, + const TStringVector& aElemNames) + { + return PElemInfo(new TTElemInfo + (theMeshInfo, + theNbElem, + theFamNum, + aElemNum, + aElemNames)); + } + + //---------------------------------------------------------------------------- + virtual + PNodeInfo + CrNodeInfo(const PMeshInfo& theMeshInfo, + TInt theNbElem, + EModeSwitch theMode = eFULL_INTERLACE, + ERepere theSystem = eCART, + EBooleen theIsElemNum = eVRAI, + EBooleen theIsElemNames = eVRAI) + { + return PNodeInfo(new TTNodeInfo + (theMeshInfo, + theNbElem, + theMode, + theSystem, + theIsElemNum, + theIsElemNames)); + } + + virtual + PNodeInfo + CrNodeInfo(const PMeshInfo& theMeshInfo, + const TFloatVector& theNodeCoords, + EModeSwitch theMode = eFULL_INTERLACE, + ERepere theSystem = eCART, + const TStringVector& theCoordNames = TStringVector(), + const TStringVector& theCoordUnits = TStringVector(), + const TIntVector& theFamilyNums = TIntVector(), + const TIntVector& theElemNums = TIntVector(), + const TStringVector& theElemNames = TStringVector()) + { + return PNodeInfo(new TTNodeInfo + (theMeshInfo, + theNodeCoords, + theMode, + theSystem, + theCoordNames, + theCoordUnits, + theFamilyNums, + theElemNums, + theElemNames)); + } + + virtual + PNodeInfo + CrNodeInfo(const PMeshInfo& theMeshInfo, + const PNodeInfo& theInfo) + { + return PNodeInfo(new TTNodeInfo + (theMeshInfo, + theInfo)); + } + + //---------------------------------------------------------------------------- + virtual + PPolygoneInfo + CrPolygoneInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TInt theNbElem, + TInt theConnSize, + EConnectivite theConnMode = eNOD, + EBooleen theIsElemNum = eVRAI, + EBooleen theIsElemNames = eVRAI) + { + return PPolygoneInfo(new TTPolygoneInfo + (theMeshInfo, + theEntity, + theGeom, + theNbElem, + theConnSize, + theConnMode, + theIsElemNum, + theIsElemNames)); + } + + virtual + PPolygoneInfo + CrPolygoneInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + const TIntVector& theIndexes, + const TIntVector& theConnectivities, + EConnectivite theConnMode = eNOD, + const TIntVector& theFamilyNums = TIntVector(), + const TIntVector& theElemNums = TIntVector(), + const TStringVector& theElemNames = TStringVector()) + { + return PPolygoneInfo(new TTPolygoneInfo + (theMeshInfo, + theEntity, + theGeom, + theIndexes, + theConnectivities, + theConnMode, + theFamilyNums, + theElemNums, + theElemNames)); + } + + virtual + PPolygoneInfo + CrPolygoneInfo(const PMeshInfo& theMeshInfo, + const PPolygoneInfo& theInfo) + { + return PPolygoneInfo(new TTPolygoneInfo + (theMeshInfo, + theInfo)); + } + + //---------------------------------------------------------------------------- + virtual + PPolyedreInfo + CrPolyedreInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TInt theNbElem, + TInt theNbFaces, + TInt theConnSize, + EConnectivite theConnMode = eNOD, + EBooleen theIsElemNum = eVRAI, + EBooleen theIsElemNames = eVRAI) + { + return PPolyedreInfo(new TTPolyedreInfo + (theMeshInfo, + theEntity, + theGeom, + theNbElem, + theNbFaces, + theConnSize, + theConnMode, + theIsElemNum, + theIsElemNames)); + } + + virtual + PPolyedreInfo + CrPolyedreInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + const TIntVector& theIndexes, + const TIntVector& theFaces, + const TIntVector& theConnectivities, + EConnectivite theConnMode = eNOD, + const TIntVector& theFamilyNums = TIntVector(), + const TIntVector& theElemNums = TIntVector(), + const TStringVector& theElemNames = TStringVector()) + { + return PPolyedreInfo(new TTPolyedreInfo + (theMeshInfo, + theEntity, + theGeom, + theIndexes, + theFaces, + theConnectivities, + theConnMode, + theFamilyNums, + theElemNums, + theElemNames)); + } + + virtual + PPolyedreInfo + CrPolyedreInfo(const PMeshInfo& theMeshInfo, + const PPolyedreInfo& theInfo) + { + return PPolyedreInfo(new TTPolyedreInfo + (theMeshInfo, + theInfo)); + } + + //---------------------------------------------------------------------------- + virtual + PCellInfo + CrCellInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TInt theNbElem, + EConnectivite theConnMode = eNOD, + EBooleen theIsElemNum = eVRAI, + EBooleen theIsElemNames = eVRAI, + EModeSwitch theMode = eFULL_INTERLACE) + { + return PCellInfo(new TTCellInfo + (theMeshInfo, + theEntity, + theGeom, + theNbElem, + theConnMode, + theIsElemNum, + theIsElemNames, + theMode)); + } + + virtual + PCellInfo + CrCellInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + const TIntVector& theConnectivities, + EConnectivite theConnMode = eNOD, + const TIntVector& theFamilyNums = TIntVector(), + const TIntVector& theElemNums = TIntVector(), + const TStringVector& theElemNames = TStringVector(), + EModeSwitch theMode = eFULL_INTERLACE) + { + return PCellInfo(new TTCellInfo + (theMeshInfo, + theEntity, + theGeom, + theConnectivities, + theConnMode, + theFamilyNums, + theElemNums, + theElemNames, + theMode)); + } + + virtual + PCellInfo + CrCellInfo(const PMeshInfo& theMeshInfo, + const PCellInfo& theInfo) + { + return PCellInfo(new TTCellInfo + (theMeshInfo, + theInfo)); + } + + //---------------------------------------------------------------------------- + //! Creates a MEDWrapper MED Balls representation + virtual PBallInfo CrBallInfo(const PMeshInfo& theMeshInfo, + TInt theNbBalls, + EBooleen theIsElemNum = eVRAI) + { + return PBallInfo( new TTBallInfo( theMeshInfo, theNbBalls, theIsElemNum )); + } + + //! Creates a MEDWrapper MED Balls representation + virtual PBallInfo CrBallInfo(const PMeshInfo& theMeshInfo, + const TIntVector& theNodes, + TFloatVector& theDiameters, + const TIntVector& theFamilyNums = TIntVector(), + const TIntVector& theElemNums = TIntVector()) + { + return PBallInfo( new TTBallInfo( theMeshInfo, theNodes, theDiameters, + theFamilyNums, theElemNums)); + } + + //! A copy-constructor for the MEDWrapper MED Balls representation + virtual PBallInfo CrBallInfo(const PMeshInfo& theMeshInfo, + const PBallInfo& theInfo) + { + return PBallInfo( new TTBallInfo( theMeshInfo, theInfo )); + } + + //---------------------------------------------------------------------------- + virtual + PFieldInfo + CrFieldInfo(const PMeshInfo& theMeshInfo, + TInt theNbComp = 0, + ETypeChamp theType = eFLOAT64, + const std::string& theValue = "", + EBooleen theIsLocal = eVRAI, + TInt theNbRef = 1) + { + return PFieldInfo(new TTFieldInfo + (theMeshInfo, + theNbComp, + theType, + theValue, + theIsLocal, + theNbRef)); + } + + virtual + PFieldInfo + CrFieldInfo(const PMeshInfo& theMeshInfo, + const PFieldInfo& theInfo) + { + return PFieldInfo(new TTFieldInfo + (theMeshInfo, + theInfo)); + } + + + //---------------------------------------------------------------------------- + virtual + PTimeStampInfo + CrTimeStampInfo(const PFieldInfo& theFieldInfo, + EEntiteMaillage theEntity, + const TGeom2Size& theGeom2Size, + const TGeom2NbGauss& theGeom2NbGauss = TGeom2NbGauss(), + TInt theNumDt = 0, + TInt theNumOrd = 0, + TFloat theDt = 0, + const std::string& theUnitDt = "", + const TGeom2Gauss& theGeom2Gauss = TGeom2Gauss()) + { + return PTimeStampInfo(new TTTimeStampInfo + (theFieldInfo, + theEntity, + theGeom2Size, + theGeom2NbGauss, + theNumDt, + theNumOrd, + theDt, + theUnitDt, + theGeom2Gauss)); + } + + virtual + PTimeStampInfo + CrTimeStampInfo(const PFieldInfo& theFieldInfo, + const PTimeStampInfo& theInfo) + { + return PTimeStampInfo(new TTTimeStampInfo + (theFieldInfo, + theInfo)); + } + + + //---------------------------------------------------------------------------- + virtual + PGaussInfo + CrGaussInfo(const TGaussInfo::TInfo& theInfo, + EModeSwitch theMode = eFULL_INTERLACE) + { + return PGaussInfo(new TTGaussInfo + (theInfo, + theMode)); + } + + + //---------------------------------------------------------------------------- + virtual + PProfileInfo + CrProfileInfo(const TProfileInfo::TInfo& theInfo, + EModeProfil theMode = eCOMPACT) + { + return PProfileInfo(new TTProfileInfo + (theInfo, + theMode)); + } + + + //---------------------------------------------------------------------------- + virtual + PTimeStampValueBase + CrTimeStampValue(const PTimeStampInfo& theTimeStampInfo, + ETypeChamp theTypeChamp, + const TGeom2Profile& theGeom2Profile = TGeom2Profile(), + EModeSwitch theMode = eFULL_INTERLACE) + { + if(theTypeChamp == eFLOAT64) + return PTimeStampValueBase(new TTTimeStampValue + (theTimeStampInfo, + theTypeChamp, + theGeom2Profile, + theMode)); + return PTimeStampValueBase(new TTTimeStampValue + (theTimeStampInfo, + theTypeChamp, + theGeom2Profile, + theMode)); + } + + virtual + PTimeStampValueBase + CrTimeStampValue(const PTimeStampInfo& theTimeStampInfo, + const PTimeStampValueBase& theInfo, + ETypeChamp theTypeChamp) + { + if(theTypeChamp == eFLOAT64) + return PTimeStampValueBase(new TTTimeStampValue + (theTimeStampInfo, + theInfo, + theTypeChamp)); + return PTimeStampValueBase(new TTTimeStampValue + (theTimeStampInfo, + theInfo, + theTypeChamp)); + } + + //---------------------------------------------------------------------------- + virtual + PGrilleInfo + CrGrilleInfo(const PMeshInfo& theMeshInfo, + const PGrilleInfo& theInfo) + { + return PGrilleInfo(new TTGrilleInfo + (theMeshInfo, + theInfo)); + } + virtual + PGrilleInfo + CrGrilleInfo(const PMeshInfo& theMeshInfo, + const EGrilleType& type) + { + return PGrilleInfo(new TTGrilleInfo + (theMeshInfo, + type)); + } + + virtual + PGrilleInfo + CrGrilleInfo(const PMeshInfo& theMeshInfo, + const EGrilleType& type, + const TInt& nbNodes) + { + return PGrilleInfo(new TTGrilleInfo + (theMeshInfo, + type, + nbNodes)); + } + + virtual + PGrilleInfo + CrGrilleInfo(const PMeshInfo& theMeshInfo, + const EGrilleType& type, + const MED::TIntVector& nbNodeVec) + { + return PGrilleInfo(new TTGrilleInfo + (theMeshInfo, + type, + nbNodeVec)); + } + //---------------------------------------------------------------------------- + }; + +} + + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_Utilities.hxx b/src/3rdParty/salomesmesh/inc/MED_Utilities.hxx new file mode 100644 index 000000000000..250a05c7cde3 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_Utilities.hxx @@ -0,0 +1,73 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// +#ifndef MED_Utilities_HeaderFile +#define MED_Utilities_HeaderFile + +#include "MED_WrapperBase.hxx" + +#include +#include +#include +#include +#include + + +namespace MED +{ + class MEDWRAPPER_EXPORT PrefixPrinter + { + static int myCounter; + bool myIsActive; + public: + PrefixPrinter(bool theIsActive = true); + ~PrefixPrinter(); + + static std::string GetPrefix(); + }; +} + +#ifdef _DEBUG_ + #define MSG(deb,msg) if(deb) std::cout< + TInt MED_V22_WRAPPER_EXPORT + GetDESCLength(); + + template<> + TInt MED_V22_WRAPPER_EXPORT + GetIDENTLength(); + + template<> + TInt MED_V22_WRAPPER_EXPORT + GetNOMLength(); + + template<> + TInt MED_V22_WRAPPER_EXPORT + GetLNOMLength(); + + template<> + TInt MED_V22_WRAPPER_EXPORT + GetPNOMLength(); + + template<> + void MED_V22_WRAPPER_EXPORT + GetVersionRelease(TInt& majeur, TInt& mineur, TInt& release); + + template<> + TInt MED_V22_WRAPPER_EXPORT + GetNbConn(EGeometrieElement typmai, + EEntiteMaillage typent, + TInt mdim); + + namespace V2_2 + { + //---------------------------------------------------------------------------- + class TFile; + typedef boost::shared_ptr PFile; + + typedef enum {eLECTURE, eLECTURE_ECRITURE, eLECTURE_AJOUT, eCREATION} EModeAcces; + + //---------------------------------------------------------------------------- + class MED_V22_WRAPPER_EXPORT TVWrapper: public MED::TTWrapper + { + TVWrapper(); + TVWrapper(const TVWrapper&); + TVWrapper& operator=(const TVWrapper&); + + public: + TVWrapper(const std::string& theFileName); + + //---------------------------------------------------------------------------- + virtual + TInt + GetNbMeshes(TErr* theErr = NULL); + + virtual + void + GetMeshInfo(TInt theMeshId, MED::TMeshInfo&, + TErr* theErr = NULL); + + virtual + void + SetMeshInfo(const MED::TMeshInfo& theInfo, + TErr* theErr = NULL); + + void SetMeshInfo(const MED::TMeshInfo& theInfo, + EModeAcces theMode, + TErr* theErr = NULL); + + + //---------------------------------------------------------------------------- + virtual + TInt + GetNbFamilies(const MED::TMeshInfo& theMeshInfo, + TErr* theErr = NULL); + + virtual + TInt + GetNbFamAttr(TInt theFamId, + const MED::TMeshInfo& theInfo, + TErr* theErr = NULL); + + virtual + TInt + GetNbFamGroup(TInt theFamId, + const MED::TMeshInfo& theInfo, + TErr* theErr = NULL); + + virtual + void + GetFamilyInfo(TInt theFamId, + MED::TFamilyInfo& theInfo, + TErr* theErr = NULL); + + virtual + void + SetFamilyInfo(const MED::TFamilyInfo& theInfo, + TErr* theErr = NULL); + + void + SetFamilyInfo(const MED::TFamilyInfo& theInfo, + EModeAcces theMode, + TErr* theErr = NULL); + + + //---------------------------------------------------------------------------- + virtual + void + GetNames(TElemInfo& theInfo, + TInt nb, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL); + + virtual + void + GetNumeration(TElemInfo& theInfo, + TInt nb, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL); + + virtual + void + GetFamilies(TElemInfo& theInfo, + TInt nb, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL); + + virtual + void + SetNames(const TElemInfo& theInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL); + + void + SetNames(const TElemInfo& theInfo, + EModeAcces theMode, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL); + + virtual + void + SetNumeration(const TElemInfo& theInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL); + void + SetNumeration(const TElemInfo& theInfo, + EModeAcces theMode, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL); + + virtual + void + SetFamilies(const TElemInfo& theInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL); + void + SetFamilies(const TElemInfo& theInfo, + EModeAcces theMode, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL); + + //---------------------------------------------------------------------------- + virtual + TInt + GetNbNodes(const MED::TMeshInfo& theMeshInfo, + TErr* theErr = NULL) + { + return GetNbNodes(theMeshInfo,eCOOR,theErr); + } + + TInt + GetNbNodes(const MED::TMeshInfo& theMeshInfo, + ETable theTable, + TErr* theErr = NULL); + + virtual + void + GetNodeInfo(MED::TNodeInfo& theInfo, + TErr* theErr = NULL); + + virtual + void + SetNodeInfo(const MED::TNodeInfo& theInfo, + TErr* theErr = NULL); + + void + SetNodeInfo(const MED::TNodeInfo& theInfo, + EModeAcces theMode, + TErr* theErr = NULL); + + //---------------------------------------------------------------------------- + virtual + void + GetPolygoneInfo(TPolygoneInfo& theInfo, + TErr* theErr = NULL); + + virtual + void + SetPolygoneInfo(const TPolygoneInfo& theInfo, + TErr* theErr = NULL); + + void + SetPolygoneInfo(const MED::TPolygoneInfo& theInfo, + EModeAcces theMode, + TErr* theErr = NULL); + + virtual + TInt + GetNbPolygones(const TMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + EConnectivite theConnMode = eNOD, + TErr* theErr = NULL); + + virtual + TInt + GetPolygoneConnSize(const TMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + EConnectivite theConnMode = eNOD, + TErr* theErr = NULL); + + //---------------------------------------------------------------------------- + virtual + void + GetPolyedreInfo(TPolyedreInfo& theInfo, + TErr* theErr = NULL); + + virtual + void + SetPolyedreInfo(const TPolyedreInfo& theInfo, + TErr* theErr = NULL); + + void + SetPolyedreInfo(const MED::TPolyedreInfo& theInfo, + EModeAcces theMode, + TErr* theErr = NULL); + + virtual + TInt + GetNbPolyedres(const TMeshInfo& theMeshInfo, + EEntiteMaillage, + EGeometrieElement, + EConnectivite, + TErr* theErr = NULL); + + virtual + void + GetPolyedreConnSize(const TMeshInfo& theMeshInfo, + TInt& theNbFaces, + TInt& theConnSize, + EConnectivite theConnMode = eNOD, + TErr* theErr = NULL); + + //---------------------------------------------------------------------------- + virtual + TEntityInfo + GetEntityInfo(const MED::TMeshInfo& theMeshInfo, + EConnectivite theConnMode = eNOD, + TErr* theErr = NULL); + + virtual + TInt + GetNbCells(const MED::TMeshInfo& theMeshInfo, + EEntiteMaillage, + EGeometrieElement, + EConnectivite theConnMode = eNOD, + TErr* theErr = NULL); + + virtual + void + GetCellInfo(MED::TCellInfo& theInfo, + TErr* theErr = NULL); + + virtual + void + SetCellInfo(const MED::TCellInfo& theInfo, + TErr* theErr = NULL); + + void + SetCellInfo(const MED::TCellInfo& theInfo, + EModeAcces theMode, + TErr* theErr = NULL); + + //---------------------------------------------------------------------------- + //! Read geom type of MED_BALL structural element + EGeometrieElement GetBallGeom(const TMeshInfo& theMeshInfo); + + //! Read number of balls in the Mesh + virtual TInt GetNbBalls(const TMeshInfo& theMeshInfo); + + //! Read a MEDWrapped representation of MED_BALL from the MED file + virtual void GetBallInfo(TBallInfo& theInfo, TErr* theErr = NULL); + + //! Write a MEDWrapped representation of MED_BALL to the MED file + virtual void SetBallInfo(const TBallInfo& theInfo, TErr* theErr); + + //! Write a MEDWrapped representation of MED_BALL to the MED file + void SetBallInfo(const TBallInfo& theInfo, EModeAcces theMode, TErr* theErr); + + //---------------------------------------------------------------------------- + virtual + TInt + GetNbFields(TErr* theErr = NULL); + + virtual + TInt + GetNbComp(TInt theFieldId, + TErr* theErr = NULL); + + virtual + void + GetFieldInfo(TInt theFieldId, + MED::TFieldInfo& theInfo, + TErr* theErr = NULL); + + virtual + void + SetFieldInfo(const MED::TFieldInfo& theInfo, + TErr* theErr = NULL); + + void + SetFieldInfo(const MED::TFieldInfo& theInfo, + EModeAcces theMode, + TErr* theErr = NULL); + + //---------------------------------------------------------------------------- + virtual + TInt + GetNbGauss(TErr* theErr = NULL); + + virtual + TGaussInfo::TInfo + GetGaussPreInfo(TInt theId, + TErr* theErr = NULL); + + virtual + void + GetGaussInfo(TInt theId, + TGaussInfo& theInfo, + TErr* theErr = NULL); + + //---------------------------------------------------------------------------- + virtual + TInt + GetNbProfiles(TErr* theErr = NULL); + + virtual + TProfileInfo::TInfo + GetProfilePreInfo(TInt theId, + TErr* theErr = NULL); + + virtual + void + GetProfileInfo(TInt theId, + TProfileInfo& theInfo, + TErr* theErr = NULL); + + virtual + void + SetProfileInfo(const TProfileInfo& theInfo, + TErr* theErr = NULL); + + void + SetProfileInfo(const TProfileInfo& theInfo, + EModeAcces theMode, + TErr* theErr = NULL); + + //---------------------------------------------------------------------------- + virtual + TInt + GetNbTimeStamps(const MED::TFieldInfo& theInfo, + const MED::TEntityInfo& theEntityInfo, + EEntiteMaillage& theEntity, + TGeom2Size& theGeom2Size, + TErr* theErr = NULL); + + virtual + void + GetTimeStampInfo(TInt theTimeStampId, + MED::TTimeStampInfo& theInfo, + TErr* theErr = NULL); + + virtual + void + GetTimeStampValue(const PTimeStampValueBase& theTimeStampValue, + const TMKey2Profile& theMKey2Profile, + const TKey2Gauss& theKey2Gauss, + TErr* theErr = NULL); + + virtual + void + SetTimeStampValue(const PTimeStampValueBase& theTimeStampValue, + TErr* theErr = NULL); + + void + SetTimeStampValue(const PTimeStampValueBase& theTimeStampValue, + EModeAcces theMode, + TErr* theErr = NULL); + + + //---------------------------------------------------------------------------- + virtual + void + GetGrilleInfo(TGrilleInfo& theGrilleInfo, + TErr* theErr = NULL); + + virtual + void + SetGrilleInfo(const MED::TGrilleInfo& theGrilleInfo, + TErr* theErr = NULL); + + void + SetGrilleInfo(const MED::TGrilleInfo& theGrilleInfo, + EModeAcces theMode, + TErr* theErr = NULL); + + virtual + void + GetGrilleType(const MED::TMeshInfo& theMeshInfo, + EGrilleType& type, + TErr* theErr = NULL); + + void + GetGrilleStruct(const MED::TMeshInfo& theMeshInfo, + TIntVector& theStruct, + TErr* theErr = NULL); + + protected: + PFile myFile; + }; + } +} + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_Vector.hxx b/src/3rdParty/salomesmesh/inc/MED_Vector.hxx new file mode 100644 index 000000000000..38fd1bd6d5d7 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_Vector.hxx @@ -0,0 +1,152 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// +#ifndef MED_Vector_HeaderFile +#define MED_Vector_HeaderFile + +#include +#include + +//#if defined(_DEBUG_) +# define MED_TVECTOR_CHECK_RANGE +//#endif + +namespace MED +{ + + //! Main purpose to introduce the class was to customize operator [] + template > + class TVector : public std::vector<_Tp, _Alloc> + { + public: + typedef size_t size_type; + + typedef std::vector<_Tp, _Alloc> superclass; + typedef typename superclass::allocator_type allocator_type; + + typedef _Tp value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + + protected: + void + check_range(size_type __n) const + { + if (__n >= this->size()) + throw std::out_of_range("TVector [] access out of range"); + } + + const_reference + get_value(size_type __n) const + { + return superclass::operator[](__n); + } + + reference + get_value(size_type __n) + { + return superclass::operator[](__n); + } + + public: + explicit + TVector(const allocator_type& __a = allocator_type()): + superclass(__a) + {} + + TVector(size_type __n, const value_type& __val, + const allocator_type& __a = allocator_type()): + superclass(__n, __val, __a) + {} + + explicit + TVector(size_type __n): + superclass(__n) + {} + + TVector(const TVector& __x): + superclass(__x) + {} + + template + TVector(_InputIterator __first, _InputIterator __last, + const allocator_type& __a = allocator_type()): + superclass(__first, __last, __a) + {} + + template + TVector(TVector<_Yp, _Al> __y): + superclass(__y.begin(), __y.end()) + {} + + TVector& + operator=(const TVector& __x) + { + superclass::operator=(__x); + return *this; + } + + template + TVector& + operator=(TVector<_Yp, _Al> __y) + { + this->assign(__y.begin(), __y.end()); + return *this; + } + + reference + operator[](size_type __n) + { +#if defined(MED_TVECTOR_CHECK_RANGE) + check_range(__n); +#endif + return get_value(__n); + } + + const_reference + operator[](size_type __n) const + { +#if defined(MED_TVECTOR_CHECK_RANGE) + check_range(__n); +#endif + return get_value(__n); + } + + reference + at(size_type __n) + { + check_range(__n); + return get_value(__n); + } + + const_reference + at(size_type __n) const + { + check_range(__n); + return get_value(__n); + } + }; + +} + +#undef MED_TVECTOR_CHECK_RANGE + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_Wrapper.hxx b/src/3rdParty/salomesmesh/inc/MED_Wrapper.hxx new file mode 100644 index 000000000000..2a14dd844c35 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_Wrapper.hxx @@ -0,0 +1,1052 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +#ifndef MED_Wrapper_HeaderFile +#define MED_Wrapper_HeaderFile + +#include "MED_WrapperBase.hxx" + +#include "MED_Structures.hxx" +#include "MED_Algorithm.hxx" + +#include + +namespace MED +{ + + //---------------------------------------------------------------------------- + //! Define a base class that wraps the MED API + struct MEDWRAPPER_EXPORT TWrapper + { + typedef boost::mutex TMutex; + //! This is a syncronization primitive which allow to support thread safety for the MED access + TMutex myMutex; + + virtual + ~TWrapper(); + + //---------------------------------------------------------------------------- + //! Gets version of the MED library used for the MED file + virtual + EVersion + GetVersion() = 0; + + //---------------------------------------------------------------------------- + //! Creates a MEDWrapper MED Mesh representation + virtual + PMeshInfo + CrMeshInfo(TInt theDim = 0, TInt theSpaceDim = 0, + const std::string& theValue = "", + EMaillage theType = eNON_STRUCTURE, + const std::string& theDesc = "") = 0; + + //! A copy-constructor for the MEDWrapper MED Mesh representation + virtual + PMeshInfo + CrMeshInfo(const PMeshInfo& theInfo) = 0; + + //! Read number of MED Mesh entities in the defined MED file + virtual + TInt + GetNbMeshes(TErr* theErr = NULL) = 0; + + //! Read a MEDWrapper MED Mesh representation by its number + virtual + void + GetMeshInfo(TInt theMeshId, + TMeshInfo& theInfo, + TErr* theErr = NULL) = 0; + + //! Write the MEDWrapper MED Mesh representation in the defined MED file + virtual + void + SetMeshInfo(const TMeshInfo& theInfo, + TErr* theErr = NULL) = 0; + + //! Read a MEDWrapper MED Mesh representation by its number + virtual + PMeshInfo + GetPMeshInfo(TInt theId, + TErr* theErr = NULL); + + + //---------------------------------------------------------------------------- + //! Read number of MED Family entities in the defined MED file + virtual + TInt + GetNbFamilies(const TMeshInfo& theMeshInfo, + TErr* theErr = NULL) = 0; + + //! Read number of attributes for defined MED Family + virtual + TInt + GetNbFamAttr(TInt theFamId, + const TMeshInfo& theInfo, + TErr* theErr = NULL) = 0; + + //! Read number of MED Groups where MED Family with the number belong to + virtual + TInt + GetNbFamGroup(TInt theFamId, + const TMeshInfo& theInfo, + TErr* theErr = NULL) = 0; + + //! Read a MEDWrapper MED Family representation by its number + virtual + void + GetFamilyInfo(TInt theFamId, + TFamilyInfo& theInfo, + TErr* theErr = NULL) = 0; + + //! Write a MEDWrapper MED Family representation by its number + virtual + void + SetFamilyInfo(const TFamilyInfo& theInfo, + TErr* theErr = NULL) = 0; + + //! Creates a MEDWrapper MED Family representation + virtual + PFamilyInfo + CrFamilyInfo(const PMeshInfo& theMeshInfo, + TInt theNbGroup = 0, + TInt theNbAttr = 0, + TInt theId = 0, + const std::string& theValue = "") = 0; + + //! Creates a MEDWrapper MED Family representation + virtual + PFamilyInfo + CrFamilyInfo(const PMeshInfo& theMeshInfo, + const std::string& theValue, + TInt theId, + const TStringSet& theGroupNames, + const TStringVector& theAttrDescs = TStringVector(), + const TIntVector& theAttrIds = TIntVector(), + const TIntVector& theAttrVals = TIntVector()) = 0; + + //! A copy-constructor for the MEDWrapper MED Family representation + virtual + PFamilyInfo + CrFamilyInfo(const PMeshInfo& theMeshInfo, + const PFamilyInfo& theInfo) = 0; + + //! Write a MEDWrapper MED Family representation by its number + PFamilyInfo + GetPFamilyInfo(const PMeshInfo& theMeshInfo, + TInt theId, + TErr* theErr = NULL); + + //---------------------------------------------------------------------------- + //! Read sequence of names for any descendant of TElemInfo + virtual + void + GetNames(TElemInfo& theInfo, + TInt theNb, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL) + {} + + //! Read sequence of numerous for any descendant of TElemInfo + virtual + void + GetNumeration(TElemInfo& theInfo, + TInt theNb, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL) + {} + + //! Read sequence MED Family indexes for any descendant of TElemInfo + virtual + void + GetFamilies(TElemInfo& theInfo, + TInt theNb, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL) + {} + + //! Write sequence of names for any descendant of TElemInfo + virtual + void + SetNames(const TElemInfo& theInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL) + {} + + //! Write sequence of numerous for any descendant of TElemInfo + virtual + void + SetNumeration(const TElemInfo& theInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL) + {} + + //! Write sequence MED Family indexes for any descendant of TElemInfo + virtual + void + SetFamilies(const TElemInfo& theInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TErr* theErr = NULL) + {} + + //! Read a MEDWrapper MED Element representation from defined MED file + PElemInfo + GetPElemInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity = eNOEUD, + EGeometrieElement theGeom = ePOINT1, + EConnectivite theConnMode = eNOD, + TErr* theErr = NULL); + + //---------------------------------------------------------------------------- + //! Read number of nodes in defined MED Mesh + virtual + TInt + GetNbNodes(const TMeshInfo& theMeshInfo, + TErr* theErr = NULL) = 0; + + virtual + TInt + GetNbNodes(const TMeshInfo& theMeshInfo, + ETable theTable, + TErr* theErr = NULL) + { + return 0; + } + + //! Read a MEDWrapper MED Nodes representation from defined MED file + virtual + void + GetNodeInfo(TNodeInfo& theInfo, + TErr* theErr = NULL) = 0; + + //! Write the MEDWrapper MED Nodes representation into defined MED file + virtual + void + SetNodeInfo(const TNodeInfo& theInfo, + TErr* theErr = NULL) = 0; + + //! Creates a MEDWrapper MED Nodes representation + virtual + PElemInfo + CrElemInfo(const PMeshInfo& theMeshInfo, + TInt theNbElem, + EBooleen theIsElemNum = eVRAI, + EBooleen theIsElemNames = eVRAI) + { + return PElemInfo(); + } + + //! Creates a MEDWrapper MED Nodes representation + virtual + PElemInfo + CrElemInfo(const PMeshInfo& theMeshInfo, + TInt theNbElem, + const TIntVector& theFamNum, + const TIntVector& aElemNum, + const TStringVector& aElemNames) + { + return PElemInfo(); + } + + //! Creates a MEDWrapper MED Nodes representation + virtual + PNodeInfo + CrNodeInfo(const PMeshInfo& theMeshInfo, + TInt theNbElem, + EModeSwitch theMode = eFULL_INTERLACE, + ERepere theSystem = eCART, + EBooleen theIsElemNum = eVRAI, + EBooleen theIsElemNames = eVRAI) = 0; + + //! Creates a MEDWrapper MED Nodes representation + virtual + PNodeInfo + CrNodeInfo(const PMeshInfo& theMeshInfo, + const TFloatVector& theNodeCoords, + EModeSwitch theMode = eFULL_INTERLACE, + ERepere theSystem = eCART, + const TStringVector& theCoordNames = TStringVector(), + const TStringVector& theCoordUnits = TStringVector(), + const TIntVector& theFamilyNums = TIntVector(), + const TIntVector& theElemNums = TIntVector(), + const TStringVector& theElemNames = TStringVector()) = 0; + + //! A copy-constructor for the MEDWrapper MED Nodes representation + virtual + PNodeInfo + CrNodeInfo(const PMeshInfo& theMeshInfo, + const PNodeInfo& theInfo) = 0; + + //! Read a MEDWrapper MED Nodes representation from defined MED file + PNodeInfo + GetPNodeInfo(const PMeshInfo& theMeshInfo, + TErr* theErr = NULL); + + //---------------------------------------------------------------------------- + //! Read a MEDWrapper MED Polygones representation from defined MED file + /*! This feature is supported only for version of 2.2 and higher */ + virtual + void + GetPolygoneInfo(TPolygoneInfo& theInfo, + TErr* theErr = NULL) + {} + + //! Write a MEDWrapper MED Polygones representation from defined MED file + /*! This feature is supported only for version of 2.2 and higher */ + virtual + void + SetPolygoneInfo(const TPolygoneInfo& theInfo, + TErr* theErr = NULL) + {} + + //! Read number of MED Polygones in defined MED Mesh + /*! This feature is supported only for version of 2.2 and higher */ + virtual + TInt + GetNbPolygones(const TMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + EConnectivite theConnMode = eNOD, + TErr* theErr = NULL) + { + return 0; + } + + //! Read connectivity infroamtion for the MED Polygones in defined MED Mesh + /*! This feature is supported only for version of 2.2 and higher */ + virtual + TInt + GetPolygoneConnSize(const TMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + EConnectivite theConnMode = eNOD, + TErr* theErr = NULL) + { + return 0; + } + + //! Creates a MEDWrapper MED Polygones representation + /*! This feature is supported only for version of 2.2 and higher */ + virtual + PPolygoneInfo + CrPolygoneInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TInt theNbElem, + TInt theConnSize, + EConnectivite theConnMode = eNOD, + EBooleen theIsElemNum = eVRAI, + EBooleen theIsElemNames = eVRAI) + { + return PPolygoneInfo(); + } + + //! Creates a MEDWrapper MED Polygones representation + /*! This feature is supported only for version of 2.2 and higher */ + virtual + PPolygoneInfo + CrPolygoneInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + const TIntVector& theIndexes, + const TIntVector& theConnectivities, + EConnectivite theConnMode = eNOD, + const TIntVector& theFamilyNums = TIntVector(), + const TIntVector& theElemNums = TIntVector(), + const TStringVector& theElemNames = TStringVector()) + { + return PPolygoneInfo(); + } + + //! A copy-constructor for the MEDWrapper MED Polygones representation + virtual + PPolygoneInfo + CrPolygoneInfo(const PMeshInfo& theMeshInfo, + const PPolygoneInfo& theInfo) + { + return PPolygoneInfo(); + } + + //! Read a MEDWrapper MED Polygones representation from defined MED file + /*! This feature is support only for version of 2.2 and higher */ + PPolygoneInfo + GetPPolygoneInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + EConnectivite theConnMode = eNOD); + + //---------------------------------------------------------------------------- + //! Read a MEDWrapper MED Polyedres representation from defined MED file + /*! This feature is support only for version of 2.2 and higher */ + virtual + void + GetPolyedreInfo(TPolyedreInfo& theInfo, + TErr* theErr = NULL) + {} + + //! Write a MEDWrapper MED Polyedres representation from defined MED file + /*! This feature is support only for version of 2.2 and higher */ + virtual + void + SetPolyedreInfo(const TPolyedreInfo& theInfo, + TErr* theErr = NULL) + {} + + //! Read number of MED Polyedres in defined MED Mesh + /*! This feature is support only for version of 2.2 and higher */ + virtual + TInt + GetNbPolyedres(const TMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + EConnectivite theConnMode = eNOD, + TErr* theErr = NULL) + { + return 0; + } + + //! Read connectivity infroamtion for the MED Polyedres in defined MED Mesh + /*! This feature is support only for version of 2.2 and higher */ + virtual + void + GetPolyedreConnSize(const TMeshInfo& theMeshInfo, + TInt& theNbFaces, + TInt& theConnSize, + EConnectivite theConnMode = eNOD, + TErr* theErr = NULL) + { + theNbFaces = theConnSize = 0; + } + + virtual + PPolyedreInfo + CrPolyedreInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TInt theNbElem, + TInt theNbFaces, + TInt theConnSize, + EConnectivite theConnMode = eNOD, + EBooleen theIsElemNum = eVRAI, + EBooleen theIsElemNames = eVRAI) + { + return PPolyedreInfo(); + } + + //! Creates a MEDWrapper MED Polyedres representation + /*! This feature is support only for version of 2.2 and higher */ + virtual + PPolyedreInfo + CrPolyedreInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + const TIntVector& theIndexes, + const TIntVector& theFaces, + const TIntVector& theConnectivities, + EConnectivite theConnMode = eNOD, + const TIntVector& theFamilyNums = TIntVector(), + const TIntVector& theElemNums = TIntVector(), + const TStringVector& theElemNames = TStringVector()) + { + return PPolyedreInfo(); + } + + //! A copy-constructor for the MEDWrapper MED Polyedres representation + virtual + PPolyedreInfo + CrPolyedreInfo(const PMeshInfo& theMeshInfo, + const PPolyedreInfo& theInfo) + { + return PPolyedreInfo(); + } + + //! Read a MEDWrapper MED Polyedres representation from defined MED file + /*! This feature is support only for version of 2.2 and higher */ + PPolyedreInfo + GetPPolyedreInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + EConnectivite theConnMode = eNOD); + + //---------------------------------------------------------------------------- + //! Get TEntityInfo which contains brief information about existing cells and their destribution among MED ENTITIES + virtual + TEntityInfo + GetEntityInfo(const TMeshInfo& theMeshInfo, + EConnectivite theConnMode = eNOD, + TErr* theErr = NULL) = 0; + + //! Read number of cells for defined MED Mesh, ENTITY and geometrical type with define mode of connectivity + virtual + TInt + GetNbCells(const TMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + EConnectivite theConnMode = eNOD, + TErr* theErr = NULL) = 0; + + //! Read a MEDWrapper MED Cells representation from defined MED file + virtual + void + GetCellInfo(TCellInfo& theInfo, + TErr* theErr = NULL) = 0; + + //! Write the MEDWrapper MED Cells representation into defined MED file + virtual + void + SetCellInfo(const TCellInfo& theInfo, + TErr* theErr = NULL) = 0; + + //! Creates a MEDWrapper MED Cells representation + virtual + PCellInfo + CrCellInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + TInt theNbElem, + EConnectivite theConnMode = eNOD, + EBooleen theIsElemNum = eVRAI, + EBooleen theIsElemNames = eVRAI, + EModeSwitch theMode = eFULL_INTERLACE) = 0; + + //! Creates a MEDWrapper MED Cells representation + virtual + PCellInfo + CrCellInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + const TIntVector& theConnectivities, + EConnectivite theConnMode = eNOD, + const TIntVector& theFamilyNums = TIntVector(), + const TIntVector& theElemNums = TIntVector(), + const TStringVector& theElemNames = TStringVector(), + EModeSwitch theMode = eFULL_INTERLACE) = 0; + + //! A copy-constructor for the MEDWrapper MED Cells representation + virtual + PCellInfo + CrCellInfo(const PMeshInfo& theMeshInfo, + const PCellInfo& theInfo) = 0; + + //! Read a MEDWrapper MED Cells representation from defined MED file + PCellInfo + GetPCellInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + EConnectivite theConnMode = eNOD, + TErr* theErr = NULL); + + //---------------------------------------------------------------------------- + //! Read number of balls in the Mesh + /*! This feature is supported since version 3.0 */ + virtual + TInt + GetNbBalls(const TMeshInfo& theMeshInfo) + { + return 0; + } + + //! Read a MEDWrapped representation of MED_BALL from the MED file + /*! This feature is supported since version 3.0 */ + virtual + void + GetBallInfo(TBallInfo& theInfo, + TErr* theErr = NULL) + {} + + //! Write a MEDWrapped representation of MED_BALL to the MED file + /*! This feature is supported since version 3.0 */ + virtual + void + SetBallInfo(const TBallInfo& theInfo, + TErr* theErr = NULL) + {} + + //! Creates a MEDWrapper MED Balls representation + /*! This feature is supported since version 3.0 */ + virtual + PBallInfo + CrBallInfo(const PMeshInfo& theMeshInfo, + TInt theNbBalls, + EBooleen theIsElemNum = eVRAI) + { + return PBallInfo(); + } + + //! Creates a MEDWrapper MED Balls representation + /*! This feature is supported since version 3.0 */ + virtual + PBallInfo + CrBallInfo(const PMeshInfo& theMeshInfo, + const TIntVector& theNodes, + TFloatVector& theDiameters, + const TIntVector& theFamilyNums = TIntVector(), + const TIntVector& theElemNums = TIntVector()) + { + return PBallInfo(); + } + + //! A copy-constructor for the MEDWrapped MED Balls representation + virtual + PBallInfo + CrBallInfo(const PMeshInfo& theMeshInfo, + const PBallInfo& theInfo) + { + return PBallInfo(); + } + + //! Read a MEDWrapped MED Balls representation from defined MED file + /*! This feature is supported since version 3.0 */ + virtual + PBallInfo + GetPBallInfo(const PMeshInfo& theMeshInfo); + + //---------------------------------------------------------------------------- + //! Read number of MED FIELDS in defined MED Mesh + virtual + TInt + GetNbFields(TErr* theErr = NULL) = 0; + + //! Read number of components for the defined MED FIELD by its order number + virtual + TInt + GetNbComp(TInt theFieldId, + TErr* theErr = NULL) = 0; + + //! Read MEDWrapper MED FIELD representation by its order number + virtual + void + GetFieldInfo(TInt theFieldId, + TFieldInfo& theInfo, + TErr* theErr = NULL) = 0; + + //! Write MEDWrapper MED FIELD representation into defined MED file + virtual + void + SetFieldInfo(const TFieldInfo& theInfo, + TErr* theErr = NULL) = 0; + + + //! Creates a MEDWrapper MED FIELD representation + virtual + PFieldInfo + CrFieldInfo(const PMeshInfo& theMeshInfo, + TInt theNbComp = 0, + ETypeChamp theType = eFLOAT64, + const std::string& theValue = "", + EBooleen theIsLocal = eVRAI, + TInt theNbRef = 1) = 0; + + //! A copy-constructor for the MEDWrapper MED FIELD representation + virtual + PFieldInfo + CrFieldInfo(const PMeshInfo& theMeshInfo, + const PFieldInfo& theInfo) = 0; + + //! Read a MEDWrapper MED FIELD representation from defined MED file + PFieldInfo + GetPFieldInfo(const PMeshInfo& theMeshInfo, + TInt theId, + TErr* theErr = NULL); + + + //---------------------------------------------------------------------------- + //! Read number of MED GAUSS in defined MED Mesh + /*! This feature is support only for version of 2.2 and higher */ + virtual + TInt + GetNbGauss(TErr* theErr = NULL) + { + return TInt(); + } + + //! Read brief MED GAUSS information by its order number from defined MED Mesh + /*! This feature is support only for version of 2.2 and higher */ + virtual + TGaussInfo::TInfo + GetGaussPreInfo(TInt theId, + TErr* theErr = NULL) + { + return TGaussInfo::TInfo( TGaussInfo::TKey(ePOINT1,""),0 ); + } + + //! Read a MEDWrapper MED GAUSS representation by its order number from defined MED file + /*! This feature is support only for version of 2.2 and higher */ + virtual + void + GetGaussInfo(TInt theId, + TGaussInfo& theInfo, + TErr* theErr = NULL) + {} + + //! Creates a MEDWrapper MED GAUSS representation + /*! This feature is support only for version of 2.2 and higher */ + virtual + PGaussInfo + CrGaussInfo(const TGaussInfo::TInfo& theInfo, + EModeSwitch theMode = eFULL_INTERLACE) = 0; + + + //---------------------------------------------------------------------------- + //! Read number of MED TIMESTAMPS in defined MED Mesh + /*! + By the way some additional information can be obtained: + - to what MED ENTITY the MED TIMESTAMP conntected to; + - on what geometrical types the MED TIMESTAMP defined to. + */ + virtual + TInt + GetNbTimeStamps(const TFieldInfo& theInfo, + const TEntityInfo& theEntityInfo, + EEntiteMaillage& theEntity, + TGeom2Size& theGeom2Size, + TErr* theErr = NULL) = 0; + + //! Read MEDWrapper MED TIMESTAMP representation by its order number + virtual + void + GetTimeStampInfo(TInt theTimeStampId, + TTimeStampInfo& theInfo, + TErr* theErr = NULL) = 0; + + //! Creates a MEDWrapper MED TIMESTAMP representation + virtual + PTimeStampInfo + CrTimeStampInfo(const PFieldInfo& theFieldInfo, + EEntiteMaillage theEntity, + const TGeom2Size& theGeom2Size, + const TGeom2NbGauss& theGeom2NbGauss = TGeom2NbGauss(), + TInt theNumDt = 0, + TInt theNumOrd = 0, + TFloat theDt = 0, + const std::string& theUnitDt = "", + const TGeom2Gauss& theGeom2Gauss = TGeom2Gauss()) = 0; + + //! A copy-constructor for the MEDWrapper MED TIMESTAMP representation + virtual + PTimeStampInfo + CrTimeStampInfo(const PFieldInfo& theFieldInfo, + const PTimeStampInfo& theInfo) = 0; + + //! Read MEDWrapper MED TIMESTAMP representation by its order number + PTimeStampInfo + GetPTimeStampInfo(const PFieldInfo& theFieldInfo, + EEntiteMaillage theEntity, + const TGeom2Size& theGeom2Size, + TInt theId, + TErr* theErr = NULL); + + + //---------------------------------------------------------------------------- + //! Read number of MED PROFILES in defined MED Mesh + virtual + TInt + GetNbProfiles(TErr* theErr = NULL) = 0; + + //! Read brief MED PROFILE information by its order number from defined MED Mesh + virtual + TProfileInfo::TInfo + GetProfilePreInfo(TInt theId, + TErr* theErr = NULL) = 0; + + //! Read a MEDWrapper MED PROFILE representation by its order number from defined MED file + virtual + void + GetProfileInfo(TInt theId, + TProfileInfo& theInfo, + TErr* theErr = NULL) = 0; + + //! Creates a MEDWrapper MED PROFILE representation + virtual + PProfileInfo + CrProfileInfo(const TProfileInfo::TInfo& theInfo, + EModeProfil theMode = eCOMPACT) = 0; + + //! Write a MEDWrapper MED PROFILE representation + virtual + void + SetProfileInfo(const TProfileInfo& theInfo, + TErr* theErr = NULL) = 0; + + //! Read a MEDWrapper MED PROFILE representation by its order number from defined MED file + PProfileInfo + GetPProfileInfo(TInt theId, + EModeProfil theMode = eCOMPACT, + TErr* theErr = NULL); + + + //---------------------------------------------------------------------------- + //! Read the values for MEDWrapper MED TIEMSTAMP from defined MED file + virtual + void + GetTimeStampValue(const PTimeStampValueBase& theTimeStampValue, + const TMKey2Profile& theMKey2Profile, + const TKey2Gauss& theKey2Gauss, + TErr* theErr = NULL) = 0; + + //! Write the values for MEDWrapper MED TIEMSTAMP to defined MED file + virtual + void + SetTimeStampValue(const PTimeStampValueBase& theTimeStampValue, + TErr* theErr = NULL) = 0; + + //! Creates the values for MEDWrapper MED TIEMSTAMP representation + virtual + PTimeStampValueBase + CrTimeStampValue(const PTimeStampInfo& theTimeStampInfo, + ETypeChamp theTypeChamp, + const TGeom2Profile& theGeom2Profile = TGeom2Profile(), + EModeSwitch theMode = eFULL_INTERLACE) = 0; + + //! Creates the values for MEDWrapper MED TIEMSTAMP representation + virtual + PTimeStampValueBase + CrTimeStampValue(const PTimeStampInfo& theTimeStampInfo, + const TGeom2Profile& theGeom2Profile = TGeom2Profile(), + EModeSwitch theMode = eFULL_INTERLACE); + + //! A copy-constructor for the values for MEDWrapper MED TIEMSTAMP representation + virtual + PTimeStampValueBase + CrTimeStampValue(const PTimeStampInfo& theTimeStampInfo, + const PTimeStampValueBase& theInfo, + ETypeChamp theTypeChamp) = 0; + + //! A copy-constructor for the values for MEDWrapper MED TIEMSTAMP representation + virtual + PTimeStampValueBase + CrTimeStampValue(const PTimeStampInfo& theTimeStampInfo, + const PTimeStampValueBase& theInfo); + + //! Read the values for MEDWrapper MED TIEMSTAMP from defined MED file + PTimeStampValueBase + GetPTimeStampValue(const PTimeStampInfo& theTimeStampInfo, + const TMKey2Profile& theMKey2Profile, + const TKey2Gauss& theKey2Gauss, + TErr* theErr = NULL); + + //---------------------------------------------------------------------------- + // Backward compatibility declarations + //! Read the values for MEDWrapper MED TIEMSTAMP from defined MED file + virtual + void + GetTimeStampVal(const PTimeStampVal& theVal, + const TMKey2Profile& theMKey2Profile, + const TKey2Gauss& theKey2Gauss, + TErr* theErr = NULL); + + //! Write the values for MEDWrapper MED TIEMSTAMP to defined MED file + virtual + void + SetTimeStamp(const PTimeStampVal& theVal, + TErr* theErr = NULL); + + //! Creates the values for MEDWrapper MED TIEMSTAMP representation + virtual + PTimeStampVal + CrTimeStampVal(const PTimeStampInfo& theTimeStampInfo, + const TGeom2Profile& theGeom2Profile = TGeom2Profile(), + EModeSwitch theMode = eFULL_INTERLACE); + + //! A copy-constructor for the values for MEDWrapper MED TIEMSTAMP representation + virtual + PTimeStampVal + CrTimeStampVal(const PTimeStampInfo& theTimeStampInfo, + const PTimeStampVal& theInfo); + + //! Read the values for MEDWrapper MED TIEMSTAMP from defined MED file + PTimeStampVal + GetPTimeStampVal(const PTimeStampInfo& theTimeStampInfo, + const TMKey2Profile& theMKey2Profile, + const TKey2Gauss& theKey2Gauss, + TErr* theErr = NULL); + + //---------------------------------------------------------------------------- + //! Read a MEDWrapper MED Grille representation from defined MED file + /*! This feature is support only for version of 2.2 and higher */ + PGrilleInfo + GetPGrilleInfo(const PMeshInfo& theMeshInfo); + + //! Read a MEDWrapper MED Grille representation from defined MED file + /*! This feature is support only for version of 2.2 and higher */ + PGrilleInfo + GetPGrilleInfo(const PMeshInfo& theMeshInfo, + const PGrilleInfo& theInfo); + + //! Read a MEDWrapper MED Grille representation from defined MED file + /*! This feature is support only for version of 2.2 and higher */ + virtual + void + GetGrilleInfo(TGrilleInfo& theInfo, + TErr* theErr = NULL) + {} + + //! Write the MEDWrapper MED Grille representation into defined MED file + /*! This feature is support only for version of 2.2 and higher */ + virtual + void + SetGrilleInfo(const TGrilleInfo& theInfo, + TErr* theErr = NULL) + {} + + /*! This feature is support only for version of 2.2 and higher */ + virtual + PGrilleInfo + CrGrilleInfo(const PMeshInfo& theMeshInfo, + const PGrilleInfo& theGrilleInfo) + { + return PGrilleInfo(); + } + + /*! This feature is support only for version of 2.2 and higher */ + virtual + PGrilleInfo + CrGrilleInfo(const PMeshInfo& theMeshInfo) + { + return PGrilleInfo(); + } + + /*! This feature is support only for version of 2.2 and higher */ + virtual + PGrilleInfo + CrGrilleInfo(const PMeshInfo& theMeshInfo, + const EGrilleType& type) + { + return PGrilleInfo(); + } + + /*! This feature is support only for version of 2.2 and higher */ + virtual + PGrilleInfo + CrGrilleInfo(const PMeshInfo& theMeshInfo, + const EGrilleType& type, + const TInt& nbNodes) + { + return PGrilleInfo(); + } + + /*! This feature is support only for version of 2.2 and higher */ + virtual + PGrilleInfo + CrGrilleInfo(const PMeshInfo& theMeshInfo, + const EGrilleType& type, + const MED::TIntVector& nbNodeVec) + { + return PGrilleInfo(); + } + + /*! This feature is support only for version of 2.2 and higher */ + virtual + void + GetGrilleType(const TMeshInfo& theMeshInfo, + EGrilleType& type, + TErr* theErr = NULL) + { + } + + }; + + + //---------------------------------------------------------------------------- + //! This class provide thread-safety for MEDWrapper interaction + class MEDWRAPPER_EXPORT TLockProxy + { + TLockProxy& operator=(const TLockProxy& ); + TWrapper* myWrapper; + + public: + TLockProxy(TWrapper* theWrapper); + + ~TLockProxy(); + + TWrapper * operator-> () const; + }; + + + //---------------------------------------------------------------------------- + //! To specialize the SharedPtr for TWrapper + template<> + class MEDWRAPPER_EXPORT SharedPtr: public boost::shared_ptr + { + public: + SharedPtr() {} + + template + explicit SharedPtr(Y * p): + boost::shared_ptr(p) + {} + + template + SharedPtr(SharedPtr const & r): + boost::shared_ptr(boost::dynamic_pointer_cast(r)) + {} + + template + SharedPtr& + operator=(SharedPtr const & r) + { + SharedPtr(r).swap(*this); + return *this; + } + + template + SharedPtr& + operator()(Y * p) // Y must be complete + { + return operator=(SharedPtr(p)); + } + + template + SharedPtr& + operator()(SharedPtr const & r) // Y must be complete + { + return operator=(SharedPtr(r)); + } + + TLockProxy operator-> () const // never throws + { + return TLockProxy(this->get()); + } + + protected: + operator const TWrapper& () const; + + operator TWrapper& (); + + TWrapper& operator* () const; + + TWrapper * get() const // never throws + { + return boost::shared_ptr::get(); + } + }; + + //---------------------------------------------------------------------------- + typedef SharedPtr PWrapper; +} + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_WrapperBase.hxx b/src/3rdParty/salomesmesh/inc/MED_WrapperBase.hxx new file mode 100755 index 000000000000..11dfc2d31e7e --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_WrapperBase.hxx @@ -0,0 +1,46 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : MED_WrapperBase.hxx +// Author : Alexander A. BORODIN +// +#ifndef _MED_WrapperBase_HXX_ +#define _MED_WrapperBase_HXX_ + +#ifdef WIN32 + #if defined MEDWRAPPER_BASE_EXPORTS || defined MEDWrapperBase_EXPORTS + #if defined WIN32 + #define MEDWRAPPER_EXPORT __declspec( dllexport ) + #else + #define MEDWRAPPER_EXPORT + #endif + #else + #if defined WIN32 + #define MEDWRAPPER_EXPORT __declspec( dllimport ) + #else + #define MEDWRAPPER_EXPORT + #endif + #endif +#else + #define MEDWRAPPER_EXPORT +#endif + +#endif diff --git a/src/3rdParty/salomesmesh/inc/MED_WrapperFactory.hxx b/src/3rdParty/salomesmesh/inc/MED_WrapperFactory.hxx new file mode 100755 index 000000000000..8bd7d0e7a9c5 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/MED_WrapperFactory.hxx @@ -0,0 +1,46 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : MED_WrapperFactory.hxx +// Author : Alexander A. BORODIN +// +#ifndef _MED_WrapperFactory_HXX_ +#define _MED_WrapperFactory_HXX_ + +#ifdef WIN32 + #if defined MEDWRAPPER_FACTORY_EXPORTS || defined MEDWrapper_EXPORTS + #if defined WIN32 + #define MEDWRAPPER_FACTORY_EXPORT __declspec( dllexport ) + #else + #define MEDWRAPPER_FACTORY_EXPORT + #endif + #else + #if defined WIN32 + #define MEDWRAPPER_FACTORY_EXPORT __declspec( dllimport ) + #else + #define MEDWRAPPER_FACTORY_EXPORT + #endif + #endif +#else + #define MEDWRAPPER_FACTORY_EXPORT +#endif + +#endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_Defs.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Defs.hxx index 2eb36ace02f5..53c3e1f8506b 100644 --- a/src/3rdParty/salomesmesh/inc/NETGENPlugin_Defs.hxx +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Defs.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + //============================================================================= // File : NETGENPlugin_Defs.hxx // Author : Alexander A. BORODIN @@ -27,7 +28,7 @@ #define _NETGENPlugin_DEFS_HXX_ #ifdef WIN32 - #ifdef NETGENPLUGIN_EXPORTS + #if defined NETGENPLUGIN_EXPORTS || defined NETGENEngine_EXPORTS #define NETGENPLUGIN_EXPORT __declspec( dllexport ) #else #define NETGENPLUGIN_EXPORT __declspec( dllimport ) diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis.hxx index 56d87070a61b..9b790ca02c35 100644 --- a/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis.hxx +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis.hxx @@ -1,31 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // NETGENPlugin : C++ implementation // File : NETGENPlugin_Hypothesis.hxx // Author : Michael Sazonov (OCN) // Date : 27/03/2006 // Project : SALOME -// $Header: /home/server/cvs/NETGENPLUGIN/NETGENPLUGIN_SRC/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx,v 1.4.2.2 2008/11/27 14:29:44 abd Exp $ -//============================================================================= // #ifndef _NETGENPlugin_Hypothesis_HXX_ #define _NETGENPlugin_Hypothesis_HXX_ @@ -33,11 +32,15 @@ #include "NETGENPlugin_Defs.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" + +#include // Parameters for work of NETGEN // +using namespace std; + class NETGENPLUGIN_EXPORT NETGENPlugin_Hypothesis: public SMESH_Hypothesis { public: @@ -47,6 +50,9 @@ public: void SetMaxSize(double theSize); double GetMaxSize() const { return _maxSize; } + void SetMinSize(double theSize); + double GetMinSize() const { return _minSize; } + void SetSecondOrder(bool theVal); bool GetSecondOrder() const { return _secondOrder; } @@ -77,6 +83,22 @@ public: void SetNbSegPerRadius(double theVal); double GetNbSegPerRadius() const { return _nbSegPerRadius; } + typedef std::map TLocalSize; + static TLocalSize GetDefaultLocalSize() { return TLocalSize(); } + void SetLocalSizeOnEntry(const std::string& entry, double localSize); + double GetLocalSizeOnEntry(const std::string& entry); + const TLocalSize& GetLocalSizesAndEntries() const { return _localSize; } + void UnsetLocalSizeOnEntry(const std::string& entry); + + void SetQuadAllowed(bool theVal); + bool GetQuadAllowed() const { return _quadAllowed; } + + void SetSurfaceCurvature(bool theVal); + bool GetSurfaceCurvature() const { return _surfaceCurvature; } + + void SetFuseEdges(bool theVal); + bool GetFuseEdges() const { return _fuseEdges; } + // the default values (taken from NETGEN 4.5 sources) static double GetDefaultMaxSize(); @@ -86,12 +108,15 @@ public: static double GetDefaultNbSegPerRadius(); static bool GetDefaultSecondOrder(); static bool GetDefaultOptimize(); + static bool GetDefaultQuadAllowed(); + static bool GetDefaultSurfaceCurvature(); + static bool GetDefaultFuseEdges(); // Persistence - virtual std::ostream & SaveTo(std::ostream & save); - virtual std::istream & LoadFrom(std::istream & load); - friend NETGENPLUGIN_EXPORT std::ostream & operator <<(std::ostream & save, NETGENPlugin_Hypothesis & hyp); - friend NETGENPLUGIN_EXPORT std::istream & operator >>(std::istream & load, NETGENPlugin_Hypothesis & hyp); + virtual ostream & SaveTo(ostream & save); + virtual istream & LoadFrom(istream & load); + friend NETGENPLUGIN_EXPORT ostream & operator <<(ostream & save, NETGENPlugin_Hypothesis & hyp); + friend NETGENPLUGIN_EXPORT istream & operator >>(istream & load, NETGENPlugin_Hypothesis & hyp); /*! * \brief Does nothing @@ -100,21 +125,25 @@ public: * \retval bool - always false */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - - /*! + + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0); private: - double _maxSize; + double _maxSize, _minSize; double _growthRate; double _nbSegPerEdge; double _nbSegPerRadius; Fineness _fineness; bool _secondOrder; bool _optimize; + TLocalSize _localSize; + bool _quadAllowed; + bool _surfaceCurvature; + bool _fuseEdges; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_2D.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_2D.hxx index 90137d2d6c05..c06cd461c1be 100644 --- a/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_2D.hxx +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_2D.hxx @@ -1,30 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // NETGENPlugin : C++ implementation // File : NETGENPlugin_Hypothesis_2D.hxx // Author : Michael Sazonov (OCN) // Date : 27/03/2006 // Project : SALOME -// $Header: /home/server/cvs/NETGENPLUGIN/NETGENPLUGIN_SRC/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.hxx,v 1.4.2.2 2008/11/27 14:29:44 abd Exp $ //============================================================================= // #ifndef _NETGENPlugin_Hypothesis_2D_HXX_ @@ -33,7 +33,7 @@ #include "NETGENPlugin_Defs.hxx" #include "NETGENPlugin_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" // Parameters for work of NETGEN. // This class is just to give 2D dimension, actually @@ -45,16 +45,16 @@ public: NETGENPlugin_Hypothesis_2D(int hypId, int studyId, SMESH_Gen * gen); - void SetQuadAllowed(bool theVal); - bool GetQuadAllowed() const { return _quadAllowed; } - static bool GetDefaultQuadAllowed(); + // void SetQuadAllowed(bool theVal); + // bool GetQuadAllowed() const { return _quadAllowed; } + // static bool GetDefaultQuadAllowed(); // Persistence - virtual std::ostream & SaveTo(std::ostream & save); - virtual std::istream & LoadFrom(std::istream & load); + // virtual ostream & SaveTo(ostream & save); + // virtual istream & LoadFrom(istream & load); -private: - bool _quadAllowed; +// private: +// bool _quadAllowed; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_2D_ONLY_i.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_2D_ONLY_i.hxx new file mode 100644 index 000000000000..a09514a938b9 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_2D_ONLY_i.hxx @@ -0,0 +1,57 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// NETGENPlugin : C++ implementation +// File : NETGENPlugin_Hypothesis_2D_ONLY_i.hxx +// Project : SALOME +//============================================================================= +// +#ifndef _NETGENPlugin_Hypothesis_2D_ONLY_i_HXX_ +#define _NETGENPlugin_Hypothesis_2D_ONLY_i_HXX_ + +#include "NETGENPlugin_Defs.hxx" + +#include +#include CORBA_SERVER_HEADER(NETGENPlugin_Algorithm) + +#include "NETGENPlugin_Hypothesis_2D_i.hxx" + +class SMESH_Gen; + +// NETGENPlugin parameters hypothesis ("2D only" case) + +class NETGENPLUGIN_EXPORT NETGENPlugin_Hypothesis_2D_ONLY_i: + public virtual POA_NETGENPlugin::NETGENPlugin_Hypothesis_2D_ONLY, + public NETGENPlugin_Hypothesis_2D_i +{ + public: + // Constructor + NETGENPlugin_Hypothesis_2D_ONLY_i (PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl); + // Destructor + virtual ~NETGENPlugin_Hypothesis_2D_ONLY_i(); + + char* GetName(); +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_2D_i.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_2D_i.hxx new file mode 100644 index 000000000000..9e90b6c08b12 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_2D_i.hxx @@ -0,0 +1,73 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// NETGENPlugin : C++ implementation +// File : NETGENPlugin_Hypothesis_2D_i.hxx +// Author : Michael Sazonov (OCN) +// Date : 03/04/2006 +// Project : SALOME +//============================================================================= +// +#ifndef _NETGENPlugin_Hypothesis_2D_i_HXX_ +#define _NETGENPlugin_Hypothesis_2D_i_HXX_ + +#include "NETGENPlugin_Defs.hxx" + +// #include +// #include CORBA_SERVER_HEADER(NETGENPlugin_Algorithm) + +#include "NETGENPlugin_Hypothesis_i.hxx" +#include "NETGENPlugin_Hypothesis_2D.hxx" + +class SMESH_Gen; + +// NETGENPlugin parameters hypothesis (2D case) + +class NETGENPLUGIN_EXPORT NETGENPlugin_Hypothesis_2D_i: + public virtual POA_NETGENPlugin::NETGENPlugin_Hypothesis_2D, + public NETGENPlugin_Hypothesis_i +{ + public: + // Constructor + NETGENPlugin_Hypothesis_2D_i (PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl); + // Destructor + virtual ~NETGENPlugin_Hypothesis_2D_i(); + + // Get implementation + ::NETGENPlugin_Hypothesis_2D* GetImpl(); + + // Verify whether hypothesis supports given entity type + CORBA::Boolean IsDimSupported( SMESH::Dimension type ); + + protected: + + // to remember whether a parameter is already set (issue 0021364) + // enum SettingMethod + // { + // METH_SetQuadAllowed = NETGENPlugin_Hypothesis_i::METH_LAST * 2, + // METH_LAST = METH_SetQuadAllowed + // }; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_3D_i.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_3D_i.hxx new file mode 100644 index 000000000000..6c7770721461 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_3D_i.hxx @@ -0,0 +1,59 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// NETGENPlugin : C++ implementation +// File : NETGENPlugin_Hypothesis_2D_i.hxx +// Project : SALOME +//============================================================================= +// +#ifndef _NETGENPlugin_Hypothesis_3D_i_HXX_ +#define _NETGENPlugin_Hypothesis_3D_i_HXX_ + +#include "NETGENPlugin_Defs.hxx" + +#include +#include CORBA_SERVER_HEADER(NETGENPlugin_Algorithm) + +#include "NETGENPlugin_Hypothesis_i.hxx" + +class SMESH_Gen; + +// NETGENPlugin parameters hypothesis (3D "only" case) + +class NETGENPLUGIN_EXPORT NETGENPlugin_Hypothesis_3D_i: + public virtual POA_NETGENPlugin::NETGENPlugin_Hypothesis_3D, + public NETGENPlugin_Hypothesis_i +{ + public: + // Constructor + NETGENPlugin_Hypothesis_3D_i (PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl); + + // Get type name of hypothesis + char* GetName(); + + // Destructor + virtual ~NETGENPlugin_Hypothesis_3D_i(); +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_i.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_i.hxx new file mode 100644 index 000000000000..5e2febc161de --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Hypothesis_i.hxx @@ -0,0 +1,151 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// NETGENPlugin : C++ implementation +// File : NETGENPlugin_Hypothesis_i.hxx +// Author : Michael Sazonov (OCN) +// Date : 03/04/2006 +// Project : SALOME +//============================================================================= +// +#ifndef _NETGENPlugin_Hypothesis_i_HXX_ +#define _NETGENPlugin_Hypothesis_i_HXX_ + +#include "NETGENPlugin_Defs.hxx" + +//#include +//#include CORBA_SERVER_HEADER(NETGENPlugin_Algorithm) + +// #include "SMESH_Hypothesis_i.hxx" +#include "NETGENPlugin_Hypothesis.hxx" + +class SMESH_Gen; +//class GEOM_Object; + +// NETGENPlugin parameters hypothesis + +class NETGENPLUGIN_EXPORT NETGENPlugin_Hypothesis_i: + public virtual POA_NETGENPlugin::NETGENPlugin_Hypothesis, + public virtual SMESH_Hypothesis_i +{ + public: + // Constructor + NETGENPlugin_Hypothesis_i (PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl); + // Destructor + virtual ~NETGENPlugin_Hypothesis_i(); + + void SetMaxSize(CORBA::Double theSize); + CORBA::Double GetMaxSize(); + + void SetMinSize(CORBA::Double theSize); + CORBA::Double GetMinSize(); + + void SetSecondOrder(CORBA::Boolean theVal); + CORBA::Boolean GetSecondOrder(); + + void SetOptimize(CORBA::Boolean theVal); + CORBA::Boolean GetOptimize(); + + void SetFineness(CORBA::Long theFineness); + CORBA::Long GetFineness(); + + void SetGrowthRate(CORBA::Double theRate); + CORBA::Double GetGrowthRate(); + + void SetNbSegPerEdge(CORBA::Double theVal); + CORBA::Double GetNbSegPerEdge(); + + void SetNbSegPerRadius(CORBA::Double theVal); + CORBA::Double GetNbSegPerRadius(); + + void SetLocalSizeOnShape(GEOM::GEOM_Object_ptr GeomObj, CORBA::Double localSize) + throw (SALOME::SALOME_Exception); + void SetLocalSizeOnEntry(const char* entry, CORBA::Double localSize); + CORBA::Double GetLocalSizeOnEntry(const char* entry); + NETGENPlugin::string_array* GetLocalSizeEntries(); + void UnsetLocalSizeOnEntry(const char* entry); + + void SetQuadAllowed(CORBA::Boolean theVal); + CORBA::Boolean GetQuadAllowed(); + + void SetUseSurfaceCurvature(CORBA::Boolean theVal); + CORBA::Boolean GetUseSurfaceCurvature(); + + void SetFuseEdges(CORBA::Boolean theVal); + CORBA::Boolean GetFuseEdges(); + + // Get implementation + ::NETGENPlugin_Hypothesis* GetImpl(); + + // Verify whether hypothesis supports given entity type + CORBA::Boolean IsDimSupported( SMESH::Dimension type ); + + protected: + + // to remember whether a parameter is already set (issue 0021364) + enum SettingMethod + { + METH_SetMaxSize = 1, + METH_SetMinSize = 2, + METH_SetSecondOrder = 4, + METH_SetOptimize = 8, + METH_SetFineness = 16, + METH_SetGrowthRate = 32, + METH_SetNbSegPerEdge = 64, + METH_SetNbSegPerRadius = 128, + METH_SetLocalSizeOnEntry = 256, + METH_SetQuadAllowed = METH_SetLocalSizeOnEntry * 2, + METH_SetSurfaceCurvature = METH_SetQuadAllowed * 2, + METH_SetFuseEdges = METH_SetSurfaceCurvature * 2, + METH_LAST = METH_SetFuseEdges + }; + int mySetMethodFlags; + + // Return true if a parameter is not yet set, else return true if a parameter changes. + // PythonDumping depends on the result of this function. + // Checking only change of a parameter is not enough because then the default values are + // not dumped and if the defaults will change then the behaviour of scripts + // created without dump of the default parameters will also change what is not good. + template + bool isToSetParameter(T curValue, T newValue, /*SettingMethod*/int meth) + { + if ( mySetMethodFlags & meth ) // already set, check if a value is changing + return ( curValue != newValue ); + else + return ( mySetMethodFlags |= meth ); // == return true + } + + public: + // method intended to remove explicit treatment of Netgen hypotheses from + // SMESH_NoteBook to assure backward compatibility after implemeneting + // issue 0021308: Remove hard-coded dependency of the external mesh plugins + virtual int getParamIndex(const TCollection_AsciiString& method, int nbVars) const; + + // method used to convert variable parameters stored in an old study + // into myMethod2VarParams. It should return a method name for an index of + // variable parameters. Index is countered from zero + virtual std::string getMethodOfParameter(const int paramIndex, int nbVars) const; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_Mesher.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Mesher.hxx index 78363ba930d4..a5d0dba1fadc 100644 --- a/src/3rdParty/salomesmesh/inc/NETGENPlugin_Mesher.hxx +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_Mesher.hxx @@ -1,52 +1,106 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // NETGENPlugin : C++ implementation // File : NETGENPlugin_Mesher.hxx // Author : Michael Sazonov (OCN) // Date : 31/03/2006 // Project : SALOME -// $Header: /home/server/cvs/NETGENPLUGIN/NETGENPLUGIN_SRC/src/NETGENPlugin/NETGENPlugin_Mesher.hxx,v 1.4.2.2 2008/11/27 14:29:44 abd Exp $ -//============================================================================= // #ifndef _NETGENPlugin_Mesher_HXX_ #define _NETGENPlugin_Mesher_HXX_ - +#include #include "NETGENPlugin_Defs.hxx" -#include "StdMeshers_FaceSide.hxx" + +#include +#include +#include +#include + +namespace nglib { +#include +} + #include +#include +#include -class SMESH_Mesh; class SMESHDS_Mesh; +class SMESH_Comment; +class SMESH_Mesh; +class SMESH_MesherHelper; class TopoDS_Shape; +// class TopTools_IndexedMapOfShape; class NETGENPlugin_Hypothesis; class NETGENPlugin_SimpleHypothesis_2D; +class NETGENPlugin_Internals; namespace netgen { class OCCGeometry; class Mesh; } +//============================================================================= +/*! + * \brief Struct storing nb of entities in netgen mesh + */ +//============================================================================= + +struct NETGENPlugin_ngMeshInfo +{ + int _nbNodes, _nbSegments, _nbFaces, _nbVolumes; + char* _copyOfLocalH; + NETGENPlugin_ngMeshInfo( netgen::Mesh* ngMesh=0); + void transferLocalH( netgen::Mesh* fromMesh, netgen::Mesh* toMesh ); + void restoreLocalH ( netgen::Mesh* ngMesh); +}; +//================================================================================ +/*! + * \brief It correctly initializes netgen library at constructor and + * correctly finishes using netgen library at destructor + */ +//================================================================================ + +struct NETGENPLUGIN_EXPORT NETGENPlugin_NetgenLibWrapper +{ + bool _isComputeOk; + nglib::Ng_Mesh * _ngMesh; + + NETGENPlugin_NetgenLibWrapper(); + ~NETGENPlugin_NetgenLibWrapper(); + void setMesh( nglib::Ng_Mesh* mesh ); + + private: + std::string getOutputFileName(); + void removeOutputFile(); + std::string _outputFileName; + + std::streambuf* _coutBuffer; // to re-/store cout.rdbuf() +}; + +//============================================================================= /*! * \brief This class calls the NETGEN mesher of OCC geometry */ +//============================================================================= class NETGENPLUGIN_EXPORT NETGENPlugin_Mesher { @@ -55,37 +109,177 @@ class NETGENPLUGIN_EXPORT NETGENPlugin_Mesher NETGENPlugin_Mesher (SMESH_Mesh* mesh, const TopoDS_Shape& aShape, const bool isVolume); + ~NETGENPlugin_Mesher(); + void SetSelfPointer( NETGENPlugin_Mesher ** ptr ); - void SetParameters(const NETGENPlugin_Hypothesis* hyp); + void SetParameters(const NETGENPlugin_Hypothesis* hyp); void SetParameters(const NETGENPlugin_SimpleHypothesis_2D* hyp); + void SetViscousLayers2DAssigned(bool isAssigned) { _isViscousLayers2D = isAssigned; } bool Compute(); + bool Evaluate(MapShapeNbElems& aResMap); + + double GetProgress(const SMESH_Algo* holder, + const int * algoProgressTic, + const double * algoProgress) const; + static void PrepareOCCgeometry(netgen::OCCGeometry& occgeom, const TopoDS_Shape& shape, SMESH_Mesh& mesh, - std::list< SMESH_subMesh* > * meshedSM=0); + std::list< SMESH_subMesh* > * meshedSM=0, + NETGENPlugin_Internals* internalShapes=0); - static void RemoveTmpFiles(); + static double GetDefaultMinSize(const TopoDS_Shape& shape, + const double maxSize); + + static void RestrictLocalSize(netgen::Mesh& ngMesh, + const gp_XYZ& p, + double size, + const bool overrideMinH=true); -protected: + static int FillSMesh(const netgen::OCCGeometry& occgeom, + netgen::Mesh& ngMesh, + const NETGENPlugin_ngMeshInfo& initState, + SMESH_Mesh& sMesh, + std::vector& nodeVec, + SMESH_Comment& comment, + SMESH_MesherHelper* quadHelper=0); - bool fillNgMesh(netgen::OCCGeometry& occgeom, + bool FillNgMesh(netgen::OCCGeometry& occgeom, netgen::Mesh& ngMesh, - std::vector& nodeVec, - const std::list< SMESH_subMesh* > & meshedSM); + std::vector& nodeVec, + const std::list< SMESH_subMesh* > & meshedSM, + SMESH_MesherHelper* quadHelper=0, + SMESH_ProxyMesh::Ptr proxyMesh=SMESH_ProxyMesh::Ptr()); + + static void FixIntFaces(const netgen::OCCGeometry& occgeom, + netgen::Mesh& ngMesh, + NETGENPlugin_Internals& internalShapes); + + static bool FixFaceMesh(const netgen::OCCGeometry& occgeom, + netgen::Mesh& ngMesh, + const int faceID); - void defaultParameters(); + static void AddIntVerticesInFaces(const netgen::OCCGeometry& occgeom, + netgen::Mesh& ngMesh, + std::vector& nodeVec, + NETGENPlugin_Internals& internalShapes); + static void AddIntVerticesInSolids(const netgen::OCCGeometry& occgeom, + netgen::Mesh& ngMesh, + std::vector& nodeVec, + NETGENPlugin_Internals& internalShapes); + + static SMESH_ComputeErrorPtr + AddSegmentsToMesh(netgen::Mesh& ngMesh, + netgen::OCCGeometry& geom, + const TSideVector& wires, + SMESH_MesherHelper& helper, + std::vector< const SMDS_MeshNode* > & nodeVec, + const bool overrideMinH=true); + + void SetDefaultParameters(); + + static void RemoveTmpFiles(); + + static SMESH_ComputeErrorPtr ReadErrors(const std::vector< const SMDS_MeshNode* >& nodeVec); + + + static void toPython( const netgen::Mesh* ngMesh, + const std::string& pyFile); // debug private: + SMESH_Mesh* _mesh; const TopoDS_Shape& _shape; bool _isVolume; bool _optimize; + int _fineness; + bool _isViscousLayers2D; + netgen::Mesh* _ngMesh; + netgen::OCCGeometry* _occgeom; + + int _curShapeIndex; + volatile int _progressTic; + volatile double _ticTime; // normalized [0,1] compute time per a SMESH_Algo::_progressTic + volatile double _totalTime; const NETGENPlugin_SimpleHypothesis_2D * _simpleHyp; - std::map< int, std::pair > _faceDescriptors; + + // a pointer to NETGENPlugin_Mesher* field of the holder, that will be + // nullified at destruction of this + NETGENPlugin_Mesher ** _ptrToMe; +}; + +//============================================================================= +/*! + * \brief Container of info needed to solve problems with internal shapes. + * + * Issue 0020676. It is made up as a class to be ready to extract from NETGEN + * and put in SMESH as soon as the same solution is needed somewhere else. + * The approach is to precompute internal edges in 2D and internal faces in 3D + * and put their mesh correctly (twice) into netgen mesh. + * In 2D, this class finds internal edges in faces and their vertices. + * In 3D, it additionally finds internal faces, their edges shared with other faces, + * and their vertices shared by several internal edges. Nodes built on the found + * shapes and mesh faces built on the found internal faces are to be doubled in + * netgen mesh to emulate a "crack" + * + * For internal faces a more simple solution is found, which is just to duplicate + * mesh faces on internal geom faces without modeling a "real crack". For this + * reason findBorderElements() is no more used anywhere. + */ +//============================================================================= + +class NETGENPLUGIN_EXPORT NETGENPlugin_Internals +{ + SMESH_Mesh& _mesh; + bool _is3D; + //2D + std::map _e2face;//! > _f2v;//! _intShapes; + std::set _borderFaces; //!< non-internal faces sharing the internal edge + std::map > _s2v;//!& getEdgesAndVerticesWithFaces() const { return _e2face; } + void getInternalEdges( TopTools_IndexedMapOfShape& fmap, + TopTools_IndexedMapOfShape& emap, + TopTools_IndexedMapOfShape& vmap, + std::list< SMESH_subMesh* > smToPrecompute[]); + // vertices + bool hasInternalVertexInFace() const { return !_f2v.empty(); } + const std::map >& getFacesWithVertices() const { return _f2v; } + + // 3D meshing + // faces + bool hasInternalFaces() const { return !_intShapes.empty(); } + bool isInternalShape( int id ) const { return _intShapes.count( id ); } + void findBorderElements( std::set< const SMDS_MeshElement*, TIDCompare > & borderElems ); + bool isBorderFace( int faceID ) const { return _borderFaces.count( faceID ); } + void getInternalFaces( TopTools_IndexedMapOfShape& fmap, + TopTools_IndexedMapOfShape& emap, + std::list< SMESH_subMesh* >& facesSM, + std::list< SMESH_subMesh* >& boundarySM); + // vertices + bool hasInternalVertexInSolid() const { return !_s2v.empty(); } + bool hasInternalVertexInSolid(int soID ) const { return _s2v.count(soID); } + const std::map >& getSolidsWithVertices() const { return _s2v; } + + }; #endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D.hxx index 52e7b8641718..fa9a91cb25a6 100644 --- a/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D.hxx +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D.hxx @@ -1,30 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // NETGENPlugin : C++ implementation // File : NETGENPlugin_NETGEN_2D.hxx // Author : Michael Sazonov (OCN) // Date : 20/03/2006 // Project : SALOME -// $Header: /home/server/cvs/NETGENPLUGIN/NETGENPLUGIN_SRC/src/NETGENPlugin/NETGENPlugin_NETGEN_2D.hxx,v 1.4.2.2 2008/11/27 14:29:44 abd Exp $ //============================================================================= // #ifndef _NETGENPlugin_NETGEN_2D_HXX_ @@ -32,12 +32,10 @@ #include "NETGENPlugin_Defs.hxx" -#include "SMESH_2D_Algo.hxx" +#include "SMESH_Algo.hxx" #include "SMESH_Mesh.hxx" -#include "StdMeshers_MaxElementVolume.hxx" -#include "SMESH_Exception.hxx" -//class NETGENPlugin_Hypothesis_2D; +class NETGENPlugin_Mesher; class NETGENPLUGIN_EXPORT NETGENPlugin_NETGEN_2D: public SMESH_2D_Algo { @@ -50,10 +48,20 @@ public: SMESH_Hypothesis::Hypothesis_Status& aStatus); virtual bool Compute(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape); + const TopoDS_Shape& aShape); + + virtual void CancelCompute(); + + virtual double GetProgress() const; + + + virtual bool Evaluate(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, + MapShapeNbElems& aResMap); protected: const SMESHDS_Hypothesis* _hypothesis; + bool _isViscousLayers2D; + NETGENPlugin_Mesher * _mesher; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D3D.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D3D.hxx index ecfdb5ba77f2..abe6adc84498 100644 --- a/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D3D.hxx +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D3D.hxx @@ -1,30 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // NETGENPlugin : C++ implementation // File : NETGENPlugin_NETGEN_2D3D.hxx // Author : Michael Sazonov (OCN) // Date : 20/03/2006 // Project : SALOME -// $Header: /home/server/cvs/NETGENPLUGIN/NETGENPLUGIN_SRC/src/NETGENPlugin/NETGENPlugin_NETGEN_2D3D.hxx,v 1.4.2.2 2008/11/27 14:29:44 abd Exp $ //============================================================================= // #ifndef _NETGENPlugin_NETGEN_2D3D_HXX_ @@ -32,12 +32,9 @@ #include "NETGENPlugin_Defs.hxx" -#include "SMESH_3D_Algo.hxx" -#include "SMESH_Mesh.hxx" -#include "StdMeshers_MaxElementVolume.hxx" -#include "SMESH_Exception.hxx" +#include -//class NETGENPlugin_Hypothesis; +class NETGENPlugin_Mesher; class NETGENPLUGIN_EXPORT NETGENPlugin_NETGEN_2D3D: public SMESH_3D_Algo { @@ -50,10 +47,20 @@ public: SMESH_Hypothesis::Hypothesis_Status& aStatus); virtual bool Compute(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape); + const TopoDS_Shape& aShape); + + virtual void CancelCompute(); + + virtual double GetProgress() const; + + + virtual bool Evaluate(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + MapShapeNbElems& aResMap); protected: const SMESHDS_Hypothesis* _hypothesis; + NETGENPlugin_Mesher * _mesher; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D3D_i.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D3D_i.hxx new file mode 100644 index 000000000000..8e084af8afd4 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D3D_i.hxx @@ -0,0 +1,59 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// NETGENPlugin : idl implementation +// File : NETGENPlugin_NETGEN_2D3D_i.hxx +// Author : Michael Sazonov (OCN) +// Module : NETGENPlugin +// $Header$ +// +#ifndef _NETGENPlugin_NETGEN_2D3D_I_HXX_ +#define _NETGENPlugin_NETGEN_2D3D_I_HXX_ + +#include "NETGENPlugin_Defs.hxx" + +#include +#include CORBA_SERVER_HEADER(NETGENPlugin_Algorithm) + +#include "SMESH_3D_Algo_i.hxx" +#include "NETGENPlugin_NETGEN_2D3D.hxx" + +// ====================================================== +// NETGEN 3d algorithm +// ====================================================== +class NETGENPLUGIN_EXPORT NETGENPlugin_NETGEN_2D3D_i: + public virtual POA_NETGENPlugin::NETGENPlugin_NETGEN_2D3D, + public virtual SMESH_3D_Algo_i +{ +public: + // Constructor + NETGENPlugin_NETGEN_2D3D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~NETGENPlugin_NETGEN_2D3D_i(); + + // Get implementation + ::NETGENPlugin_NETGEN_2D3D* GetImpl(); +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D_ONLY.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D_ONLY.hxx index 2be5858371fc..d389c2aa2d3e 100644 --- a/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D_ONLY.hxx +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D_ONLY.hxx @@ -1,24 +1,22 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 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, or (at your option) any later version. // -// 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. // -// 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 // -// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : NETGENPlugin_NETGEN_2D_ONLY.hxx // Project : SALOME // Author : Edward AGAPOV (OCC) @@ -26,28 +24,12 @@ #ifndef _NETGENPlugin_NETGEN_2D_ONLY_HXX_ #define _NETGENPlugin_NETGEN_2D_ONLY_HXX_ -#include "SMESH_2D_Algo.hxx" -#include "SMESH_Mesh.hxx" - -/*#define OCCGEOMETRY -#include -#include //amv*/ +#include +#include class StdMeshers_MaxElementArea; class StdMeshers_LengthFromEdges; -class StdMeshers_QuadranglePreference; -//class NETGENPlugin_Hypothesis; - -/*namespace netgen { - class OCCGeometry; -}*/ -/*namespace netgen { - class OCCGeometry; - extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, int, int, char*); - extern MeshingParameters mparam; -}*/ - -//using namespace netgen; +class NETGENPlugin_Hypothesis_2D; /*! * \brief Mesher generating 2D elements on a geometrical face taking @@ -70,17 +52,20 @@ public: virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); - /*static TError AddSegmentsToMesh(netgen::Mesh& ngMesh, - OCCGeometry& geom, - const TSideVector& wires, - SMESH_MesherHelper& helper, - vector< const SMDS_MeshNode* > & nodeVec); //amv*/ + virtual void CancelCompute(); + + virtual double GetProgress() const; + + virtual bool Evaluate(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, + MapShapeNbElems& aResMap); protected: const StdMeshers_MaxElementArea* _hypMaxElementArea; const StdMeshers_LengthFromEdges* _hypLengthFromEdges; - const StdMeshers_QuadranglePreference* _hypQuadranglePreference; - // const NETGENPlugin_Hypothesis* _hypothesis; + const SMESHDS_Hypothesis* _hypQuadranglePreference; + const NETGENPlugin_Hypothesis_2D* _hypParameters; + + double _progressByTic; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D_ONLY_i.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D_ONLY_i.hxx new file mode 100644 index 000000000000..164935f15e25 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D_ONLY_i.hxx @@ -0,0 +1,53 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// File : NETGENPlugin_NETGEN_2D_ONLY_i.cxx +// Author : Edward AGAPOV (OCC) +// Module : SMESH +// +#ifndef _NETGENPlugin_NETGEN_2D_ONLY_I_HXX_ +#define _NETGENPlugin_NETGEN_2D_ONLY_I_HXX_ + +#include +#include CORBA_SERVER_HEADER(NETGENPlugin_Algorithm) + +#include "SMESH_2D_Algo_i.hxx" +#include "NETGENPlugin_NETGEN_2D_ONLY.hxx" + +// ====================================================== +// NETGEN 2D algorithm +// ====================================================== +class NETGENPlugin_NETGEN_2D_ONLY_i: + public virtual POA_NETGENPlugin::NETGENPlugin_NETGEN_2D_ONLY, + public virtual SMESH_2D_Algo_i +{ +public: + // Constructor + NETGENPlugin_NETGEN_2D_ONLY_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~NETGENPlugin_NETGEN_2D_ONLY_i(); + + // Get implementation + ::NETGENPlugin_NETGEN_2D_ONLY* GetImpl(); +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D_i.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D_i.hxx new file mode 100644 index 000000000000..92b5390c514e --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_2D_i.hxx @@ -0,0 +1,59 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// NETGENPlugin : idl implementation +// File : NETGENPlugin_NETGEN_2D_i.hxx +// Author : Michael Sazonov (OCN) +// Module : NETGENPlugin +// $Header$ +// +#ifndef _NETGENPlugin_NETGEN_2D_I_HXX_ +#define _NETGENPlugin_NETGEN_2D_I_HXX_ + +#include "NETGENPlugin_Defs.hxx" + +#include +#include CORBA_SERVER_HEADER(NETGENPlugin_Algorithm) + +#include "SMESH_2D_Algo_i.hxx" +#include "NETGENPlugin_NETGEN_2D.hxx" + +// ====================================================== +// NETGEN 3d algorithm +// ====================================================== +class NETGENPLUGIN_EXPORT NETGENPlugin_NETGEN_2D_i: + public virtual POA_NETGENPlugin::NETGENPlugin_NETGEN_2D, + public virtual SMESH_2D_Algo_i +{ +public: + // Constructor + NETGENPlugin_NETGEN_2D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~NETGENPlugin_NETGEN_2D_i(); + + // Get implementation + ::NETGENPlugin_NETGEN_2D* GetImpl(); +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_3D.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_3D.hxx index 571b8c7da8dd..d27ce932e86a 100644 --- a/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_3D.hxx +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_3D.hxx @@ -1,46 +1,49 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + //============================================================================= // File : NETGENPlugin_NETGEN_3D.hxx // Moved here from SMESH_NETGEN_3D.hxx // Created : lundi 27 Janvier 2003 // Author : Nadir BOUHAMOU (CEA) // Project : SALOME -// $Header: /home/server/cvs/NETGENPLUGIN/NETGENPLUGIN_SRC/src/NETGENPlugin/NETGENPlugin_NETGEN_3D.hxx,v 1.4.2.1 2008/11/27 14:29:45 abd Exp $ //============================================================================= // #ifndef _NETGENPlugin_NETGEN_3D_HXX_ #define _NETGENPlugin_NETGEN_3D_HXX_ #include "NETGENPlugin_Defs.hxx" +#include "NETGENPlugin_Mesher.hxx" + +#include "SMESH_Algo.hxx" +#include "Utils_SALOME_Exception.hxx" -#include "SMESH_3D_Algo.hxx" -#include "SMESH_Mesh.hxx" -#include "StdMeshers_MaxElementVolume.hxx" -#include "SMESH_Exception.hxx" +class StdMeshers_ViscousLayers; +class StdMeshers_MaxElementVolume; +class NETGENPlugin_Hypothesis; class NETGENPLUGIN_EXPORT NETGENPlugin_NETGEN_3D: public SMESH_3D_Algo { -public: + public: NETGENPlugin_NETGEN_3D(int hypId, int studyId, SMESH_Gen* gen); virtual ~NETGENPlugin_NETGEN_3D(); @@ -49,15 +52,32 @@ public: SMESH_Hypothesis::Hypothesis_Status& aStatus); virtual bool Compute(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape); + const TopoDS_Shape& aShape); virtual bool Compute(SMESH_Mesh& aMesh, SMESH_MesherHelper* aHelper); - -protected: + + virtual void CancelCompute(); + + virtual double GetProgress() const; + + virtual bool Evaluate(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + MapShapeNbElems& aResMap); + + protected: + + bool compute(SMESH_Mesh& mesh, + SMESH_MesherHelper& helper, + vector< const SMDS_MeshNode* >& nodeVec, + nglib::Ng_Mesh* ngMesh); + double _maxElementVolume; + const NETGENPlugin_Hypothesis * _hypParameters; const StdMeshers_MaxElementVolume* _hypMaxElementVolume; + const StdMeshers_ViscousLayers* _viscousLayersHyp; + double _progressByTic; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_3D_i.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_3D_i.hxx new file mode 100644 index 000000000000..e6a2cec6e71e --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_NETGEN_3D_i.hxx @@ -0,0 +1,60 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// File : NETGENPlugin_NETGEN_3D_i.hxx +// Moved here from SMESH_NETGEN_3D_i.hxx +// Author : Nadir Bouhamou CEA +// Module : SMESH +// $Header$ +// +#ifndef _NETGENPlugin_NETGEN_3D_I_HXX_ +#define _NETGENPlugin_NETGEN_3D_I_HXX_ + +#include "NETGENPlugin_Defs.hxx" + +#include +#include CORBA_SERVER_HEADER(NETGENPlugin_Algorithm) + +#include "SMESH_3D_Algo_i.hxx" +#include "NETGENPlugin_NETGEN_3D.hxx" + +// ====================================================== +// NETGEN 3d algorithm +// ====================================================== +class NETGENPLUGIN_EXPORT NETGENPlugin_NETGEN_3D_i: + public virtual POA_NETGENPlugin::NETGENPlugin_NETGEN_3D, + public virtual SMESH_3D_Algo_i +{ +public: + // Constructor + NETGENPlugin_NETGEN_3D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~NETGENPlugin_NETGEN_3D_i(); + + // Get implementation + ::NETGENPlugin_NETGEN_3D* GetImpl(); +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_2D.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_2D.hxx index f7aaa3ce2b1b..c54120a8be93 100644 --- a/src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_2D.hxx +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_2D.hxx @@ -1,24 +1,22 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 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, or (at your option) any later version. // -// 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. // -// 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 // -// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // NETGENPlugin : C++ implementation // File : NETGENPlugin_SimpleHypothesis_2D.hxx // Author : Edward AGAPOV @@ -31,11 +29,13 @@ #include "NETGENPlugin_Defs.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" // Simplified parameters of NETGEN // +using namespace std; + class NETGENPLUGIN_EXPORT NETGENPlugin_SimpleHypothesis_2D: public SMESH_Hypothesis { public: @@ -45,7 +45,7 @@ public: /*! * Sets value */ - void SetNumberOfSegments(int nb) throw (SMESH_Exception); + void SetNumberOfSegments(int nb) throw (SALOME_Exception); /*! * Returns value. * Can be zero in case if LocalLength() has been set @@ -55,7 +55,7 @@ public: /*! * Sets value */ - void SetLocalLength(double segmentLength) throw (SMESH_Exception); + void SetLocalLength(double segmentLength) throw (SALOME_Exception); /*! * Returns value. * Can be zero in case if NumberOfSegments() has been set @@ -78,9 +78,18 @@ public: */ double GetMaxElementArea() const { return _area; } + /*! + * Enables/disables generation of quadrangular faces + */ + void SetAllowQuadrangles(bool toAllow); + /*! + * Returns true if generation of quadrangular faces is enabled + */ + bool GetAllowQuadrangles() const; + // Persistence - virtual std::ostream & SaveTo(std::ostream & save); - virtual std::istream & LoadFrom(std::istream & load); + virtual ostream & SaveTo(ostream & save); + virtual istream & LoadFrom(istream & load); /*! * \brief Set parameters by mesh @@ -89,16 +98,17 @@ public: * \retval bool - true if theShape is meshed */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - - /*! + + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0); - + private: int _nbSegments; double _segmentLength, _area; + bool _allowQuad; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_2D_i.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_2D_i.hxx new file mode 100644 index 000000000000..3976e7a61674 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_2D_i.hxx @@ -0,0 +1,86 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// NETGENPlugin : C++ implementation +// File : NETGENPlugin_SimpleHypothesis_2D_i.hxx +// Author : Edward AGAPOV +// Project : SALOME +//============================================================================= +// +#ifndef _NETGENPlugin_SimpleHypothesis_2D_i_HXX_ +#define _NETGENPlugin_SimpleHypothesis_2D_i_HXX_ + +#include "NETGENPlugin_Defs.hxx" + +#include +#include CORBA_SERVER_HEADER(NETGENPlugin_Algorithm) + +#include "SMESH_Hypothesis_i.hxx" + +class SMESH_Gen; +class NETGENPlugin_SimpleHypothesis_2D; + +// Simplified NETGEN parameters (2D case) + +class NETGENPLUGIN_EXPORT NETGENPlugin_SimpleHypothesis_2D_i: + public virtual POA_NETGENPlugin::NETGENPlugin_SimpleHypothesis_2D, + public virtual SMESH_Hypothesis_i +{ + public: + // Constructor + NETGENPlugin_SimpleHypothesis_2D_i (PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl); + // Destructor + virtual ~NETGENPlugin_SimpleHypothesis_2D_i(); + + void SetNumberOfSegments(CORBA::Short nb) throw ( SALOME::SALOME_Exception ); + CORBA::Short GetNumberOfSegments(); + + void SetLocalLength(CORBA::Double segmentLength); + CORBA::Double GetLocalLength(); + + + void LengthFromEdges(); + + void SetMaxElementArea(CORBA::Double area); + CORBA::Double GetMaxElementArea(); + + void SetAllowQuadrangles(CORBA::Boolean toAllow); + CORBA::Boolean GetAllowQuadrangles(); + + // Get implementation + ::NETGENPlugin_SimpleHypothesis_2D* GetImpl() const; + + // Verify whether hypothesis supports given entity type + CORBA::Boolean IsDimSupported( SMESH::Dimension type ); + + public: + // method intended to remove explicit treatment of Netgen hypotheses from + // SMESH_NoteBook to assure backward compatibility after implemeneting + // issue 0021308: Remove hard-coded dependency of the external mesh plugins + virtual int getParamIndex(const TCollection_AsciiString& method, int nbVars) const; + + // method used to convert variable parameters stored in an old study + // into myMethod2VarParams. It should return a method name for an index of + // variable parameters. Index is countered from zero + virtual std::string getMethodOfParameter(const int paramIndex, int nbVars) const; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_3D.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_3D.hxx index b083af486f65..b955148f3b21 100644 --- a/src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_3D.hxx +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_3D.hxx @@ -1,24 +1,22 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 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, or (at your option) any later version. // -// 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. // -// 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 // -// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // NETGENPlugin : C++ implementation // File : NETGENPlugin_SimpleHypothesis_3D.hxx // Author : Edward AGAPOV @@ -31,11 +29,13 @@ #include "NETGENPlugin_Defs.hxx" #include "NETGENPlugin_SimpleHypothesis_2D.hxx" -#include +#include // Simplified parameters of NETGEN // +using namespace std; + class NETGENPLUGIN_EXPORT NETGENPlugin_SimpleHypothesis_3D: public NETGENPlugin_SimpleHypothesis_2D { public: @@ -48,8 +48,8 @@ public: double GetMaxElementVolume() const { return _volume; } // Persistence - virtual std::ostream & SaveTo(std::ostream & save); - virtual std::istream & LoadFrom(std::istream & load); + virtual ostream & SaveTo(ostream & save); + virtual istream & LoadFrom(istream & load); /*! * \brief Set parameters by mesh diff --git a/src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_3D_i.hxx b/src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_3D_i.hxx new file mode 100644 index 000000000000..9c48340cb3e0 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/NETGENPlugin_SimpleHypothesis_3D_i.hxx @@ -0,0 +1,64 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// NETGENPlugin : C++ implementation +// File : NETGENPlugin_SimpleHypothesis_3D_i.hxx +// Author : Edward AGAPOV +// Project : SALOME +//============================================================================= +// +#ifndef _NETGENPlugin_SimpleHypothesis_3D_i_HXX_ +#define _NETGENPlugin_SimpleHypothesis_3D_i_HXX_ + +#include "NETGENPlugin_Defs.hxx" +#include "NETGENPlugin_SimpleHypothesis_2D_i.hxx" + +#include +#include CORBA_SERVER_HEADER(NETGENPlugin_Algorithm) + +class SMESH_Gen; +class NETGENPlugin_SimpleHypothesis_3D; + +// Simplified NETGEN parameters (3D case) + +class NETGENPLUGIN_EXPORT NETGENPlugin_SimpleHypothesis_3D_i: + public virtual POA_NETGENPlugin::NETGENPlugin_SimpleHypothesis_3D, + public virtual NETGENPlugin_SimpleHypothesis_2D_i +{ + public: + // Constructor + NETGENPlugin_SimpleHypothesis_3D_i (PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl); + // Destructor + virtual ~NETGENPlugin_SimpleHypothesis_3D_i(); + + void LengthFromFaces(); + + void SetMaxElementVolume(CORBA::Double value); + CORBA::Double GetMaxElementVolume(); + + // Get implementation + ::NETGENPlugin_SimpleHypothesis_3D* GetImpl(); + + // Verify whether hypothesis supports given entity type + CORBA::Boolean IsDimSupported( SMESH::Dimension type ); +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/ObjectPool.hxx b/src/3rdParty/salomesmesh/inc/ObjectPool.hxx new file mode 100644 index 000000000000..f27161122c98 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/ObjectPool.hxx @@ -0,0 +1,174 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +#ifndef _OBJECTPOOL_HXX_ +#define _OBJECTPOOL_HXX_ + +#include +//#include +#include + +namespace +{ + // assure deallocation of memory of a vector + template void clearVector(std::vector& v ) + { + std::vector emptyVec; v.swap( emptyVec ); + } +} + +template class ObjectPool +{ + +private: + std::vector _chunkList; + std::vector _freeList; + int _nextFree; + int _maxAvail; + int _chunkSize; + int _maxOccupied; + int _nbHoles; + + int getNextFree() + { + // Don't iterate on the _freeList if all the "holes" + // are filled. Go straight to the last occupied ID + 1 + if ( _nbHoles == 0 ) + return std::min(_maxOccupied + 1, _maxAvail); + + for (int i = _nextFree; i < _maxAvail; i++) + if (_freeList[i] == true) + { + return i; + break; + } + return _maxAvail; + } + + void checkDelete(int chunkId) + { + int i0 = _chunkSize * chunkId; + int i1 = _chunkSize * (chunkId + 1); + for (int i = i0; i < i1; i++) + if (_freeList[i] == false) + return; + std::cerr << "a chunk to delete" << std::endl; + // compactage des vecteurs un peu lourd, pas necessaire + //X* chunk = _chunkList[chunkId]; + //delete [] chunk; + } + +public: + ObjectPool(int nblk) + { + _chunkSize = nblk; + _nextFree = 0; + _maxAvail = 0; + _maxOccupied = 0; + _nbHoles = 0; + _chunkList.clear(); + _freeList.clear(); + } + + virtual ~ObjectPool() + { + for (size_t i = 0; i < _chunkList.size(); i++) + delete[] _chunkList[i]; + } + + X* getNew() + { + X *obj = 0; + _nextFree = getNextFree(); + if (_nextFree == _maxAvail) + { + X* newChunk = new X[_chunkSize]; + _chunkList.push_back(newChunk); + _freeList.insert(_freeList.end(), _chunkSize, true); + _maxAvail += _chunkSize; + _freeList[_nextFree] = false; + obj = newChunk; // &newChunk[0]; + } + else + { + int chunkId = _nextFree / _chunkSize; + int rank = _nextFree - chunkId * _chunkSize; + _freeList[_nextFree] = false; + obj = _chunkList[chunkId] + rank; // &_chunkList[chunkId][rank]; + } + if (_nextFree < _maxOccupied) + { + _nbHoles-=1; + } + else + { + _maxOccupied = _nextFree; + } + //obj->init(); + return obj; + } + + void destroy(X* obj) + { + long adrobj = (long) (obj); + for (size_t i = 0; i < _chunkList.size(); i++) + { + X* chunk = _chunkList[i]; + long adrmin = (long) (chunk); + if (adrobj < adrmin) + continue; + long adrmax = (long) (chunk + _chunkSize); + if (adrobj >= adrmax) + continue; + int rank = (adrobj - adrmin) / sizeof(X); + int toFree = i * _chunkSize + rank; + _freeList[toFree] = true; + if (toFree < _nextFree) + _nextFree = toFree; + if (toFree < _maxOccupied) + _nbHoles += 1; + //obj->clean(); + //checkDelete(i); compactage non fait + break; + } + } + + void clear() + { + _nextFree = 0; + _maxAvail = 0; + _maxOccupied = 0; + _nbHoles = 0; + for (size_t i = 0; i < _chunkList.size(); i++) + delete[] _chunkList[i]; + clearVector( _chunkList ); + clearVector( _freeList ); + } + + // void destroy(int toFree) + // { + // // no control 0<= toFree < _freeList.size() + // _freeList[toFree] = true; + // if (toFree < _nextFree) + // _nextFree = toFree; + // } + +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/OpUtil.hxx b/src/3rdParty/salomesmesh/inc/OpUtil.hxx new file mode 100644 index 000000000000..0605002c6480 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/OpUtil.hxx @@ -0,0 +1,34 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SALOME Utils : general SALOME's definitions and tools +// File : OpUtil.hxx +// Module : SALOME +// +#ifndef _OPUTIL_HXX +#define _OPUTIL_HXX + +#include "SALOME_Utils.hxx" + +UTILS_EXPORT const char *duplicate(const char * const); + +#endif diff --git a/src/3rdParty/salomesmesh/inc/Rn.h b/src/3rdParty/salomesmesh/inc/Rn.h index 63c6ec26640f..6ec871d932eb 100644 --- a/src/3rdParty/salomesmesh/inc/Rn.h +++ b/src/3rdParty/salomesmesh/inc/Rn.h @@ -1,24 +1,22 @@ // MEFISTO : library to compute 2D triangulation from segmented boundaries // -// Copyright (C) 2006 Laboratoire J.-L. Lions UPMC Paris -// -// 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.ann.jussieu.fr/~perronne or email Perronnet@ann.jussieu.fr -// or email Hecht@ann.jussieu.fr +// Copyright (C) 2006-2015 CEA/DEN, EDF R&D, OPEN CASCADE // +// 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, or (at your option) any later version. +// +// 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 : Rn.h // Module : SMESH @@ -172,8 +170,8 @@ class R3 bool DansPave( R3 & xyzMin, R3 & xyzMax ) { return xyzMin.x<=x && x<=xyzMax.x && - xyzMin.y<=y && y<=xyzMax.y && - xyzMin.z<=z && z<=xyzMax.z; } + xyzMin.y<=y && y<=xyzMax.y && + xyzMin.z<=z && z<=xyzMax.z; } }; //la classe R4 diff --git a/src/3rdParty/salomesmesh/inc/SALOMEDS.hxx b/src/3rdParty/salomesmesh/inc/SALOMEDS.hxx new file mode 100644 index 000000000000..e47ac3e75aa5 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SALOMEDS.hxx @@ -0,0 +1,68 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SALOME SALOMEDS : data structure of SALOME and sources of Salome data server +// File : SALOMEDS.hxx +// Author : Sergey ANIKIN +// Module : SALOME +// $Header$ +// +#ifndef SALOMEDS_HeaderFile +#define SALOMEDS_HeaderFile + +#include "SALOMEDS_Defines.hxx" + +#include + +namespace SALOMEDS +{ + // PAL8065: san -- Implementation of convenient locker based on simple recursive + // mutex for POSIX platforms. + // This class is to protect SALOMEDS CORBA methods which deal with OCC calls from + // parallel access by several threads + // To protect some method, an instance of Locker class should be created + // on the stack at the beginning of guarded code: + // + // Locker lock; + // + class SALOMEDS_EXPORT Locker : public Utils_Locker + { + public: + Locker(); + virtual ~Locker(); + + private: + static Utils_Mutex MutexDS; + + friend void lock(); + friend void unlock(); + }; + + // Convenient functions to lock/unlock the global SALOMEDS mutex temporarily. + // In particular, "unlock-dosomething-lock" scheme should be used, when some non-SALOMEDS + // CORBA interface is called (component's engine), to avoid deadlocks in case of + // indirect recursion. + void lock(); + void unlock(); +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SALOMEDS_Tool.hxx b/src/3rdParty/salomesmesh/inc/SALOMEDS_Tool.hxx new file mode 100644 index 000000000000..b38bbfd2744d --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SALOMEDS_Tool.hxx @@ -0,0 +1,122 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SALOMEDS_Tool.hxx +// Created : Mon Oct 21 16:24:50 2002 +// Author : Sergey RUIN +// Project : SALOME +// Module : SALOMEDS +// +#ifndef __SALOMEDS_Tool_H__ +#define __SALOMEDS_Tool_H__ + +#include +#include +#include + +// IDL headers + +#ifdef WIN32 +# if defined TOOLSDS_EXPORTS +# define TOOLSDS_EXPORT __declspec( dllexport ) +# else +# define TOOLSDS_EXPORT __declspec( dllimport ) +# endif +#else +# define TOOLSDS_EXPORT +#endif + +class TOOLSDS_EXPORT SALOMEDS_Tool +{ +public: + + // Returns the unique temporary directory, that is defined in SALOME_TMP_DIR if this variable is set + // otherwise return /tmp/something/ for Unix or c:\something\ for WIN32 + static std::string GetTmpDir(); + + + // Removes files which are in , the files for deletion are listed in + // if is true is also deleted if it is empty + static void RemoveTemporaryFiles(const std::string& theDirectory, + const SALOMEDS::ListOfFileNames& theFiles, + const bool IsDirDeleted); + + // Converts files listed in which are in into a byte sequence TMPFile + static SALOMEDS::TMPFile* PutFilesToStream(const std::string& theFromDirectory, + const SALOMEDS::ListOfFileNames& theFiles, + const int theNamesOnly = 0); + + // Converts files listed in which will be named as pointed in the into a byte sequence TMPFile + static SALOMEDS::TMPFile* PutFilesToStream(const SALOMEDS::ListOfFileNames& theFiles, + const SALOMEDS::ListOfFileNames& theFileNames); + + // Converts a byte sequence to files and places them in + static SALOMEDS::ListOfFileNames_var PutStreamToFiles(const SALOMEDS::TMPFile& theStream, + const std::string& theToDirectory, + const int theNamesOnly = 0); + + // Returns the name by the path + // for an example: if thePath = "/tmp/aaa/doc1.hdf" the function returns "doc1" + static std::string GetNameFromPath(const std::string& thePath); + + // Returns the directory by the path + // for an example: if thePath = "/tmp/aaa/doc1.hdf" the function returns "/tmp/aaa" + static std::string GetDirFromPath(const std::string& thePath); + + // Retrieves specified flaf from "AttributeFlags" attribute + static bool GetFlag( const int theFlag, + SALOMEDS::Study_var theStudy, + SALOMEDS::SObject_var theObj ); + + // Sets/Unsets specified flaf from "AttributeFlags" attribute + static bool SetFlag( const int theFlag, + SALOMEDS::Study_var theStudy, + const std::string& theEntry, + const bool theValue ); + + // Get all children of object. If theObj is null all objects of study are returned + static void GetAllChildren( SALOMEDS::Study_var theStudy, + SALOMEDS::SObject_var theObj, + std::list& theList ); + +}; +#endif + + + + + + + + + + + + + + + + + + + + diff --git a/src/3rdParty/salomesmesh/inc/SALOMEDS_defines.hxx b/src/3rdParty/salomesmesh/inc/SALOMEDS_defines.hxx new file mode 100755 index 000000000000..4c04e848f68e --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SALOMEDS_defines.hxx @@ -0,0 +1,40 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SALOMEDS_Defines.hxx +// Author : Alexander A. BORODIN +// Module : SALOME +// +#ifndef _SALOMEDS_Defines_HXX_ +#define _SALOMEDS_Defines_HXX_ + +#ifdef WIN32 +# if defined SALOMEDS_EXPORTS || defined SalomeDS_EXPORTS +# define SALOMEDS_EXPORT __declspec( dllexport ) +# else +# define SALOMEDS_EXPORT __declspec( dllimport ) +# endif +#else +# define SALOMEDS_EXPORT +#endif + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SALOME_Basics.hxx b/src/3rdParty/salomesmesh/inc/SALOME_Basics.hxx new file mode 100644 index 000000000000..bfd387bc537b --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SALOME_Basics.hxx @@ -0,0 +1,40 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SALOME Basics : general SALOME definitions and tools (C++ part - no CORBA) +// File : SALOME_Basics.hxx +// Author : Alexander A. BORODIN +// Module : SALOME +// $Header$ +// +#ifndef _SALOME_BASICS_HXX_ +#define _SALOME_BASICS_HXX_ + + +#ifdef WIN32 +# if defined BASICS_EXPORTS || defined SALOMEBasics_EXPORTS +# define BASICS_EXPORT __declspec( dllexport ) +# else +# define BASICS_EXPORT __declspec( dllimport ) +# endif +#else +# define BASICS_EXPORT +#endif + +#endif //_SALOME_BASICS_HXX_ diff --git a/src/3rdParty/salomesmesh/inc/SALOME_Utils.hxx b/src/3rdParty/salomesmesh/inc/SALOME_Utils.hxx new file mode 100755 index 000000000000..8c112385aa83 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SALOME_Utils.hxx @@ -0,0 +1,40 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SALOME_Utils.hxx +// Author : Alexander A. BORODIN +// Module : SALOME +// +#ifndef _SALOME_UTILS_HXX_ +#define _SALOME_UTILS_HXX_ + +#ifdef WIN32 +# if defined UTILS_EXPORTS || defined OpUtil_EXPORTS +# define UTILS_EXPORT __declspec( dllexport ) +# else +# define UTILS_EXPORT __declspec( dllimport ) +# endif +#else +# define UTILS_EXPORT +#endif + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMDSAbs_ElementType.hxx b/src/3rdParty/salomesmesh/inc/SMDSAbs_ElementType.hxx index 2a5d8e3ba51d..6abda2839154 100644 --- a/src/3rdParty/salomesmesh/inc/SMDSAbs_ElementType.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDSAbs_ElementType.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDSAbs_ElementType.hxx // Module : SMESH @@ -30,33 +31,40 @@ /// Type (node, edge, face or volume) of elements /////////////////////////////////////////////////////////////////////////////// enum SMDSAbs_ElementType -{ - SMDSAbs_All, - SMDSAbs_Node, - SMDSAbs_Edge, - SMDSAbs_Face, - SMDSAbs_Volume, - SMDSAbs_NbElementTypes -}; + { + SMDSAbs_All, + SMDSAbs_Node, + SMDSAbs_Edge, + SMDSAbs_Face, + SMDSAbs_Volume, + SMDSAbs_0DElement, + SMDSAbs_Ball, + SMDSAbs_NbElementTypes + }; /*! enumeration for element geometry type */ enum SMDSAbs_GeometryType -{ - // 0D element - SMDSGeom_POINT, - // 1D element - SMDSGeom_EDGE, - // 2D element - SMDSGeom_TRIANGLE, - SMDSGeom_QUADRANGLE, - SMDSGeom_POLYGON, - // 3D element - SMDSGeom_TETRA, - SMDSGeom_PYRAMID, - SMDSGeom_HEXA, - SMDSGeom_PENTA, - SMDSGeom_POLYHEDRA, -}; + { + // 0D element + SMDSGeom_POINT, + // 1D element + SMDSGeom_EDGE, + // 2D element + SMDSGeom_TRIANGLE, + SMDSGeom_QUADRANGLE, + SMDSGeom_POLYGON, + // 3D element + SMDSGeom_TETRA, + SMDSGeom_PYRAMID, + SMDSGeom_HEXA, + SMDSGeom_PENTA, + SMDSGeom_HEXAGONAL_PRISM, + SMDSGeom_POLYHEDRA, + // Discrete elements + SMDSGeom_BALL, + // + SMDSGeom_NONE + }; enum SMDSAbs_ElementOrder { @@ -65,4 +73,36 @@ enum SMDSAbs_ElementOrder { ORDER_QUADRATIC /*! entities of 2nd order */ }; +/*! + * Enumeration of entity type used in mesh info array + */ +enum SMDSAbs_EntityType { + SMDSEntity_Node, + SMDSEntity_0D, + SMDSEntity_Edge, + SMDSEntity_Quad_Edge, + SMDSEntity_Triangle, + SMDSEntity_Quad_Triangle, + SMDSEntity_BiQuad_Triangle, + SMDSEntity_Quadrangle, + SMDSEntity_Quad_Quadrangle, + SMDSEntity_BiQuad_Quadrangle, + SMDSEntity_Polygon, + SMDSEntity_Quad_Polygon, + SMDSEntity_Tetra, + SMDSEntity_Quad_Tetra, + SMDSEntity_Pyramid, + SMDSEntity_Quad_Pyramid, + SMDSEntity_Hexa, + SMDSEntity_Quad_Hexa, + SMDSEntity_TriQuad_Hexa, + SMDSEntity_Penta, + SMDSEntity_Quad_Penta, + SMDSEntity_Hexagonal_Prism, + SMDSEntity_Polyhedra, + SMDSEntity_Quad_Polyhedra, + SMDSEntity_Ball, + SMDSEntity_Last +}; + #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_BallElement.hxx b/src/3rdParty/salomesmesh/inc/SMDS_BallElement.hxx new file mode 100644 index 000000000000..d54b207123f1 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMDS_BallElement.hxx @@ -0,0 +1,60 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMDS : implementaion of Salome mesh data structure +// File : SMDS_BallElement.hxx +// Module : SMESH +// +#ifndef _SMDS_BallElement_HeaderFile +#define _SMDS_BallElement_HeaderFile + +#include "SMESH_SMDS.hxx" +#include "SMDS_MeshCell.hxx" + +#include + +class SMDS_EXPORT SMDS_BallElement: public SMDS_MeshCell +{ + public: + SMDS_BallElement(); + SMDS_BallElement (const SMDS_MeshNode * node, double diameter); + SMDS_BallElement(vtkIdType nodeId, double diameter, SMDS_Mesh* mesh); + void init(vtkIdType nodeId, double diameter, SMDS_Mesh* mesh); + double GetDiameter() const; + void SetDiameter(double diameter); + bool ChangeNode (const SMDS_MeshNode * node); + + virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], + const int nbNodes) { return ChangeNode( nodes[0] ); } + virtual void Print (std::ostream & OS) const; + + virtual SMDSAbs_ElementType GetType() const { return SMDSAbs_Ball; } + virtual vtkIdType GetVtkType() const { return VTK_POLY_VERTEX; } + virtual SMDSAbs_EntityType GetEntityType() const { return SMDSEntity_Ball; } + virtual SMDSAbs_GeometryType GetGeomType() const { return SMDSGeom_BALL; } + virtual int NbNodes() const { return 1; } + virtual int NbEdges() const { return 0; } + virtual int NbFaces() const { return 0; } + virtual const SMDS_MeshNode* GetNode (const int ind) const; + + protected: + SMDS_ElemIteratorPtr elementsIterator (SMDSAbs_ElementType type) const; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_Downward.hxx b/src/3rdParty/salomesmesh/inc/SMDS_Downward.hxx new file mode 100644 index 000000000000..34cded571b2c --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMDS_Downward.hxx @@ -0,0 +1,381 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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: SMDS_Downward.hxx +// Created: Jun 3, 2010 +// Author: prascle + +#ifndef SMDS_DOWNWARD_HXX_ +#define SMDS_DOWNWARD_HXX_ + +#include "SMDS_UnstructuredGrid.hxx" + +#include +#include + +typedef struct +{ + int nodeIds[8]; //!< max number of nodes in a face or edge: quad quad = 8 + int nbNodes; + unsigned char vtkType; +} ElemByNodesType; // TODO resize for polyhedrons + +typedef struct +{ + ElemByNodesType elems[6]; //!< max number of faces in a volume or edges in a face : hexahedron = 6 + int nbElems; +} ListElemByNodesType; // TODO resize for polyhedrons + +class SMDS_EXPORT DownIdType +{ +public: + DownIdType(int a, unsigned char b) : + cellId(a), cellType(b) + { + } + int cellId; + unsigned char cellType; +}; + +struct DownIdCompare +{ + bool operator ()(const DownIdType e1, const DownIdType e2) const + { + if (e1.cellId == e2.cellId) + return (e1.cellType < e2.cellType); + else + return (e1.cellId < e2.cellId); + } +}; + +class SMDS_EXPORT SMDS_Downward +{ + friend class SMDS_UnstructuredGrid; + friend class SMDS_Down2D; + friend class SMDS_Down3D; +public: + virtual int getNumberOfDownCells(int cellId); + virtual const int* getDownCells(int cellId); + virtual const unsigned char* getDownTypes(int cellId); + virtual int getNumberOfUpCells(int cellId) = 0; + virtual const int* getUpCells(int cellId) = 0; + virtual const unsigned char* getUpTypes(int cellId) = 0; + virtual void getNodeIds(int cellId, std::set& nodeSet) = 0; + virtual int getNodes(int cellId, int* nodevec) {return 0; } + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) {}; + int getVtkCellId(int cellId) + { + return _vtkCellIds[cellId]; + } + int getMaxId() + { + return _maxId; + } + static int getCellDimension(unsigned char cellType); +protected: + SMDS_Downward(SMDS_UnstructuredGrid *grid, int nbDownCells); + ~SMDS_Downward(); + int addCell(int vtkId = -1); + virtual void initCell(int cellId); + virtual void allocate(int nbElems) = 0; + virtual void compactStorage() = 0; + virtual void addDownCell(int cellId, int lowCellId, unsigned char aType); //!< Id's are downward connectivity id's + virtual void addUpCell(int cellId, int upCellId, unsigned char aType); //!< Id's are downward connectivity id's + virtual int getNodeSet(int cellId, int* nodeSet); + + SMDS_UnstructuredGrid* _grid; + int _maxId; + int _nbDownCells; //!< the same number for all cells of a derived class + std::vector _cellIds; //!< growing size: all the down cell id's, size = _maxId * _nbDownCells + std::vector _vtkCellIds; //!< growing size: size = _maxId, either vtkId or -1 + std::vector _cellTypes; //!< fixed size: the same vector for all cells of a derived class + + static std::vector _cellDimension; //!< conversion table: type --> dimension +}; + +class SMDS_EXPORT SMDS_Down1D: public SMDS_Downward +{ + friend class SMDS_UnstructuredGrid; +public: + virtual int getNumberOfUpCells(int cellId); + virtual const int* getUpCells(int cellId); + virtual const unsigned char* getUpTypes(int cellId); + virtual void getNodeIds(int cellId, std::set& nodeSet); + virtual int getNodes(int cellId, int* nodevec) { return getNodeSet(cellId, nodevec); } +protected: + SMDS_Down1D(SMDS_UnstructuredGrid *grid, int nbDownCells); + ~SMDS_Down1D(); + virtual void initCell(int cellId); + virtual void allocate(int nbElems); + virtual void compactStorage(); + virtual void addUpCell(int cellId, int upCellId, unsigned char aType); //!< Id's are downward connectivity id's + virtual int getNodeSet(int cellId, int* nodeSet); + void setNodes(int cellId, int vtkId); + void setNodes(int cellId, const int* nodeIds); + int computeVtkCells(int cellId, std::vector& vtkIds); + int computeVtkCells(int* pts, std::vector& vtkIds); + int computeFaces(int cellId, int* vtkIds, int nbcells, int* downFaces, unsigned char* downTypes); + int computeFaces(int* pts, int* vtkIds, int nbcells, int* downFaces, unsigned char* downTypes); + + std::vector > _upCellIdsVector; //!< the number of faces sharing an edge is not known + std::vector > _upCellTypesVector; //!< the number of faces sharing an edge is not known + std::vector _upCellIds; //!< compacted storage after connectivity calculation + std::vector _upCellTypes; //!< compacted storage after connectivity calculation + std::vector _upCellIndex; //!< compacted storage after connectivity calculation +}; + +class SMDS_EXPORT SMDS_Down2D: public SMDS_Downward +{ + friend class SMDS_UnstructuredGrid; + friend class SMDS_Down1D; +public: + virtual int getNumberOfUpCells(int cellId); + virtual const int* getUpCells(int cellId); + virtual const unsigned char* getUpTypes(int cellId); + virtual void getNodeIds(int cellId, std::set& nodeSet); +protected: + SMDS_Down2D(SMDS_UnstructuredGrid *grid, int nbDownCells); + ~SMDS_Down2D(); + virtual void allocate(int nbElems); + virtual void compactStorage(); + virtual void addUpCell(int cellId, int upCellId, unsigned char aType); + virtual void computeEdgesWithNodes(int cellId, ListElemByNodesType& facesWithNodes) = 0; + virtual int getNodeSet(int cellId, int* nodeSet); + int computeVolumeIds(int cellId, int* ids); + int computeVolumeIds(ElemByNodesType& faceByNodes, int* ids); + int computeVolumeIdsFromNodesFace(int* nodes, int nbNodes, int* ids); + void setTempNodes(int cellId, int vtkId); + void setTempNodes(int cellId, ElemByNodesType& faceByNodes); + bool isInFace(int cellId, int *pts, int npts); + int FindEdgeByNodes(int cellId, ElemByNodesType& edgeByNodes); + + std::vector _upCellIds; //!< 2 volumes max. per face + std::vector _upCellTypes; //!< 2 volume types per face + std::vector _tempNodes; //!< temporary storage of nodes, until downward connectivity completion + int _nbNodes; //!< number of nodes in a face +}; + +class SMDS_EXPORT SMDS_Down3D: public SMDS_Downward +{ + friend class SMDS_UnstructuredGrid; +public: + virtual int getNumberOfUpCells(int cellId); + virtual const int* getUpCells(int cellId); + virtual const unsigned char* getUpTypes(int cellId); + virtual void getNodeIds(int cellId, std::set& nodeSet); +protected: + SMDS_Down3D(SMDS_UnstructuredGrid *grid, int nbDownCells); + ~SMDS_Down3D(); + virtual void allocate(int nbElems); + virtual void compactStorage(); + virtual void computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes) = 0; + int FindFaceByNodes(int cellId, ElemByNodesType& faceByNodes); +}; + +class SMDS_EXPORT SMDS_DownEdge: public SMDS_Down1D +{ + friend class SMDS_UnstructuredGrid; +public: +protected: + SMDS_DownEdge(SMDS_UnstructuredGrid *grid); + ~SMDS_DownEdge(); +}; + +class SMDS_EXPORT SMDS_DownQuadEdge: public SMDS_Down1D +{ + friend class SMDS_UnstructuredGrid; +public: +protected: + SMDS_DownQuadEdge(SMDS_UnstructuredGrid *grid); + ~SMDS_DownQuadEdge(); +}; + +class SMDS_EXPORT SMDS_DownTriangle: public SMDS_Down2D +{ + friend class SMDS_UnstructuredGrid; +public: +protected: + SMDS_DownTriangle(SMDS_UnstructuredGrid *grid); + ~SMDS_DownTriangle(); + virtual void computeEdgesWithNodes(int cellId, ListElemByNodesType& edgesWithNodes); + virtual void addDownCell(int cellId, int lowCellId, unsigned char aType); //!< Id's are downward connectivity id's +}; + +class SMDS_EXPORT SMDS_DownQuadTriangle: public SMDS_Down2D +{ + friend class SMDS_UnstructuredGrid; +public: +protected: + SMDS_DownQuadTriangle(SMDS_UnstructuredGrid *grid); + ~SMDS_DownQuadTriangle(); + virtual void computeEdgesWithNodes(int cellId, ListElemByNodesType& edgesWithNodes); + virtual void addDownCell(int cellId, int lowCellId, unsigned char aType); //!< Id's are downward connectivity id's +}; + +class SMDS_EXPORT SMDS_DownQuadrangle: public SMDS_Down2D +{ + friend class SMDS_UnstructuredGrid; +public: +protected: + SMDS_DownQuadrangle(SMDS_UnstructuredGrid *grid); + ~SMDS_DownQuadrangle(); + virtual void computeEdgesWithNodes(int cellId, ListElemByNodesType& edgesWithNodes); + virtual void addDownCell(int cellId, int lowCellId, unsigned char aType); //!< Id's are downward connectivity id's +}; + +class SMDS_EXPORT SMDS_DownQuadQuadrangle: public SMDS_Down2D +{ + friend class SMDS_UnstructuredGrid; +public: +protected: + SMDS_DownQuadQuadrangle(SMDS_UnstructuredGrid *grid); + ~SMDS_DownQuadQuadrangle(); + virtual void computeEdgesWithNodes(int cellId, ListElemByNodesType& edgesWithNodes); + virtual void addDownCell(int cellId, int lowCellId, unsigned char aType); //!< Id's are downward connectivity id's +}; + +//class SMDS_DownPolygon: public SMDS_Down2D +//{ +//public: +// SMDS_DownPolygon(SMDS_UnstructuredGrid *grid); +// ~SMDS_DownPolygon(); +//protected: +//}; + +//class SMDS_DownQuadPolygon: public SMDS_Down2D +//{ +//public: +// SMDS_DownQuadPolygon(SMDS_UnstructuredGrid *grid); +// ~SMDS_DownQuadPolygon(); +//protected: +//}; + +class SMDS_EXPORT SMDS_DownTetra: public SMDS_Down3D +{ + friend class SMDS_UnstructuredGrid; +public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); +protected: + SMDS_DownTetra(SMDS_UnstructuredGrid *grid); + ~SMDS_DownTetra(); + virtual void addDownCell(int cellId, int lowCellId, unsigned char aType); + virtual void computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes); +}; + +class SMDS_EXPORT SMDS_DownQuadTetra: public SMDS_Down3D +{ + friend class SMDS_UnstructuredGrid; +public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); +protected: + SMDS_DownQuadTetra(SMDS_UnstructuredGrid *grid); + ~SMDS_DownQuadTetra(); + virtual void addDownCell(int cellId, int lowCellId, unsigned char aType); + virtual void computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes); +}; + +class SMDS_EXPORT SMDS_DownPyramid: public SMDS_Down3D +{ + friend class SMDS_UnstructuredGrid; +public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); +protected: + SMDS_DownPyramid(SMDS_UnstructuredGrid *grid); + ~SMDS_DownPyramid(); + virtual void addDownCell(int cellId, int lowCellId, unsigned char aType); + virtual void computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes); +}; + +class SMDS_EXPORT SMDS_DownQuadPyramid: public SMDS_Down3D +{ + friend class SMDS_UnstructuredGrid; +public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); +protected: + SMDS_DownQuadPyramid(SMDS_UnstructuredGrid *grid); + ~SMDS_DownQuadPyramid(); + virtual void addDownCell(int cellId, int lowCellId, unsigned char aType); + virtual void computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes); +}; + +class SMDS_EXPORT SMDS_DownPenta: public SMDS_Down3D +{ + friend class SMDS_UnstructuredGrid; +public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); +protected: + SMDS_DownPenta(SMDS_UnstructuredGrid *grid); + ~SMDS_DownPenta(); + virtual void addDownCell(int cellId, int lowCellId, unsigned char aType); + virtual void computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes); +}; + +class SMDS_EXPORT SMDS_DownQuadPenta: public SMDS_Down3D +{ + friend class SMDS_UnstructuredGrid; +public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); +protected: + SMDS_DownQuadPenta(SMDS_UnstructuredGrid *grid); + ~SMDS_DownQuadPenta(); + virtual void addDownCell(int cellId, int lowCellId, unsigned char aType); + virtual void computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes); +}; + +class SMDS_EXPORT SMDS_DownHexa: public SMDS_Down3D +{ + friend class SMDS_UnstructuredGrid; +public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); +protected: + SMDS_DownHexa(SMDS_UnstructuredGrid *grid); + ~SMDS_DownHexa(); + virtual void addDownCell(int cellId, int lowCellId, unsigned char aType); + virtual void computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes); +}; + +class SMDS_EXPORT SMDS_DownQuadHexa: public SMDS_Down3D +{ + friend class SMDS_UnstructuredGrid; +public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); +protected: + SMDS_DownQuadHexa(SMDS_UnstructuredGrid *grid); + ~SMDS_DownQuadHexa(); + virtual void addDownCell(int cellId, int lowCellId, unsigned char aType); + virtual void computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes); +}; + +//class SMDS_DownPolyhedra: public SMDS_Down3D +//{ +//public: +// SMDS_DownPolyhedra(SMDS_UnstructuredGrid *grid); +// ~SMDS_DownPolyhedra(); +//protected: +//}; + +//class SMDS_DownQuadPolyhedra: public SMDS_Down3D +//{ +//public: +// SMDS_DownQuadPolyhedra(SMDS_UnstructuredGrid *grid); +// ~SMDS_DownQuadPolyhedra(); +//protected: +//}; + +#endif /* SMDS_DOWNWARD_HXX_ */ diff --git a/src/3rdParty/salomesmesh/inc/SMDS_EdgePosition.hxx b/src/3rdParty/salomesmesh/inc/SMDS_EdgePosition.hxx index f6005e947138..1a38e20b8d10 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_EdgePosition.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_EdgePosition.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_EdgePosition.hxx // Module : SMESH @@ -34,15 +35,14 @@ class SMDS_EXPORT SMDS_EdgePosition:public SMDS_Position { public: - SMDS_EdgePosition(const int aEdgeId=0, const double aUParam=0); - const virtual double * Coords() const; - SMDS_TypeOfPosition GetTypeOfPosition() const; - void SetUParameter(double aUparam); - double GetUParameter() const; + SMDS_EdgePosition(const double aUParam=0); + SMDS_TypeOfPosition GetTypeOfPosition() const; + void SetUParameter(double aUparam); + double GetUParameter() const; private: - double myUParameter; + double myUParameter; }; diff --git a/src/3rdParty/salomesmesh/inc/SMDS_ElemIterator.hxx b/src/3rdParty/salomesmesh/inc/SMDS_ElemIterator.hxx index 511426e5d891..6a38073e2b75 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_ElemIterator.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_ElemIterator.hxx @@ -1,29 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshElement.hxx // Module : SMESH -// Created: 12.01.05 18:02:52 -// Author: Michael Sazonov +// Created: 12.01.05 18:02:52 +// Author: Michael Sazonov // #ifndef SMDS_ElemIterator_HeaderFile #define SMDS_ElemIterator_HeaderFile @@ -33,6 +34,7 @@ class SMDS_MeshElement; class SMDS_MeshNode; +class SMDS_Mesh0DElement; class SMDS_MeshEdge; class SMDS_MeshFace; class SMDS_MeshVolume; @@ -43,6 +45,9 @@ typedef boost::shared_ptr > SMDS_ElemIte typedef SMDS_Iterator SMDS_NodeIterator; typedef boost::shared_ptr > SMDS_NodeIteratorPtr; +typedef SMDS_Iterator SMDS_0DElementIterator; +typedef boost::shared_ptr > SMDS_0DElementIteratorPtr; + typedef SMDS_Iterator SMDS_EdgeIterator; typedef boost::shared_ptr > SMDS_EdgeIteratorPtr; diff --git a/src/3rdParty/salomesmesh/inc/SMDS_FaceOfEdges.hxx b/src/3rdParty/salomesmesh/inc/SMDS_FaceOfEdges.hxx index 27cfe59e4cea..e8dfdc85ddc2 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_FaceOfEdges.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_FaceOfEdges.hxx @@ -1,25 +1,26 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMDS : implementaion of Salome mesh data structure + +// SMESH SMDS : implementation of Salome mesh data structure // #ifndef _SMDS_FaceOfEdges_HeaderFile #define _SMDS_FaceOfEdges_HeaderFile @@ -36,35 +37,30 @@ class SMDS_EXPORT SMDS_FaceOfEdges:public SMDS_MeshFace { public: - void Print(std::ostream & OS) const; - SMDS_FaceOfEdges(const SMDS_MeshEdge* edge1, + void Print(std::ostream & OS) const; + SMDS_FaceOfEdges(const SMDS_MeshEdge* edge1, const SMDS_MeshEdge* edge2, const SMDS_MeshEdge* edge3); - SMDS_FaceOfEdges(const SMDS_MeshEdge* edge1, + SMDS_FaceOfEdges(const SMDS_MeshEdge* edge1, const SMDS_MeshEdge* edge2, const SMDS_MeshEdge* edge3, const SMDS_MeshEdge* edge4); - - SMDSAbs_ElementType GetType() const; - int NbNodes() const; - int NbEdges() const; - int NbFaces() const; -// friend bool operator<(const SMDS_FaceOfEdges& e1, const SMDS_FaceOfEdges& e2); - - - /*! - * \brief Return node by its index - * \param ind - node index - * \retval const SMDS_MeshNode* - the node - */ - virtual const SMDS_MeshNode* GetNode(const int ind) const; + + virtual SMDSAbs_ElementType GetType() const; + virtual SMDSAbs_EntityType GetEntityType() const; + virtual SMDSAbs_GeometryType GetGeomType() const; + virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], + const int nbNodes) {return false;} + virtual int NbNodes() const; + virtual int NbEdges() const; + virtual int NbFaces() const; + virtual const SMDS_MeshNode* GetNode(const int ind) const; protected: - SMDS_ElemIteratorPtr - elementsIterator(SMDSAbs_ElementType type) const; + virtual SMDS_ElemIteratorPtr elementsIterator(SMDSAbs_ElementType type) const; private: - const SMDS_MeshEdge* myEdges[4]; + const SMDS_MeshEdge* myEdges[4]; int myNbEdges; }; diff --git a/src/3rdParty/salomesmesh/inc/SMDS_FaceOfNodes.hxx b/src/3rdParty/salomesmesh/inc/SMDS_FaceOfNodes.hxx index 018d5778aca6..71471df36889 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_FaceOfNodes.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_FaceOfNodes.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // #ifndef _SMDS_FaceOfNodes_HeaderFile @@ -35,19 +36,19 @@ class SMDS_EXPORT SMDS_FaceOfNodes:public SMDS_MeshFace { public: - void Print(std::ostream & OS) const; - SMDS_FaceOfNodes(const SMDS_MeshNode* node1, + void Print(std::ostream & OS) const; + SMDS_FaceOfNodes(const SMDS_MeshNode* node1, const SMDS_MeshNode* node2, const SMDS_MeshNode* node3); - SMDS_FaceOfNodes(const SMDS_MeshNode* node1, + SMDS_FaceOfNodes(const SMDS_MeshNode* node1, const SMDS_MeshNode* node2, const SMDS_MeshNode* node3, const SMDS_MeshNode* node4); bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes); - int NbEdges() const; - int NbFaces() const; - int NbNodes() const; + int NbEdges() const; + int NbFaces() const; + int NbNodes() const; /*! * \brief Return node by its index @@ -56,12 +57,15 @@ class SMDS_EXPORT SMDS_FaceOfNodes:public SMDS_MeshFace */ virtual const SMDS_MeshNode* GetNode(const int ind) const; + virtual SMDSAbs_EntityType GetEntityType() const; + virtual SMDSAbs_GeometryType GetGeomType() const; + protected: - SMDS_ElemIteratorPtr - elementsIterator(SMDSAbs_ElementType type) const; + SMDS_ElemIteratorPtr + elementsIterator(SMDSAbs_ElementType type) const; private: - const SMDS_MeshNode* myNodes[4]; + const SMDS_MeshNode* myNodes[4]; int myNbNodes; }; diff --git a/src/3rdParty/salomesmesh/inc/SMDS_FacePosition.hxx b/src/3rdParty/salomesmesh/inc/SMDS_FacePosition.hxx index 425d7cf1c118..3bbe79e566cc 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_FacePosition.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_FacePosition.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_FacePosition.hxx // Module : SMESH @@ -34,17 +35,16 @@ class SMDS_EXPORT SMDS_FacePosition:public SMDS_Position { public: - SMDS_FacePosition(int aFaceId=0, double aUParam=0, - double aVParam=0); - const virtual double * Coords() const; - SMDS_TypeOfPosition GetTypeOfPosition() const; - void SetUParameter(double aUparam); - void SetVParameter(double aVparam); - double GetUParameter() const; - double GetVParameter() const; + SMDS_FacePosition(double aUParam=0, double aVParam=0); + SMDS_TypeOfPosition GetTypeOfPosition() const; + void SetUParameter(double aUparam); + void SetVParameter(double aVparam); + void SetParameters(double aUparam, double aVparam); + double GetUParameter() const; + double GetVParameter() const; private: - double myUParameter; - double myVParameter; + double myUParameter; + double myVParameter; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_Iterator.hxx b/src/3rdParty/salomesmesh/inc/SMDS_Iterator.hxx index e4e900b5bc72..6f8100c0ea65 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_Iterator.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_Iterator.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // #ifndef _SMDS_Iterator_HeaderFile @@ -33,18 +34,18 @@ template class SMDS_Iterator { public: - /// Return true if and only if there are other object in this iterator - virtual bool more()=0; - - /// Return the current object and step to the next one - virtual VALUE next()=0; - - /// Delete the current element and step to the next one - virtual void remove(){} - - /// Provide virtual destructor just for case if some derived iterator + /// Return true if and only if there are other object in this iterator + virtual bool more()=0; + + /// Return the current object and step to the next one + virtual VALUE next()=0; + + /// Delete the current element and step to the next one + virtual void remove(){} + + /// Provide virtual destructor just for case if some derived iterator /// must have a destructor - virtual ~SMDS_Iterator(){} + virtual ~SMDS_Iterator(){} }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_IteratorOfElements.hxx b/src/3rdParty/salomesmesh/inc/SMDS_IteratorOfElements.hxx index 381ff647a442..e0756198c9d2 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_IteratorOfElements.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_IteratorOfElements.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // #include "SMESH_SMDS.hxx" @@ -35,22 +36,22 @@ class SMDS_EXPORT SMDS_IteratorOfElements:public SMDS_ElemIterator /// Create an iterator which look for elements of type type which are linked /// to the element element. it is the iterator to get connectivity of element ////////////////////////////////////////////////////////////////////////////// - SMDS_IteratorOfElements(const SMDS_MeshElement * element, + SMDS_IteratorOfElements(const SMDS_MeshElement * element, SMDSAbs_ElementType type, const SMDS_ElemIteratorPtr& it); - bool more(); - const SMDS_MeshElement * next(); + bool more(); + const SMDS_MeshElement * next(); private: - SMDS_ElemIteratorPtr t2Iterator; - SMDS_ElemIteratorPtr t1Iterator; - SMDSAbs_ElementType myType; - const SMDS_MeshElement * myProxyElement; - const SMDS_MeshElement * myElement; - bool myReverseIteration; + SMDS_ElemIteratorPtr t2Iterator; + SMDS_ElemIteratorPtr t1Iterator; + SMDSAbs_ElementType myType; + const SMDS_MeshElement * myProxyElement; + const SMDS_MeshElement * myElement; + bool myReverseIteration; - std::set alreadyReturnedElements; - std::set::iterator itAlreadyReturned; - bool subMore(); - const SMDS_MeshElement * subNext(); + std::set alreadyReturnedElements; + std::set::iterator itAlreadyReturned; + bool subMore(); + const SMDS_MeshElement * subNext(); }; diff --git a/src/3rdParty/salomesmesh/inc/SMDS_IteratorOnIterators.hxx b/src/3rdParty/salomesmesh/inc/SMDS_IteratorOnIterators.hxx new file mode 100644 index 000000000000..4eace32e68ef --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMDS_IteratorOnIterators.hxx @@ -0,0 +1,67 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMDS : implementaion of Salome mesh data structure +// File : SMDS_IteratorOnIterators.hxx +// Author : Edward AGAPOV (eap) +// +#ifndef SMDS_IteratorOnIterators_HeaderFile +#define SMDS_IteratorOnIterators_HeaderFile + +#include "SMDS_Iterator.hxx" + +/////////////////////////////////////////////////////////////////////////////// +/// SMDS_Iterator iterating over all elements provided by other iterators +/// +/// Other iterators must implement SMDS_Iterator iterface and +/// must be provided within a stl-like container +/// BE CAREFUL: iterator pointed value is static_cast'ed to VALUE +/////////////////////////////////////////////////////////////////////////////// + +template +class SMDS_IteratorOnIterators : public SMDS_Iterator +{ +protected: + CONTAINER_OF_ITERATORS _iterators; + typename CONTAINER_OF_ITERATORS::iterator _beg, _end; +public: + SMDS_IteratorOnIterators(const CONTAINER_OF_ITERATORS& iterators): + _iterators( iterators ), _beg( _iterators.begin()), _end(_iterators.end() ) + { + while ( _beg != _end && !(*_beg)->more()) ++_beg; + } + + /// Return true iff there are other object in this iterator + virtual bool more() { return _beg != _end && (*_beg)->more(); } + + /// Return the current object and step to the next one + virtual VALUE next() + { + VALUE __v = (VALUE)(*_beg)->next(); + while ( _beg != _end && !(*_beg)->more()) + ++_beg; + return __v; + } +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_LinearEdge.hxx b/src/3rdParty/salomesmesh/inc/SMDS_LinearEdge.hxx new file mode 100644 index 000000000000..38a29e7ddace --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMDS_LinearEdge.hxx @@ -0,0 +1,68 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SMDS_LinearEdge.hxx +// Module : SMESH +// +#ifndef _SMDS_LinearEdge_HeaderFile +#define _SMDS_LinearEdge_HeaderFile + +#include "SMESH_SMDS.hxx" + +#include "SMDS_MeshEdge.hxx" +#include + +class SMDS_EXPORT SMDS_LinearEdge: public SMDS_MeshEdge +{ + +public: + SMDS_LinearEdge(const SMDS_MeshNode * node1, const SMDS_MeshNode * node2); + bool ChangeNodes(const SMDS_MeshNode * node1, const SMDS_MeshNode * node2); + void Print(std::ostream & OS) const; + + virtual SMDSAbs_EntityType GetEntityType() const + { + return SMDSEntity_Edge; + } + virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) + { + return false; + } + int NbNodes() const; + int NbEdges() const; + friend bool operator<(const SMDS_LinearEdge& e1, const SMDS_LinearEdge& e2); + + /*! + * \brief Return node by its index + * \param ind - node index + * \retval const SMDS_MeshNode* - the node + */ + virtual const SMDS_MeshNode* GetNode(const int ind) const; + +protected: + SMDS_ElemIteratorPtr + elementsIterator(SMDSAbs_ElementType type) const; + +protected: + const SMDS_MeshNode* myNodes[3]; + +}; +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_Mesh.hxx b/src/3rdParty/salomesmesh/inc/SMDS_Mesh.hxx index bb6b9f082695..7c728d6f9656 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_Mesh.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_Mesh.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_Mesh.hxx // Module : SMESH @@ -29,73 +30,113 @@ #include "SMESH_SMDS.hxx" #include "SMDS_MeshNode.hxx" +#include "SMDS_MeshCell.hxx" +#include "SMDS_Mesh0DElement.hxx" #include "SMDS_MeshEdge.hxx" #include "SMDS_MeshFace.hxx" #include "SMDS_MeshVolume.hxx" +#include "SMDS_MeshNodeIDFactory.hxx" #include "SMDS_MeshElementIDFactory.hxx" #include "SMDS_MeshInfo.hxx" #include "SMDS_ElemIterator.hxx" -#include +#include "SMDS_VolumeOfNodes.hxx" +#include "SMDS_VtkEdge.hxx" +#include "SMDS_VtkFace.hxx" +#include "SMDS_VtkVolume.hxx" +#include "ObjectPool.hxx" +#include "SMDS_UnstructuredGrid.hxx" +#include "SMDS_BallElement.hxx" #include #include #include +#include +#include +#include + +#include "Utils_SALOME_Exception.hxx" -class SMDS_EXPORT SMDS_Mesh:public SMDS_MeshObject{ +#define MYASSERT(val) if (!(val)) throw SALOME_Exception(LOCALIZED("assertion not verified")); + +class SMDS_EXPORT SMDS_Mesh : public SMDS_MeshObject +{ public: - + friend class SMDS_MeshIDFactory; + friend class SMDS_MeshNodeIDFactory; + friend class SMDS_MeshElementIDFactory; + friend class SMDS_MeshVolumeVtkNodes; + friend class SMDS_MeshNode; + SMDS_Mesh(); - SMDS_NodeIteratorPtr nodesIterator() const; - SMDS_EdgeIteratorPtr edgesIterator() const; - SMDS_FaceIteratorPtr facesIterator() const; - SMDS_VolumeIteratorPtr volumesIterator() const; - SMDS_ElemIteratorPtr elementsIterator() const; - + //! to retreive this SMDS_Mesh instance from its elements (index stored in SMDS_Elements) + static std::vector _meshList; + + //! actual nodes coordinates, cells definition and reverse connectivity are stored in a vtkUnstructuredGrid + inline SMDS_UnstructuredGrid* getGrid() {return myGrid; } + inline int getMeshId() {return myMeshId; } + + virtual SMDS_NodeIteratorPtr nodesIterator (bool idInceasingOrder=false) const; + virtual SMDS_EdgeIteratorPtr edgesIterator (bool idInceasingOrder=false) const; + virtual SMDS_FaceIteratorPtr facesIterator (bool idInceasingOrder=false) const; + virtual SMDS_VolumeIteratorPtr volumesIterator (bool idInceasingOrder=false) const; + + virtual SMDS_ElemIteratorPtr elementsIterator(SMDSAbs_ElementType type=SMDSAbs_All) const; + virtual SMDS_ElemIteratorPtr elementGeomIterator(SMDSAbs_GeometryType type) const; + virtual SMDS_ElemIteratorPtr elementEntityIterator(SMDSAbs_EntityType type) const; + SMDSAbs_ElementType GetElementType( const int id, const bool iselem ) const; SMDS_Mesh *AddSubMesh(); - + virtual SMDS_MeshNode* AddNodeWithID(double x, double y, double z, int ID); - virtual SMDS_MeshNode* AddNode(double x, double y, double z); - + virtual SMDS_MeshNode* AddNode (double x, double y, double z); + + virtual SMDS_Mesh0DElement* Add0DElementWithID(int n, int ID); + virtual SMDS_Mesh0DElement* Add0DElementWithID(const SMDS_MeshNode * n, int ID); + virtual SMDS_Mesh0DElement* Add0DElement (const SMDS_MeshNode * n); + + virtual SMDS_BallElement* AddBallWithID(int n, double diameter, int ID); + virtual SMDS_BallElement* AddBallWithID(const SMDS_MeshNode * n, double diameter, int ID); + virtual SMDS_BallElement* AddBall (const SMDS_MeshNode * n, double diameter); + virtual SMDS_MeshEdge* AddEdgeWithID(int n1, int n2, int ID); virtual SMDS_MeshEdge* AddEdgeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - int ID); + const SMDS_MeshNode * n2, + int ID); virtual SMDS_MeshEdge* AddEdge(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2); - + const SMDS_MeshNode * n2); + // 2d order edge with 3 nodes: n12 - node between n1 and n2 virtual SMDS_MeshEdge* AddEdgeWithID(int n1, int n2, int n12, int ID); virtual SMDS_MeshEdge* AddEdgeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n12, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n12, + int ID); virtual SMDS_MeshEdge* AddEdge(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, const SMDS_MeshNode * n12); virtual SMDS_MeshFace* AddFaceWithID(int n1, int n2, int n3, int ID); virtual SMDS_MeshFace* AddFaceWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + int ID); virtual SMDS_MeshFace* AddFace(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3); - + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3); + virtual SMDS_MeshFace* AddFaceWithID(int n1, int n2, int n3, int n4, int ID); virtual SMDS_MeshFace* AddFaceWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + int ID); virtual SMDS_MeshFace* AddFace(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4); - + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4); + virtual SMDS_MeshFace* AddFaceWithID(const SMDS_MeshEdge * e1, const SMDS_MeshEdge * e2, const SMDS_MeshEdge * e3, int ID); @@ -116,100 +157,141 @@ public: virtual SMDS_MeshFace* AddFaceWithID(int n1, int n2, int n3, int n12,int n23,int n31, int ID); virtual SMDS_MeshFace* AddFaceWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31, + int ID); + virtual SMDS_MeshFace* AddFace(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31); + + // 2d order triangle of 7 nodes + virtual SMDS_MeshFace* AddFaceWithID(int n1, int n2, int n3, + int n12,int n23,int n31, int nCenter, int ID); + virtual SMDS_MeshFace* AddFaceWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31, + const SMDS_MeshNode * nCenter, + int ID); virtual SMDS_MeshFace* AddFace(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31); + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31, + const SMDS_MeshNode * nCenter); // 2d order quadrangle virtual SMDS_MeshFace* AddFaceWithID(int n1, int n2, int n3, int n4, int n12,int n23,int n34,int n41, int ID); virtual SMDS_MeshFace* AddFaceWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + int ID); virtual SMDS_MeshFace* AddFace(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41); + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41); + + virtual SMDS_MeshFace* AddFaceWithID(int n1, int n2, int n3, int n4, + int n12,int n23,int n34,int n41, int nCenter, int ID); + virtual SMDS_MeshFace* AddFaceWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * nCenter, + int ID); + virtual SMDS_MeshFace* AddFace(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * nCenter); virtual SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4); - + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4); + virtual SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5); - + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5); + virtual SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6); - + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6); + virtual SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6, int n7, int n8, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshFace * f1, const SMDS_MeshFace * f2, @@ -244,29 +326,59 @@ public: const SMDS_MeshFace * f5, const SMDS_MeshFace * f6); + // hexagonal prism + virtual SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6, + int n7, int n8, int n9, int n10, int n11, int n12, + int ID); + virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n9, + const SMDS_MeshNode * n10, + const SMDS_MeshNode * n11, + const SMDS_MeshNode * n12, + int ID); + virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n9, + const SMDS_MeshNode * n10, + const SMDS_MeshNode * n11, + const SMDS_MeshNode * n12); + // 2d order tetrahedron of 10 nodes virtual SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n12,int n23,int n31, int n14,int n24,int n34, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31, - const SMDS_MeshNode * n14, - const SMDS_MeshNode * n24, - const SMDS_MeshNode * n34, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31, + const SMDS_MeshNode * n14, + const SMDS_MeshNode * n24, + const SMDS_MeshNode * n34, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n31, - const SMDS_MeshNode * n14, + const SMDS_MeshNode * n14, const SMDS_MeshNode * n24, const SMDS_MeshNode * n34); @@ -276,28 +388,28 @@ public: int n15,int n25,int n35,int n45, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, - const SMDS_MeshNode * n15, - const SMDS_MeshNode * n25, - const SMDS_MeshNode * n35, - const SMDS_MeshNode * n45, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * n15, + const SMDS_MeshNode * n25, + const SMDS_MeshNode * n35, + const SMDS_MeshNode * n45, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, + const SMDS_MeshNode * n41, const SMDS_MeshNode * n15, const SMDS_MeshNode * n25, const SMDS_MeshNode * n35, @@ -311,33 +423,33 @@ public: int n14,int n25,int n36, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31, - const SMDS_MeshNode * n45, - const SMDS_MeshNode * n56, - const SMDS_MeshNode * n64, - const SMDS_MeshNode * n14, - const SMDS_MeshNode * n25, - const SMDS_MeshNode * n36, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31, + const SMDS_MeshNode * n45, + const SMDS_MeshNode * n56, + const SMDS_MeshNode * n64, + const SMDS_MeshNode * n14, + const SMDS_MeshNode * n25, + const SMDS_MeshNode * n36, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31, + const SMDS_MeshNode * n31, const SMDS_MeshNode * n45, const SMDS_MeshNode * n56, - const SMDS_MeshNode * n64, + const SMDS_MeshNode * n64, const SMDS_MeshNode * n14, const SMDS_MeshNode * n25, const SMDS_MeshNode * n36); @@ -350,75 +462,160 @@ public: int n15,int n26,int n37,int n48, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, - const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, - const SMDS_MeshNode * n56, - const SMDS_MeshNode * n67, - const SMDS_MeshNode * n78, - const SMDS_MeshNode * n85, - const SMDS_MeshNode * n15, - const SMDS_MeshNode * n26, - const SMDS_MeshNode * n37, - const SMDS_MeshNode * n48, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * n56, + const SMDS_MeshNode * n67, + const SMDS_MeshNode * n78, + const SMDS_MeshNode * n85, + const SMDS_MeshNode * n15, + const SMDS_MeshNode * n26, + const SMDS_MeshNode * n37, + const SMDS_MeshNode * n48, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, + const SMDS_MeshNode * n41, const SMDS_MeshNode * n56, const SMDS_MeshNode * n67, const SMDS_MeshNode * n78, - const SMDS_MeshNode * n85, + const SMDS_MeshNode * n85, const SMDS_MeshNode * n15, const SMDS_MeshNode * n26, const SMDS_MeshNode * n37, const SMDS_MeshNode * n48); - virtual SMDS_MeshFace* AddPolygonalFaceWithID (std::vector nodes_ids, - const int ID); + // 2d oreder Hexahedrons with 27 nodes + virtual SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, + int n5, int n6, int n7, int n8, + int n12,int n23,int n34,int n41, + int n56,int n67,int n78,int n85, + int n15,int n26,int n37,int n48, + int n1234,int n1256,int n2367,int n3478, + int n1458,int n5678,int nCenter, + int ID); + virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * n56, + const SMDS_MeshNode * n67, + const SMDS_MeshNode * n78, + const SMDS_MeshNode * n85, + const SMDS_MeshNode * n15, + const SMDS_MeshNode * n26, + const SMDS_MeshNode * n37, + const SMDS_MeshNode * n48, + const SMDS_MeshNode * n1234, + const SMDS_MeshNode * n1256, + const SMDS_MeshNode * n2367, + const SMDS_MeshNode * n3478, + const SMDS_MeshNode * n1458, + const SMDS_MeshNode * n5678, + const SMDS_MeshNode * nCenter, + int ID); + virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * n56, + const SMDS_MeshNode * n67, + const SMDS_MeshNode * n78, + const SMDS_MeshNode * n85, + const SMDS_MeshNode * n15, + const SMDS_MeshNode * n26, + const SMDS_MeshNode * n37, + const SMDS_MeshNode * n48, + const SMDS_MeshNode * n1234, + const SMDS_MeshNode * n1256, + const SMDS_MeshNode * n2367, + const SMDS_MeshNode * n3478, + const SMDS_MeshNode * n1458, + const SMDS_MeshNode * n5678, + const SMDS_MeshNode * nCenter); + + virtual SMDS_MeshFace* AddPolygonalFaceWithID (const std::vector & nodes_ids, + const int ID); + + virtual SMDS_MeshFace* AddPolygonalFaceWithID (const std::vector & nodes, + const int ID); - virtual SMDS_MeshFace* AddPolygonalFaceWithID (std::vector nodes, - const int ID); + virtual SMDS_MeshFace* AddPolygonalFace (const std::vector & nodes); - virtual SMDS_MeshFace* AddPolygonalFace (std::vector nodes); + virtual SMDS_MeshFace* AddQuadPolygonalFaceWithID(const std::vector & nodes_ids, + const int ID); + + virtual SMDS_MeshFace* AddQuadPolygonalFaceWithID(const std::vector & nodes, + const int ID); + + virtual SMDS_MeshFace* AddQuadPolygonalFace(const std::vector & nodes); virtual SMDS_MeshVolume* AddPolyhedralVolumeWithID - (std::vector nodes_ids, - std::vector quantities, - const int ID); + (const std::vector & nodes_ids, + const std::vector & quantities, + const int ID); virtual SMDS_MeshVolume* AddPolyhedralVolumeWithID - (std::vector nodes, - std::vector quantities, - const int ID); + (const std::vector & nodes, + const std::vector & quantities, + const int ID); virtual SMDS_MeshVolume* AddPolyhedralVolume - (std::vector nodes, - std::vector quantities); + (const std::vector & nodes, + const std::vector & quantities); + + virtual SMDS_MeshVolume* AddVolumeFromVtkIds(const std::vector& vtkNodeIds); + + virtual SMDS_MeshVolume* AddVolumeFromVtkIdsWithID(const std::vector& vtkNodeIds, + const int ID); + + virtual SMDS_MeshFace* AddFaceFromVtkIds(const std::vector& vtkNodeIds); + + virtual SMDS_MeshFace* AddFaceFromVtkIdsWithID(const std::vector& vtkNodeIds, + const int ID); + virtual void MoveNode(const SMDS_MeshNode *n, double x, double y, double z); virtual void RemoveElement(const SMDS_MeshElement * elem, std::list& removedElems, std::list& removedNodes, - bool removenodes = false); + const bool removenodes = false); virtual void RemoveElement(const SMDS_MeshElement * elem, bool removenodes = false); virtual void RemoveNode(const SMDS_MeshNode * node); + virtual void Remove0DElement(const SMDS_Mesh0DElement * elem0d); virtual void RemoveEdge(const SMDS_MeshEdge * edge); virtual void RemoveFace(const SMDS_MeshFace * face); virtual void RemoveVolume(const SMDS_MeshVolume * volume); @@ -430,7 +627,7 @@ public: virtual void RemoveFreeElement(const SMDS_MeshElement * elem); virtual void Clear(); - + virtual bool RemoveFromParent(); virtual bool RemoveSubMesh(const SMDS_Mesh * aMesh); @@ -443,8 +640,12 @@ public: virtual void Renumber (const bool isNodes, const int startID = 1, const int deltaID = 1); // Renumber all nodes or elements. + virtual void compactMesh(); const SMDS_MeshNode *FindNode(int idnode) const; + const SMDS_MeshNode *FindNodeVtk(int idnode) const; + const SMDS_Mesh0DElement* Find0DElement(int idnode) const; + const SMDS_BallElement* FindBall(int idnode) const; const SMDS_MeshEdge *FindEdge(int idnode1, int idnode2) const; const SMDS_MeshEdge *FindEdge(int idnode1, int idnode2, int idnode3) const; const SMDS_MeshFace *FindFace(int idnode1, int idnode2, int idnode3) const; @@ -454,6 +655,8 @@ public: const SMDS_MeshFace *FindFace(int idnode1, int idnode2, int idnode3, int idnode4, int idnode5, int idnode6, int idnode7, int idnode8) const; const SMDS_MeshElement *FindElement(int IDelem) const; + static const SMDS_Mesh0DElement* Find0DElement(const SMDS_MeshNode * n); + static const SMDS_BallElement* FindBall(const SMDS_MeshNode * n); static const SMDS_MeshEdge* FindEdge(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2); static const SMDS_MeshEdge* FindEdge(const SMDS_MeshNode * n1, @@ -481,8 +684,11 @@ public: const SMDS_MeshNode *n7, const SMDS_MeshNode *n8); - const SMDS_MeshFace *FindFace(std::vector nodes_ids) const; - static const SMDS_MeshFace* FindFace(std::vector nodes); + const SMDS_MeshFace *FindFace(const std::vector& nodes_ids) const; + static const SMDS_MeshFace* FindFace(const std::vector& nodes); + static const SMDS_MeshElement* FindElement(const std::vector& nodes, + const SMDSAbs_ElementType type=SMDSAbs_All, + const bool noMedium=true); /*! * \brief Raise an exception if free memory (ram+swap) too low @@ -498,19 +704,23 @@ public: const SMDS_MeshInfo& GetMeshInfo() const { return myInfo; } - int NbNodes() const; - int NbEdges() const; - int NbFaces() const; - int NbVolumes() const; - int NbSubMesh() const; + virtual int NbNodes() const; + virtual int Nb0DElements() const; + virtual int NbBalls() const; + virtual int NbEdges() const; + virtual int NbFaces() const; + virtual int NbVolumes() const; + virtual int NbSubMesh() const; + void DumpNodes() const; + void Dump0DElements() const; void DumpEdges() const; void DumpFaces() const; void DumpVolumes() const; void DebugStats() const; - SMDS_Mesh *boundaryFaces(); - SMDS_Mesh *boundaryEdges(); + virtual ~SMDS_Mesh(); + bool hasConstructionEdges(); bool hasConstructionFaces(); bool hasInverseElements(); @@ -526,52 +736,127 @@ public: */ bool Contains (const SMDS_MeshElement* elem) const; - typedef NCollection_Map SetOfNodes; - typedef NCollection_Map SetOfEdges; - typedef NCollection_Map SetOfFaces; - typedef NCollection_Map SetOfVolumes; + typedef std::vector SetOfNodes; + typedef std::vector SetOfCells; + + void updateNodeMinMax(); + void updateBoundingBox(); + double getMaxDim(); + int fromVtkToSmds(int vtkid); + + void incrementNodesCapacity(int nbNodes); + void incrementCellsCapacity(int nbCells); + void adjustStructure(); + void dumpGrid(string ficdump="dumpGrid"); + static int chunkSize; + + //! low level modification: add, change or remove node or element + inline void setMyModified() { this->myModified = true; } + + void Modified(); + unsigned long GetMTime() const; + bool isCompacted(); -private: +protected: SMDS_Mesh(SMDS_Mesh * parent); - SMDS_MeshFace * createTriangle(const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2, - const SMDS_MeshNode * node3); + SMDS_MeshFace * createTriangle(const SMDS_MeshNode * node1, + const SMDS_MeshNode * node2, + const SMDS_MeshNode * node3, + int ID); SMDS_MeshFace * createQuadrangle(const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2, - const SMDS_MeshNode * node3, - const SMDS_MeshNode * node4); + const SMDS_MeshNode * node2, + const SMDS_MeshNode * node3, + const SMDS_MeshNode * node4, + int ID); SMDS_MeshEdge* FindEdgeOrCreate(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2); + const SMDS_MeshNode * n2); SMDS_MeshFace* FindFaceOrCreate(const SMDS_MeshNode *n1, - const SMDS_MeshNode *n2, - const SMDS_MeshNode *n3); + const SMDS_MeshNode *n2, + const SMDS_MeshNode *n3); SMDS_MeshFace* FindFaceOrCreate(const SMDS_MeshNode *n1, - const SMDS_MeshNode *n2, - const SMDS_MeshNode *n3, - const SMDS_MeshNode *n4); + const SMDS_MeshNode *n2, + const SMDS_MeshNode *n3, + const SMDS_MeshNode *n4); bool registerElement(int ID, SMDS_MeshElement * element); - void addChildrenWithNodes(std::set& setOfChildren, - const SMDS_MeshElement * element, - std::set& nodes); + void addChildrenWithNodes(std::set& setOfChildren, + const SMDS_MeshElement * element, + std::set& nodes); + + inline void adjustmyCellsCapacity(int ID) + { + assert(ID >= 0); + myElementIDFactory->adjustMaxId(ID); + if (ID >= myCells.size()) + myCells.resize(ID+SMDS_Mesh::chunkSize,0); + } + + inline void adjustBoundingBox(double x, double y, double z) + { + if (x > xmax) xmax = x; + else if (x < xmin) xmin = x; + if (y > ymax) ymax = y; + else if (y < ymin) ymin = y; + if (z > zmax) zmax = z; + else if (z < zmin) zmin = z; + } // Fields PRIVATE - + + //! index of this SMDS_mesh in the static vector _meshList + int myMeshId; + + //! actual nodes coordinates, cells definition and reverse connectivity are stored in a vtkUnstructuredGrid + SMDS_UnstructuredGrid* myGrid; + + //! Small objects like SMDS_MeshNode are allocated by chunks to limit memory costs of new + ObjectPool* myNodePool; + + //! Small objects like SMDS_VtkVolume are allocated by chunks to limit memory costs of new + ObjectPool* myVolumePool; + ObjectPool* myFacePool; + ObjectPool* myEdgePool; + ObjectPool* myBallPool; + + //! SMDS_MeshNodes refer to vtk nodes (vtk id = index in myNodes),store reference to this mesh, and sub-shape SetOfNodes myNodes; - SetOfEdges myEdges; - SetOfFaces myFaces; - SetOfVolumes myVolumes; + + //! SMDS_MeshCells refer to vtk cells (vtk id != index in myCells),store reference to this mesh, and sub-shape + SetOfCells myCells; + + //! a buffer to speed up elements addition by excluding some memory allocation + std::vector myNodeIds; + + //! for cells only: index = ID in vtkUnstructuredGrid, value = ID for SMDS users + std::vector myCellIdVtkToSmds; + SMDS_Mesh * myParent; std::list myChildren; - SMDS_MeshElementIDFactory *myNodeIDFactory; + SMDS_MeshNodeIDFactory *myNodeIDFactory; SMDS_MeshElementIDFactory *myElementIDFactory; SMDS_MeshInfo myInfo; + //! use a counter to keep track of modifications + unsigned long myModifTime, myCompactTime; + + int myNodeMin; + int myNodeMax; + bool myHasConstructionEdges; bool myHasConstructionFaces; bool myHasInverseElements; + + //! any add, remove or change of node or cell + bool myModified; + + double xmin; + double xmax; + double ymin; + double ymax; + double zmin; + double zmax; }; diff --git a/src/3rdParty/salomesmesh/inc/SMDS_Mesh0DElement.hxx b/src/3rdParty/salomesmesh/inc/SMDS_Mesh0DElement.hxx new file mode 100644 index 000000000000..d0c07696067c --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMDS_Mesh0DElement.hxx @@ -0,0 +1,55 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMDS : implementaion of Salome mesh data structure +// File : SMDS_Mesh0DElement.hxx +// Module : SMESH +// +#ifndef _SMDS_Mesh0DElement_HeaderFile +#define _SMDS_Mesh0DElement_HeaderFile + +#include "SMESH_SMDS.hxx" + +#include "SMDS_MeshCell.hxx" + +#include + +class SMDS_EXPORT SMDS_Mesh0DElement: public SMDS_MeshCell +{ + public: + SMDS_Mesh0DElement (const SMDS_MeshNode * node); + virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes); + virtual void Print (std::ostream & OS) const; + + virtual SMDSAbs_ElementType GetType() const; + virtual vtkIdType GetVtkType() const; + virtual SMDSAbs_EntityType GetEntityType() const {return SMDSEntity_0D;} + virtual SMDSAbs_GeometryType GetGeomType() const { return SMDSGeom_POINT; } + virtual const SMDS_MeshNode* GetNode (const int ind) const; + virtual int NbNodes() const; + virtual int NbEdges() const; + + protected: + virtual SMDS_ElemIteratorPtr elementsIterator (SMDSAbs_ElementType type) const; + + protected: + const SMDS_MeshNode* myNode; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_MeshCell.hxx b/src/3rdParty/salomesmesh/inc/SMDS_MeshCell.hxx new file mode 100644 index 000000000000..d56f7b5dea63 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMDS_MeshCell.hxx @@ -0,0 +1,83 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +#ifndef _SMDS_MESHCELL_HXX_ +#define _SMDS_MESHCELL_HXX_ + +#include "SMDS_MeshElement.hxx" + +/*! + * \brief Base class for all cells + */ + +class SMDS_EXPORT SMDS_MeshCell: public SMDS_MeshElement +{ +public: + SMDS_MeshCell(); + virtual ~SMDS_MeshCell(); + + virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes)= 0; + virtual bool vtkOrder(const SMDS_MeshNode* nodes[], const int nbNodes) {return true; } + + static VTKCellType toVtkType (SMDSAbs_EntityType vtkType); + static SMDSAbs_EntityType toSmdsType(VTKCellType vtkType); + static SMDSAbs_ElementType toSmdsType(SMDSAbs_GeometryType geomType); + static SMDSAbs_ElementType toSmdsType(SMDSAbs_EntityType entityType); + + static const std::vector& toVtkOrder(VTKCellType vtkType); + static const std::vector& toVtkOrder(SMDSAbs_EntityType smdsType); + static const std::vector& fromVtkOrder(VTKCellType vtkType); + static const std::vector& fromVtkOrder(SMDSAbs_EntityType smdsType); + + static const std::vector& reverseSmdsOrder(SMDSAbs_EntityType smdsType, + const size_t nbNodes=0); + static const std::vector& interlacedSmdsOrder(SMDSAbs_EntityType smdsType, + const size_t nbNodes=0); + + template< class VECT > // interlacedIDs[i] = smdsIDs[ indices[ i ]] + static void applyInterlace( const std::vector& interlace, VECT & data) + { + if ( interlace.empty() ) return; + VECT tmpData( data.size() ); + for ( size_t i = 0; i < data.size(); ++i ) + tmpData[i] = data[ interlace[i] ]; + data.swap( tmpData ); + } + template< class VECT > // interlacedIDs[ indices[ i ]] = smdsIDs[i] + static void applyInterlaceRev( const std::vector& interlace, VECT & data) + { + if ( interlace.empty() ) return; + VECT tmpData( data.size() ); + for ( size_t i = 0; i < data.size(); ++i ) + tmpData[ interlace[i] ] = data[i]; + data.swap( tmpData ); + } + + static int nbCells; + +protected: + inline void exchange(const SMDS_MeshNode* nodes[],int a, int b) + { + const SMDS_MeshNode* noda = nodes[a]; + nodes[a] = nodes[b]; + nodes[b] = noda; + } +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_MeshEdge.hxx b/src/3rdParty/salomesmesh/inc/SMDS_MeshEdge.hxx index 84998e129490..782bb67da71e 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_MeshEdge.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_MeshEdge.hxx @@ -1,24 +1,22 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 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, or (at your option) any later version. // -// 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. // -// 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 // -// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshEdge.hxx // Module : SMESH @@ -28,37 +26,14 @@ #include "SMESH_SMDS.hxx" -#include "SMDS_MeshElement.hxx" -#include +#include "SMDS_MeshCell.hxx" -class SMDS_EXPORT SMDS_MeshEdge:public SMDS_MeshElement +class SMDS_EXPORT SMDS_MeshEdge: public SMDS_MeshCell { - - public: - SMDS_MeshEdge(const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2); - bool ChangeNodes(const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2); - void Print(std::ostream & OS) const; - - SMDSAbs_ElementType GetType() const; - int NbNodes() const; - int NbEdges() const; - friend bool operator<(const SMDS_MeshEdge& e1, const SMDS_MeshEdge& e2); - - /*! - * \brief Return node by its index - * \param ind - node index - * \retval const SMDS_MeshNode* - the node - */ - virtual const SMDS_MeshNode* GetNode(const int ind) const; - - protected: - SMDS_ElemIteratorPtr - elementsIterator(SMDSAbs_ElementType type) const; - - protected: - const SMDS_MeshNode* myNodes[3]; - + + public: + virtual SMDSAbs_ElementType GetType() const; + virtual vtkIdType GetVtkType() const; + virtual SMDSAbs_GeometryType GetGeomType() const { return SMDSGeom_EDGE; } }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_MeshElement.hxx b/src/3rdParty/salomesmesh/inc/SMDS_MeshElement.hxx index 13498092ab86..8d0d674e0916 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_MeshElement.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_MeshElement.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshElement.hxx // Module : SMESH @@ -27,18 +28,27 @@ #define _SMDS_MeshElement_HeaderFile #include "SMESH_SMDS.hxx" - + #include "SMDSAbs_ElementType.hxx" #include "SMDS_MeshObject.hxx" #include "SMDS_ElemIterator.hxx" #include "SMDS_MeshElementIDFactory.hxx" +#include "SMDS_StdIterator.hxx" #include #include +#include +#include + +//typedef unsigned short UShortType; +typedef short ShortType; +typedef int LongType; + class SMDS_MeshNode; class SMDS_MeshEdge; -class SMDS_MeshFace; +class SMDS_MeshFace; +class SMDS_Mesh; // ============================================================ /*! @@ -46,6 +56,7 @@ class SMDS_MeshFace; */ // ============================================================ + class SMDS_EXPORT SMDS_MeshElement:public SMDS_MeshObject { public: @@ -54,21 +65,39 @@ public: SMDS_ElemIteratorPtr edgesIterator() const; SMDS_ElemIteratorPtr facesIterator() const; virtual SMDS_ElemIteratorPtr elementsIterator(SMDSAbs_ElementType type) const; + virtual SMDS_ElemIteratorPtr interlacedNodesElemIterator() const; + + virtual SMDS_NodeIteratorPtr nodeIterator() const; + virtual SMDS_NodeIteratorPtr interlacedNodesIterator() const; + virtual SMDS_NodeIteratorPtr nodesIteratorToUNV() const; + + // std-like iteration on nodes + typedef SMDS_StdIterator< const SMDS_MeshNode*, SMDS_ElemIteratorPtr > iterator; + iterator begin_nodes() const { return iterator( nodesIterator() ); } + iterator end_nodes() const { return iterator(); } virtual int NbNodes() const; virtual int NbEdges() const; virtual int NbFaces() const; - int GetID() const; + inline int GetID() const { return myID; } ///Return the type of the current element virtual SMDSAbs_ElementType GetType() const = 0; - virtual bool IsPoly() const { return false; }; + virtual SMDSAbs_EntityType GetEntityType() const = 0; + virtual SMDSAbs_GeometryType GetGeomType() const = 0; + virtual vtkIdType GetVtkType() const = 0; + virtual bool IsPoly() const { return false; } virtual bool IsQuadratic() const; virtual bool IsMediumNode(const SMDS_MeshNode* node) const; + virtual int NbCornerNodes() const; friend SMDS_EXPORT std::ostream & operator <<(std::ostream & OS, const SMDS_MeshElement *); - friend SMDS_EXPORT bool SMDS_MeshElementIDFactory::BindID(int ID,SMDS_MeshElement*elem); + friend SMDS_EXPORT bool SMDS_MeshElementIDFactory::BindID(int ID,SMDS_MeshElement* elem); + friend class SMDS_Mesh; + friend class SMESHDS_Mesh; + friend class SMESHDS_SubMesh; + friend class SMDS_MeshElementIDFactory; // =========================== // Access to nodes by index @@ -112,22 +141,80 @@ public: * \param node - the node to check * \retval int - node index within the element, -1 if not found */ - int GetNodeIndex( const SMDS_MeshNode* node ) const; + virtual int GetNodeIndex( const SMDS_MeshNode* node ) const; + + inline ShortType getMeshId() const { return myMeshId; } + inline LongType getshapeId() const { return myShapeId; } + inline int getIdInShape() const { return myIdInShape; } + inline int getVtkId() const { return myVtkID; } + + /*! + * \brief Filters of elements, to be used with SMDS_SetIterator + */ + struct Filter + { + virtual bool operator()(const SMDS_MeshElement* e) const = 0; + virtual ~Filter() {} + }; + struct NonNullFilter: public Filter + { + bool operator()(const SMDS_MeshElement* e) const { return e; } + }; + struct TypeFilter : public Filter + { + SMDSAbs_ElementType _type; + TypeFilter( SMDSAbs_ElementType t = SMDSAbs_NbElementTypes ):_type(t) {} + bool operator()(const SMDS_MeshElement* e) const { return e && e->GetType() == _type; } + }; + struct EntityFilter : public Filter + { + SMDSAbs_EntityType _type; + EntityFilter( SMDSAbs_EntityType t = SMDSEntity_Last ):_type(t) {} + bool operator()(const SMDS_MeshElement* e) const { return e && e->GetEntityType() == _type; } + }; + struct GeomFilter : public Filter + { + SMDSAbs_GeometryType _type; + GeomFilter( SMDSAbs_GeometryType t = SMDSGeom_NONE ):_type(t) {} + bool operator()(const SMDS_MeshElement* e) const { return e && e->GetGeomType() == _type; } + }; protected: + inline void setId(int id) {myID = id; } + inline void setShapeId(LongType shapeId) {myShapeId = shapeId; } + inline void setIdInShape(int id) { myIdInShape = id; } + inline void setVtkId(int vtkId) { myVtkID = vtkId; } SMDS_MeshElement(int ID=-1); + SMDS_MeshElement(int id, ShortType meshId, LongType shapeId = 0); + virtual void init(int id = -1, ShortType meshId = -1, LongType shapeId = 0); virtual void Print(std::ostream & OS) const; -private: + //! Element index in vector SMDS_Mesh::myNodes or SMDS_Mesh::myCells int myID; + //! index in vtkUnstructuredGrid + int myVtkID; + //! SMDS_Mesh identification in SMESH + ShortType myMeshId; + //! SubShape and SubMesh identification in SMESHDS + LongType myShapeId; + //! Element index in SMESHDS_SubMesh vector + int myIdInShape; }; + // ============================================================ /*! * \brief Comparator of elements by ID for usage in std containers */ // ============================================================ +struct TIDTypeCompare { + bool operator () (const SMDS_MeshElement* e1, const SMDS_MeshElement* e2) const + { return e1->GetType() == e2->GetType() ? e1->GetID() < e2->GetID() : e1->GetType() < e2->GetType(); } +}; + +// WARNING: this comparator makes impossible to store both nodes and elements in the same set +// because there are nodes and elements with the same ID. Use TIDTypeCompare for such containers. struct TIDCompare { bool operator () (const SMDS_MeshElement* e1, const SMDS_MeshElement* e2) const { return e1->GetID() < e2->GetID(); } diff --git a/src/3rdParty/salomesmesh/inc/SMDS_MeshElementIDFactory.hxx b/src/3rdParty/salomesmesh/inc/SMDS_MeshElementIDFactory.hxx index a574def92ad1..9b8ee15b7a06 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_MeshElementIDFactory.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_MeshElementIDFactory.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshElementIDFactory.hxx // Module : SMESH @@ -28,28 +29,28 @@ #include "SMESH_SMDS.hxx" -#include "SMDS_MeshIDFactory.hxx" -#include "SMDS_ElemIterator.hxx" +#include "SMDS_MeshNodeIDFactory.hxx" -#include +#include class SMDS_MeshElement; +class SMDS_Mesh; -typedef NCollection_DataMap SMDS_IdElementMap; - -class SMDS_EXPORT SMDS_MeshElementIDFactory:public SMDS_MeshIDFactory +class SMDS_EXPORT SMDS_MeshElementIDFactory:public SMDS_MeshNodeIDFactory { public: + friend class SMDS_Mesh; + SMDS_MeshElementIDFactory(); bool BindID(int ID, SMDS_MeshElement * elem); + int SetInVtkGrid(SMDS_MeshElement * elem); SMDS_MeshElement * MeshElement(int ID); virtual int GetFreeID(); - virtual void ReleaseID(int ID); - int GetMaxID() const; - int GetMinID() const; + virtual void ReleaseID(int ID, int vtkId = -1); SMDS_ElemIteratorPtr elementsIterator() const; virtual void Clear(); -private: + +protected: void updateMinMax() const; void updateMinMax(int id) const { @@ -57,9 +58,6 @@ private: if (id < myMin) myMin = id; } - SMDS_IdElementMap myIDElements; - mutable int myMin, myMax; - }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_MeshFace.hxx b/src/3rdParty/salomesmesh/inc/SMDS_MeshFace.hxx index a633e4ecf0f8..76a32c867fb2 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_MeshFace.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_MeshFace.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshFace.hxx // Module : SMESH @@ -28,12 +29,13 @@ #include "SMESH_SMDS.hxx" -#include "SMDS_MeshElement.hxx" +#include "SMDS_MeshCell.hxx" -class SMDS_EXPORT SMDS_MeshFace:public SMDS_MeshElement +class SMDS_EXPORT SMDS_MeshFace:public SMDS_MeshCell { public: - SMDSAbs_ElementType GetType() const; + SMDSAbs_ElementType GetType() const; + virtual vtkIdType GetVtkType() const; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_MeshGroup.hxx b/src/3rdParty/salomesmesh/inc/SMDS_MeshGroup.hxx index 788aaa79a729..dc630439492f 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_MeshGroup.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_MeshGroup.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshGroup.hxx // Module : SMESH @@ -34,27 +35,28 @@ class SMDS_EXPORT SMDS_MeshGroup:public SMDS_MeshObject { public: - SMDS_MeshGroup(const SMDS_Mesh * theMesh, + SMDS_MeshGroup(const SMDS_Mesh * theMesh, const SMDSAbs_ElementType theType = SMDSAbs_All); - const SMDS_MeshGroup * AddSubGroup + const SMDS_MeshGroup * AddSubGroup (const SMDSAbs_ElementType theType = SMDSAbs_All); - virtual bool RemoveSubGroup(const SMDS_MeshGroup* theGroup); - virtual bool RemoveFromParent(); + virtual bool RemoveSubGroup(const SMDS_MeshGroup* theGroup); + virtual bool RemoveFromParent(); const SMDS_Mesh* GetMesh() const { return myMesh; } void SetType (const SMDSAbs_ElementType theType); void Clear(); - void Add(const SMDS_MeshElement * theElem); - bool Remove(const SMDS_MeshElement * theElem); - bool IsEmpty() const { return myElements.empty(); } - int Extent() const { return myElements.size(); } + bool Add(const SMDS_MeshElement * theElem); + bool Remove(const SMDS_MeshElement * theElem); + bool IsEmpty() const { return myElements.empty(); } + int Extent() const { return myElements.size(); } + int Tic() const { return myTic; } - int SubGroupsNb() const { return myChildren.size(); } + int SubGroupsNb() const { return myChildren.size(); } SMDSAbs_ElementType GetType() const { return myType; } - bool Contains(const SMDS_MeshElement * theElem) const; + bool Contains(const SMDS_MeshElement * theElem) const; void InitIterator() const { const_cast(myIterator) = myElements.begin(); } @@ -73,18 +75,19 @@ class SMDS_EXPORT SMDS_MeshGroup:public SMDS_MeshObject { return *(const_cast(myGroupIterator))++; } private: - SMDS_MeshGroup(SMDS_MeshGroup* theParent, + SMDS_MeshGroup(SMDS_MeshGroup* theParent, const SMDSAbs_ElementType theType = SMDSAbs_All); typedef std::set::const_iterator TIterator; typedef std::list::const_iterator TGroupIterator; - const SMDS_Mesh * myMesh; - SMDSAbs_ElementType myType; - std::set myElements; - SMDS_MeshGroup * myParent; - std::list myChildren; + const SMDS_Mesh * myMesh; + SMDSAbs_ElementType myType; + std::set myElements; /* - not sorted by ID because it */ + SMDS_MeshGroup * myParent; /* can contain deleted elements */ + std::list myChildren; TIterator myIterator; TGroupIterator myGroupIterator; + int myTic; // to track changes }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_MeshIDFactory.hxx b/src/3rdParty/salomesmesh/inc/SMDS_MeshIDFactory.hxx index e81b41890597..587a72746262 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_MeshIDFactory.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_MeshIDFactory.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshIDFactory.hxx // Module : SMESH @@ -31,18 +32,25 @@ #include "SMDS_MeshObject.hxx" #include +class SMDS_Mesh; class SMDS_EXPORT SMDS_MeshIDFactory:public SMDS_MeshObject { public: - virtual int GetFreeID(); - virtual void ReleaseID(int ID); + int GetFreeID(); + virtual void ReleaseID(int ID, int vtkId = -1); virtual void Clear(); - protected: - SMDS_MeshIDFactory(); - int myMaxID; - std::set myPoolOfID; + void SetMesh(SMDS_Mesh *mesh); + SMDS_Mesh* GetMesh(); + inline bool isPoolIdEmpty() { return myPoolOfID.empty(); }; + virtual void emptyPool(int maxId); + inline void adjustMaxId(int ID) { if (ID > myMaxID) myMaxID = ID;}; +protected: + SMDS_MeshIDFactory(); + int myMaxID; + std::set myPoolOfID; + SMDS_Mesh *myMesh; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_MeshInfo.hxx b/src/3rdParty/salomesmesh/inc/SMDS_MeshInfo.hxx index 8d3467fd756d..5c22d7f9b0e6 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_MeshInfo.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_MeshInfo.hxx @@ -1,24 +1,22 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 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, or (at your option) any later version. // -// 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. // -// 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 // -// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : SMDS_MeshInfo.hxx // Created : Mon Sep 24 18:32:41 2007 // Author : Edward AGAPOV (eap) @@ -26,6 +24,7 @@ #ifndef SMDS_MeshInfo_HeaderFile #define SMDS_MeshInfo_HeaderFile +#include using namespace std; #include "SMESH_SMDS.hxx" @@ -37,30 +36,48 @@ class SMDS_EXPORT SMDS_MeshInfo public: inline SMDS_MeshInfo(); + inline SMDS_MeshInfo& operator=(const SMDS_MeshInfo& other); inline void Clear(); - int NbNodes() const { return myNbNodes; } + inline int NbElements(SMDSAbs_ElementType type=SMDSAbs_All) const; + inline int NbElements(SMDSAbs_EntityType type) const { return NbEntities(type); } + inline int NbElements(SMDSAbs_GeometryType type) const { return NbElementsOfGeom(type); } + inline int NbEntities(SMDSAbs_EntityType type) const; + inline int NbElementsOfGeom(SMDSAbs_GeometryType geom) const; + + int NbNodes() const { return myNbNodes; } + int Nb0DElements() const { return myNb0DElements; } + int NbBalls() const { return myNbBalls; } inline int NbEdges (SMDSAbs_ElementOrder order = ORDER_ANY) const; + inline int NbFaces (SMDSAbs_ElementOrder order = ORDER_ANY) const; inline int NbTriangles (SMDSAbs_ElementOrder order = ORDER_ANY) const; inline int NbQuadrangles(SMDSAbs_ElementOrder order = ORDER_ANY) const; - int NbPolygons() const { return myNbPolygons; } + int NbBiQuadTriangles() const { return myNbBiQuadTriangles; } + int NbBiQuadQuadrangles() const { return myNbBiQuadQuadrangles; } + inline int NbPolygons(SMDSAbs_ElementOrder order = ORDER_ANY) const; inline int NbVolumes (SMDSAbs_ElementOrder order = ORDER_ANY) const; inline int NbTetras (SMDSAbs_ElementOrder order = ORDER_ANY) const; inline int NbHexas (SMDSAbs_ElementOrder order = ORDER_ANY) const; inline int NbPyramids(SMDSAbs_ElementOrder order = ORDER_ANY) const; inline int NbPrisms (SMDSAbs_ElementOrder order = ORDER_ANY) const; + inline int NbHexPrisms(SMDSAbs_ElementOrder order = ORDER_ANY) const; + int NbTriQuadHexas() const { return myNbTriQuadHexas; } int NbPolyhedrons() const { return myNbPolyhedrons; } +protected: + inline void addWithPoly(const SMDS_MeshElement* el); + inline void setNb(const SMDSAbs_EntityType geomType, const int nb); + private: friend class SMDS_Mesh; // methods to count NOT POLY elements inline void remove(const SMDS_MeshElement* el); inline void add (const SMDS_MeshElement* el); - inline int index(SMDSAbs_ElementType type, int nbNodes); + inline int index(SMDSAbs_ElementType type, int nbNodes) const; // methods to remove elements of ANY kind inline void RemoveEdge(const SMDS_MeshElement* el); inline void RemoveFace(const SMDS_MeshElement* el); @@ -68,15 +85,18 @@ private: int myNbNodes; + int myNb0DElements; + int myNbBalls; int myNbEdges , myNbQuadEdges ; - int myNbTriangles , myNbQuadTriangles ; - int myNbQuadrangles, myNbQuadQuadrangles; - int myNbPolygons; + int myNbTriangles , myNbQuadTriangles, myNbBiQuadTriangles ; + int myNbQuadrangles, myNbQuadQuadrangles, myNbBiQuadQuadrangles; + int myNbPolygons , myNbQuadPolygons; int myNbTetras , myNbQuadTetras ; - int myNbHexas , myNbQuadHexas ; + int myNbHexas , myNbQuadHexas, myNbTriQuadHexas; int myNbPyramids, myNbQuadPyramids; int myNbPrisms , myNbQuadPrisms ; + int myNbHexPrism; int myNbPolyhedrons; std::vector myNb; // pointers to myNb... fields @@ -84,76 +104,109 @@ private: }; inline SMDS_MeshInfo::SMDS_MeshInfo(): - myNbNodes(0), + myNbNodes (0), + myNb0DElements (0), + myNbBalls (0), myNbEdges (0), myNbQuadEdges (0), - myNbTriangles (0), myNbQuadTriangles (0), - myNbQuadrangles(0), myNbQuadQuadrangles(0), - myNbPolygons(0), - myNbTetras (0), myNbQuadTetras (0), - myNbHexas (0), myNbQuadHexas (0), - myNbPyramids(0), myNbQuadPyramids(0), - myNbPrisms (0), myNbQuadPrisms (0), + myNbTriangles (0), myNbQuadTriangles (0), myNbBiQuadTriangles(0), + myNbQuadrangles(0), myNbQuadQuadrangles(0), myNbBiQuadQuadrangles(0), + myNbPolygons (0), myNbQuadPolygons (0), + myNbTetras (0), myNbQuadTetras (0), + myNbHexas (0), myNbQuadHexas (0), myNbTriQuadHexas(0), + myNbPyramids (0), myNbQuadPyramids(0), + myNbPrisms (0), myNbQuadPrisms (0), + myNbHexPrism (0), myNbPolyhedrons(0) { - // Number of nodes in standard element types - // n v f e - // o o a d - // d l c g - // e e e - // ----------- - // 1 - // 2 * - // 3 * - // 4 * * * - // 5 * - // 6 * * - // 7 - // 8 * * - // 9 - // 10 * - // 11 - // 12 - // 13 * - // 14 - // 15 * - // 16 - // 17 - // 18 - // 19 - // 20 * + // Number of nodes in standard element types (. - actual nb, * - after the shift) + // n v f e 0 n b + // o o a d d o a + // d l c g d l + // e e e e l + // s + // ==================== + // 0 ------------------ - DON't USE 0!!! + // 1 . * . + // 2 . * + // 3 . . * + // 4 * . + // 5 * + // 6 * . + // 7 . + // 8 * . + // 9 . + // 10 * + // 11 + // 12 * + // 13 * + // 14 + // 15 * + // 16 * + // 17 * + // 18 * + // 19 * + // 20 * + // 21 * + // 22 * + // 23 * + // 24 * + // 25 + // 26 + // 27 * // // So to have a unique index for each type basing on nb of nodes, we use a shift: - myShift.resize(SMDSAbs_Volume + 1, 0); - myShift[ SMDSAbs_Face ] = +8; // 3->11, 4->12, 6->14, 8->16 - myShift[ SMDSAbs_Edge ] = -2; // 2->0, 4->2 + myShift.resize(SMDSAbs_NbElementTypes, 0); + + myShift[ SMDSAbs_Face ] = +15;// 3->18, 4->19, etc. + myShift[ SMDSAbs_Edge ] = +14;// 2->16, 3->17 + myShift[ SMDSAbs_0DElement ] = +2; // 1->3 + myShift[ SMDSAbs_Ball ] = +1; // 1->2 + + myNb.resize( index( SMDSAbs_Volume,27 ) + 1, NULL); - myNb.resize( index( SMDSAbs_Volume,20 ) + 1, NULL); myNb[ index( SMDSAbs_Node,1 )] = & myNbNodes; + myNb[ index( SMDSAbs_0DElement,1 )] = & myNb0DElements; + myNb[ index( SMDSAbs_Ball,1 )] = & myNbBalls; myNb[ index( SMDSAbs_Edge,2 )] = & myNbEdges; - myNb[ index( SMDSAbs_Edge,4 )] = & myNbQuadEdges; + myNb[ index( SMDSAbs_Edge,3 )] = & myNbQuadEdges; myNb[ index( SMDSAbs_Face,3 )] = & myNbTriangles; myNb[ index( SMDSAbs_Face,4 )] = & myNbQuadrangles; myNb[ index( SMDSAbs_Face,6 )] = & myNbQuadTriangles; + myNb[ index( SMDSAbs_Face,7 )] = & myNbBiQuadTriangles; myNb[ index( SMDSAbs_Face,8 )] = & myNbQuadQuadrangles; + myNb[ index( SMDSAbs_Face,9 )] = & myNbBiQuadQuadrangles; myNb[ index( SMDSAbs_Volume, 4)] = & myNbTetras; myNb[ index( SMDSAbs_Volume, 5)] = & myNbPyramids; myNb[ index( SMDSAbs_Volume, 6)] = & myNbPrisms; myNb[ index( SMDSAbs_Volume, 8)] = & myNbHexas; myNb[ index( SMDSAbs_Volume, 10)] = & myNbQuadTetras; + myNb[ index( SMDSAbs_Volume, 12)] = & myNbHexPrism; myNb[ index( SMDSAbs_Volume, 13)] = & myNbQuadPyramids; myNb[ index( SMDSAbs_Volume, 15)] = & myNbQuadPrisms; myNb[ index( SMDSAbs_Volume, 20)] = & myNbQuadHexas; + myNb[ index( SMDSAbs_Volume, 27)] = & myNbTriQuadHexas; } + +inline SMDS_MeshInfo& // operator= +SMDS_MeshInfo::operator=(const SMDS_MeshInfo& other) +{ for ( int i=0; iGetType(), el->NbNodes()) ]); } +inline void // addWithPoly +SMDS_MeshInfo::addWithPoly(const SMDS_MeshElement* el) { + switch ( el->GetEntityType() ) { + case SMDSEntity_Polygon: ++myNbPolygons; break; + case SMDSEntity_Quad_Polygon: ++myNbQuadPolygons; break; + case SMDSEntity_Polyhedra: ++myNbPolyhedrons; break; + default: add(el); + } +} inline void // RemoveEdge SMDS_MeshInfo::RemoveEdge(const SMDS_MeshElement* el) { if ( el->IsQuadratic() ) --myNbQuadEdges; else --myNbEdges; } inline void // RemoveFace -SMDS_MeshInfo::RemoveFace(const SMDS_MeshElement* el) -{ if ( el->IsPoly() ) --myNbPolygons; else remove( el ); } +SMDS_MeshInfo::RemoveFace(const SMDS_MeshElement* el) { + switch ( el->GetEntityType() ) { + case SMDSEntity_Polygon: --myNbPolygons; break; + case SMDSEntity_Quad_Polygon: --myNbQuadPolygons; break; + default: remove(el); + } +} inline void // RemoveVolume SMDS_MeshInfo::RemoveVolume(const SMDS_MeshElement* el) { if ( el->IsPoly() ) --myNbPolyhedrons; else remove( el ); } -inline int // NbEdges +inline int // NbEdges SMDS_MeshInfo::NbEdges (SMDSAbs_ElementOrder order) const { return order == ORDER_ANY ? myNbEdges+myNbQuadEdges : order == ORDER_LINEAR ? myNbEdges : myNbQuadEdges; } -inline int // NbFaces +inline int // NbFaces SMDS_MeshInfo::NbFaces (SMDSAbs_ElementOrder order) const -{ return NbTriangles(order)+NbQuadrangles(order)+(order == ORDER_QUADRATIC ? 0 : myNbPolygons); } +{ return NbTriangles(order)+NbQuadrangles(order)+(order == ORDER_ANY ? myNbPolygons+myNbQuadPolygons : order == ORDER_LINEAR ? myNbPolygons : myNbQuadPolygons ); } -inline int // NbTriangles +inline int // NbTriangles SMDS_MeshInfo::NbTriangles (SMDSAbs_ElementOrder order) const -{ return order == ORDER_ANY ? myNbTriangles+myNbQuadTriangles : order == ORDER_LINEAR ? myNbTriangles : myNbQuadTriangles; } +{ return order == ORDER_ANY ? myNbTriangles+myNbQuadTriangles+myNbBiQuadTriangles : order == ORDER_LINEAR ? myNbTriangles : myNbQuadTriangles+myNbBiQuadTriangles; } -inline int // NbQuadrangles +inline int // NbQuadrangles SMDS_MeshInfo::NbQuadrangles(SMDSAbs_ElementOrder order) const -{ return order == ORDER_ANY ? myNbQuadrangles+myNbQuadQuadrangles : order == ORDER_LINEAR ? myNbQuadrangles : myNbQuadQuadrangles; } +{ return order == ORDER_ANY ? myNbQuadrangles+myNbQuadQuadrangles+myNbBiQuadQuadrangles : order == ORDER_LINEAR ? myNbQuadrangles : myNbQuadQuadrangles+myNbBiQuadQuadrangles; } -inline int // NbVolumes +inline int // NbPolygons +SMDS_MeshInfo::NbPolygons(SMDSAbs_ElementOrder order) const +{ return order == ORDER_ANY ? myNbPolygons+myNbQuadPolygons : order == ORDER_LINEAR ? myNbPolygons : myNbQuadPolygons; } + +inline int // NbVolumes SMDS_MeshInfo::NbVolumes (SMDSAbs_ElementOrder order) const -{ return NbTetras(order) + NbHexas(order) + NbPyramids(order) + NbPrisms(order) + (order == ORDER_QUADRATIC ? 0 : myNbPolyhedrons); } +{ return NbTetras(order) + NbHexas(order) + NbPyramids(order) + NbPrisms(order) + NbHexPrisms(order) + (order == ORDER_QUADRATIC ? 0 : myNbPolyhedrons); } -inline int // NbTetras +inline int // NbTetras SMDS_MeshInfo::NbTetras (SMDSAbs_ElementOrder order) const { return order == ORDER_ANY ? myNbTetras+myNbQuadTetras : order == ORDER_LINEAR ? myNbTetras : myNbQuadTetras; } -inline int // NbHexas +inline int // NbHexas SMDS_MeshInfo::NbHexas (SMDSAbs_ElementOrder order) const -{ return order == ORDER_ANY ? myNbHexas+myNbQuadHexas : order == ORDER_LINEAR ? myNbHexas : myNbQuadHexas; } +{ return order == ORDER_ANY ? myNbHexas+myNbQuadHexas+myNbTriQuadHexas : order == ORDER_LINEAR ? myNbHexas : myNbQuadHexas+myNbTriQuadHexas; } -inline int // NbPyramids +inline int // NbPyramids SMDS_MeshInfo::NbPyramids(SMDSAbs_ElementOrder order) const { return order == ORDER_ANY ? myNbPyramids+myNbQuadPyramids : order == ORDER_LINEAR ? myNbPyramids : myNbQuadPyramids; } -inline int // NbPrisms +inline int // NbPrisms SMDS_MeshInfo::NbPrisms (SMDSAbs_ElementOrder order) const { return order == ORDER_ANY ? myNbPrisms+myNbQuadPrisms : order == ORDER_LINEAR ? myNbPrisms : myNbQuadPrisms; } +inline int // NbHexPrisms +SMDS_MeshInfo::NbHexPrisms (SMDSAbs_ElementOrder order) const +{ return order == ORDER_ANY ? myNbHexPrism : order == ORDER_LINEAR ? myNbHexPrism : 0; } + +inline int // NbElements +SMDS_MeshInfo::NbElements(SMDSAbs_ElementType type) const +{ + int nb = 0; + switch (type) { + case SMDSAbs_All: + for ( int i=1+index( SMDSAbs_Node,1 ); i +#include "ObjectPool.hxx" -class SMDS_EXPORT SMDS_MeshNode:public SMDS_MeshElement +class SMDS_EXPORT SMDS_MeshNode: public SMDS_MeshElement { +public: + friend class SMESHDS_Mesh; + friend class SMDS_Mesh; + friend class ObjectPool; + friend class SMDS_VtkFace; + + void Print(std::ostream & OS) const; + double X() const; // ! NOT thread safe methods ! + double Y() const; + double Z() const; + void GetXYZ(double xyz[3]) const; // thread safe getting coords + SMDS_ElemIteratorPtr GetInverseElementIterator(SMDSAbs_ElementType type=SMDSAbs_All) const; + int NbInverseElements(SMDSAbs_ElementType type=SMDSAbs_All) const; + const SMDS_PositionPtr& GetPosition() const; + virtual SMDSAbs_ElementType GetType() const; + virtual vtkIdType GetVtkType() const; + virtual SMDSAbs_EntityType GetEntityType() const { return SMDSEntity_Node;} + virtual SMDSAbs_GeometryType GetGeomType() const { return SMDSGeom_NONE; } + virtual int NbNodes() const; + + void SetPosition(const SMDS_PositionPtr& aPos); + void setXYZ(double x, double y, double z); - public: - SMDS_MeshNode(double x, double y, double z); - void Print(std::ostream & OS) const; - double X() const; - double Y() const; - double Z() const; - void AddInverseElement(const SMDS_MeshElement * ME); - void RemoveInverseElement(const SMDS_MeshElement * parent); - void ClearInverseElements(); - bool emptyInverseElements(); - SMDS_ElemIteratorPtr GetInverseElementIterator(SMDSAbs_ElementType type=SMDSAbs_All) const; - int NbInverseElements(SMDSAbs_ElementType type=SMDSAbs_All) const; - void SetPosition(const SMDS_PositionPtr& aPos); - const SMDS_PositionPtr& GetPosition() const; - SMDSAbs_ElementType GetType() const; - int NbNodes() const; - void setXYZ(double x, double y, double z); - friend bool operator<(const SMDS_MeshNode& e1, const SMDS_MeshNode& e2); + static int nbNodes; - /*! - * \brief Return node by its index - * \param ind - node index - * \retval const SMDS_MeshNode* - the node - */ - virtual const SMDS_MeshNode* GetNode(const int) const { return this; } +protected: + SMDS_MeshNode(); + SMDS_MeshNode(int id, int meshId, int shapeId = -1, double x=0, double y=0, double z=0); + virtual ~SMDS_MeshNode(); + void init(int id, int meshId, int shapeId = -1, double x=0, double y=0, double z=0); + double* getCoord() const; + void AddInverseElement(const SMDS_MeshElement * ME); + void RemoveInverseElement(const SMDS_MeshElement * parent); + void ClearInverseElements(); + bool emptyInverseElements(); - protected: - SMDS_ElemIteratorPtr - elementsIterator(SMDSAbs_ElementType type) const; + SMDS_ElemIteratorPtr + elementsIterator(SMDSAbs_ElementType type) const; - private: - double myX, myY, myZ; - SMDS_PositionPtr myPosition; - NCollection_List myInverseElements; +private: + SMDS_PositionPtr myPosition; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_MeshNodeIDFactory.hxx b/src/3rdParty/salomesmesh/inc/SMDS_MeshNodeIDFactory.hxx new file mode 100644 index 000000000000..eb786c3e210f --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMDS_MeshNodeIDFactory.hxx @@ -0,0 +1,65 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SMDS_MeshElementIDFactory.hxx +// Module : SMESH +// +#ifndef _SMDS_MeshNodeIDFactory_HeaderFile +#define _SMDS_MeshNodeIDFactory_HeaderFile + +#include "SMESH_SMDS.hxx" + +#include "SMDS_MeshIDFactory.hxx" +#include "SMDS_ElemIterator.hxx" + +#include + +class SMDS_MeshElement; + +class SMDS_EXPORT SMDS_MeshNodeIDFactory: public SMDS_MeshIDFactory +{ +public: + SMDS_MeshNodeIDFactory(); + bool BindID(int ID, SMDS_MeshElement * elem); + SMDS_MeshElement * MeshElement(int ID); + virtual int GetFreeID(); + virtual void ReleaseID(int ID, int vtkId = -1); + int GetMaxID() const; + int GetMinID() const; + SMDS_ElemIteratorPtr elementsIterator() const; + virtual void Clear(); + virtual void emptyPool(int maxId); + +protected: + void updateMinMax() const; + void updateMinMax(int id) const + { + if (id > myMax) + myMax = id; + if (id < myMin) + myMin = id; + } + + mutable int myMin, myMax; + +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_MeshObject.hxx b/src/3rdParty/salomesmesh/inc/SMDS_MeshObject.hxx index 8004fcbf9a6d..1a30daff3a56 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_MeshObject.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_MeshObject.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshObject.hxx // Module : SMESH diff --git a/src/3rdParty/salomesmesh/inc/SMDS_MeshVolume.hxx b/src/3rdParty/salomesmesh/inc/SMDS_MeshVolume.hxx index aa3498eac3b7..f91b03ac23fe 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_MeshVolume.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_MeshVolume.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshVolume.hxx // Module : SMESH @@ -28,12 +29,13 @@ #include "SMESH_SMDS.hxx" -#include "SMDS_MeshElement.hxx" +#include "SMDS_MeshCell.hxx" -class SMDS_EXPORT SMDS_MeshVolume:public SMDS_MeshElement +class SMDS_EXPORT SMDS_MeshVolume:public SMDS_MeshCell { - + public: - SMDSAbs_ElementType GetType() const; + SMDSAbs_ElementType GetType() const; + virtual vtkIdType GetVtkType() const; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_PolygonalFaceOfNodes.hxx b/src/3rdParty/salomesmesh/inc/SMDS_PolygonalFaceOfNodes.hxx index 71b083a3fdd8..bf6a1a5ff21a 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_PolygonalFaceOfNodes.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_PolygonalFaceOfNodes.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // #ifndef _SMDS_PolygonalFaceOfNodes_HeaderFile @@ -37,9 +38,11 @@ class SMDS_EXPORT SMDS_PolygonalFaceOfNodes:public SMDS_MeshFace { public: - SMDS_PolygonalFaceOfNodes (std::vector nodes); + SMDS_PolygonalFaceOfNodes (const std::vector& nodes); virtual SMDSAbs_ElementType GetType() const; + virtual SMDSAbs_EntityType GetEntityType() const { return SMDSEntity_Polygon; } + virtual SMDSAbs_GeometryType GetGeomType() const { return SMDSGeom_POLYGON; } virtual bool IsPoly() const { return true; }; bool ChangeNodes (std::vector nodes); diff --git a/src/3rdParty/salomesmesh/inc/SMDS_PolyhedralVolumeOfNodes.hxx b/src/3rdParty/salomesmesh/inc/SMDS_PolyhedralVolumeOfNodes.hxx index 9cddb1f02b77..ef8addebdebb 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_PolyhedralVolumeOfNodes.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_PolyhedralVolumeOfNodes.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_PolyhedralVolumeOfNodes.hxx // Module : SMESH @@ -38,7 +39,8 @@ class SMDS_EXPORT SMDS_PolyhedralVolumeOfNodes:public SMDS_VolumeOfNodes //virtual ~SMDS_PolyhedralVolumeOfNodes(); - virtual SMDSAbs_ElementType GetType() const; + virtual SMDSAbs_ElementType GetType() const; + virtual SMDSAbs_EntityType GetEntityType() const { return SMDSEntity_Polyhedra; } virtual bool IsPoly() const { return true; }; bool ChangeNodes (const std::vector & nodes, diff --git a/src/3rdParty/salomesmesh/inc/SMDS_Position.hxx b/src/3rdParty/salomesmesh/inc/SMDS_Position.hxx index 687bc098ebcf..d3265cd00880 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_Position.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_Position.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_Position.hxx // Module : SMESH @@ -32,24 +33,19 @@ #include class SMDS_Position; -typedef boost::shared_ptr SMDS_PositionPtr; +//typedef boost::shared_ptr SMDS_PositionPtr; +typedef SMDS_Position* SMDS_PositionPtr; class SMDS_EXPORT SMDS_Position { public: - const virtual double * Coords() const = 0; - virtual SMDS_TypeOfPosition GetTypeOfPosition() const = 0; - virtual int GetDim() const; - void SetShapeId(int aShapeId); - int GetShapeId() const; - virtual ~SMDS_Position() {} + virtual SMDS_TypeOfPosition GetTypeOfPosition() const = 0; + virtual int GetDim() const; + virtual ~SMDS_Position() {} protected: - SMDS_Position(int aShapeId); - - private: - int myShapeId; + SMDS_Position(); }; diff --git a/src/3rdParty/salomesmesh/inc/SMDS_QuadraticEdge.hxx b/src/3rdParty/salomesmesh/inc/SMDS_QuadraticEdge.hxx index 83877d6a16bd..c9bb8a04cc6b 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_QuadraticEdge.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_QuadraticEdge.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_QuadraticEdge.hxx // Module : SMESH @@ -28,10 +29,10 @@ #include "SMESH_SMDS.hxx" -#include "SMDS_MeshEdge.hxx" +#include "SMDS_LinearEdge.hxx" #include -class SMDS_EXPORT SMDS_QuadraticEdge: public SMDS_MeshEdge +class SMDS_EXPORT SMDS_QuadraticEdge: public SMDS_LinearEdge { public: @@ -47,14 +48,14 @@ public: int NbNodes() const; + virtual SMDSAbs_EntityType GetEntityType() const { return SMDSEntity_Quad_Edge; } + virtual bool IsQuadratic() const { return true; } virtual bool IsMediumNode(const SMDS_MeshNode* node) const; SMDS_NodeIteratorPtr interlacedNodesIterator() const; - SMDS_ElemIteratorPtr interlacedNodesElemIterator() const; - protected: SMDS_ElemIteratorPtr elementsIterator(SMDSAbs_ElementType type) const; diff --git a/src/3rdParty/salomesmesh/inc/SMDS_QuadraticFaceOfNodes.hxx b/src/3rdParty/salomesmesh/inc/SMDS_QuadraticFaceOfNodes.hxx index 58c709f2255a..0a82c7f36166 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_QuadraticFaceOfNodes.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_QuadraticFaceOfNodes.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_QuadraticVolumeOfNodes.hxx // Module : SMESH @@ -49,6 +50,7 @@ public: const SMDS_MeshNode * n34, const SMDS_MeshNode * n41); + virtual SMDSAbs_EntityType GetEntityType() const; virtual bool IsQuadratic() const { return true; } virtual bool IsMediumNode(const SMDS_MeshNode* node) const; @@ -64,8 +66,6 @@ public: SMDS_NodeIteratorPtr interlacedNodesIterator() const; - SMDS_ElemIteratorPtr interlacedNodesElemIterator() const; - /*! * \brief Return node by its index * \param ind - node index diff --git a/src/3rdParty/salomesmesh/inc/SMDS_QuadraticVolumeOfNodes.hxx b/src/3rdParty/salomesmesh/inc/SMDS_QuadraticVolumeOfNodes.hxx index 3a004f4481f0..ae7b9aa09185 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_QuadraticVolumeOfNodes.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_QuadraticVolumeOfNodes.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_QuadraticVolumeOfNodes.hxx // Module : SMESH @@ -99,6 +100,7 @@ public: const SMDS_MeshNode * n37, const SMDS_MeshNode * n48); + virtual SMDSAbs_EntityType GetEntityType() const; virtual bool IsQuadratic() const { return true; } virtual bool IsMediumNode(const SMDS_MeshNode* node) const; diff --git a/src/3rdParty/salomesmesh/inc/SMDS_SetIterator.hxx b/src/3rdParty/salomesmesh/inc/SMDS_SetIterator.hxx index e76ea8ce5699..b604abc776e2 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_SetIterator.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_SetIterator.hxx @@ -1,27 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_SetIterator.hxx -// Created : Mon Feb 27 16:57:43 2006 +// Created : Feb 27 2006 // Author : Edward AGAPOV (eap) // #ifndef SMDS_SetIterator_HeaderFile @@ -29,12 +30,12 @@ #include "SMDS_Iterator.hxx" -/////////////////////////////////////////////////////////////////////////////// -/// Accessors to value pointed by iterator -/////////////////////////////////////////////////////////////////////////////// - namespace SMDS { + /////////////////////////////////////////////////////////////////////////////// + /// Accessors to value pointed by iterator + /////////////////////////////////////////////////////////////////////////////// + template struct SimpleAccessor { static VALUE value(VALUE_SET_ITERATOR it) { return (VALUE) *it; } @@ -49,6 +50,22 @@ namespace SMDS { struct ValueAccessor { static VALUE value(VALUE_SET_ITERATOR it) { return (VALUE) it->second; } }; + + /////////////////////////////////////////////////////////////////////////////// + /// Filters of value pointed by iterator + /////////////////////////////////////////////////////////////////////////////// + + template + struct PassAllValueFilter + { + bool operator()(const VALUE& t ) { return true; } + }; + + template + struct NonNullFilter + { + bool operator()(const VALUE& t ) { return bool( t ); } + }; } /////////////////////////////////////////////////////////////////////////////// @@ -60,26 +77,43 @@ namespace SMDS { template > + typename ACCESOR=SMDS::SimpleAccessor, + typename VALUE_FILTER=SMDS::PassAllValueFilter > class SMDS_SetIterator : public SMDS_Iterator { protected: VALUE_SET_ITERATOR _beg, _end; + VALUE_FILTER _filter; public: SMDS_SetIterator(const VALUE_SET_ITERATOR & begin, - const VALUE_SET_ITERATOR & end) - { init ( begin, end ); } + const VALUE_SET_ITERATOR & end, + const VALUE_FILTER& filter=VALUE_FILTER()) + { init ( begin, end, filter ); } /// Initialization virtual void init(const VALUE_SET_ITERATOR & begin, - const VALUE_SET_ITERATOR & end) - { _beg = begin; _end = end; } - - /// Return true if and only if there are other object in this iterator - virtual bool more() { return _beg != _end; } - + const VALUE_SET_ITERATOR & end, + const VALUE_FILTER& filter=VALUE_FILTER()) + { + _beg = begin; + _end = end; + _filter = filter; + if ( more() && !_filter( ACCESOR::value( _beg ))) + next(); + } + /// Return true iff there are other object in this iterator + virtual bool more() + { + return _beg != _end; + } /// Return the current object and step to the next one - virtual VALUE next() { return ACCESOR::value( _beg++ ); } + virtual VALUE next() + { + VALUE ret = ACCESOR::value( _beg++ ); + while ( more() && !_filter( ACCESOR::value( _beg ))) + ++_beg; + return ret; + } }; /////////////////////////////////////////////////////////////////////////////// diff --git a/src/3rdParty/salomesmesh/inc/SMDS_SpacePosition.hxx b/src/3rdParty/salomesmesh/inc/SMDS_SpacePosition.hxx index f80f3210af37..31f64234429b 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_SpacePosition.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_SpacePosition.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_SpacePosition.hxx // Module : SMESH @@ -33,14 +34,12 @@ class SMDS_EXPORT SMDS_SpacePosition:public SMDS_Position { - public: - SMDS_SpacePosition(double x=0, double y=0, double z=0); - const virtual double * Coords() const; - virtual inline SMDS_TypeOfPosition GetTypeOfPosition() const; - inline void SetCoords(const double x, const double y, const double z); - static SMDS_PositionPtr originSpacePosition(); - private: - double myCoords[3]; +public: + SMDS_SpacePosition(double x=0, double y=0, double z=0); + virtual inline SMDS_TypeOfPosition GetTypeOfPosition() const; + static SMDS_PositionPtr originSpacePosition(); +private: + static SMDS_SpacePosition* _originPosition; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_StdIterator.hxx b/src/3rdParty/salomesmesh/inc/SMDS_StdIterator.hxx new file mode 100644 index 000000000000..034b61983113 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMDS_StdIterator.hxx @@ -0,0 +1,80 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMDS : implementaion of Salome mesh data structure +// File : SMDS_StdIterator.hxx +// Created : Fri Feb 5 11:03:46 2010 +// Author : Edward AGAPOV (eap) +// +#ifndef __SMDS_StdIterator_HXX__ +#define __SMDS_StdIterator_HXX__ + + +/////////////////////////////////////////////////////////////////////////////// +/*! + * \brief Wrapper over pointer to SMDS_Iterator, like SMDS_ElemIteratorPtr, enabling + * its usage in std-like way: provide operators ++, *, etc. + */ +/////////////////////////////////////////////////////////////////////////////// + +template > +class SMDS_StdIterator : public std::iterator< std::input_iterator_tag, VALUE > +{ + VALUE _value; + PtrSMDSIterator _piterator; + EqualVALUE _EqualVALUE; + +public: + typedef SMDS_StdIterator _Self; + + // constructor to use as return from begin() + SMDS_StdIterator( PtrSMDSIterator pItr ) + : _value( pItr->more() ? (VALUE)(pItr->next()) : 0 ), _piterator(pItr) + {} + // constructor to use as return from end() + SMDS_StdIterator(): _value( 0 ) + {} + + /// Return the current object + VALUE operator*() const + { return _value; } + + // Step to the next one + _Self& + operator++() + { _value = _piterator->more() ? VALUE( _piterator->next()) : 0; return *this; } + + // Step to the next one + _Self + operator++(int) + { _Self res = *this; _value = _piterator->more() ? VALUE( _piterator->next()) : 0; return res; } + + // Test of end + bool + operator!=(const _Self& __x) const + { return !_EqualVALUE( _value, __x._value); } + + // Test of equality + bool + operator==(const _Self& __x) const + { return _EqualVALUE( _value, __x._value); } + +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_TypeOfPosition.hxx b/src/3rdParty/salomesmesh/inc/SMDS_TypeOfPosition.hxx index da5b39c48eab..49807b3a9f5a 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_TypeOfPosition.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_TypeOfPosition.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_TypeOfPosition.hxx // Module : SMESH @@ -28,11 +29,11 @@ enum SMDS_TypeOfPosition // Value is equal to shape dimention { - SMDS_TOP_UNSPEC = -1, - SMDS_TOP_VERTEX = 0, - SMDS_TOP_EDGE = 1, - SMDS_TOP_FACE = 2, - SMDS_TOP_3DSPACE = 3 + SMDS_TOP_UNSPEC = -1, + SMDS_TOP_VERTEX = 0, + SMDS_TOP_EDGE = 1, + SMDS_TOP_FACE = 2, + SMDS_TOP_3DSPACE = 3 }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_UnstructuredGrid.hxx b/src/3rdParty/salomesmesh/inc/SMDS_UnstructuredGrid.hxx new file mode 100644 index 000000000000..e5ce97512a00 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMDS_UnstructuredGrid.hxx @@ -0,0 +1,125 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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: SMDS_UnstructuredGrid.hxx +// Author: prascle +// Created: September 16, 2009, 10:28 PM + +#ifndef _SMDS_UNSTRUCTUREDGRID_HXX +#define _SMDS_UNSTRUCTUREDGRID_HXX + +#include "SMESH_SMDS.hxx" + +#include +#include + +#include +#include +#include + +//#define VTK_HAVE_POLYHEDRON +//#ifdef VTK_HAVE_POLYHEDRON +#define VTK_MAXTYPE VTK_POLYHEDRON +//#else +// #define VTK_MAXTYPE VTK_QUADRATIC_PYRAMID +//#endif + +#define NBMAXNEIGHBORS 100 + +// allow very huge polyhedrons in tests +#define NBMAXNODESINCELL 5000 + +class SMDS_Downward; +class SMDS_Mesh; +class SMDS_MeshCell; +class SMDS_MeshVolume; + +class SMDS_EXPORT SMDS_CellLinks: public vtkCellLinks +{ +public: + void ResizeForPoint(vtkIdType vtkID); + static SMDS_CellLinks* New(); +protected: + SMDS_CellLinks(); + ~SMDS_CellLinks(); +}; + +class SMDS_EXPORT SMDS_UnstructuredGrid: public vtkUnstructuredGrid +{ +public: + void setSMDS_mesh(SMDS_Mesh *mesh); + void compactGrid(std::vector& idNodesOldToNew, + int newNodeSize, + std::vector& idCellsOldToNew, + int newCellSize); + virtual unsigned long GetMTime(); + // OUV_PORTING_VTK6: seems to be useless + //virtual void Update(); + //virtual void UpdateInformation(); + virtual vtkPoints *GetPoints(); + + //#ifdef VTK_HAVE_POLYHEDRON + int InsertNextLinkedCell(int type, int npts, vtkIdType *pts); + //#endif + + int CellIdToDownId(int vtkCellId); + void setCellIdToDownId(int vtkCellId, int downId); + void CleanDownwardConnectivity(); + void BuildDownwardConnectivity(bool withEdges); + int GetNeighbors(int* neighborsVtkIds, int* downIds, unsigned char* downTypes, int vtkId, bool getSkin=false); + int GetParentVolumes(int* volVtkIds, int vtkId); + int GetParentVolumes(int* volVtkIds, int downId, unsigned char downType); + void GetNodeIds(std::set& nodeSet, int downId, unsigned char downType); + void ModifyCellNodes(int vtkVolId, std::map localClonedNodeIds); + int getOrderedNodesOfFace(int vtkVolId, int& dim, std::vector& orderedNodes); + void BuildLinks(); + SMDS_MeshCell* extrudeVolumeFromFace(int vtkVolId, int domain1, int domain2, + std::set& originalNodes, + std::map >& nodeDomains, + std::map >& nodeQuadDomains); + vtkCellLinks* GetLinks() + { + return Links; + } + SMDS_Downward* getDownArray(unsigned char vtkType) + { + return _downArray[vtkType]; + } + void AllocateDiameters( vtkIdType maxVtkID ); + void SetBallDiameter( vtkIdType vtkID, double diameter ); + double GetBallDiameter( vtkIdType vtkID ) const; + + static SMDS_UnstructuredGrid* New(); + SMDS_Mesh *_mesh; + +protected: + SMDS_UnstructuredGrid(); + ~SMDS_UnstructuredGrid(); + void copyNodes(vtkPoints *newPoints, std::vector& idNodesOldToNew, int& alreadyCopied, int start, int end); + void copyBloc(vtkUnsignedCharArray *newTypes, std::vector& idCellsOldToNew, std::vector& idNodesOldToNew, + vtkCellArray* newConnectivity, vtkIdTypeArray* newLocations, vtkIdType* pointsCell, int& alreadyCopied, + int start, int end); + + std::vector _cellIdToDownId; //!< convert vtk Id to downward[vtkType] id, initialized with -1 + std::vector _downTypes; + std::vector _downArray; +}; + +#endif /* _SMDS_UNSTRUCTUREDGRID_HXX */ + diff --git a/src/3rdParty/salomesmesh/inc/SMDS_VertexPosition.hxx b/src/3rdParty/salomesmesh/inc/SMDS_VertexPosition.hxx index dad7b5a13208..a42dee62bb6b 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_VertexPosition.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_VertexPosition.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_VertexPosition.hxx // Module : SMESH @@ -33,10 +34,9 @@ class SMDS_EXPORT SMDS_VertexPosition:public SMDS_Position { - public: - SMDS_TypeOfPosition GetTypeOfPosition() const; - SMDS_VertexPosition(int aVertexId=0); - const double *Coords() const; + public: + SMDS_TypeOfPosition GetTypeOfPosition() const; + SMDS_VertexPosition(); }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_VolumeOfFaces.hxx b/src/3rdParty/salomesmesh/inc/SMDS_VolumeOfFaces.hxx index 074fbec23d54..58d56168cf94 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_VolumeOfFaces.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_VolumeOfFaces.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_VolumeOfFaces.hxx // Module : SMESH @@ -36,32 +37,35 @@ class SMDS_EXPORT SMDS_VolumeOfFaces:public SMDS_MeshVolume { - + public: - SMDS_VolumeOfFaces(const SMDS_MeshFace * face1, + SMDS_VolumeOfFaces(const SMDS_MeshFace * face1, const SMDS_MeshFace * face2, const SMDS_MeshFace * face3, const SMDS_MeshFace * face4); - SMDS_VolumeOfFaces(const SMDS_MeshFace * face1, + SMDS_VolumeOfFaces(const SMDS_MeshFace * face1, const SMDS_MeshFace * face2, const SMDS_MeshFace * face3, const SMDS_MeshFace * face4, const SMDS_MeshFace * face5); - SMDS_VolumeOfFaces(const SMDS_MeshFace * face1, + SMDS_VolumeOfFaces(const SMDS_MeshFace * face1, const SMDS_MeshFace * face2, const SMDS_MeshFace * face3, const SMDS_MeshFace * face4, const SMDS_MeshFace * face5, const SMDS_MeshFace * face6); - void Print(std::ostream & OS) const; - - int NbFaces() const; + virtual SMDSAbs_EntityType GetEntityType() const; + virtual SMDSAbs_GeometryType GetGeomType() const; + virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], + const int nbNodes) {return false;} + virtual void Print(std::ostream & OS) const; + + virtual int NbFaces() const; protected: - SMDS_ElemIteratorPtr - elementsIterator(SMDSAbs_ElementType type) const; - const SMDS_MeshFace * myFaces[6]; - int myNbFaces; + virtual SMDS_ElemIteratorPtr elementsIterator(SMDSAbs_ElementType type) const; + const SMDS_MeshFace * myFaces[6]; + int myNbFaces; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_VolumeOfNodes.hxx b/src/3rdParty/salomesmesh/inc/SMDS_VolumeOfNodes.hxx index 7f35af2a4def..af79410fca5e 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_VolumeOfNodes.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_VolumeOfNodes.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshVolume.hxx // Module : SMESH @@ -32,44 +33,46 @@ class SMDS_EXPORT SMDS_VolumeOfNodes:public SMDS_MeshVolume { - + public: - SMDS_VolumeOfNodes( - const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2, - const SMDS_MeshNode * node3, - const SMDS_MeshNode * node4); - SMDS_VolumeOfNodes( - const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2, - const SMDS_MeshNode * node3, - const SMDS_MeshNode * node4, - const SMDS_MeshNode * node5); - SMDS_VolumeOfNodes( - const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2, - const SMDS_MeshNode * node3, - const SMDS_MeshNode * node4, - const SMDS_MeshNode * node5, - const SMDS_MeshNode * node6); - SMDS_VolumeOfNodes( - const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2, - const SMDS_MeshNode * node3, - const SMDS_MeshNode * node4, - const SMDS_MeshNode * node5, - const SMDS_MeshNode * node6, - const SMDS_MeshNode * node7, - const SMDS_MeshNode * node8); + SMDS_VolumeOfNodes( + const SMDS_MeshNode * node1, + const SMDS_MeshNode * node2, + const SMDS_MeshNode * node3, + const SMDS_MeshNode * node4); + SMDS_VolumeOfNodes( + const SMDS_MeshNode * node1, + const SMDS_MeshNode * node2, + const SMDS_MeshNode * node3, + const SMDS_MeshNode * node4, + const SMDS_MeshNode * node5); + SMDS_VolumeOfNodes( + const SMDS_MeshNode * node1, + const SMDS_MeshNode * node2, + const SMDS_MeshNode * node3, + const SMDS_MeshNode * node4, + const SMDS_MeshNode * node5, + const SMDS_MeshNode * node6); + SMDS_VolumeOfNodes( + const SMDS_MeshNode * node1, + const SMDS_MeshNode * node2, + const SMDS_MeshNode * node3, + const SMDS_MeshNode * node4, + const SMDS_MeshNode * node5, + const SMDS_MeshNode * node6, + const SMDS_MeshNode * node7, + const SMDS_MeshNode * node8); bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes); ~SMDS_VolumeOfNodes(); - void Print(std::ostream & OS) const; - int NbFaces() const; - int NbNodes() const; - int NbEdges() const; - SMDSAbs_ElementType GetType() const; + void Print(std::ostream & OS) const; + int NbFaces() const; + int NbNodes() const; + int NbEdges() const; + virtual SMDSAbs_ElementType GetType() const; + virtual SMDSAbs_EntityType GetEntityType() const; + virtual SMDSAbs_GeometryType GetGeomType() const; /*! * \brief Return node by its index @@ -79,9 +82,11 @@ class SMDS_EXPORT SMDS_VolumeOfNodes:public SMDS_MeshVolume virtual const SMDS_MeshNode* GetNode(const int ind) const; protected: - SMDS_ElemIteratorPtr - elementsIterator(SMDSAbs_ElementType type) const; - const SMDS_MeshNode** myNodes; - int myNbNodes; + SMDS_ElemIteratorPtr + elementsIterator(SMDSAbs_ElementType type) const; + const SMDS_MeshNode** myNodes; + int myNbNodes; + }; + #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_VolumeTool.hxx b/src/3rdParty/salomesmesh/inc/SMDS_VolumeTool.hxx index b95bc8a620f4..7e88f7c1a309 100644 --- a/src/3rdParty/salomesmesh/inc/SMDS_VolumeTool.hxx +++ b/src/3rdParty/salomesmesh/inc/SMDS_VolumeTool.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_VolumeTool.hxx // Module : SMESH @@ -32,11 +33,12 @@ class SMDS_MeshElement; class SMDS_MeshNode; -class SMDS_PolyhedralVolumeOfNodes; +class SMDS_VtkVolume; class SMDS_MeshVolume; #include #include +#include // ========================================================================= // @@ -50,23 +52,30 @@ class SMDS_EXPORT SMDS_VolumeTool { public: - enum VolumeType { UNKNOWN = -1, TETRA = 0, PYRAM, PENTA, HEXA, QUAD_TETRA, - QUAD_PYRAM, QUAD_PENTA, QUAD_HEXA, POLYHEDA }; + enum VolumeType { UNKNOWN = -1, TETRA = 0, PYRAM, PENTA, HEXA, + HEX_PRISM, QUAD_TETRA, QUAD_PYRAM, QUAD_PENTA, QUAD_HEXA, + POLYHEDA, NB_VOLUME_TYPES }; // to keep synchronised with GetSize()! SMDS_VolumeTool (); ~SMDS_VolumeTool (); - SMDS_VolumeTool (const SMDS_MeshElement* theVolume); + SMDS_VolumeTool (const SMDS_MeshElement* theVolume, + const bool ignoreCentralNodes=true); - bool Set (const SMDS_MeshElement* theVolume); + bool Set (const SMDS_MeshElement* theVolume, + const bool ignoreCentralNodes=true); // Set volume. - // Return false if theVolume is not of type SMDSAbs_Volume + // Return false if theVolume is not of type SMDSAbs_Volume. + // ignoreCentralNodes makes skip nodes at face centers when returning + // nodes of faces of SMDSEntity_TriQuad_Hexa - const SMDS_MeshVolume* Get() const; + const SMDS_MeshVolume* Element() const; // return element int ID() const; // return element ID + bool IsPoly() const { return myPolyedre; } + // ----------------------- // general info // ----------------------- @@ -82,10 +91,10 @@ class SMDS_EXPORT SMDS_VolumeTool // top and bottom faces are reversed. // Result of IsForward() and methods returning nodes change - const SMDS_MeshNode** GetNodes() { return myVolumeNodes; } + const SMDS_MeshNode** GetNodes() { return &myVolumeNodes[0]; } // Return array of volume nodes - int NbNodes() { return myVolumeNbNodes; } + int NbNodes() { return myVolumeNodes.size(); } // Return array of volume nodes double GetSize() const; @@ -93,19 +102,25 @@ class SMDS_EXPORT SMDS_VolumeTool bool GetBaryCenter (double & X, double & Y, double & Z) const; + bool IsOut(double X, double Y, double Z, double tol) const; + // Classify a point // ----------------------- // info on node connection // ----------------------- bool IsLinked (const SMDS_MeshNode* theNode1, - const SMDS_MeshNode* theNode2) const; + const SMDS_MeshNode* theNode2, + const bool theIgnoreMediumNodes=false) const; // Return true if theNode1 is linked with theNode2. + // If theIgnoreMediumNodes then corner nodes of quadratic cell are considered linked as well bool IsLinked (const int theNode1Index, - const int theNode2Index) const; + const int theNode2Index, + bool theIgnoreMediumNodes=false) const; // Return true if the node with theNode1Index is linked // with the node with theNode2Index + // If theIgnoreMediumNodes then corner nodes of quadratic cell are considered linked as well int GetNodeIndex(const SMDS_MeshNode* theNode) const; // Return an index of theNode @@ -113,9 +128,18 @@ class SMDS_EXPORT SMDS_VolumeTool int GetAllExistingEdges(std::vector & edges) const; // Fill vector with boundary edges existing in the mesh + double MinLinearSize2() const; + // Return minimal square distance between connected corner nodes + + double MaxLinearSize2() const; + // Return maximal square distance between connected corner nodes + // ------------- // info on faces // ------------- + // For all elements, 0-th face is bottom based on the first nodes. + // For prismatic elements (tetra,hexa,prisms), 1-th face is a top one. + // For all elements, side faces follow order of bottom nodes void SetExternalNormal (); // Node order in faces will be so that faces normals are external. @@ -124,44 +148,62 @@ class SMDS_EXPORT SMDS_VolumeTool // Return number of faces of the volume. In the following // methods 0 <= faceIndex < NbFaces() - int NbFaceNodes( int faceIndex ); + int NbFaceNodes( int faceIndex ) const; // Return number of nodes in the array of face nodes - const int* GetFaceNodesIndices( int faceIndex ); + const int* GetFaceNodesIndices( int faceIndex ) const; // Return the array of face nodes indices // To comfort link iteration, the array // length == NbFaceNodes( faceIndex ) + 1 and - // the last node index == the first one. + // the last node index == the first one, except for + // SMDSEntity_TriQuad_Hexa at ignoreCentralNodes==false. + // NOTE: for the quadratic volume, node indices are in the order the nodes encounter + // in face boundary and not the order they are in the mesh face - const SMDS_MeshNode** GetFaceNodes( int faceIndex ); + const SMDS_MeshNode** GetFaceNodes( int faceIndex ) const; // Return the array of face nodes. // To comfort link iteration, the array // length == NbFaceNodes( faceIndex ) + 1 and - // the last node == the first one. + // the last node == the first one, except for + // SMDSEntity_TriQuad_Hexa at ignoreCentralNodes==false. + // NOTE: for the quadratic volume, nodes are in the order they encounter in face boundary + // and not the order they are in the mesh face // WARNING: do not modify the array, some methods // work basing on its contents bool GetFaceNodes (int faceIndex, - std::set& theFaceNodes ); + std::set& theFaceNodes ) const; // Return a set of face nodes. - bool IsFaceExternal( int faceIndex ); + bool IsFaceExternal( int faceIndex ) const; // Check normal orientation of a face. // SetExternalNormal() is taken into account. - bool IsFreeFace( int faceIndex ); - // Check that all volumes built on the face nodes lays on one side + bool IsFreeFace( int faceIndex, const SMDS_MeshElement** otherVol=0 ) const; + // Fast check that only one volume is built on nodes of a given face + // otherVol returns another volume sharing the given facet + + bool IsFreeFaceAdv( int faceIndex, const SMDS_MeshElement** otherVol=0 ) const; + // Thorough check that all volumes built on the face nodes lays on one side + // otherVol returns another volume sharing the given facet - bool GetFaceNormal (int faceIndex, double & X, double & Y, double & Z); + bool GetFaceNormal (int faceIndex, double & X, double & Y, double & Z) const; // Return a normal to a face - double GetFaceArea( int faceIndex ); + bool GetFaceBaryCenter (int faceIndex, double & X, double & Y, double & Z) const; + // Return barycenter of a face + + double GetFaceArea( int faceIndex ) const; // Return face area int GetOppFaceIndex( int faceIndex ) const; // Return index of the opposite face if it exists, else -1. - int GetFaceIndex( const std::set& theFaceNodes ); + int GetCenterNodeIndex( int faceIndex ) const; + // Return index of the node located at face center of a quadratic element like HEX27 + + int GetFaceIndex( const std::set& theFaceNodes, + const int theFaceIndexHint=-1) const; // Return index of a face formed by theFaceNodes. // Return -1 if a face not found @@ -169,7 +211,7 @@ class SMDS_EXPORT SMDS_VolumeTool // Return index of a face formed by theFaceNodesIndices // Return -1 if a face not found - int GetAllExistingFaces(std::vector & faces); + int GetAllExistingFaces(std::vector & faces) const; // Fill vector with boundary faces existing in the mesh // ------------------------ @@ -189,32 +231,54 @@ class SMDS_EXPORT SMDS_VolumeTool // To comfort link iteration, the array // length == NbFaceNodes( faceIndex ) + 1 and // the last node index == the first one. + // Nodes at face centers of SMDSEntity_TriQuad_Hexa are ignored - static int NbFaceNodes(VolumeType type, - int faceIndex ); + static int NbFaceNodes(VolumeType type, int faceIndex ); // Return number of nodes in the array of face nodes + // Nodes at face centers of SMDSEntity_TriQuad_Hexa are ignored static int NbCornerNodes(VolumeType type); // Useful to know nb of corner nodes of a quadratic volume -private: + static int GetOppFaceIndexOfHex( int faceIndex ); + // Return index of the opposite face of the hexahedron + + private: - bool setFace( int faceIndex ); + bool setFace( int faceIndex ) const; + + bool projectNodesToNormal( int faceIndex, double& minProj, double& maxProj ) const; const SMDS_MeshElement* myVolume; - const SMDS_PolyhedralVolumeOfNodes* myPolyedre; + const SMDS_VtkVolume* myPolyedre; + bool myIgnoreCentralNodes; bool myVolForward; int myNbFaces; - int myVolumeNbNodes; - const SMDS_MeshNode** myVolumeNodes; - - bool myExternalFaces; - - int myCurFace; - int myFaceNbNodes; - int* myFaceNodeIndices; - const SMDS_MeshNode** myFaceNodes; + std::vector myVolumeNodes; + std::vector< int > myPolyIndices; // of a myCurFace + std::vector< int > myPolyQuantities; + std::vector< int > myPolyFacetOri; // -1-in, +1-out, 0-undef + + typedef std::pair Link; + std::map myFwdLinks; // used in IsFaceExternal() to find out myPolyFacetOri + + mutable bool myExternalFaces; + + mutable const int* myAllFacesNodeIndices_F; + mutable const int* myAllFacesNodeIndices_RE; + mutable const int* myAllFacesNbNodes; + mutable int myMaxFaceNbNodes; + + struct SaveFacet; + struct Facet + { + int myIndex; + int myNbNodes; + int* myNodeIndices; + std::vector myNodes; + }; + mutable Facet myCurFace; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_VtkCellIterator.hxx b/src/3rdParty/salomesmesh/inc/SMDS_VtkCellIterator.hxx new file mode 100644 index 000000000000..0ff0a6d637ad --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMDS_VtkCellIterator.hxx @@ -0,0 +1,74 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +#ifndef _SMDS_VTKCELLITERATOR_HXX_ +#define _SMDS_VTKCELLITERATOR_HXX_ + +#include "SMDS_ElemIterator.hxx" +#include "SMDS_Mesh.hxx" +#include "SMDSAbs_ElementType.hxx" + +#include +#include + +class SMDS_VtkCellIterator: public SMDS_ElemIterator +{ +public: + SMDS_VtkCellIterator(SMDS_Mesh* mesh, int vtkCellId, SMDSAbs_EntityType aType); + virtual ~SMDS_VtkCellIterator(); + virtual bool more(); + virtual const SMDS_MeshElement* next(); + inline void exchange(vtkIdType a, vtkIdType b) + { + vtkIdType t = _vtkIdList->GetId(a); + _vtkIdList->SetId(a, _vtkIdList->GetId(b)); + _vtkIdList->SetId(b, t); + } + +protected: + SMDS_VtkCellIterator() {}; + + SMDS_Mesh* _mesh; + int _cellId; + int _index; + int _nbNodes; + SMDSAbs_EntityType _type; + vtkIdList* _vtkIdList; +}; + +class SMDS_VtkCellIteratorToUNV: public SMDS_NodeIterator, protected SMDS_VtkCellIterator +{ +public: + SMDS_VtkCellIteratorToUNV(SMDS_Mesh* mesh, int vtkCellId, SMDSAbs_EntityType aType); + virtual const SMDS_MeshNode* next(); + virtual bool more(); + virtual ~SMDS_VtkCellIteratorToUNV(); +}; + +class SMDS_VtkCellIteratorPolyH: public SMDS_VtkCellIterator +{ +public: + SMDS_VtkCellIteratorPolyH(SMDS_Mesh* mesh, int vtkCellId, SMDSAbs_EntityType aType); + virtual ~SMDS_VtkCellIteratorPolyH(); + virtual bool more(); +protected: + int _nbNodesInFaces; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_VtkEdge.hxx b/src/3rdParty/salomesmesh/inc/SMDS_VtkEdge.hxx new file mode 100644 index 000000000000..c68812ad7371 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMDS_VtkEdge.hxx @@ -0,0 +1,59 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMDS : implementaion of Salome mesh data structure +// File : SMDS_VtkEdge.hxx +// Module : SMESH + +#ifndef _SMDS_VTKEDGE_HXX_ +#define _SMDS_VTKEDGE_HXX_ + +#include "SMESH_SMDS.hxx" + +#include "SMDS_MeshEdge.hxx" +#include +#include + +class SMDS_EXPORT SMDS_VtkEdge: public SMDS_MeshEdge +{ + +public: + SMDS_VtkEdge(); + SMDS_VtkEdge(std::vector& nodeIds, SMDS_Mesh* mesh); + ~SMDS_VtkEdge(); + void init(std::vector& nodeIds, SMDS_Mesh* mesh); + bool ChangeNodes(const SMDS_MeshNode * node1, const SMDS_MeshNode * node2); + virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes); + virtual bool IsMediumNode(const SMDS_MeshNode* node) const; + + virtual void Print(std::ostream & OS) const; + virtual int NbNodes() const; + virtual int NbEdges() const; + + virtual vtkIdType GetVtkType() const; + virtual SMDSAbs_EntityType GetEntityType() const; + virtual const SMDS_MeshNode* GetNode(const int ind) const; + virtual bool IsQuadratic() const; + + virtual SMDS_ElemIteratorPtr elementsIterator(SMDSAbs_ElementType type) const; + virtual SMDS_NodeIteratorPtr nodesIteratorToUNV() const; + virtual SMDS_NodeIteratorPtr interlacedNodesIterator() const; +protected: +}; +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_VtkFace.hxx b/src/3rdParty/salomesmesh/inc/SMDS_VtkFace.hxx new file mode 100644 index 000000000000..235a9c2d8046 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMDS_VtkFace.hxx @@ -0,0 +1,64 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +#ifndef _SMDS_VTKFACE_HXX_ +#define _SMDS_VTKFACE_HXX_ + +#include "SMESH_SMDS.hxx" + +#include "SMDS_MeshFace.hxx" +#include +#include + +class SMDS_EXPORT SMDS_VtkFace: public SMDS_MeshFace +{ +public: + SMDS_VtkFace(); + SMDS_VtkFace(const std::vector& nodeIds, SMDS_Mesh* mesh); + ~SMDS_VtkFace(); + void init(const std::vector& nodeIds, SMDS_Mesh* mesh); + void initPoly(const std::vector& nodeIds, SMDS_Mesh* mesh); + void initQuadPoly(const std::vector& nodeIds, SMDS_Mesh* mesh); + + bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes); + void ChangeApex(SMDS_MeshNode* node); // to use only for tmp triangles + + virtual void Print(std::ostream & OS) const; + virtual int NbEdges() const; + virtual int NbFaces() const; + virtual int NbNodes() const; + + virtual vtkIdType GetVtkType() const; + virtual SMDSAbs_EntityType GetEntityType() const; + virtual SMDSAbs_GeometryType GetGeomType() const; + virtual const SMDS_MeshNode* GetNode(const int ind) const; + virtual int GetNodeIndex( const SMDS_MeshNode* node ) const; + + virtual bool IsQuadratic() const; + virtual bool IsPoly() const; + virtual bool IsMediumNode(const SMDS_MeshNode* node) const; + virtual int NbCornerNodes() const; + + virtual SMDS_ElemIteratorPtr elementsIterator(SMDSAbs_ElementType type) const; + virtual SMDS_NodeIteratorPtr nodesIteratorToUNV() const; + virtual SMDS_NodeIteratorPtr interlacedNodesIterator() const; +protected: +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMDS_VtkVolume.hxx b/src/3rdParty/salomesmesh/inc/SMDS_VtkVolume.hxx new file mode 100644 index 000000000000..09d61fc5c1ae --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMDS_VtkVolume.hxx @@ -0,0 +1,80 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +#ifndef _SMDS_VTKVOLUME_HXX_ +#define _SMDS_VTKVOLUME_HXX_ + +#include "SMESH_SMDS.hxx" + +#include "SMDS_MeshVolume.hxx" +#include "SMDS_UnstructuredGrid.hxx" +#include + +class SMDS_EXPORT SMDS_VtkVolume: public SMDS_MeshVolume +{ +public: + SMDS_VtkVolume(); + SMDS_VtkVolume(const std::vector& nodeIds, SMDS_Mesh* mesh); + ~SMDS_VtkVolume(); + void init(const std::vector& nodeIds, SMDS_Mesh* mesh); +//#ifdef VTK_HAVE_POLYHEDRON + void initPoly(const std::vector& nodeIds, + const std::vector& nbNodesPerFace, SMDS_Mesh* mesh); +//#endif + virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes); + virtual bool vtkOrder(const SMDS_MeshNode* nodes[], const int nbNodes); + + virtual void Print(std::ostream & OS) const; + virtual int NbFaces() const; + virtual int NbNodes() const; + virtual int NbEdges() const; + + // 1 <= face_ind <= NbFaces() + int NbFaceNodes (const int face_ind) const; + // 1 <= face_ind <= NbFaces() + // 1 <= node_ind <= NbFaceNodes() + const SMDS_MeshNode* GetFaceNode (const int face_ind, const int node_ind) const; + + virtual SMDSAbs_ElementType GetType() const; + virtual vtkIdType GetVtkType() const; + virtual SMDSAbs_EntityType GetEntityType() const; + virtual SMDSAbs_GeometryType GetGeomType() const; + virtual const SMDS_MeshNode* GetNode(const int ind) const; + virtual int GetNodeIndex( const SMDS_MeshNode* node ) const; + virtual bool IsQuadratic() const; + virtual bool IsPoly() const; + virtual bool IsMediumNode(const SMDS_MeshNode* node) const; + virtual int NbCornerNodes() const; + static void gravityCenter(SMDS_UnstructuredGrid* grid, + const vtkIdType *nodeIds, + int nbNodes, + double* result); + static bool isForward(double* a,double* b,double* c,double* d); + int NbUniqueNodes() const; + SMDS_ElemIteratorPtr uniqueNodesIterator() const; + std::vector GetQuantities() const; + + virtual SMDS_ElemIteratorPtr elementsIterator(SMDSAbs_ElementType type) const; + virtual SMDS_NodeIteratorPtr nodesIteratorToUNV() const; + virtual SMDS_NodeIteratorPtr interlacedNodesIterator() const; + +protected: +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESHDS_Command.hxx b/src/3rdParty/salomesmesh/inc/SMESHDS_Command.hxx index 09d720b9acba..583cebe4a3a9 100644 --- a/src/3rdParty/salomesmesh/inc/SMESHDS_Command.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESHDS_Command.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESHDS_Command.hxx // Module : SMESH @@ -36,31 +37,42 @@ class SMESHDS_EXPORT SMESHDS_Command { public: - SMESHDS_Command(const SMESHDS_CommandType aType); - void AddNode(int NewNodeID, double x, double y, double z); - void AddEdge(int NewEdgeID, int idnode1, int idnode2); - void AddFace(int NewFaceID, int idnode1, int idnode2, int idnode3); - void AddFace(int NewFaceID, int idnode1, int idnode2, int idnode3, - int idnode4); - void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, - int idnode4); - void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, - int idnode4, int idnode5); - void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, - int idnode4, int idnode5, int idnode6); - void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, - int idnode4, int idnode5, int idnode6, int idnode7, int idnode8); - void AddPolygonalFace (const int ElementID, - std::vector nodes_ids); - void AddPolyhedralVolume (const int ElementID, - std::vector nodes_ids, - std::vector quantities); + SMESHDS_Command(const SMESHDS_CommandType aType); + void AddNode(int NewNodeID, double x, double y, double z); + void Add0DElement(int New0DElementID, int idnode); + void AddEdge(int NewEdgeID, int idnode1, int idnode2); + void AddFace(int NewFaceID, int idnode1, int idnode2, int idnode3); + void AddFace(int NewFaceID, int idnode1, int idnode2, int idnode3, + int idnode4); + void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, + int idnode4); + void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, + int idnode4, int idnode5); + void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, + int idnode4, int idnode5, int idnode6); + void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, + int idnode4, int idnode5, int idnode6, int idnode7, int idnode8); + void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, + int idnode4, int idnode5, int idnode6, int idnode7, int idnode8, + int idnode9, int idnode10, int idnode11, int idnode12); + void AddPolygonalFace (const int ElementID, + const std::vector& nodes_ids); + void AddQuadPolygonalFace (const int ElementID, + const std::vector& nodes_ids); + void AddPolyhedralVolume (const int ElementID, + const std::vector& nodes_ids, + const std::vector& quantities); + void AddBall(int NewBallID, int node, double diameter); // special methods for quadratic elements - void AddEdge(int NewEdgeID, int n1, int n2, int n12); + void AddEdge(int NewEdgeID, int n1, int n2, int n12); void AddFace(int NewFaceID, int n1, int n2, int n3, int n12, int n23, int n31); + void AddFace(int NewFaceID, int n1, int n2, int n3, + int n12, int n23, int n31, int nCenter); void AddFace(int NewFaceID, int n1, int n2, int n3, int n4, int n12, int n23, int n34, int n41); + void AddFace(int NewFaceID, int n1, int n2, int n3, int n4, + int n12, int n23, int n34, int n41, int nCenter); void AddVolume(int NewVolID, int n1, int n2, int n3, int n4, int n12, int n23, int n31, int n14, int n24, int n34); void AddVolume(int NewVolID, int n1, int n2, int n3, int n4, int n5, @@ -72,28 +84,35 @@ class SMESHDS_EXPORT SMESHDS_Command int n45, int n56, int n64, int n14, int n25, int n36); void AddVolume(int NewVolID, int n1, int n2, int n3, int n4, - int n5, int n6, int n7, int n8, + int n5, int n6, int n7, int n8, int n12, int n23, int n34, int n41, int n56, int n67, int n78, int n85, int n15, int n26, int n37, int n48); + void AddVolume(int NewVolID, int n1, int n2, int n3, int n4, + int n5, int n6, int n7, int n8, + int n12, int n23, int n34, int n41, + int n56, int n67, int n78, int n85, + int n15, int n26, int n37, int n48, + int n1234,int n1256,int n2367,int n3478, + int n1458,int n5678,int nCenter); - void MoveNode(int NewNodeID, double x, double y, double z); - void RemoveNode(int NodeID); - void RemoveElement(int ElementID); - void ChangeElementNodes(int ElementID, int nodes[], int nbnodes); - void ChangePolyhedronNodes(const int ElementID, - std::vector nodes_ids, - std::vector quantities); - void Renumber (const bool isNodes, const int startID, const int deltaID); - SMESHDS_CommandType GetType(); - int GetNumber(); - const std::list & GetIndexes(); - const std::list & GetCoords(); - ~SMESHDS_Command(); + void MoveNode(int NewNodeID, double x, double y, double z); + void RemoveNode(int NodeID); + void RemoveElement(int ElementID); + void ChangeElementNodes(int ElementID, int nodes[], int nbnodes); + void ChangePolyhedronNodes(const int ElementID, + const std::vector& nodes_ids, + const std::vector& quantities); + void Renumber (const bool isNodes, const int startID, const int deltaID); + SMESHDS_CommandType GetType(); + int GetNumber(); + const std::list & GetIndexes(); + const std::list & GetCoords(); + ~SMESHDS_Command(); private: - SMESHDS_CommandType myType; - int myNumber; - std::list myReals; - std::list myIntegers; + SMESHDS_CommandType myType; + int myNumber; + std::list myReals; + std::list myIntegers; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMESHDS_CommandType.hxx b/src/3rdParty/salomesmesh/inc/SMESHDS_CommandType.hxx index bafaba8632f0..c355386e54d9 100644 --- a/src/3rdParty/salomesmesh/inc/SMESHDS_CommandType.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESHDS_CommandType.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESHDS_CommandType.hxx // Module : SMESH @@ -26,8 +27,6 @@ #ifndef _SMESHDS_CommandType_HeaderFile #define _SMESHDS_CommandType_HeaderFile -//#include - enum SMESHDS_CommandType { SMESHDS_AddNode, SMESHDS_AddEdge, @@ -46,14 +45,22 @@ enum SMESHDS_CommandType { SMESHDS_ChangePolyhedronNodes, SMESHDS_Renumber, SMESHDS_ClearAll, - // special types for quadratic elements + // quadratic elements SMESHDS_AddQuadEdge, SMESHDS_AddQuadTriangle, SMESHDS_AddQuadQuadrangle, + SMESHDS_AddQuadPolygon, SMESHDS_AddQuadTetrahedron, SMESHDS_AddQuadPyramid, SMESHDS_AddQuadPentahedron, - SMESHDS_AddQuadHexahedron + SMESHDS_AddQuadHexahedron, + // + SMESHDS_Add0DElement, + SMESHDS_AddBiQuadTriangle, + SMESHDS_AddBiQuadQuadrangle, + SMESHDS_AddTriQuadHexa, + SMESHDS_AddHexagonalPrism, + SMESHDS_AddBall }; diff --git a/src/3rdParty/salomesmesh/inc/SMESHDS_DataMapOfShape.hxx b/src/3rdParty/salomesmesh/inc/SMESHDS_DataMapOfShape.hxx index ae748956484f..3e083cd84d78 100644 --- a/src/3rdParty/salomesmesh/inc/SMESHDS_DataMapOfShape.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESHDS_DataMapOfShape.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File: SMESHDS_DataMapOfShape.hxx // Created: 20.09.05 09:51:12 // Author: Alexander BORODIN @@ -31,13 +32,19 @@ /* * This method needed for instance NCollection_DataMap with TopoDS_Shape as key */ - -inline Standard_Boolean IsEqual(const TopoDS_Shape& S1, - const TopoDS_Shape& S2) +struct SMESHDS_Hasher { - return S1.IsSame(S2); -} - + static inline Standard_Boolean IsEqual(const TopoDS_Shape& S1, + const TopoDS_Shape& S2) + { + return S1.IsSame(S2); + } + static inline Standard_Integer HashCode(const TopoDS_Shape& S, + const Standard_Integer Upper) + { + return ::HashCode( S, Upper); + } +}; -#endif +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESHDS_Document.hxx b/src/3rdParty/salomesmesh/inc/SMESHDS_Document.hxx index 6abea04a4083..9143fb36489e 100644 --- a/src/3rdParty/salomesmesh/inc/SMESHDS_Document.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESHDS_Document.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESHDS_Document.hxx // Module : SMESH @@ -36,29 +37,29 @@ class SMESHDS_EXPORT SMESHDS_Document { public: - SMESHDS_Document(int UserID); - int NewMesh(bool theIsEmbeddedMode); - void RemoveMesh(int MeshID); - SMESHDS_Mesh * GetMesh(int MeshID); - void AddHypothesis(SMESHDS_Hypothesis * H); - void RemoveHypothesis(int HypID); - SMESHDS_Hypothesis * GetHypothesis(int HypID); - int NbMeshes(); - int NbHypothesis(); - void InitMeshesIterator(); - SMESHDS_Mesh * NextMesh(); - bool MoreMesh(); - void InitHypothesisIterator(); - SMESHDS_Hypothesis * NextHypothesis(); - bool MoreHypothesis(); - ~SMESHDS_Document(); + SMESHDS_Document(int UserID); + ~SMESHDS_Document(); + SMESHDS_Mesh * NewMesh(bool theIsEmbeddedMode, int MeshID); + void RemoveMesh(int MeshID); + SMESHDS_Mesh * GetMesh(int MeshID); + void AddHypothesis(SMESHDS_Hypothesis * H); + void RemoveHypothesis(int HypID); + SMESHDS_Hypothesis * GetHypothesis(int HypID); + int NbMeshes(); + int NbHypothesis(); + void InitMeshesIterator(); + SMESHDS_Mesh * NextMesh(); + bool MoreMesh(); + void InitHypothesisIterator(); + SMESHDS_Hypothesis * NextHypothesis(); + bool MoreHypothesis(); private: - int myUserID; - std::map myMeshes; - std::map myHypothesis; - std::map::iterator myMeshesIt; - std::map::iterator myHypothesisIt; + int myUserID; + std::map myMeshes; + std::map myHypothesis; + std::map::iterator myMeshesIt; + std::map::iterator myHypothesisIt; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMESHDS_Group.hxx b/src/3rdParty/salomesmesh/inc/SMESHDS_Group.hxx index 18fc37e4b624..ab03035a967d 100644 --- a/src/3rdParty/salomesmesh/inc/SMESHDS_Group.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESHDS_Group.hxx @@ -1,28 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESHDS_Group.hxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESHDS/SMESHDS_Group.hxx,v 1.7.2.1 2008/11/27 12:31:37 abd Exp $ +// $Header$ // #ifndef _SMESHDS_Group_HeaderFile #define _SMESHDS_Group_HeaderFile @@ -45,7 +46,7 @@ class SMESHDS_EXPORT SMESHDS_Group : public SMESHDS_GroupBase virtual void SetType(SMDSAbs_ElementType theType); - virtual int Extent(); + virtual int Extent() const; virtual bool IsEmpty(); @@ -53,10 +54,14 @@ class SMESHDS_EXPORT SMESHDS_Group : public SMESHDS_GroupBase virtual bool Contains (const SMDS_MeshElement* elem); - virtual SMDS_ElemIteratorPtr GetElements(); + virtual SMDS_ElemIteratorPtr GetElements() const; + + virtual int GetTic() const; bool Add (const int theID); + bool Add (const SMDS_MeshElement* theElem ); + bool Remove (const int theID); void Clear(); diff --git a/src/3rdParty/salomesmesh/inc/SMESHDS_GroupBase.hxx b/src/3rdParty/salomesmesh/inc/SMESHDS_GroupBase.hxx index b8a177319266..bb0bf250f413 100644 --- a/src/3rdParty/salomesmesh/inc/SMESHDS_GroupBase.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESHDS_GroupBase.hxx @@ -1,28 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESHDS_Group.hxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESHDS/SMESHDS_GroupBase.hxx,v 1.8.2.1 2008/11/27 12:31:37 abd Exp $ +// $Header$ // #ifndef _SMESHDS_GroupBase_HeaderFile #define _SMESHDS_GroupBase_HeaderFile @@ -57,7 +58,7 @@ class SMESHDS_EXPORT SMESHDS_GroupBase const char* GetStoreName () const { return myStoreName.c_str(); } - virtual int Extent(); + virtual int Extent() const; virtual bool IsEmpty(); @@ -65,11 +66,13 @@ class SMESHDS_EXPORT SMESHDS_GroupBase virtual bool Contains (const SMDS_MeshElement* elem); - virtual SMDS_ElemIteratorPtr GetElements() = 0; + virtual SMDS_ElemIteratorPtr GetElements() const = 0; - int GetID (const int theIndex); + virtual int GetID (const int theIndex); // use it for iterations 1..Extent() + virtual int GetTic() const = 0; + virtual ~SMESHDS_GroupBase() {} void SetColor (const Quantity_Color& theColor) @@ -82,6 +85,9 @@ class SMESHDS_EXPORT SMESHDS_GroupBase int GetColorGroup() const; + static void SetDefaultColor (const Quantity_Color& theColor) + { myDefaultColor = theColor;} + protected: const SMDS_MeshElement* findInMesh (const int theID) const; void resetIterator(); @@ -96,11 +102,14 @@ class SMESHDS_EXPORT SMESHDS_GroupBase const SMESHDS_Mesh* myMesh; SMDSAbs_ElementType myType; std::string myStoreName; + Quantity_Color myColor; + // for GetID() int myCurIndex; int myCurID; SMDS_ElemIteratorPtr myIterator; - Quantity_Color myColor; + + static Quantity_Color myDefaultColor; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMESHDS_GroupOnFilter.hxx b/src/3rdParty/salomesmesh/inc/SMESHDS_GroupOnFilter.hxx new file mode 100644 index 000000000000..c53f3bc8fae1 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMESHDS_GroupOnFilter.hxx @@ -0,0 +1,94 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SMESHDS_GroupOnFilter.hxx +// Module : SMESH +// +#ifndef _SMESHDS_GroupOnFilter_HeaderFile +#define _SMESHDS_GroupOnFilter_HeaderFile + +#include "SMESH_SMESHDS.hxx" + +#include "SMESHDS_GroupBase.hxx" +#include "SMESH_Controls.hxx" + +/*! + * \brief Groups whose contents is dynamically updated using the filter + */ +class SMESHDS_EXPORT SMESHDS_GroupOnFilter: public SMESHDS_GroupBase +{ + public: + + SMESHDS_GroupOnFilter (const int theID, + const SMESHDS_Mesh* theMesh, + const SMDSAbs_ElementType theType, + const SMESH_PredicatePtr& thePredicate); + + void SetPredicate( const SMESH_PredicatePtr& thePredicate); + + SMESH_PredicatePtr GetPredicate() const { return myPredicate; } + + std::vector< int > GetMeshInfo() const; + + template< typename IDTYPE > + int GetElementIds( IDTYPE* ids ) const + { + return getElementIds( (void*)ids, sizeof(IDTYPE)); + } + + + virtual int Extent() const; + + virtual bool IsEmpty(); + + virtual bool Contains (const int theID); + + virtual bool Contains (const SMDS_MeshElement* elem); + + virtual SMDS_ElemIteratorPtr GetElements() const; + + virtual int GetTic() const; + + bool IsUpToDate() const; + + private: + + void update() const; + void setChanged(bool changed=true); + const SMDS_MeshElement* setNbElemToSkip( SMDS_ElemIteratorPtr& elIt ); + int getElementIds( void* ids, size_t idSize ) const; + + // We use two ways of optimaization: + // 1) The case of little free memory. Remember nb of KO elements (myNbElemToSkip) + // to skip before the first OK element. As well remember total nb of OK + // elements (myMeshInfo) to stop iteration as all OK elements are found. + // 2) The case of enough free memory. Remember all OK elements (myElements). + + SMESH_PredicatePtr myPredicate; + std::vector< int > myMeshInfo; + std::vector< const SMDS_MeshElement*> myElements; + bool myElementsOK; + size_t myMeshModifTime; // when myMeshInfo was updated + int myPredicateTic; + size_t myNbElemToSkip; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESHDS_GroupOnGeom.hxx b/src/3rdParty/salomesmesh/inc/SMESHDS_GroupOnGeom.hxx index ed01df758b7c..42a567e17681 100644 --- a/src/3rdParty/salomesmesh/inc/SMESHDS_GroupOnGeom.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESHDS_GroupOnGeom.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESHDS_GroupOnGeom.hxx // Module : SMESH @@ -50,7 +51,9 @@ class SMESHDS_EXPORT SMESHDS_GroupOnGeom: public SMESHDS_GroupBase virtual bool Contains (const SMDS_MeshElement* elem); - virtual SMDS_ElemIteratorPtr GetElements(); + virtual SMDS_ElemIteratorPtr GetElements() const; + + virtual int GetTic() const; private: diff --git a/src/3rdParty/salomesmesh/inc/SMESHDS_Hypothesis.hxx b/src/3rdParty/salomesmesh/inc/SMESHDS_Hypothesis.hxx index 39583246744b..26a66c3a276b 100644 --- a/src/3rdParty/salomesmesh/inc/SMESHDS_Hypothesis.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESHDS_Hypothesis.hxx @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESHDS_Hypothesis.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESHDS/SMESHDS_Hypothesis.hxx,v 1.10.2.1 2008/11/27 12:31:37 abd Exp $ // #ifndef _SMESHDS_HYPOTHESIS_HXX_ #define _SMESHDS_HYPOTHESIS_HXX_ @@ -35,23 +35,27 @@ class SMESHDS_EXPORT SMESHDS_Hypothesis { -public: + public: SMESHDS_Hypothesis(int hypId); virtual ~SMESHDS_Hypothesis(); + enum hypothesis_type { PARAM_ALGO, ALGO_0D, ALGO_1D, ALGO_2D, ALGO_3D }; + const char* GetName() const; - int GetID() const; - int GetType() const; + int GetID() const; + int GetType() const; virtual std::ostream & SaveTo(std::ostream & save)=0; virtual std::istream & LoadFrom(std::istream & load)=0; -enum hypothesis_type {PARAM_ALGO, ALGO_0D, ALGO_1D, ALGO_2D, ALGO_3D}; + bool IsSameName( const SMESHDS_Hypothesis& other) const; + virtual bool operator==(const SMESHDS_Hypothesis& other) const; + bool operator!=(const SMESHDS_Hypothesis& other) const { return !(*this==other); } -protected: - std::string _name; - int _hypId; - int _type; + protected: + std::string _name; // identifier of hypothesis type + int _hypId; // ID unique within application session + hypothesis_type _type; // enum hypothesis_type }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMESHDS_Mesh.hxx b/src/3rdParty/salomesmesh/inc/SMESHDS_Mesh.hxx index 534c26cfaa9e..6ec2d3d9cabf 100644 --- a/src/3rdParty/salomesmesh/inc/SMESHDS_Mesh.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESHDS_Mesh.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESHDS_Mesh.hxx // Module : SMESH @@ -29,36 +30,47 @@ #include "SMESH_SMESHDS.hxx" #include "SMDS_Mesh.hxx" -#include "SMDS_MeshNode.hxx" -#include "SMDS_MeshEdge.hxx" -#include "SMDS_MeshFace.hxx" -#include "SMDS_MeshVolume.hxx" -#include "SMESHDS_Hypothesis.hxx" #include "SMESHDS_SubMesh.hxx" -#include "SMESHDS_Script.hxx" #include #include -#include -#include -#include -#include -#include -#include #include + +class TopoDS_Solid ; +class TopoDS_Shell ; +class TopoDS_Face ; +class TopoDS_Vertex; +class TopoDS_Edge ; + +class SMESHDS_Script; +class SMESHDS_Hypothesis; +class SMDS_MeshNode ; +class SMDS_MeshEdge ; +class SMDS_MeshFace ; +class SMDS_MeshVolume ; +class SMDS_Mesh0DElement; +class SMDS_BallElement; + /* - * Using of native haah_map isn't portable and don't work on WIN32 platform. + * Using of native hash_map isn't portable and don't work on WIN32 platform. * So this functionality implement on new NCollection_DataMap technology */ +#include #include "SMESHDS_DataMapOfShape.hxx" +typedef std::list THypList; +typedef NCollection_DataMap< TopoDS_Shape, THypList, SMESHDS_Hasher > ShapeToHypothesis; class SMESHDS_GroupBase; +class DownIdType; -class SMESHDS_EXPORT SMESHDS_Mesh:public SMDS_Mesh{ +class SMESHDS_EXPORT SMESHDS_Mesh : public SMDS_Mesh +{ public: SMESHDS_Mesh(int theMeshID, bool theIsEmbeddedMode); bool IsEmbeddedMode(); + void SetPersistentId(int id); + int GetPersistentId() const; void ShapeToMesh(const TopoDS_Shape & S); TopoDS_Shape ShapeToMesh() const; @@ -66,160 +78,238 @@ public: bool RemoveHypothesis(const TopoDS_Shape & S, const SMESHDS_Hypothesis * H); virtual SMDS_MeshNode* AddNodeWithID(double x, double y, double z, int ID); - virtual SMDS_MeshNode * AddNode(double x, double y, double z); + virtual SMDS_MeshNode* AddNode(double x, double y, double z); + virtual SMDS_Mesh0DElement* Add0DElementWithID(int nodeID, int ID); + virtual SMDS_Mesh0DElement* Add0DElementWithID(const SMDS_MeshNode * node, int ID); + virtual SMDS_Mesh0DElement* Add0DElement (const SMDS_MeshNode * node); + + virtual SMDS_BallElement* AddBallWithID(int n, double diameter, int ID); + virtual SMDS_BallElement* AddBallWithID(const SMDS_MeshNode * n, double diameter, int ID); + virtual SMDS_BallElement* AddBall (const SMDS_MeshNode * n, double diameter); + virtual SMDS_MeshEdge* AddEdgeWithID(int n1, int n2, int ID); virtual SMDS_MeshEdge* AddEdgeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - int ID); + const SMDS_MeshNode * n2, + int ID); virtual SMDS_MeshEdge* AddEdge(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2); + const SMDS_MeshNode * n2); // 2d order edge with 3 nodes: n12 - node between n1 and n2 virtual SMDS_MeshEdge* AddEdgeWithID(int n1, int n2, int n12, int ID); virtual SMDS_MeshEdge* AddEdgeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n12, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n12, + int ID); virtual SMDS_MeshEdge* AddEdge(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, const SMDS_MeshNode * n12); - + // tria 3 virtual SMDS_MeshFace* AddFaceWithID(int n1, int n2, int n3, int ID); virtual SMDS_MeshFace* AddFaceWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + int ID); virtual SMDS_MeshFace* AddFace(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3); - + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3); + // quad 4 virtual SMDS_MeshFace* AddFaceWithID(int n1, int n2, int n3, int n4, int ID); virtual SMDS_MeshFace* AddFaceWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + int ID); virtual SMDS_MeshFace* AddFace(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4); // 2d order triangle of 6 nodes virtual SMDS_MeshFace* AddFaceWithID(int n1, int n2, int n3, int n12,int n23,int n31, int ID); virtual SMDS_MeshFace* AddFaceWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31, + int ID); virtual SMDS_MeshFace* AddFace(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31); + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31); + + // biquadratic triangle of 7 nodes + virtual SMDS_MeshFace* AddFaceWithID(int n1, int n2, int n3, + int n12,int n23,int n31, int nCenter, int ID); + virtual SMDS_MeshFace* AddFaceWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31, + const SMDS_MeshNode * nCenter, + int ID); + virtual SMDS_MeshFace* AddFace(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31, + const SMDS_MeshNode * nCenter); // 2d order quadrangle virtual SMDS_MeshFace* AddFaceWithID(int n1, int n2, int n3, int n4, int n12,int n23,int n34,int n41, int ID); virtual SMDS_MeshFace* AddFaceWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + int ID); virtual SMDS_MeshFace* AddFace(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41); + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41); + // biquadratic quadrangle of 9 nodes + virtual SMDS_MeshFace* AddFaceWithID(int n1, int n2, int n3, int n4, + int n12,int n23,int n34,int n41, int nCenter, int ID); + virtual SMDS_MeshFace* AddFaceWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * nCenter, + int ID); + virtual SMDS_MeshFace* AddFace(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * nCenter); + // tetra 4 virtual SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4); - + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4); + // pyra 5 virtual SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5); - + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5); + // penta 6 virtual SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6); - + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6); + // hexa 8 virtual SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6, int n7, int n8, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8); - + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8); + // hexagonal prism of 12 nodes + virtual SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6, + int n7, int n8, int n9, int n10, int n11, int n12, int ID); + virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n9, + const SMDS_MeshNode * n10, + const SMDS_MeshNode * n11, + const SMDS_MeshNode * n12, + int ID); + virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n9, + const SMDS_MeshNode * n10, + const SMDS_MeshNode * n11, + const SMDS_MeshNode * n12); + // 2d order tetrahedron of 10 nodes virtual SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n12,int n23,int n31, int n14,int n24,int n34, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31, - const SMDS_MeshNode * n14, - const SMDS_MeshNode * n24, - const SMDS_MeshNode * n34, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31, + const SMDS_MeshNode * n14, + const SMDS_MeshNode * n24, + const SMDS_MeshNode * n34, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n31, @@ -233,24 +323,24 @@ public: int n15,int n25,int n35,int n45, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, - const SMDS_MeshNode * n15, - const SMDS_MeshNode * n25, - const SMDS_MeshNode * n35, - const SMDS_MeshNode * n45, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * n15, + const SMDS_MeshNode * n25, + const SMDS_MeshNode * n35, + const SMDS_MeshNode * n45, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, @@ -268,27 +358,27 @@ public: int n14,int n25,int n36, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31, - const SMDS_MeshNode * n45, - const SMDS_MeshNode * n56, - const SMDS_MeshNode * n64, - const SMDS_MeshNode * n14, - const SMDS_MeshNode * n25, - const SMDS_MeshNode * n36, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31, + const SMDS_MeshNode * n45, + const SMDS_MeshNode * n56, + const SMDS_MeshNode * n64, + const SMDS_MeshNode * n14, + const SMDS_MeshNode * n25, + const SMDS_MeshNode * n36, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n31, @@ -307,34 +397,34 @@ public: int n15,int n26,int n37,int n48, int ID); virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, - const SMDS_MeshNode * n12, - const SMDS_MeshNode * n23, - const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, - const SMDS_MeshNode * n56, - const SMDS_MeshNode * n67, - const SMDS_MeshNode * n78, - const SMDS_MeshNode * n85, - const SMDS_MeshNode * n15, - const SMDS_MeshNode * n26, - const SMDS_MeshNode * n37, - const SMDS_MeshNode * n48, - int ID); + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * n56, + const SMDS_MeshNode * n67, + const SMDS_MeshNode * n78, + const SMDS_MeshNode * n85, + const SMDS_MeshNode * n15, + const SMDS_MeshNode * n26, + const SMDS_MeshNode * n37, + const SMDS_MeshNode * n48, + int ID); virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, @@ -348,31 +438,104 @@ public: const SMDS_MeshNode * n37, const SMDS_MeshNode * n48); - virtual SMDS_MeshFace* AddPolygonalFaceWithID (std::vector nodes_ids, - const int ID); + // 2d order Hexahedrons with 27 nodes + virtual SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, + int n5, int n6, int n7, int n8, + int n12,int n23,int n34,int n41, + int n56,int n67,int n78,int n85, + int n15,int n26,int n37,int n48, + int n1234,int n1256,int n2367,int n3478, + int n1458,int n5678,int nCenter, + int ID); + virtual SMDS_MeshVolume* AddVolumeWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * n56, + const SMDS_MeshNode * n67, + const SMDS_MeshNode * n78, + const SMDS_MeshNode * n85, + const SMDS_MeshNode * n15, + const SMDS_MeshNode * n26, + const SMDS_MeshNode * n37, + const SMDS_MeshNode * n48, + const SMDS_MeshNode * n1234, + const SMDS_MeshNode * n1256, + const SMDS_MeshNode * n2367, + const SMDS_MeshNode * n3478, + const SMDS_MeshNode * n1458, + const SMDS_MeshNode * n5678, + const SMDS_MeshNode * nCenter, + int ID); + virtual SMDS_MeshVolume* AddVolume(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * n56, + const SMDS_MeshNode * n67, + const SMDS_MeshNode * n78, + const SMDS_MeshNode * n85, + const SMDS_MeshNode * n15, + const SMDS_MeshNode * n26, + const SMDS_MeshNode * n37, + const SMDS_MeshNode * n48, + const SMDS_MeshNode * n1234, + const SMDS_MeshNode * n1256, + const SMDS_MeshNode * n2367, + const SMDS_MeshNode * n3478, + const SMDS_MeshNode * n1458, + const SMDS_MeshNode * n5678, + const SMDS_MeshNode * nCenter); + + virtual SMDS_MeshFace* AddPolygonalFaceWithID (const std::vector& nodes_ids, + const int ID); - virtual SMDS_MeshFace* AddPolygonalFaceWithID (std::vector nodes, - const int ID); + virtual SMDS_MeshFace* AddPolygonalFaceWithID (const std::vector& nodes, + const int ID); - virtual SMDS_MeshFace* AddPolygonalFace (std::vector nodes); + virtual SMDS_MeshFace* AddPolygonalFace (const std::vector& nodes); + + virtual SMDS_MeshFace* AddQuadPolygonalFaceWithID(const std::vector & nodes_ids, + const int ID); + + virtual SMDS_MeshFace* AddQuadPolygonalFaceWithID(const std::vector & nodes, + const int ID); + + virtual SMDS_MeshFace* AddQuadPolygonalFace(const std::vector & nodes); virtual SMDS_MeshVolume* AddPolyhedralVolumeWithID - (std::vector nodes_ids, - std::vector quantities, - const int ID); + (const std::vector& nodes_ids, + const std::vector& quantities, + const int ID); virtual SMDS_MeshVolume* AddPolyhedralVolumeWithID - (std::vector nodes, - std::vector quantities, - const int ID); + (const std::vector& nodes, + const std::vector& quantities, + const int ID); virtual SMDS_MeshVolume* AddPolyhedralVolume - (std::vector nodes, - std::vector quantities); + (const std::vector& nodes, + const std::vector& quantities); - void MoveNode(const SMDS_MeshNode *, double x, double y, double z); + virtual void MoveNode(const SMDS_MeshNode *, double x, double y, double z); virtual void RemoveNode(const SMDS_MeshNode *); - virtual void RemoveElement(const SMDS_MeshElement *, bool removenodes = false); + void RemoveElement(const SMDS_MeshElement *); /*! Remove only the given element/node and only if it is free. * Methods do not work for meshes with descendants. @@ -380,7 +543,6 @@ public: */ void RemoveFreeNode (const SMDS_MeshNode *, SMESHDS_SubMesh *, bool fromGroups=true); void RemoveFreeElement(const SMDS_MeshElement *, SMESHDS_SubMesh *, bool fromGroups=true); - virtual void RemoveFreeElement(const SMDS_MeshElement *); ///< reimplement virtual from the base class void ClearMesh(); @@ -392,41 +554,45 @@ public: bool ChangePolyhedronNodes(const SMDS_MeshElement * elem, std::vector nodes, std::vector quantities); + bool ModifyCellNodes(int smdsVolId, std::map localClonedNodeIds); void Renumber (const bool isNodes, const int startID=1, const int deltaID=1); - void SetNodeInVolume(SMDS_MeshNode * aNode, const TopoDS_Shell & S); - void SetNodeInVolume(SMDS_MeshNode * aNode, const TopoDS_Solid & S); - void SetNodeOnFace(SMDS_MeshNode * aNode, const TopoDS_Face & S, double u=0., double v=0.); - void SetNodeOnEdge(SMDS_MeshNode * aNode, const TopoDS_Edge & S, double u=0.); - void SetNodeOnVertex(SMDS_MeshNode * aNode, const TopoDS_Vertex & S); + void SetNodeInVolume(const SMDS_MeshNode * aNode, const TopoDS_Shell & S); + void SetNodeInVolume(const SMDS_MeshNode * aNode, const TopoDS_Solid & S); + void SetNodeOnFace (const SMDS_MeshNode * aNode, const TopoDS_Face& S, double u=0.,double v=0.); + void SetNodeOnEdge (const SMDS_MeshNode * aNode, const TopoDS_Edge& S, double u=0.); + void SetNodeOnVertex(const SMDS_MeshNode * aNode, const TopoDS_Vertex & S); void UnSetNodeOnShape(const SMDS_MeshNode * aNode); - void SetMeshElementOnShape(const SMDS_MeshElement * anElt, - const TopoDS_Shape & S); - void UnSetMeshElementOnShape(const SMDS_MeshElement * anElt, - const TopoDS_Shape & S); - bool HasMeshElements(const TopoDS_Shape & S); + void SetMeshElementOnShape (const SMDS_MeshElement * anElt, const TopoDS_Shape & S); + void UnSetMeshElementOnShape(const SMDS_MeshElement * anElt, const TopoDS_Shape & S); + void SetNodeInVolume(const SMDS_MeshNode * aNode, int Index); + void SetNodeOnFace (const SMDS_MeshNode * aNode, int Index, double u=0., double v=0.); + void SetNodeOnEdge (const SMDS_MeshNode * aNode, int Index, double u=0.); + void SetNodeOnVertex(const SMDS_MeshNode * aNode, int Index); + void SetMeshElementOnShape(const SMDS_MeshElement * anElt, int Index); + bool HasMeshElements(const TopoDS_Shape & S) const; SMESHDS_SubMesh * MeshElements(const TopoDS_Shape & S) const; - SMESHDS_SubMesh * MeshElements(const int Index); - std::list SubMeshIndices(); - const std::map& SubMeshes() const - { return myShapeIndexToSubMesh; } + SMESHDS_SubMesh * MeshElements(const int Index) const; + std::list SubMeshIndices() const; + SMESHDS_SubMeshIteratorPtr SubMeshes() const; bool HasHypothesis(const TopoDS_Shape & S); const std::list& GetHypothesis(const TopoDS_Shape & S) const; + bool IsUsedHypothesis(const SMESHDS_Hypothesis * H) const; + const ShapeToHypothesis & GetHypotheses() const { return myShapeToHypothesis; } + SMESHDS_Script * GetScript(); void ClearScript(); + int ShapeToIndex(const TopoDS_Shape & aShape) const; const TopoDS_Shape& IndexToShape(int ShapeIndex) const; int MaxShapeIndex() const { return myIndexToShape.Extent(); } + int MaxSubMeshIndex() const; SMESHDS_SubMesh * NewSubMesh(int Index); int AddCompoundSubmesh(const TopoDS_Shape& S, TopAbs_ShapeEnum type = TopAbs_SHAPE); - void SetNodeInVolume(const SMDS_MeshNode * aNode, int Index); - void SetNodeOnFace(SMDS_MeshNode * aNode, int Index , double u=0., double v=0.); - void SetNodeOnEdge(SMDS_MeshNode * aNode, int Index , double u=0.); - void SetNodeOnVertex(SMDS_MeshNode * aNode, int Index); - void SetMeshElementOnShape(const SMDS_MeshElement * anElt, int Index); + // Groups. SMESHDS_Mesh is not an owner of groups void AddGroup (SMESHDS_GroupBase* theGroup) { myGroups.insert(theGroup); } void RemoveGroup (SMESHDS_GroupBase* theGroup) { myGroups.erase(theGroup); } int GetNbGroups() const { return myGroups.size(); } @@ -434,34 +600,21 @@ public: bool IsGroupOfSubShapes (const TopoDS_Shape& aSubShape) const; + virtual void compactMesh(); + void CleanDownWardConnectivity(); + void BuildDownWardConnectivity(bool withEdges); + ~SMESHDS_Mesh(); private: - void addNodeToSubmesh( const SMDS_MeshNode* aNode, int Index ) - { - //Update or build submesh - std::map::iterator it = myShapeIndexToSubMesh.find( Index ); - if ( it == myShapeIndexToSubMesh.end() ) - it = myShapeIndexToSubMesh.insert( std::make_pair(Index, new SMESHDS_SubMesh() )).first; - it->second->AddNode( aNode ); // add aNode to submesh - } - - /*int HashCode( const TopoDS_Shape& S, const Standard_Integer theUpper ) const - { - return S.HashCode(2147483647); - }*/ - - typedef std::list THypList; - - typedef NCollection_DataMap< TopoDS_Shape, THypList > ShapeToHypothesis; ShapeToHypothesis myShapeToHypothesis; - int myMeshID; + int myMeshID, myPersistentID; TopoDS_Shape myShape; - typedef std::map TShapeIndexToSubMesh; - TShapeIndexToSubMesh myShapeIndexToSubMesh; + class SubMeshHolder; + SubMeshHolder* mySubMeshHolder; TopTools_IndexedMapOfShape myIndexToShape; @@ -471,14 +624,8 @@ private: SMESHDS_Script* myScript; bool myIsEmbeddedMode; - // optimize addition of nodes/elements to submeshes by, SetNodeInVolume() etc: - // avoid search of submeshes in maps bool add( const SMDS_MeshElement* elem, SMESHDS_SubMesh* subMesh ); SMESHDS_SubMesh* getSubmesh( const TopoDS_Shape & shape); - SMESHDS_SubMesh* getSubmesh( const int Index ); - int myCurSubID; - TopoDS_Shape myCurSubShape; - SMESHDS_SubMesh* myCurSubMesh; }; diff --git a/src/3rdParty/salomesmesh/inc/SMESHDS_Script.hxx b/src/3rdParty/salomesmesh/inc/SMESHDS_Script.hxx index 808066bc3e8f..3401ca6acd5c 100644 --- a/src/3rdParty/salomesmesh/inc/SMESHDS_Script.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESHDS_Script.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESHDS_Script.hxx // Module : SMESH @@ -37,38 +38,49 @@ class SMESHDS_EXPORT SMESHDS_Script { public: - SMESHDS_Script(bool theIsEmbeddedMode); - ~SMESHDS_Script(); + SMESHDS_Script(bool theIsEmbeddedMode); + ~SMESHDS_Script(); void SetModified(bool theModified); bool IsModified(); - void AddNode(int NewNodeID, double x, double y, double z); - void AddEdge(int NewEdgeID, int idnode1, int idnode2); - void AddFace(int NewFaceID, int idnode1, int idnode2, int idnode3); - void AddFace(int NewFaceID, int idnode1, int idnode2, int idnode3, - int idnode4); - void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, - int idnode4); - void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, - int idnode4, int idnode5); - void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, - int idnode4, int idnode5, int idnode6); - void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, - int idnode4, int idnode5, int idnode6, int idnode7, int idnode8); + void AddNode(int NewNodeID, double x, double y, double z); + void Add0DElement(int New0DElementID, int idnode); + void AddEdge(int NewEdgeID, int idnode1, int idnode2); + void AddFace(int NewFaceID, int idnode1, int idnode2, int idnode3); + void AddFace(int NewFaceID, int idnode1, int idnode2, int idnode3, + int idnode4); + void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, + int idnode4); + void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, + int idnode4, int idnode5); + void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, + int idnode4, int idnode5, int idnode6); + void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, + int idnode4, int idnode5, int idnode6, int idnode7, int idnode8); + void AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, + int idnode4, int idnode5, int idnode6, int idnode7, int idnode8, + int idnode9, int idnode10, int idnode11, int idnode12); - void AddPolygonalFace (const int NewFaceID, - std::vector nodes_ids); - void AddPolyhedralVolume (const int NewVolID, - std::vector nodes_ids, - std::vector quantities); + void AddPolygonalFace (const int NewFaceID, + const std::vector& nodes_ids); + void AddQuadPolygonalFace (const int NewFaceID, + const std::vector& nodes_ids); + void AddPolyhedralVolume (const int NewVolID, + const std::vector& nodes_ids, + const std::vector& quantities); + void AddBall(int NewBallID, int node, double diameter); // special methods for quadratic elements - void AddEdge(int NewEdgeID, int n1, int n2, int n12); + void AddEdge(int NewEdgeID, int n1, int n2, int n12); void AddFace(int NewFaceID, int n1, int n2, int n3, int n12, int n23, int n31); + void AddFace(int NewFaceID, int n1, int n2, int n3, + int n12, int n23, int n31, int nCenter); void AddFace(int NewFaceID, int n1, int n2, int n3, int n4, int n12, int n23, int n34, int n41); + void AddFace(int NewFaceID, int n1, int n2, int n3, int n4, + int n12, int n23, int n34, int n41, int nCenter); void AddVolume(int NewVolID, int n1, int n2, int n3, int n4, int n12, int n23, int n31, int n14, int n24, int n34); void AddVolume(int NewVolID, int n1, int n2, int n3, int n4, int n5, @@ -84,22 +96,29 @@ class SMESHDS_EXPORT SMESHDS_Script int n12, int n23, int n34, int n41, int n56, int n67, int n78, int n85, int n15, int n26, int n37, int n48); + void AddVolume(int NewVolID, int n1, int n2, int n3, int n4, + int n5, int n6, int n7, int n8, + int n12, int n23, int n34, int n41, + int n56, int n67, int n78, int n85, + int n15, int n26, int n37, int n48, + int n1234,int n1256,int n2367,int n3478, + int n1458,int n5678,int nCenter); void MoveNode(int NewNodeID, double x, double y, double z); - void RemoveNode(int NodeID); - void RemoveElement(int ElementID); - void ChangeElementNodes(int ElementID, int nodes[], int nbnodes); - void ChangePolyhedronNodes(const int ElementID, - std::vector nodes_ids, - std::vector quantities); - void Renumber (const bool isNodes, const int startID, const int deltaID); - void ClearMesh(); - void Clear(); - const std::list & GetCommands(); + void RemoveNode(int NodeID); + void RemoveElement(int ElementID); + void ChangeElementNodes(int ElementID, int nodes[], int nbnodes); + void ChangePolyhedronNodes(const int ElementID, + const std::vector& nodes_ids, + const std::vector& quantities); + void Renumber (const bool isNodes, const int startID, const int deltaID); + void ClearMesh(); + void Clear(); + const std::list & GetCommands(); private: - SMESHDS_Command* getCommand(const SMESHDS_CommandType aType); + SMESHDS_Command* getCommand(const SMESHDS_CommandType aType); - std::list myCommands; + std::list myCommands; bool myIsEmbeddedMode; bool myIsModified; diff --git a/src/3rdParty/salomesmesh/inc/SMESHDS_SubMesh.hxx b/src/3rdParty/salomesmesh/inc/SMESHDS_SubMesh.hxx index 0b18640f68e9..58266c0bf130 100644 --- a/src/3rdParty/salomesmesh/inc/SMESHDS_SubMesh.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESHDS_SubMesh.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESHDS_SubMesh.hxx // Module : SMESH @@ -30,44 +31,62 @@ #include "SMDS_Mesh.hxx" #include +#include class SMESHDS_SubMesh; typedef SMDS_Iterator SMESHDS_SubMeshIterator; typedef boost::shared_ptr< SMESHDS_SubMeshIterator > SMESHDS_SubMeshIteratorPtr; +class SMESHDS_Mesh; + class SMESHDS_EXPORT SMESHDS_SubMesh { public: + SMESHDS_SubMesh(SMESHDS_Mesh *parent, int index); + virtual ~SMESHDS_SubMesh(); - bool IsComplexSubmesh() const { return !mySubMeshes.empty(); } + virtual bool IsComplexSubmesh() const { return !mySubMeshes.empty(); } // if !IsComplexSubmesh() - void AddElement(const SMDS_MeshElement * ME); - bool RemoveElement(const SMDS_MeshElement * ME, bool isElemDeleted); // ret true if ME was in - void AddNode(const SMDS_MeshNode * ME); - bool RemoveNode(const SMDS_MeshNode * ME, bool isNodeDeleted); // ret true if ME was in + virtual void AddElement(const SMDS_MeshElement * ME); + virtual bool RemoveElement(const SMDS_MeshElement * ME, bool isElemDeleted); // ret true if ME was in + virtual void AddNode(const SMDS_MeshNode * ME); + virtual bool RemoveNode(const SMDS_MeshNode * ME, bool isNodeDeleted); // ret true if ME was in + virtual const SMDS_MeshElement* GetElement( size_t idInShape ) const; + virtual const SMDS_MeshNode* GetNode ( size_t idInShape ) const; // if IsComplexSubmesh() void AddSubMesh( const SMESHDS_SubMesh* theSubMesh ); bool RemoveSubMesh( const SMESHDS_SubMesh* theSubMesh ); + void RemoveAllSubmeshes(); bool ContainsSubMesh( const SMESHDS_SubMesh* theSubMesh ) const; int NbSubMeshes() const { return mySubMeshes.size(); } SMESHDS_SubMeshIteratorPtr GetSubMeshIterator() const; // for both types - int NbElements() const; - SMDS_ElemIteratorPtr GetElements() const; - int NbNodes() const; - SMDS_NodeIteratorPtr GetNodes() const; - bool Contains(const SMDS_MeshElement * ME) const; // check if elem or node is in + virtual int NbElements() const; + virtual SMDS_ElemIteratorPtr GetElements() const; + virtual int NbNodes() const; + virtual SMDS_NodeIteratorPtr GetNodes() const; + virtual bool Contains(const SMDS_MeshElement * ME) const; // check if elem or node is in + virtual bool IsQuadratic() const; // clear the contents - void Clear(); + virtual void Clear(); + int getSize(); + void compactList(); + + SMESHDS_Mesh* GetParent() const { return const_cast< SMESHDS_Mesh*>( myParent ); } + int GetID() const { return myIndex; } private: + SMESHDS_Mesh * myParent; + std::vector myElements; + std::vector myNodes; - typedef std::set TElemSet; - TElemSet myElements, myNodes; + int myUnusedIdNodes; + int myUnusedIdElements; + int myIndex; std::set mySubMeshes; }; diff --git a/src/3rdParty/salomesmesh/inc/SMESHDS_TSubMeshHolder.hxx b/src/3rdParty/salomesmesh/inc/SMESHDS_TSubMeshHolder.hxx new file mode 100644 index 000000000000..eebb4247036e --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMESHDS_TSubMeshHolder.hxx @@ -0,0 +1,151 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// +#ifndef __SMESHDS_SubMeshHolder_HXX__ +#define __SMESHDS_SubMeshHolder_HXX__ + +#include +#include + +//======================================================================= +/*! + * \brief A binder of a sub-mesh to its ID which can be negative. Provides fast + * access to a sub-mesh by its ID. + * + * Issue 52457: Addition of hypotheses is 8 time longer than meshing. + */ +//======================================================================= + +template +class SMESHDS_TSubMeshHolder +{ + std::vector< SUBMESH* > myVec; // for ID >= 0 + std::map< int, SUBMESH* > myMap; // for ID < 0 + +public: + + ~SMESHDS_TSubMeshHolder() + { + DeleteAll(); + } + void Add( int id, SUBMESH* sm ) + { + if ( id < 0 ) + { + myMap[ id ] = sm; + } + else + { + if ( myVec.size() <= id ) + myVec.resize( id+1, (SUBMESH*) NULL ); + myVec[ id ] = sm; + } + } + SUBMESH* Get( int id ) const + { + if ( id < 0 ) + { + typename std::map< int, SUBMESH* >::const_iterator i2sm = myMap.find( id ); + return (SUBMESH*) ( i2sm == myMap.end() ? NULL : i2sm->second ); + } + else + { + return (SUBMESH*) ( id >= myVec.size() ? NULL : myVec[ id ]); + } + } + void DeleteAll() + { + for ( size_t i = 0; i < myVec.size(); ++i ) + if ( SUBMESH* sm = myVec[i] ) + { + myVec[i] = 0; // avoid access via Get(i) + delete sm; + } + myVec.clear(); + + typename std::map< int, SUBMESH* >::iterator i2sm = myMap.begin(); + for ( ; i2sm != myMap.end(); ++i2sm ) + if ( SUBMESH* sm = i2sm->second ) + { + i2sm->second = 0; // avoid access via Get(i) + delete sm; + } + myMap.clear(); + } + int GetMinID() const + { + return myMap.empty() ? 0 : myMap.begin()->first; + } + int GetMaxID() const + { + return myVec.empty() ? ( myMap.empty() ? 0 : myMap.rbegin()->first ) : myVec.size(); + } + + //----------------------------------------------------------------------- + struct Iterator : public SMDS_Iterator< SUBMESH* > + { + const SMESHDS_TSubMeshHolder* myHolder; + SUBMESH* myNext; + int myCurID, myEndID, myIDDelta; + + void init( const SMESHDS_TSubMeshHolder* holder, + int firstID, int endID, int delta ) + { + myHolder = holder; + myNext = 0; + myCurID = firstID; + myEndID = endID; + myIDDelta = delta; + + next(); + } + + bool more() + { + return myNext; + } + + SUBMESH* next() + { + SUBMESH* res = myNext; + myNext = 0; + while ( !myNext && myCurID != myEndID ) + { + myNext = myHolder->Get( myCurID ); + myCurID += myIDDelta; + } + return res; + } + virtual ~Iterator() {} + }; + //----------------------------------------------------------------------- + + SMDS_Iterator< SUBMESH* >* GetIterator(const bool reverse=false) const + { + Iterator* iter = new Iterator; + if ( reverse ) iter->init( this, GetMaxID(), GetMinID()-1, -1 ); + else iter->init( this, GetMinID(), GetMaxID()+1, +1 ); + return iter; + } +}; + + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_Algo.hxx b/src/3rdParty/salomesmesh/inc/SMESH_Algo.hxx index 4bad06a893d2..a362ed290bc2 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_Algo.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_Algo.hxx @@ -1,38 +1,39 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : SMESH_Algo.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESH/SMESH_Algo.hxx,v 1.12.2.4 2008/11/27 12:25:15 abd Exp $ // #ifndef _SMESH_ALGO_HXX_ #define _SMESH_ALGO_HXX_ #include "SMESH_SMESH.hxx" -#include "SMESH_Hypothesis.hxx" -#include "SMESH_ComputeError.hxx" +#include "SMDSAbs_ElementType.hxx" #include "SMESH_Comment.hxx" +#include "SMESH_ComputeError.hxx" +#include "SMESH_Hypothesis.hxx" #include #include @@ -42,22 +43,63 @@ #include #include #include +#include +class SMDS_MeshNode; +class SMESHDS_Mesh; +class SMESHDS_SubMesh; class SMESH_Gen; -class SMESH_Mesh; class SMESH_HypoFilter; -class TopoDS_Vertex; +class SMESH_Mesh; +class SMESH_MesherHelper; +class SMESH_ProxyMesh; +class SMESH_subMesh; class TopoDS_Face; class TopoDS_Shape; -class SMESHDS_Mesh; -class SMDS_MeshNode; -class SMESH_subMesh; -class SMESH_MesherHelper; - - -class SMESH_EXPORT SMESH_Algo:public SMESH_Hypothesis +class TopoDS_Vertex; +class TopoDS_Wire; +class gp_XYZ; + +typedef std::map< SMESH_subMesh*, std::vector > MapShapeNbElems; +typedef std::map< SMESH_subMesh*, std::vector >::iterator MapShapeNbElemsItr; + +// ================================================================================== +/*! + * \brief Root of all algorithms + * + * Methods of the class are grouped into several parts: + * - main lifecycle methods, like Compute() + * - methods describing features of the algorithm, like NeedShape() + * - methods related to dependencies between sub-meshes imposed by the algorith + * - static utilities, like EdgeLength() + */ +// ================================================================================== + +class SMESH_EXPORT SMESH_Algo : public SMESH_Hypothesis { -public: + public: + //================================================================================== + /*! + * \brief Structure describing algorithm features + */ + // -------------------------------------------------------------------------------- + struct Features + { + int _dim; + std::set _inElemTypes; // acceptable types of input mesh element + std::set _outElemTypes; // produced types of mesh elements + std::string _label; // GUI type name + + bool IsCompatible( const Features& algo2 ) const; + }; + /*! + * \brief Returns a structure describing algorithm features + */ + static const Features& GetFeatures( const std::string& algoType ); + const Features& GetFeatures() const { return GetFeatures( _name ); } + + public: + //================================================================================== /*! * \brief Creates algorithm * \param hypId - algorithm ID @@ -74,14 +116,14 @@ public: /*! * \brief Saves nothing in a stream * \param save - the stream - * \retval virtual std::ostream & - the stream + * \retval std::ostream & - the stream */ virtual std::ostream & SaveTo(std::ostream & save); /*! * \brief Loads nothing from a stream * \param load - the stream - * \retval virtual std::ostream & - the stream + * \retval std::ostream & - the stream */ virtual std::istream & LoadFrom(std::istream & load); @@ -96,6 +138,8 @@ public: * \param aShape - the shape * \param aStatus - check result * \retval bool - true if hypothesis is well defined + * + * Textual description of a problem can be stored in _comment field. */ virtual bool CheckHypothesis(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, @@ -106,9 +150,9 @@ public: * \param aShape - the shape * \retval bool - is a success * - * Algorithms that !NeedDescretBoundary() || !OnlyUnaryInput() are + * Algorithms that !NeedDiscreteBoundary() || !OnlyUnaryInput() are * to set SMESH_ComputeError returned by SMESH_submesh::GetComputeError() - * to report problematic subshapes + * to report problematic sub-shapes */ virtual bool Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape) = 0; @@ -122,6 +166,27 @@ public: */ virtual bool Compute(SMESH_Mesh & aMesh, SMESH_MesherHelper* aHelper); + /*! + * \brief Sets _computeCanceled to true. It's usage depends on + * implementation of a particular mesher. + */ + virtual void CancelCompute(); + + /*! + * \brief If possible, returns progress of computation [0.,1.] + */ + virtual double GetProgress() const; + + /*! + * \brief evaluates size of prospective mesh on a shape + * \param aMesh - the mesh + * \param aShape - the shape + * \param aResMap - prospective number of elements by SMDSAbs_ElementType by a sub-mesh + * \retval bool - is a success + */ + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap) = 0; + /*! * \brief Returns a list of compatible hypotheses used to mesh a shape * \param aMesh - the mesh @@ -138,7 +203,7 @@ public: virtual const std::list & GetUsedHypothesis(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, - const bool ignoreAuxiliary=true); + const bool ignoreAuxiliary=true) const; /*! * \brief Returns a list of compatible hypotheses assigned to a shape in a mesh * \param aMesh - the mesh @@ -153,19 +218,16 @@ public: const std::list & GetAppliedHypothesis(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, - const bool ignoreAuxiliary=true); + const bool ignoreAuxiliary=true) const; /*! - * \brief Make the filter recognize only compatible hypotheses - * \param theFilter - the filter to initialize - * \param ignoreAuxiliary - make filter ignore compatible auxiliary hypotheses - * \retval bool - true if the algo has compatible hypotheses + * \brief Returns the filter recognizing only compatible hypotheses + * \param ignoreAuxiliary - make filter ignore compatible auxiliary hypotheses + * \retval SMESH_HypoFilter* - the filter that can be NULL */ - bool InitCompatibleHypoFilter( SMESH_HypoFilter & theFilter, - const bool ignoreAuxiliary) const; + const SMESH_HypoFilter* GetCompatibleHypoFilter(const bool ignoreAuxiliary) const; + /*! - * \brief Initialize my parameter values by the mesh built on the geometry - * - * Just return false as the algorithm does not hold parameters values + * \brief Just return false as the algorithm does not hold parameters values */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0); @@ -175,9 +237,17 @@ public: */ SMESH_ComputeErrorPtr GetComputeError() const; /*! - * \brief initialize compute error + * \brief initialize compute error etc. before call of Compute() */ void InitComputeError(); + /*! + * \brief Return compute progress by nb of calls of this method + */ + double GetProgressByTic() const; + /*! + * Return a vector of sub-meshes to Compute() + */ + std::vector& SubMeshesToCompute() { return _smToCompute; } public: // ================================================================== @@ -196,15 +266,19 @@ public: // an input temporary shape that is neither MainShape nor // its child. - bool NeedDescretBoundary() const { return _requireDescretBoundary; } + bool NeedDiscreteBoundary() const { return _requireDiscreteBoundary; } // 3 - is a Dim-1 mesh prerequisite bool NeedShape() const { return _requireShape; } // 4 - is shape existance required bool SupportSubmeshes() const { return _supportSubmeshes; } - // 5 - whether supports submeshes if !NeedDescretBoundary() + // 5 - whether supports submeshes if !NeedDiscreteBoundary() + bool NeedLowerHyps(int dim) const { return _neededLowerHyps[ dim ]; } + // 6 - if algo !NeedDiscreteBoundary() but requires presence of + // hypotheses of dimension to generate all-dimensional mesh. + // This info is used not to issue warnings on hiding of lower global algos. public: // ================================================================== @@ -217,7 +291,7 @@ public: * * This method is called when a submesh gets HYP_OK algo_state. * After being set, event listener is notified on each event of a submesh. - * By default non listener is set + * By default none listener is set */ virtual void SetEventListener(SMESH_subMesh* subMesh); @@ -239,33 +313,27 @@ public: * \param theEdge - The geometrical edge of interest * \param theParams - The resulting vector of sorted node parameters * \retval bool - false if not all parameters are OK + * \warning Nodes moved to other geometry by MergeNodes() are NOT returned. */ static bool GetNodeParamOnEdge(const SMESHDS_Mesh* theMesh, const TopoDS_Edge& theEdge, std::vector< double > & theParams); - - /*! + /*! * \brief Fill map of node parameter on geometrical edge to node it-self * \param theMesh - The mesh containing nodes * \param theEdge - The geometrical edge of interest * \param theNodes - The resulting map * \param ignoreMediumNodes - to store medium nodes of quadratic elements or not + * \param typeToCheck - type of elements to check for medium nodes * \retval bool - false if not all parameters are OK + * \warning Nodes moved to other geometry by MergeNodes() are NOT returned. */ static bool GetSortedNodesOnEdge(const SMESHDS_Mesh* theMesh, const TopoDS_Edge& theEdge, const bool ignoreMediumNodes, - std::map< double, const SMDS_MeshNode* > & theNodes); - - /*! - * \brief Find out elements orientation on a geometrical face - * \param theFace - The face correctly oriented in the shape being meshed - * \param theMeshDS - The mesh data structure - * \retval bool - true if the face normal and the normal of first element - * in the correspoding submesh point in different directions - */ - static bool IsReversedSubMesh (const TopoDS_Face& theFace, - SMESHDS_Mesh* theMeshDS); + std::map< double, const SMDS_MeshNode* > & theNodes, + const SMDSAbs_ElementType typeToCheck = SMDSAbs_All); + /*! * \brief Compute length of an edge * \param E - the edge @@ -273,13 +341,15 @@ public: */ static double EdgeLength(const TopoDS_Edge & E); + int NumberOfPoints(SMESH_Mesh& aMesh,const TopoDS_Wire& W); + /*! * \brief Return continuity of two edges * \param E1 - the 1st edge * \param E2 - the 2nd edge * \retval GeomAbs_Shape - regularity at the junction between E1 and E2 */ - static GeomAbs_Shape Continuity(const TopoDS_Edge & E1, const TopoDS_Edge & E2); + static GeomAbs_Shape Continuity(TopoDS_Edge E1, TopoDS_Edge E2); /*! * \brief Return true if an edge can be considered as a continuation of another @@ -287,17 +357,54 @@ public: static bool IsContinuous(const TopoDS_Edge & E1, const TopoDS_Edge & E2) { return ( Continuity( E1, E2 ) >= GeomAbs_G1 ); } + /*! + * \brief Return true if an edge can be considered straight + */ + static bool IsStraight( const TopoDS_Edge & E, const bool degenResult=false ); + /*! + * \brief Return true if an edge has no 3D curve + */ + static bool isDegenerated( const TopoDS_Edge & E ); /*! * \brief Return the node built on a vertex * \param V - the vertex - * \param meshDS - mesh + * \param meshDS - mesh data structure * \retval const SMDS_MeshNode* - found node or NULL */ - static const SMDS_MeshNode* VertexNode(const TopoDS_Vertex& V, - const SMESHDS_Mesh* meshDS); + static const SMDS_MeshNode* VertexNode(const TopoDS_Vertex& V, const SMESHDS_Mesh* meshDS); -protected: + /*! + * \brief Return the node built on a vertex. + * A node moved to other geometry by MergeNodes() is also returned. + * \param V - the vertex + * \param mesh - mesh + * \retval const SMDS_MeshNode* - found node or NULL + */ + static const SMDS_MeshNode* VertexNode(const TopoDS_Vertex& V, const SMESH_Mesh* mesh); + + /*! + * \brief Return the node built on a vertex. + * A node moved to other geometry by MergeNodes() is also returned. + * \param V - the vertex + * \param edgeSM - sub-mesh of a meshed EDGE sharing the vertex + * \param mesh - the mesh + * \param checkV - if \c true, presence of a node on the vertex is checked + * \retval const SMDS_MeshNode* - found node or NULL + */ + static const SMDS_MeshNode* VertexNode(const TopoDS_Vertex& V, + const SMESHDS_SubMesh* edgeSM, + const SMESH_Mesh* mesh, + const bool checkV=true); + + enum EMeshError { MEr_OK = 0, MEr_HOLES, MEr_BAD_ORI, MEr_EMPTY }; + + /*! + * \brief Finds topological errors of a sub-mesh + */ + static EMeshError GetMeshError(SMESH_subMesh* subMesh); + + protected: /*! * \brief store error and comment and then return ( error == COMPERR_OK ) @@ -319,27 +426,73 @@ protected: */ void addBadInputElement(const SMDS_MeshElement* elem); + void addBadInputElements(const SMESHDS_SubMesh* sm, + const bool addNodes=false); + protected: + const SMESH_HypoFilter * _compatibleAllHypFilter; + const SMESH_HypoFilter * _compatibleNoAuxHypFilter; std::vector _compatibleHypothesis; std::list _appliedHypList; std::list _usedHypList; + // Algo features influencing which Compute() and how is called: // in what turn and with what input shape. - // This fields must be redefined if necessary by each descendant at constructor. + // These fields must be redefined if necessary by each descendant at constructor. bool _onlyUnaryInput; // mesh one shape of GetDim() at once. Default TRUE - bool _requireDescretBoundary; // GetDim()-1 mesh must be present. Default TRUE + bool _requireDiscreteBoundary;// GetDim()-1 mesh must be present. Default TRUE bool _requireShape; // work with GetDim()-1 mesh bound to geom only. Default TRUE - bool _supportSubmeshes; // if !_requireDescretBoundary. Default FALSE + bool _supportSubmeshes; // if !_requireDiscreteBoundary. Default FALSE + bool _neededLowerHyps[4]; // hyp dims needed by algo that !_requireDiscreteBoundary. Df. FALSE - // quadratic mesh creation required, - // is usually set trough SMESH_MesherHelper::IsQuadraticSubMesh() + // indicates if quadratic mesh creation is required, + // is usually set like this: _quadraticMesh = SMESH_MesherHelper::IsQuadraticSubMesh(shape) bool _quadraticMesh; int _error; //!< SMESH_ComputeErrorName or anything algo specific std::string _comment; //!< any text explaining what is wrong in Compute() std::list _badInputElements; //!< to explain COMPERR_BAD_INPUT_MESH + + volatile bool _computeCanceled; //!< is set to True while computing to stop it + + double _progress; /* progress of Compute() [0.,1.], + to be set by an algo really tracking the progress */ + int _progressTic; // counter of calls from SMESH_Mesh::GetComputeProgress() + std::vector _smToCompute; // sub-meshes to Compute() +}; + + +class SMESH_EXPORT SMESH_0D_Algo: public SMESH_Algo +{ +public: + SMESH_0D_Algo(int hypId, int studyId, SMESH_Gen* gen); +}; + +class SMESH_EXPORT SMESH_1D_Algo: public SMESH_Algo +{ +public: + SMESH_1D_Algo(int hypId, int studyId, SMESH_Gen* gen); +}; + +class SMESH_EXPORT SMESH_2D_Algo: public SMESH_Algo +{ +public: + SMESH_2D_Algo(int hypId, int studyId, SMESH_Gen* gen); + /*! + * \brief Method in which an algorithm generating a structured mesh + * fixes positions of in-face nodes after there movement + * due to insertion of viscous layers. + */ + virtual bool FixInternalNodes(const SMESH_ProxyMesh& mesh, + const TopoDS_Face& face); +}; + +class SMESH_EXPORT SMESH_3D_Algo: public SMESH_Algo +{ +public: + SMESH_3D_Algo(int hypId, int studyId, SMESH_Gen* gen); }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_Block.hxx b/src/3rdParty/salomesmesh/inc/SMESH_Block.hxx index 20c18163b9f0..1fb9e6ae8c05 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_Block.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_Block.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : SMESH_Block.hxx // Created : Tue Nov 30 12:42:18 2004 // Author : Edward AGAPOV (eap) @@ -26,11 +27,11 @@ #ifndef SMESH_Block_HeaderFile #define SMESH_Block_HeaderFile -#include "SMESH_SMESH.hxx" +#include "SMESH_Utils.hxx" -//#include -//#include -//#include +// #include +// #include +// #include #include #include @@ -58,7 +59,7 @@ class gp_Pnt; // parameters inside the block and vice versa // ========================================================= -class SMESH_EXPORT SMESH_Block: public math_FunctionSetWithDerivatives +class SMESHUtils_EXPORT SMESH_Block: public math_FunctionSetWithDerivatives { public: enum TShapeID { @@ -67,20 +68,19 @@ class SMESH_EXPORT SMESH_Block: public math_FunctionSetWithDerivatives // ---------------------------- ID_NONE = 0, - ID_V000 = 1, ID_V100, ID_V010, ID_V110, ID_V001, ID_V101, ID_V011, ID_V111, + ID_V000 = 1, ID_V100, ID_V010, ID_V110, ID_V001, ID_V101, ID_V011, ID_V111, // 1-8 - ID_Ex00, ID_Ex10, ID_Ex01, ID_Ex11, - ID_E0y0, ID_E1y0, ID_E0y1, ID_E1y1, - ID_E00z, ID_E10z, ID_E01z, ID_E11z, + ID_Ex00, ID_Ex10, ID_Ex01, ID_Ex11, // 9-12 + ID_E0y0, ID_E1y0, ID_E0y1, ID_E1y1, // 13-16 + ID_E00z, ID_E10z, ID_E01z, ID_E11z, // 17-20 - ID_Fxy0, ID_Fxy1, ID_Fx0z, ID_Fx1z, ID_F0yz, ID_F1yz, + ID_Fxy0, ID_Fxy1, ID_Fx0z, ID_Fx1z, ID_F0yz, ID_F1yz, // 21-26 - ID_Shell - }; - enum { // to use TShapeID for indexing certain type subshapes + ID_Shell, // 27 - ID_FirstV = ID_V000, ID_FirstE = ID_Ex00, ID_FirstF = ID_Fxy0 + // to use TShapeID for indexing certain type subshapes + ID_FirstV = ID_V000, ID_FirstE = ID_Ex00, ID_FirstF = ID_Fxy0 }; @@ -245,6 +245,8 @@ public: const gp_XYZ& theParamsHint = gp_XYZ(-1,-1,-1)); // compute point parameters in the block. // Note: for edges, it is better to use EdgeParameters() + // Return false only in case of "hard" failure, use IsToleranceReached() etc + // to evaluate quality of the found solution bool VertexParameters(const int theVertexID, gp_XYZ& theParams); // return parameters of a vertex given by TShapeID @@ -252,14 +254,18 @@ public: bool EdgeParameters(const int theEdgeID, const double theU, gp_XYZ& theParams); // return parameters of a point given by theU on edge + void SetTolerance(const double tol); + // set tolerance for ComputeParameters() - public: - // --------------- - // Block geomerty - // --------------- + double GetTolerance() const { return myTolerance; } + // return current tolerance of ComputeParameters() + + bool IsToleranceReached() const; + // return true if solution found by ComputeParameters() is within the tolerance + + double DistanceReached() const { return distance(); } + // return distance between solution found by ComputeParameters() and thePoint - - public: // --------- // Services @@ -274,13 +280,16 @@ public: // Return true if an in-block parameter increases along theEdge curve static int GetOrderedEdges (const TopoDS_Face& theFace, - TopoDS_Vertex theFirstVertex, std::list< TopoDS_Edge >& theEdges, - std::list< int > & theNbVertexInWires); - // Return nb wires and a list of oredered edges. + std::list< int > & theNbEdgesInWires, + TopoDS_Vertex theFirstVertex=TopoDS_Vertex(), + const bool theShapeAnalysisAlgo=false); + // Return nb wires and a list of ordered edges. // It is used to assign indices to subshapes. // theFirstVertex may be NULL. // Always try to set a seam edge first + // if (theShapeAnalysisAlgo) then ShapeAnalysis::OuterWire() is used to find the outer + // wire else BRepTools::OuterWire() is used public: // ----------------------------------------------------------- @@ -307,7 +316,7 @@ public: // Note 2: curve adaptors need to have only Value(double), FirstParameter() and // LastParameter() defined to be used by Block algoritms - class SMESH_EXPORT TEdge { + class SMESHUtils_EXPORT TEdge { int myCoordInd; double myFirst; double myLast; @@ -327,7 +336,7 @@ public: ~TEdge(); }; - class SMESH_EXPORT TFace { + class SMESHUtils_EXPORT TFace { // 4 edges in the order u0, u1, 0v, 1v int myCoordInd[ 4 ]; double myFirst [ 4 ]; @@ -348,6 +357,11 @@ public: int GetUInd() const { return myCoordInd[ 0 ]; } int GetVInd() const { return myCoordInd[ 2 ]; } void GetCoefs( int i, const gp_XYZ& theParams, double& eCoef, double& vCoef ) const; + const Adaptor3d_Surface* Surface() const { return myS; } + bool IsUVInQuad( const gp_XY& uv, + const gp_XYZ& param0, const gp_XYZ& param1, + const gp_XYZ& param2, const gp_XYZ& param3 ) const; + gp_XY GetUVRange() const; TFace(): myS(0) { myC2d[0]=myC2d[1]=myC2d[2]=myC2d[3]=0; } ~TFace(); }; @@ -365,7 +379,13 @@ public: enum { SQUARE_DIST = 0, DRV_1, DRV_2, DRV_3 }; double distance () const { return sqrt( myValues[ SQUARE_DIST ]); } double funcValue(double sqDist) const { return mySquareFunc ? sqDist : sqrt(sqDist); } - bool computeParameters(const gp_Pnt& thePoint, gp_XYZ& theParams, const gp_XYZ& theParamsHint); + bool computeParameters(const gp_Pnt& thePoint, gp_XYZ& theParams, const gp_XYZ& theParamsHint, int); + void refineParametersOnFace( const gp_Pnt& thePoint, gp_XYZ& theParams, int theFaceID ); + bool findUVByHalfDivision( const gp_Pnt& thePoint, const gp_XY& theUV, + const TFace& tface, gp_XYZ& theParams); + bool findUVAround( const gp_Pnt& thePoint, const gp_XY& theUV, + const TFace& tface, gp_XYZ& theParams, int nbGetWorstLimit ); + bool saveBetterSolution( const gp_XYZ& theNewParams, gp_XYZ& theParams, double sqDistance ); int myFaceIndex; double myFaceParam; @@ -379,7 +399,7 @@ public: double myValues[ 4 ]; // values computed at myParam: square distance and 3 derivatives typedef std::pair TxyzPair; - TxyzPair my3x3x3GridNodes[ 27 ]; // to compute the first param guess + TxyzPair my3x3x3GridNodes[ 1000 ]; // to compute the first param guess bool myGridComputed; }; diff --git a/src/3rdParty/salomesmesh/inc/SMESH_Comment.hxx b/src/3rdParty/salomesmesh/inc/SMESH_Comment.hxx index ca9351cd4de4..5e6420fda11f 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_Comment.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_Comment.hxx @@ -1,24 +1,22 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 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, or (at your option) any later version. // -// 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. // -// 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 // -// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : SMESH_Comment.hxx // Created : Wed Mar 14 18:28:45 2007 @@ -32,33 +30,40 @@ # include # include +using namespace std; /*! * \brief Class to generate string from any type */ -class SMESH_Comment : public std::string +class SMESH_Comment : public string { - std::ostringstream _s ; + ostringstream _s ; public : - SMESH_Comment():std::string("") {} + SMESH_Comment():string("") {} + + SMESH_Comment(const SMESH_Comment& c):string() { + _s << c.c_str() ; + this->string::operator=( _s.str() ); + } - SMESH_Comment(const SMESH_Comment& c):std::string() { + SMESH_Comment & operator=(const SMESH_Comment& c) { _s << c.c_str() ; - this->std::string::operator=( _s.str() ); + this->string::operator=( _s.str() ); + return *this; } template SMESH_Comment( const T &anything ) { _s << anything ; - this->std::string::operator=( _s.str() ); + this->string::operator=( _s.str() ); } template SMESH_Comment & operator<<( const T &anything ) { _s << anything ; - this->std::string::operator=( _s.str() ); + this->string::operator=( _s.str() ); return *this ; } diff --git a/src/3rdParty/salomesmesh/inc/SMESH_ComputeError.hxx b/src/3rdParty/salomesmesh/inc/SMESH_ComputeError.hxx index a764f0a3b34e..8e90db5823b6 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_ComputeError.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_ComputeError.hxx @@ -1,33 +1,31 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 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, or (at your option) any later version. // -// 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. // -// 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 // -// 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 // -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// SMESH SMESH : implementaion of SMESH idl descriptions -// File : SMESH_Hypothesis.hxx + +// File : SMESH_ComputeError.hxx // Author : Edward AGAPOV (eap) // Module : SMESH -// $Header: // #ifndef SMESH_ComputeError_HeaderFile #define SMESH_ComputeError_HeaderFile +#include "SMESH_Utils.hxx" + #include #include #include @@ -44,24 +42,34 @@ enum SMESH_ComputeErrorName { // If you modify it, pls update SMESH_ComputeError::CommonName() below. // Positive values are for algo specific errors - COMPERR_OK = -1, - COMPERR_BAD_INPUT_MESH = -2, //!< wrong mesh on lower submesh - COMPERR_STD_EXCEPTION = -3, //!< some std exception raised - COMPERR_OCC_EXCEPTION = -4, //!< OCC exception raised - COMPERR_SLM_EXCEPTION = -5, //!< SALOME exception raised - COMPERR_EXCEPTION = -6, //!< other exception raised - COMPERR_MEMORY_PB = -7, //!< std::bad_alloc exception - COMPERR_ALGO_FAILED = -8, //!< algo failed for some reason - COMPERR_BAD_SHAPE = -9 //!< bad geometry + COMPERR_OK = -1, + COMPERR_BAD_INPUT_MESH = -2, //!< wrong mesh on lower submesh + COMPERR_STD_EXCEPTION = -3, //!< some std exception raised + COMPERR_OCC_EXCEPTION = -4, //!< OCC exception raised + COMPERR_SLM_EXCEPTION = -5, //!< SALOME exception raised + COMPERR_EXCEPTION = -6, //!< other exception raised + COMPERR_MEMORY_PB = -7, //!< std::bad_alloc exception + COMPERR_ALGO_FAILED = -8, //!< algo failed for some reason + COMPERR_BAD_SHAPE = -9, //!< bad geometry + COMPERR_WARNING = -10, //!< algo reports error but sub-mesh is computed anyway + COMPERR_CANCELED = -11, //!< compute canceled + COMPERR_NO_MESH_ON_SHAPE = -12, //!< no mesh elements assigned to sub-shape + COMPERR_BAD_PARMETERS = -13, //!< incorrect hypotheses parameters + COMPERR_LAST_ALGO_ERROR = -100,//!< terminator of mesh computation errors + // Errors of SMESH_MeshEditor follow + EDITERR_NO_MEDIUM_ON_GEOM= -101 /* during conversion to quadratic, + some medium nodes not placed on geometry + to avoid distorting elements, which are + stored in SMESH_ComputeError::myBadElements */ }; // ============================================================= /*! - * \brief Contains algorithm and description of occured error + * \brief Contains an algorithm and description of an occured error */ // ============================================================= -struct SMESH_ComputeError +struct SMESHUtils_EXPORT SMESH_ComputeError { int myName; //!< SMESH_ComputeErrorName or anything algo specific std::string myComment; @@ -79,28 +87,19 @@ struct SMESH_ComputeError const SMESH_Algo* algo = 0) :myName(error),myComment(comment),myAlgo(algo) {} - bool IsOK() { return myName == COMPERR_OK; } - bool IsCommon() { return myName < 0; } - inline std::string CommonName() const; + bool IsOK() const { return myName == COMPERR_OK; } + bool IsKO() const { return myName != COMPERR_OK && myName != COMPERR_WARNING; } + bool IsCommon() const { return myName < 0 && myName > COMPERR_LAST_ALGO_ERROR; } + bool HasBadElems() const { return !myBadElements.empty(); } -}; + // not inline methods are implemented in src/SMESHUtils/SMESH_TryCatch.cxx -#define _case2char(err) case err: return #err; + // Return myName as text, to be used to dump errors in terminal + std::string CommonName() const; -std::string SMESH_ComputeError::CommonName() const -{ - switch( myName ) { - _case2char(COMPERR_OK ); - _case2char(COMPERR_BAD_INPUT_MESH); - _case2char(COMPERR_STD_EXCEPTION ); - _case2char(COMPERR_OCC_EXCEPTION ); - _case2char(COMPERR_SLM_EXCEPTION ); - _case2char(COMPERR_EXCEPTION ); - _case2char(COMPERR_MEMORY_PB ); - _case2char(COMPERR_ALGO_FAILED ); - default:; - } - return ""; -} + // Return the most severe error + static SMESH_ComputeErrorPtr Worst( SMESH_ComputeErrorPtr er1, + SMESH_ComputeErrorPtr er2 ); +}; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_Controls.hxx b/src/3rdParty/salomesmesh/inc/SMESH_Controls.hxx index 3bab160252de..ee7c742f5387 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_Controls.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_Controls.hxx @@ -1,45 +1,83 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #ifndef _SMESH_CONTROLS_HXX_ #define _SMESH_CONTROLS_HXX_ +// This file is named incosistently with others, i.e. not SMESHDS_Controls.hxx, +// because it was moved from ../Controls/SMESH_Controls.hxx. +// It was moved here for the sake of SMESHDS_GroupOnFilter + +#include "SMDSAbs_ElementType.hxx" + #include +#ifdef WIN32 + #if defined SMESHCONTROLS_EXPORTS || defined SMESHControls_EXPORTS + #define SMESHCONTROLS_EXPORT __declspec( dllexport ) + #else + #define SMESHCONTROLS_EXPORT __declspec( dllimport ) + #endif +#else + #define SMESHCONTROLS_EXPORT +#endif + +class SMDS_Mesh; + namespace SMESH{ namespace Controls{ - class Functor; + /* + Class : Functor + Description : Root of all Functors defined in ../Controls/SMESH_ControlsDef.hxx + */ + class SMESHCONTROLS_EXPORT Functor + { + public: + ~Functor(){} + virtual void SetMesh( const SMDS_Mesh* theMesh ) = 0; + virtual SMDSAbs_ElementType GetType() const = 0; + }; typedef boost::shared_ptr FunctorPtr; class NumericalFunctor; typedef boost::shared_ptr NumericalFunctorPtr; - - class Predicate; + /* + Class : Predicate + Description : Base class for all predicates + */ + class SMESHCONTROLS_EXPORT Predicate: public virtual Functor{ + public: + virtual bool IsSatisfy( long theElementId ) = 0; + virtual SMDSAbs_ElementType GetType() const = 0; + }; typedef boost::shared_ptr PredicatePtr; } } +typedef SMESH::Controls::PredicatePtr SMESH_PredicatePtr; + #endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_ControlsDef.hxx b/src/3rdParty/salomesmesh/inc/SMESH_ControlsDef.hxx index 38a507c84bf1..8a2ff7e245be 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_ControlsDef.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_ControlsDef.hxx @@ -1,59 +1,50 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #ifndef _SMESH_CONTROLSDEF_HXX_ #define _SMESH_CONTROLSDEF_HXX_ -#include -#include -#include +#include "SMESH_Controls.hxx" -#include +#include "SMDS_MeshNode.hxx" +#include "SMESH_TypeDefs.hxx" -#include -#include +#include +#include #include -#include +#include +#include #include +#include #include #include #include -#include -#include -#include - -#include "SMDSAbs_ElementType.hxx" -#include "SMDS_MeshNode.hxx" +#include -#include "SMESH_Controls.hxx" +#include +#include +#include -#ifdef WNT - #if defined SMESHCONTROLS_EXPORTS || defined SMESHControls_EXPORTS - #define SMESHCONTROLS_EXPORT __declspec( dllexport ) - #else - #define SMESHCONTROLS_EXPORT __declspec( dllimport ) - #endif -#else - #define SMESHCONTROLS_EXPORT -#endif +#include class SMDS_MeshElement; class SMDS_MeshFace; @@ -62,48 +53,70 @@ class SMDS_Mesh; class SMESHDS_Mesh; class SMESHDS_SubMesh; +class SMESHDS_GroupBase; class gp_Pnt; namespace SMESH{ namespace Controls{ - class SMESHCONTROLS_EXPORT TSequenceOfXYZ: public std::vector + class SMESHCONTROLS_EXPORT TSequenceOfXYZ { + typedef std::vector::size_type size_type; + public: TSequenceOfXYZ(); - TSequenceOfXYZ(size_type n); + explicit TSequenceOfXYZ(size_type n); - TSequenceOfXYZ(size_type n, const value_type& t); + TSequenceOfXYZ(size_type n, const gp_XYZ& t); TSequenceOfXYZ(const TSequenceOfXYZ& theSequenceOfXYZ); template TSequenceOfXYZ(InputIterator theBegin, InputIterator theEnd); + ~TSequenceOfXYZ(); + TSequenceOfXYZ& operator=(const TSequenceOfXYZ& theSequenceOfXYZ); - reference operator()(size_type n); + gp_XYZ& operator()(size_type n); - const_reference operator()(size_type n) const; + const gp_XYZ& operator()(size_type n) const; - private: - reference operator[](size_type n); + void clear(); + + void reserve(size_type n); - const_reference operator[](size_type n) const; + void push_back(const gp_XYZ& v); + + size_type size() const; + + + void setElement(const SMDS_MeshElement* e) { myElem = e; } + + const SMDS_MeshElement* getElement() const { return myElem; } + + SMDSAbs_EntityType getElementEntity() const; + + private: + std::vector myArray; + const SMDS_MeshElement* myElem; }; - /* - Class : Functor - Description : Root of all Functors - */ - class SMESHCONTROLS_EXPORT Functor + /*! + * \brief Class used to detect mesh modification: IsMeshModified() returns + * true if a mesh has changed since last calling IsMeshModified() + */ + class SMESHCONTROLS_EXPORT TMeshModifTracer { + unsigned long myMeshModifTime; + const SMDS_Mesh* myMesh; public: - ~Functor(){} - virtual void SetMesh( const SMDS_Mesh* theMesh ) = 0; - virtual SMDSAbs_ElementType GetType() const = 0; + TMeshModifTracer(); + void SetMesh( const SMDS_Mesh* theMesh ); + const SMDS_Mesh* GetMesh() const { return myMesh; } + bool IsMeshModified(); }; /* @@ -116,19 +129,25 @@ namespace SMESH{ virtual void SetMesh( const SMDS_Mesh* theMesh ); virtual double GetValue( long theElementId ); virtual double GetValue(const TSequenceOfXYZ& thePoints) { return -1.0;}; + void GetHistogram(int nbIntervals, + std::vector& nbEvents, + std::vector& funValues, + const std::vector& elements, + const double* minmax=0, + const bool isLogarithmic = false); virtual SMDSAbs_ElementType GetType() const = 0; virtual double GetBadRate( double Value, int nbNodes ) const = 0; long GetPrecision() const; void SetPrecision( const long thePrecision ); + double Round( const double & value ); - bool GetPoints(const int theId, - TSequenceOfXYZ& theRes) const; - static bool GetPoints(const SMDS_MeshElement* theElem, - TSequenceOfXYZ& theRes); + bool GetPoints(const int theId, TSequenceOfXYZ& theRes) const; + static bool GetPoints(const SMDS_MeshElement* theElem, TSequenceOfXYZ& theRes); protected: - const SMDS_Mesh* myMesh; + const SMDS_Mesh* myMesh; const SMDS_MeshElement* myCurrElement; - long myPrecision; + long myPrecision; + double myPrecisionValue; }; @@ -145,6 +164,31 @@ namespace SMESH{ }; + /* + Class : MaxElementLength2D + Description : Functor calculating maximum length of 2D element + */ + class SMESHCONTROLS_EXPORT MaxElementLength2D: public virtual NumericalFunctor{ + public: + virtual double GetValue( long theElementId ); + virtual double GetValue( const TSequenceOfXYZ& P ); + virtual double GetBadRate( double Value, int nbNodes ) const; + virtual SMDSAbs_ElementType GetType() const; + }; + + + /* + Class : MaxElementLength3D + Description : Functor calculating maximum length of 3D element + */ + class SMESHCONTROLS_EXPORT MaxElementLength3D: public virtual NumericalFunctor{ + public: + virtual double GetValue( long theElementId ); + virtual double GetBadRate( double Value, int nbNodes ) const; + virtual SMDSAbs_ElementType GetType() const; + }; + + /* Class : SMESH_MinimumAngle Description : Functor for calculation of minimum angle @@ -163,6 +207,7 @@ namespace SMESH{ */ class SMESHCONTROLS_EXPORT AspectRatio: public virtual NumericalFunctor{ public: + virtual double GetValue( long theElementId ); virtual double GetValue( const TSequenceOfXYZ& thePoints ); virtual double GetBadRate( double Value, int nbNodes ) const; virtual SMDSAbs_ElementType GetType() const; @@ -175,6 +220,7 @@ namespace SMESH{ */ class SMESHCONTROLS_EXPORT AspectRatio3D: public virtual NumericalFunctor{ public: + virtual double GetValue( long theElementId ); virtual double GetValue( const TSequenceOfXYZ& thePoints ); virtual double GetBadRate( double Value, int nbNodes ) const; virtual SMDSAbs_ElementType GetType() const; @@ -207,7 +253,6 @@ namespace SMESH{ virtual SMDSAbs_ElementType GetType() const; }; - /* Class : Skew Description : Functor for calculating skew in degrees @@ -253,10 +298,10 @@ namespace SMESH{ virtual double GetBadRate( double Value, int nbNodes ) const; virtual SMDSAbs_ElementType GetType() const; struct Value{ - double myLength; - long myPntId[2]; - Value(double theLength, long thePntId1, long thePntId2); - bool operator<(const Value& x) const; + double myLength; + long myPntId[2]; + Value(double theLength, long thePntId1, long thePntId2); + bool operator<(const Value& x) const; }; typedef std::set TValues; void GetValues(TValues& theValues); @@ -265,7 +310,7 @@ namespace SMESH{ /* Class : MultiConnection - Description : Functor for calculating number of faces conneted to the edge + Description : Functor for calculating number of faces connected to the edge */ class SMESHCONTROLS_EXPORT MultiConnection: public virtual NumericalFunctor{ public: @@ -277,7 +322,7 @@ namespace SMESH{ /* Class : MultiConnection2D - Description : Functor for calculating number of faces conneted to the edge + Description : Functor for calculating number of faces connected to the edge */ class SMESHCONTROLS_EXPORT MultiConnection2D: public virtual NumericalFunctor{ public: @@ -286,29 +331,80 @@ namespace SMESH{ virtual double GetBadRate( double Value, int nbNodes ) const; virtual SMDSAbs_ElementType GetType() const; struct Value{ - long myPntId[2]; - Value(long thePntId1, long thePntId2); - bool operator<(const Value& x) const; + long myPntId[2]; + Value(long thePntId1, long thePntId2); + bool operator<(const Value& x) const; }; typedef std::map MValues; void GetValues(MValues& theValues); }; typedef boost::shared_ptr MultiConnection2DPtr; + + /* + Class : BallDiameter + Description : Functor returning diameter of a ball element + */ + class SMESHCONTROLS_EXPORT BallDiameter: public virtual NumericalFunctor{ + public: + virtual double GetValue( long theElementId ); + virtual double GetBadRate( double Value, int nbNodes ) const; + virtual SMDSAbs_ElementType GetType() const; + }; + + /* PREDICATES */ /* - Class : Predicate - Description : Base class for all predicates + Class : CoincidentNodes + Description : Predicate of Coincident Nodes + Note : This class is suitable only for visualization of Coincident Nodes */ - class SMESHCONTROLS_EXPORT Predicate: public virtual Functor{ + class SMESHCONTROLS_EXPORT CoincidentNodes: public Predicate { public: - virtual bool IsSatisfy( long theElementId ) = 0; - virtual SMDSAbs_ElementType GetType() const = 0; + CoincidentNodes(); + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual bool IsSatisfy( long theElementId ); + virtual SMDSAbs_ElementType GetType() const; + + void SetTolerance (const double theToler) { myToler = theToler; } + double GetTolerance () const { return myToler; } + + private: + double myToler; + TColStd_MapOfInteger myCoincidentIDs; + TMeshModifTracer myMeshModifTracer; }; - - + typedef boost::shared_ptr CoincidentNodesPtr; + + /* + Class : CoincidentElements + Description : Predicate of Coincident Elements + Note : This class is suitable only for visualization of Coincident Elements + */ + class SMESHCONTROLS_EXPORT CoincidentElements: public Predicate { + public: + CoincidentElements(); + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual bool IsSatisfy( long theElementId ); + + private: + const SMDS_Mesh* myMesh; + }; + class SMESHCONTROLS_EXPORT CoincidentElements1D: public CoincidentElements { + public: + virtual SMDSAbs_ElementType GetType() const; + }; + class SMESHCONTROLS_EXPORT CoincidentElements2D: public CoincidentElements { + public: + virtual SMDSAbs_ElementType GetType() const; + }; + class SMESHCONTROLS_EXPORT CoincidentElements3D: public CoincidentElements { + public: + virtual SMDSAbs_ElementType GetType() const; + }; + /* Class : FreeBorders Description : Predicate for free borders @@ -335,11 +431,93 @@ namespace SMESH{ virtual void SetMesh( const SMDS_Mesh* theMesh ); virtual bool IsSatisfy( long theElementId ); virtual SMDSAbs_ElementType GetType() const; - + protected: const SMDS_Mesh* myMesh; }; - + + /* + Class : ElemEntityType + Description : Functor for calculating entity type + */ + class SMESHCONTROLS_EXPORT ElemEntityType: public virtual Predicate{ + public: + ElemEntityType(); + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual bool IsSatisfy( long theElementId ); + void SetType( SMDSAbs_ElementType theType ); + virtual SMDSAbs_ElementType GetType() const; + void SetElemEntityType( SMDSAbs_EntityType theEntityType ); + SMDSAbs_EntityType GetElemEntityType() const; + + private: + const SMDS_Mesh* myMesh; + SMDSAbs_ElementType myType; + SMDSAbs_EntityType myEntityType; + }; + typedef boost::shared_ptr ElemEntityTypePtr; + + + /* + BareBorderVolume + */ + class SMESHCONTROLS_EXPORT BareBorderVolume: public Predicate + { + public: + BareBorderVolume():myMesh(0) {} + virtual void SetMesh( const SMDS_Mesh* theMesh ) { myMesh = theMesh; } + virtual SMDSAbs_ElementType GetType() const { return SMDSAbs_Volume; } + virtual bool IsSatisfy( long theElementId ); + protected: + const SMDS_Mesh* myMesh; + }; + typedef boost::shared_ptr BareBorderVolumePtr; + + /* + BareBorderFace + */ + class SMESHCONTROLS_EXPORT BareBorderFace: public Predicate + { + public: + BareBorderFace():myMesh(0) {} + virtual void SetMesh( const SMDS_Mesh* theMesh ) { myMesh = theMesh; } + virtual SMDSAbs_ElementType GetType() const { return SMDSAbs_Face; } + virtual bool IsSatisfy( long theElementId ); + protected: + const SMDS_Mesh* myMesh; + std::vector< const SMDS_MeshNode* > myLinkNodes; + }; + typedef boost::shared_ptr BareBorderFacePtr; + + /* + OverConstrainedVolume + */ + class SMESHCONTROLS_EXPORT OverConstrainedVolume: public Predicate + { + public: + OverConstrainedVolume():myMesh(0) {} + virtual void SetMesh( const SMDS_Mesh* theMesh ) { myMesh = theMesh; } + virtual SMDSAbs_ElementType GetType() const { return SMDSAbs_Volume; } + virtual bool IsSatisfy( long theElementId ); + protected: + const SMDS_Mesh* myMesh; + }; + typedef boost::shared_ptr OverConstrainedVolumePtr; + + /* + OverConstrainedFace + */ + class SMESHCONTROLS_EXPORT OverConstrainedFace: public Predicate + { + public: + OverConstrainedFace():myMesh(0) {} + virtual void SetMesh( const SMDS_Mesh* theMesh ) { myMesh = theMesh; } + virtual SMDSAbs_ElementType GetType() const { return SMDSAbs_Face; } + virtual bool IsSatisfy( long theElementId ); + protected: + const SMDS_Mesh* myMesh; + }; + typedef boost::shared_ptr OverConstrainedFacePtr; /* Class : FreeEdges @@ -354,14 +532,14 @@ namespace SMESH{ static bool IsFreeEdge( const SMDS_MeshNode** theNodes, const int theFaceId ); typedef long TElemId; struct Border{ - TElemId myElemId; - TElemId myPntId[2]; - Border(long theElemId, long thePntId1, long thePntId2); - bool operator<(const Border& x) const; + TElemId myElemId; + TElemId myPntId[2]; + Border(long theElemId, long thePntId1, long thePntId2); + bool operator<(const Border& x) const; }; typedef std::set TBorders; void GetBoreders(TBorders& theBorders); - + protected: const SMDS_Mesh* myMesh; }; @@ -593,8 +771,8 @@ namespace SMESH{ TMapOfLink& theNonManifold, SMDS_MeshFace* theNextFace ) const; - void getFacesByLink( const Link& theLink, - TVectorOfFacePtr& theFaces ) const; + void getFacesByLink( const Link& theLink, + TVectorOfFacePtr& theFaces ) const; private: const SMDS_Mesh* myMesh; @@ -609,6 +787,27 @@ namespace SMESH{ }; typedef boost::shared_ptr ManifoldPartPtr; + /* + Class : BelongToMeshGroup + Description : Verify whether a mesh element is included into a mesh group + */ + class SMESHCONTROLS_EXPORT BelongToMeshGroup : public virtual Predicate + { + public: + BelongToMeshGroup(); + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual bool IsSatisfy( long theElementId ); + virtual SMDSAbs_ElementType GetType() const; + + void SetGroup( SMESHDS_GroupBase* g ); + void SetStoreName( const std::string& sn ); + const SMESHDS_GroupBase* GetGroup() const { return myGroup; } + + private: + SMESHDS_GroupBase* myGroup; + std::string myStoreName; + }; + typedef boost::shared_ptr BelongToMeshGroupPtr; /* Class : ElementsOnSurface @@ -636,10 +835,9 @@ namespace SMESH{ bool isOnSurface( const SMDS_MeshNode* theNode ); private: - const SMDS_Mesh* myMesh; + TMeshModifTracer myMeshModifTracer; TColStd_MapOfInteger myIds; SMDSAbs_ElementType myType; - //Handle(Geom_Surface) mySurf; TopoDS_Face mySurf; double myToler; bool myUseBoundaries; @@ -672,30 +870,126 @@ namespace SMESH{ const SMDSAbs_ElementType theType); private: - void addShape (const TopoDS_Shape& theShape); - void process(); - void process (const SMDS_MeshElement* theElem); - - private: - const SMDS_Mesh* myMesh; - TColStd_MapOfInteger myIds; - SMDSAbs_ElementType myType; - TopoDS_Shape myShape; - double myToler; - bool myAllNodesFlag; - TopTools_MapOfShape myShapesMap; - TopAbs_ShapeEnum myCurShapeType; // type of current sub-shape - BRepClass3d_SolidClassifier myCurSC; // current SOLID - GeomAPI_ProjectPointOnSurf myCurProjFace; // current FACE - TopoDS_Face myCurFace; // current FACE - GeomAPI_ProjectPointOnCurve myCurProjEdge; // current EDGE - gp_Pnt myCurPnt; // current VERTEX + struct TClassifier + { + TClassifier(const TopoDS_Shape& s, double tol) { Init(s,tol); } + void Init(const TopoDS_Shape& s, double tol); + bool IsOut(const gp_Pnt& p); + TopAbs_ShapeEnum ShapeType() const; + private: + bool isOutOfSolid (const gp_Pnt& p); + bool isOutOfBox (const gp_Pnt& p); + bool isOutOfFace (const gp_Pnt& p); + bool isOutOfEdge (const gp_Pnt& p); + bool isOutOfVertex(const gp_Pnt& p); + bool isBox (const TopoDS_Shape& s); + + bool (TClassifier::* myIsOutFun)(const gp_Pnt& p); + BRepClass3d_SolidClassifier mySolidClfr; + Bnd_B3d myBox; + GeomAPI_ProjectPointOnSurf myProjFace; + GeomAPI_ProjectPointOnCurve myProjEdge; + gp_Pnt myVertexXYZ; + TopoDS_Shape myShape; + double myTol; + }; + void clearClassifiers(); + bool getNodeIsOut( const SMDS_MeshNode* n, bool& isOut ); + void setNodeIsOut( const SMDS_MeshNode* n, bool isOut ); + + std::vector< TClassifier* > myClassifiers; + SMDSAbs_ElementType myType; + TopoDS_Shape myShape; + double myToler; + bool myAllNodesFlag; + + TMeshModifTracer myMeshModifTracer; + std::vector myNodeIsChecked; + std::vector myNodeIsOut; }; typedef boost::shared_ptr ElementsOnShapePtr; + /* + Class : BelongToGeom + Description : Predicate for verifying whether entiy belong to + specified geometrical support + */ + class SMESHCONTROLS_EXPORT BelongToGeom: public virtual Predicate + { + public: + BelongToGeom(); + + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual void SetGeom( const TopoDS_Shape& theShape ); + + virtual bool IsSatisfy( long theElementId ); + + virtual void SetType( SMDSAbs_ElementType theType ); + virtual SMDSAbs_ElementType GetType() const; + + TopoDS_Shape GetShape(); + const SMESHDS_Mesh* GetMeshDS() const; + + void SetTolerance( double ); + double GetTolerance(); + + private: + virtual void init(); + + TopoDS_Shape myShape; + const SMESHDS_Mesh* myMeshDS; + SMDSAbs_ElementType myType; + bool myIsSubshape; + double myTolerance; // only if myIsSubshape == false + Controls::ElementsOnShapePtr myElementsOnShapePtr; // only if myIsSubshape == false + }; + typedef boost::shared_ptr BelongToGeomPtr; + + /* + Class : LyingOnGeom + Description : Predicate for verifying whether entiy lying or partially lying on + specified geometrical support + */ + class SMESHCONTROLS_EXPORT LyingOnGeom: public virtual Predicate + { + public: + LyingOnGeom(); + + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual void SetGeom( const TopoDS_Shape& theShape ); + + virtual bool IsSatisfy( long theElementId ); + + virtual void SetType( SMDSAbs_ElementType theType ); + virtual SMDSAbs_ElementType GetType() const; + + TopoDS_Shape GetShape(); + const SMESHDS_Mesh* GetMeshDS() const; + + void SetTolerance( double ); + double GetTolerance(); + + virtual bool Contains( const SMESHDS_Mesh* theMeshDS, + const TopoDS_Shape& theShape, + const SMDS_MeshElement* theElem, + TopAbs_ShapeEnum theFindShapeEnum, + TopAbs_ShapeEnum theAvoidShapeEnum = TopAbs_SHAPE ); + private: + virtual void init(); + + TopoDS_Shape myShape; + TColStd_MapOfInteger mySubShapesIDs; + const SMESHDS_Mesh* myMeshDS; + SMDSAbs_ElementType myType; + bool myIsSubshape; + double myTolerance; // only if myIsSubshape == false + Controls::ElementsOnShapePtr myElementsOnShapePtr; // only if myIsSubshape == false + }; + typedef boost::shared_ptr LyingOnGeomPtr; + /* Class : FreeFaces Description : Predicate for free faces @@ -759,12 +1053,12 @@ namespace SMESH{ class SMESHCONTROLS_EXPORT ElemGeomType: public virtual Predicate{ public: ElemGeomType(); - virtual void SetMesh( const SMDS_Mesh* theMesh ); - virtual bool IsSatisfy( long theElementId ); - void SetType( SMDSAbs_ElementType theType ); - virtual SMDSAbs_ElementType GetType() const; - void SetGeomType( SMDSAbs_GeometryType theType ); - virtual SMDSAbs_GeometryType GetGeomType() const; + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual bool IsSatisfy( long theElementId ); + void SetType( SMDSAbs_ElementType theType ); + virtual SMDSAbs_ElementType GetType() const; + void SetGeomType( SMDSAbs_GeometryType theType ); + SMDSAbs_GeometryType GetGeomType() const; private: const SMDS_Mesh* myMesh; @@ -773,10 +1067,68 @@ namespace SMESH{ }; typedef boost::shared_ptr ElemGeomTypePtr; + /* + Class : CoplanarFaces + Description : Predicate to check angle between faces + */ + class SMESHCONTROLS_EXPORT CoplanarFaces: public virtual Predicate + { + public: + CoplanarFaces(); + void SetFace( long theID ) { myFaceID = theID; } + long GetFace() const { return myFaceID; } + void SetTolerance (const double theToler) { myToler = theToler; } + double GetTolerance () const { return myToler; } + virtual SMDSAbs_ElementType GetType() const { return SMDSAbs_Face; } + + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual bool IsSatisfy( long theElementId ); + + private: + TMeshModifTracer myMeshModifTracer; + long myFaceID; + double myToler; + std::set< long > myCoplanarIDs; + }; + typedef boost::shared_ptr CoplanarFacesPtr; + + /* + Class : ConnectedElements + Description : Predicate to get elements of one domain + */ + class SMESHCONTROLS_EXPORT ConnectedElements: public virtual Predicate + { + public: + ConnectedElements(); + void SetNode( int nodeID ); + void SetPoint( double x, double y, double z ); + int GetNode() const; + std::vector GetPoint() const; + + void SetType( SMDSAbs_ElementType theType ); + virtual SMDSAbs_ElementType GetType() const; + + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual bool IsSatisfy( long theElementId ); + + //const std::set& GetDomainIDs() const { return myOkIDs; } + + private: + int myNodeID; + std::vector myXYZ; + SMDSAbs_ElementType myType; + TMeshModifTracer myMeshModifTracer; + + void clearOkIDs(); + bool myOkIDsReady; + std::set< int > myOkIDs; // empty means that there is one domain + }; + typedef boost::shared_ptr ConnectedElementsPtr; + /* FILTER */ - class SMESHCONTROLS_EXPORT Filter{ + class SMESHCONTROLS_EXPORT Filter { public: Filter(); virtual ~Filter(); @@ -787,13 +1139,13 @@ namespace SMESH{ virtual void GetElementsId( const SMDS_Mesh* theMesh, - TIdSequence& theSequence ); + TIdSequence& theSequence ); static void GetElementsId( const SMDS_Mesh* theMesh, - PredicatePtr thePredicate, - TIdSequence& theSequence ); + PredicatePtr thePredicate, + TIdSequence& theSequence ); protected: PredicatePtr myPredicate; diff --git a/src/3rdParty/salomesmesh/inc/SMESH_DriverDAT.hxx b/src/3rdParty/salomesmesh/inc/SMESH_DriverDAT.hxx index 9020c6fc1b7e..a0efc29173b8 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_DriverDAT.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_DriverDAT.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : SMESH_DriverDAT.hxx // Author : Alexander A. BORODIN // Module : SMESH @@ -26,8 +27,8 @@ #ifndef _SMESH_DriverDAT_HXX_ #define _SMESH_DriverDAT_HXX_ -#ifdef WNT - #if defined MESHDRIVERDAT_EXPORTS +#ifdef WIN32 + #if defined MESHDRIVERDAT_EXPORTS || defined MeshDriverDAT_EXPORTS #define MESHDRIVERDAT_EXPORT __declspec( dllexport ) #else #define MESHDRIVERDAT_EXPORT __declspec( dllimport ) diff --git a/src/3rdParty/salomesmesh/inc/SMESH_DriverGMF.hxx b/src/3rdParty/salomesmesh/inc/SMESH_DriverGMF.hxx new file mode 100755 index 000000000000..b11a9c76e8f7 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMESH_DriverGMF.hxx @@ -0,0 +1,40 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SMESH_DriverGMF.hxx +// Author : Alexander A. BORODIN +// Module : SMESH +// +#ifndef _SMESH_DriverGMF_HXX_ +#define _SMESH_DriverGMF_HXX_ + +#ifdef WIN32 + #if defined MESHDriverGMF_EXPORTS || defined MeshDriverGMF_EXPORTS + #define MESHDriverGMF_EXPORT __declspec( dllexport ) + #else + #define MESHDriverGMF_EXPORT __declspec( dllimport ) + #endif +#else + #define MESHDriverGMF_EXPORT +#endif + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_DriverMED.hxx b/src/3rdParty/salomesmesh/inc/SMESH_DriverMED.hxx new file mode 100755 index 000000000000..b53c5821b103 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMESH_DriverMED.hxx @@ -0,0 +1,40 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SMESH_DriverMED.hxx +// Author : Alexander A. BORODIN +// Module : SMESH +// +#ifndef _SMESH_DriverMED_HXX_ +#define _SMESH_DriverMED_HXX_ + +#ifdef WIN32 + #if defined MESHDRIVERMED_EXPORTS || defined MeshDriverMED_EXPORTS + #define MESHDRIVERMED_EXPORT __declspec( dllexport ) + #else + #define MESHDRIVERMED_EXPORT __declspec( dllimport ) + #endif +#else + #define MESHDRIVERMED_EXPORT +#endif + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_DriverSTL.hxx b/src/3rdParty/salomesmesh/inc/SMESH_DriverSTL.hxx index 4246d18adb2e..b3f533b20bf9 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_DriverSTL.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_DriverSTL.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : SMESH_DriverSTL.hxx // Author : Alexander A. BORODIN // Module : SMESH @@ -26,8 +27,8 @@ #ifndef _SMESH_DriverSTL_HXX_ #define _SMESH_DriverSTL_HXX_ -#ifdef WNT - #if defined MESHDRIVERSTL_EXPORTS +#ifdef WIN32 + #if defined MESHDRIVERSTL_EXPORTS || defined MeshDriverSTL_EXPORTS #define MESHDRIVERSTL_EXPORT __declspec( dllexport ) #else #define MESHDRIVERSTL_EXPORT __declspec( dllimport ) diff --git a/src/3rdParty/salomesmesh/inc/SMESH_DriverUNV.hxx b/src/3rdParty/salomesmesh/inc/SMESH_DriverUNV.hxx index 106b6e93903d..9f9ef953635a 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_DriverUNV.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_DriverUNV.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : SMESH_DriverUNV.hxx // Author : Alexander A. BORODIN // Module : SMESH @@ -26,8 +27,8 @@ #ifndef _SMESH_DriverUNV_HXX_ #define _SMESH_DriverUNV_HXX_ -#ifdef WNT - #if defined MESHDRIVERUNV_EXPORTS +#ifdef WIN32 + #if defined MESHDRIVERUNV_EXPORTS || defined MeshDriverUNV_EXPORTS #define MESHDRIVERUNV_EXPORT __declspec( dllexport ) #else #define MESHDRIVERUNV_EXPORT __declspec( dllimport ) diff --git a/src/3rdParty/salomesmesh/inc/SMESH_File.hxx b/src/3rdParty/salomesmesh/inc/SMESH_File.hxx new file mode 100644 index 000000000000..cf36b652b680 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMESH_File.hxx @@ -0,0 +1,124 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 : SMESH_File.hxx +// Created : Wed Mar 10 10:33:04 2010 +// Author : Edward AGAPOV (eap) +// +#ifndef __SMESH_File_HXX__ +#define __SMESH_File_HXX__ + +#include "SMESH_Utils.hxx" + +#include +#include + +#ifdef WIN32 +#include +#else +#include +#endif + +/*! + * \brief High level util for effective file reading and other file operations + */ +class SMESHUtils_EXPORT SMESH_File +{ +public: + + SMESH_File(const std::string& name, bool openForReading=true); + + ~SMESH_File(); + + std::string getName() const { return _name; } + + const std::string& error() const { return _error; } + + void close(); + + bool remove(); + + long size(); + + bool exists(); + + bool isDirectory(); + + // ------------------------ + // Access to file contents + // ------------------------ + + bool open(); // for reading + + operator const char*() const { return _pos; } + + bool operator++() { return ++_pos < _end; } + + void operator +=(int posDelta) { _pos+=posDelta; } + + bool eof() const { return _pos >= _end; } + + const char* end() const { return _end; } + + const char* getPos() const { return _pos; } + + void setPos(const char* pos); + + std::string getLine(); + + void rewind(); + + bool getInts(std::vector& ids); + + // ------------------------ + // Writting a binary file + // ------------------------ + + bool openForWriting(); // binary writing only + + template + bool write( const T* values, size_t nbTValues ) + { + return writeRaw((const void*) values, nbTValues * sizeof(T)); + } + + template + bool write( const T& value ) + { + return writeRaw((const void*) & value, sizeof(T)); + } + + bool writeRaw(const void* data, size_t size); + +private: + + std::string _name; //!< file name + int _size; //!< file size + std::string _error; +#ifdef WIN32 + HANDLE _file, _mapObj; +#else + int _file; +#endif + void* _map; + const char* _pos; //!< current position + const char* _end; //!< position after file end +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_Gen.hxx b/src/3rdParty/salomesmesh/inc/SMESH_Gen.hxx index 093d0714ca90..eb09db52b466 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_Gen.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_Gen.hxx @@ -1,50 +1,48 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : SMESH_Gen.hxx // Author : Paul RASCLE, EDF // Module : SMESH // - #ifndef _SMESH_GEN_HXX_ #define _SMESH_GEN_HXX_ #include "SMESH_SMESH.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" #include "SMESH_Hypothesis.hxx" #include "SMESH_ComputeError.hxx" #include "SMESH_Algo.hxx" -#include "SMESH_0D_Algo.hxx" -#include "SMESH_1D_Algo.hxx" -#include "SMESH_2D_Algo.hxx" -#include "SMESH_3D_Algo.hxx" #include "SMESH_Mesh.hxx" #include #include #include +#include +#include class SMESHDS_Document; @@ -61,15 +59,17 @@ typedef std::set TSetOfInt; class SMESH_EXPORT SMESH_Gen { - public: +public: SMESH_Gen(); ~SMESH_Gen(); SMESH_Mesh* CreateMesh(int theStudyId, bool theIsEmbeddedMode) - throw(SMESH_Exception); + throw(SALOME_Exception); /*! * \brief Computes aMesh on aShape + * \param aShapeOnly - if true, algo->OnlyUnaryInput() feature is ignored and + * only \a aShape is computed. * \param anUpward - compute from vertices up to more complex shape (internal usage) * \param aDim - upper level dimension of the mesh computation * \param aShapesId - list of shapes with computed mesh entities (elements or nodes) @@ -77,9 +77,30 @@ class SMESH_EXPORT SMESH_Gen */ bool Compute(::SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + const bool aShapeOnly=false, const bool anUpward=false, - const ::MeshDimension aDim=::MeshDim_3D, - TSetOfInt* aShapesId=0); + const ::MeshDimension aDim=::MeshDim_3D, + TSetOfInt* aShapesId=0); + + void PrepareCompute(::SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape); + void CancelCompute(::SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape); + + const SMESH_subMesh* GetCurrentSubMesh() const; + + /*! + * \brief evaluates size of prospective mesh on a shape + * \param aMesh - the mesh + * \param aShape - the shape + * \param aResMap - map for prospective numbers of elements + * \retval bool - is a success + */ + bool Evaluate(::SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap, + const bool anUpward=false, + TSetOfInt* aShapesId=0); bool CheckAlgoState(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); // notify on bad state of attached algos, return false @@ -96,7 +117,7 @@ class SMESH_EXPORT SMESH_Gen */ void SetDefaultNbSegments(int nb) { _nbSegments = nb; } int GetDefaultNbSegments() const { return _nbSegments; } - + struct TAlgoStateError { TAlgoStateErrorName _name; @@ -104,7 +125,7 @@ class SMESH_EXPORT SMESH_Gen int _algoDim; bool _isGlobalAlgo; - TAlgoStateError(): _name(SMESH_Hypothesis::HYP_OK),_algo(0),_algoDim(0) {} + TAlgoStateError(): _algoDim(0),_algo(0),_name(SMESH_Hypothesis::HYP_OK) {} void Set(TAlgoStateErrorName name, const SMESH_Algo* algo, bool isGlobal) { _name = name; _algo = algo; _algoDim = algo->GetDim(); _isGlobalAlgo = isGlobal; } void Set(TAlgoStateErrorName name, const int algoDim, bool isGlobal) @@ -122,30 +143,25 @@ class SMESH_EXPORT SMESH_Gen static int GetShapeDim(const TopAbs_ShapeEnum & aShapeType); static int GetShapeDim(const TopoDS_Shape & aShape) { return GetShapeDim( aShape.ShapeType() ); } - SMESH_Algo* GetAlgo(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, TopoDS_Shape* assignedTo=0); - static bool IsGlobalHypothesis(const SMESH_Hypothesis* theHyp, SMESH_Mesh& aMesh); - // inherited methods from SALOMEDS::Driver + SMESH_Algo* GetAlgo(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, TopoDS_Shape* assignedTo=0); + SMESH_Algo* GetAlgo(SMESH_subMesh * aSubMesh, TopoDS_Shape* assignedTo=0); -// void Save(int studyId, const char *aUrlOfFile); -// void Load(int studyId, const char *aUrlOfFile); -// void Close(int studyId); -// const char *ComponentDataType(); + static bool IsGlobalHypothesis(const SMESH_Hypothesis* theHyp, SMESH_Mesh& aMesh); -// const char *IORToLocalPersistentID(const char *IORString, bool & IsAFile); -// const char *LocalPersistentIDToIOR(const char *aLocalPersistentID); + static std::vector< std::string > GetPluginXMLPaths(); int GetANewId(); - std::map < int, SMESH_Algo * >_mapAlgo; - std::map < int, SMESH_0D_Algo * >_map0D_Algo; - std::map < int, SMESH_1D_Algo * >_map1D_Algo; - std::map < int, SMESH_2D_Algo * >_map2D_Algo; - std::map < int, SMESH_3D_Algo * >_map3D_Algo; + // std::map < int, SMESH_Algo * >_mapAlgo; + // std::map < int, SMESH_0D_Algo * >_map0D_Algo; + // std::map < int, SMESH_1D_Algo * >_map1D_Algo; + // std::map < int, SMESH_2D_Algo * >_map2D_Algo; + // std::map < int, SMESH_3D_Algo * >_map3D_Algo; - private: +private: - int _localId; // unique Id of created objects, within SMESH_Gen entity + int _localId; // unique Id of created objects, within SMESH_Gen entity std::map < int, StudyContextStruct * >_mapStudyContext; // hypotheses managing @@ -154,8 +170,14 @@ class SMESH_EXPORT SMESH_Gen // number of segments per diagonal of boundary box of geometry by which // default segment length of appropriate 1D hypotheses is defined int _segmentation; - // default of segments + // default number of segments int _nbSegments; + + void setCurrentSubMesh(SMESH_subMesh* sm); + void resetCurrentSubMesh(); + + volatile bool _compute_canceled; + std::list< SMESH_subMesh* > _sm_current; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_Group.hxx b/src/3rdParty/salomesmesh/inc/SMESH_Group.hxx index 80a8276a9143..1dd657ed56b2 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_Group.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_Group.hxx @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : SMESH_Group.hxx // Author : Michael Sazonov (OCC) // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESH/SMESH_Group.hxx,v 1.8.2.1 2008/11/27 12:25:15 abd Exp $ // #ifndef _SMESH_Group_HeaderFile #define _SMESH_Group_HeaderFile @@ -31,6 +31,7 @@ #include "SMESH_SMESH.hxx" #include "SMDSAbs_ElementType.hxx" +#include "SMESH_Controls.hxx" #include #include @@ -46,10 +47,12 @@ class SMESH_EXPORT SMESH_Group const SMESH_Mesh* theMesh, const SMDSAbs_ElementType theType, const char* theName, - const TopoDS_Shape& theShape = TopoDS_Shape()); + const TopoDS_Shape& theShape = TopoDS_Shape(), + const SMESH_PredicatePtr& thePredicate = SMESH_PredicatePtr()); + SMESH_Group (SMESHDS_GroupBase* groupDS); ~SMESH_Group (); - void SetName (const char* theName) { myName = theName; } + void SetName (const char* theName); const char* GetName () const { return myName.c_str(); } diff --git a/src/3rdParty/salomesmesh/inc/SMESH_HypoFilter.hxx b/src/3rdParty/salomesmesh/inc/SMESH_HypoFilter.hxx index 801a46252aa9..e971dfae4bb0 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_HypoFilter.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_HypoFilter.hxx @@ -1,28 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : SMESH_HypoFilter.hxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESH/SMESH_HypoFilter.hxx,v 1.6.2.2 2008/11/27 12:25:15 abd Exp $ // #ifndef SMESH_HypoFilter_HeaderFile #define SMESH_HypoFilter_HeaderFile @@ -36,9 +36,11 @@ #include #include #include +#include class SMESH_HypoFilter; class SMESH_Hypothesis; +class SMESH_Mesh; class SMESH_EXPORT SMESH_HypoPredicate { public: @@ -57,9 +59,9 @@ class SMESH_EXPORT SMESH_HypoFilter: public SMESH_HypoPredicate // Create and add predicates. // Added predicates will be destroyed by filter when it dies SMESH_HypoFilter(); - SMESH_HypoFilter( SMESH_HypoPredicate* aPredicate, bool notNagate = true ); - // notNagate==false means !aPredicate->IsOk() - SMESH_HypoFilter & Init ( SMESH_HypoPredicate* aPredicate, bool notNagate = true ); + explicit SMESH_HypoFilter( SMESH_HypoPredicate* aPredicate, bool notNegate = true ); + // notNegate==false means !aPredicate->IsOk() + SMESH_HypoFilter & Init ( SMESH_HypoPredicate* aPredicate, bool notNegate = true ); SMESH_HypoFilter & And ( SMESH_HypoPredicate* aPredicate ); SMESH_HypoFilter & AndNot( SMESH_HypoPredicate* aPredicate ); SMESH_HypoFilter & Or ( SMESH_HypoPredicate* aPredicate ); @@ -72,11 +74,14 @@ class SMESH_EXPORT SMESH_HypoFilter: public SMESH_HypoPredicate static SMESH_HypoPredicate* IsAssignedTo(const TopoDS_Shape& theShape); static SMESH_HypoPredicate* Is(const SMESH_Hypothesis* theHypo); static SMESH_HypoPredicate* IsGlobal(const TopoDS_Shape& theMainShape); - static SMESH_HypoPredicate* IsMoreLocalThan(const TopoDS_Shape& theShape); + static SMESH_HypoPredicate* IsMoreLocalThan(const TopoDS_Shape& theShape, + const SMESH_Mesh& theMesh); static SMESH_HypoPredicate* HasName(const std::string & theName); static SMESH_HypoPredicate* HasDim(const int theDim); static SMESH_HypoPredicate* HasType(const int theHypType); + bool IsEmpty() const { return myNbPredicates == 0; } + /*! * \brief check aHyp or/and aShape it is assigned to */ @@ -85,7 +90,7 @@ class SMESH_EXPORT SMESH_HypoFilter: public SMESH_HypoPredicate /*! * \brief return true if contains no predicates */ - bool IsAny() const { return myPredicates.empty(); } + bool IsAny() const { return myNbPredicates > 0; } ~SMESH_HypoFilter(); @@ -93,20 +98,22 @@ class SMESH_EXPORT SMESH_HypoFilter: public SMESH_HypoPredicate protected: // fields - std::list myPredicates; + //std::list myPredicates; + SMESH_HypoPredicate* myPredicates[100]; + int myNbPredicates; // private methods - public: + enum Logical { AND, AND_NOT, OR, OR_NOT }; enum Comparison { EQUAL, NOT_EQUAL, MORE, LESS }; - protected: + SMESH_HypoFilter(const SMESH_HypoFilter& other){} void add( Logical bool_op, SMESH_HypoPredicate* pred ) { if ( pred ) { pred->_logical_op = bool_op; - myPredicates.push_back( pred ); + myPredicates[ myNbPredicates++ ] = pred; } } @@ -167,10 +174,15 @@ class SMESH_EXPORT SMESH_HypoFilter: public SMESH_HypoPredicate }; struct IsMoreLocalThanPredicate : public SMESH_HypoPredicate { - TopAbs_ShapeEnum _shapeType; - IsMoreLocalThanPredicate( const TopoDS_Shape& shape ):_shapeType(shape.ShapeType()){} + TopoDS_Shape _shape; + const SMESH_Mesh& _mesh; + TopTools_MapOfShape _preferableShapes; + IsMoreLocalThanPredicate( const TopoDS_Shape& shape, + const SMESH_Mesh& mesh ) + :_shape(shape),_mesh(mesh) { findPreferable(); } bool IsOk(const SMESH_Hypothesis* aHyp, const TopoDS_Shape& aShape) const; + void findPreferable(); }; struct IsAuxiliaryPredicate : public SMESH_HypoPredicate { diff --git a/src/3rdParty/salomesmesh/inc/SMESH_Hypothesis.hxx b/src/3rdParty/salomesmesh/inc/SMESH_Hypothesis.hxx index 55ed9dd5fb2f..49ed80945a1c 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_Hypothesis.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_Hypothesis.hxx @@ -1,30 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : SMESH_Hypothesis.hxx // Author : Paul RASCLE, EDF // Module : SMESH // - #ifndef _SMESH_HYPOTHESIS_HXX_ #define _SMESH_HYPOTHESIS_HXX_ @@ -51,7 +51,7 @@ public: { HYP_OK = 0, HYP_MISSING, // algo misses a hypothesis - HYP_CONCURENT, // several applicable hypotheses + HYP_CONCURENT, // several applicable hypotheses assigned to father shapes HYP_BAD_PARAMETER,// hypothesis has a bad parameter value HYP_HIDDEN_ALGO, // an algo is hidden by an upper dim algo generating all-dim elements HYP_HIDING_ALGO, // an algo hides lower dim algos by generating all-dim elements @@ -59,11 +59,12 @@ public: // for Add/RemoveHypothesis operations HYP_INCOMPATIBLE, // hypothesis does not fit algo HYP_NOTCONFORM, // not conform mesh is produced appling a hypothesis - HYP_ALREADY_EXIST,// such hypothesis already exist + HYP_ALREADY_EXIST,// several applicable hypothesis of same priority assigned HYP_BAD_DIM, // bad dimension - HYP_BAD_SUBSHAPE, // shape is neither the main one, nor its subshape, nor a group + HYP_BAD_SUBSHAPE, // shape is neither the main one, nor its sub-shape, nor a group HYP_BAD_GEOMETRY, // shape geometry mismatches algorithm's expectation - HYP_NEED_SHAPE // algorithm can work on shape only + HYP_NEED_SHAPE, // algorithm can work on shape only + HYP_INCOMPAT_HYPS // several additional hypotheses are incompatible one with other }; static bool IsStatusFatal(Hypothesis_Status theStatus) { return theStatus >= HYP_UNKNOWN_FATAL; } @@ -71,19 +72,27 @@ public: SMESH_Hypothesis(int hypId, int studyId, SMESH_Gen* gen); virtual ~SMESH_Hypothesis(); virtual int GetDim() const; - int GetStudyId() const; - virtual void NotifySubMeshesHypothesisModification(); + int GetStudyId() const; + SMESH_Gen* GetGen() const { return (SMESH_Gen*) _gen; } virtual int GetShapeType() const; virtual const char* GetLibName() const; + virtual void NotifySubMeshesHypothesisModification(); void SetLibName(const char* theLibName); + /*! + * \brief The returned value is used by NotifySubMeshesHypothesisModification() + * to decide to call subMesh->AlgoStateEngine( MODIF_HYP, hyp ) or not + * if subMesh is ready to be computed (algo+hyp==OK) but not yet computed. + * True result is reasonable for example if EventListeners depend on + * parameters of hypothesis. + */ + virtual bool DataDependOnParams() const { return false; } void SetParameters(const char *theParameters); char* GetParameters() const; void SetLastParameters(const char* theParameters); char* GetLastParameters() const; void ClearParameters(); - /*! * \brief Initialize my parameter values by the mesh built on the geometry * \param theMesh - the built mesh @@ -94,8 +103,9 @@ public: struct TDefaults { - double _elemLength; - int _nbSegments; + double _elemLength; + int _nbSegments; + TopoDS_Shape* _shape; // future shape of the mesh being created }; /*! * \brief Initialize my parameter values by default parameters. @@ -114,14 +124,19 @@ public: virtual bool IsAuxiliary() const { return GetType() == PARAM_ALGO && _param_algo_dim < 0; } + /*! + * \brief Find a mesh with given persistent ID + */ + SMESH_Mesh* GetMeshByPersistentID(int id); + protected: SMESH_Gen* _gen; - int _studyId; - int _shapeType; - int _param_algo_dim; + int _studyId; + int _shapeType; + int _param_algo_dim; // to be set at descendant hypothesis constructor private: - std::string _libName; + std::string _libName; // name of library of plug-in Engine std::string _parameters; std::string _lastParameters; }; diff --git a/src/3rdParty/salomesmesh/inc/SMESH_MAT2d.hxx b/src/3rdParty/salomesmesh/inc/SMESH_MAT2d.hxx new file mode 100644 index 000000000000..618608e07e73 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMESH_MAT2d.hxx @@ -0,0 +1,238 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SMESH_MAT2d.hxx +// Created : Thu May 28 17:49:53 2015 +// Author : Edward AGAPOV (eap) + +#ifndef __SMESH_MAT2d_HXX__ +#define __SMESH_MAT2d_HXX__ + +#include "SMESH_Utils.hxx" + +#include +#include + +#include +#include + +#include +#include + +class Adaptor3d_Curve; + +// Medial Axis Transform 2D +namespace SMESH_MAT2d +{ + class MedialAxis; // MedialAxis is the entry point + class Branch; + class BranchEnd; + class Boundary; + struct BoundaryPoint; + + typedef boost::polygon::voronoi_diagram TVD; + typedef TVD::cell_type TVDCell; + typedef TVD::edge_type TVDEdge; + typedef TVD::vertex_type TVDVertex; + + //------------------------------------------------------------------------------------- + // type of Branch end point + enum BranchEndType { BE_UNDEF, + BE_ON_VERTEX, // branch ends at a convex VRTEX + BE_BRANCH_POINT, // branch meats 2 or more other branches + BE_END // branch end equidistant from several adjacent segments + }; + //------------------------------------------------------------------------------------- + /*! + * \brief End point of MA Branch + */ + struct SMESHUtils_EXPORT BranchEnd + { + const TVDVertex* _vertex; + BranchEndType _type; + std::vector< const Branch* > _branches; + + BranchEnd(): _vertex(0), _type( BE_UNDEF ) {} + }; + //------------------------------------------------------------------------------------- + /*! + * \brief Point on MA Branch + */ + struct SMESHUtils_EXPORT BranchPoint + { + const Branch* _branch; + std::size_t _iEdge; // MA edge index within the branch + double _edgeParam; // normalized param within the MA edge + + BranchPoint( const Branch* b = 0, std::size_t e = 0, double u = -1 ): + _branch(b), _iEdge(e), _edgeParam(u) {} + }; + //------------------------------------------------------------------------------------- + /*! + * \brief Branch is a set of MA edges enclosed between branch points and/or MA ends. + * It's main feature is to return two BoundaryPoint's per a point on it. + * Points on a Branch are defined by [0,1] parameter + */ + class SMESHUtils_EXPORT Branch + { + public: + bool getBoundaryPoints(double param, BoundaryPoint& bp1, BoundaryPoint& bp2 ) const; + bool getBoundaryPoints(std::size_t iMAEdge, double maEdgeParam, + BoundaryPoint& bp1, BoundaryPoint& bp2 ) const; + bool getBoundaryPoints(const BranchPoint& p, + BoundaryPoint& bp1, BoundaryPoint& bp2 ) const; + bool getParameter(const BranchPoint& p, double & u ) const; + + std::size_t nbEdges() const { return _maEdges.size(); } + + const BranchEnd* getEnd(bool the2nd) const { return & ( the2nd ? _endPoint2 : _endPoint1 ); } + + bool hasEndOfType(BranchEndType type) const; + + void getPoints( std::vector< gp_XY >& points, const double scale[2]) const; + + void getGeomEdges( std::vector< std::size_t >& edgeIDs1, + std::vector< std::size_t >& edgeIDs2 ) const; + + void getOppositeGeomEdges( std::vector< std::size_t >& edgeIDs1, + std::vector< std::size_t >& edgeIDs2, + std::vector< BranchPoint >& divPoints) const; + + bool isRemoved() const { return _proxyPoint._branch; } + + public: // internal: construction + + void init( std::vector& maEdges, + const Boundary* boundary, + std::map< const TVDVertex*, BranchEndType > endType); + void setBranchesToEnds( const std::vector< Branch >& branches); + BranchPoint getPoint( const TVDVertex* vertex ) const; + void setRemoved( const BranchPoint& proxyPoint ); + + static void setGeomEdge ( std::size_t geomIndex, const TVDEdge* maEdge ); + static std::size_t getGeomEdge ( const TVDEdge* maEdge ); + static void setBndSegment( std::size_t segIndex, const TVDEdge* maEdge ); + static std::size_t getBndSegment( const TVDEdge* maEdge ); + + private: + + bool addDivPntForConcaVertex( std::vector< std::size_t >& edgeIDs1, + std::vector< std::size_t >& edgeIDs2, + std::vector< BranchPoint >& divPoints, + const std::vector& maEdges, + const std::vector& maEdgesTwin, + int & i) const; + + // association of _maEdges with boundary segments is stored in this way: + // index of an EDGE: TVDEdge->cell()->color() + // index of a segment on EDGE: TVDEdge->color() + std::vector _maEdges; // MA edges ending at points located at _params + std::vector _params; // params of points on MA, normalized [0;1] within this branch + const Boundary* _boundary; // face boundary + BranchEnd _endPoint1; + BranchEnd _endPoint2; + BranchPoint _proxyPoint; + }; + + //------------------------------------------------------------------------------------- + /*! + * \brief Data of a discretized EDGE allowing to get a point on MA by a parameter on EDGE + */ + struct BndPoints + { + std::vector< double > _params; // params of discretization points on an EDGE + std::vector< std::pair< const Branch*, int > > _maEdges; /* index of TVDEdge in branch; + index sign means orientation; + index == Branch->nbEdges() means + end point of a Branch */ + }; + //------------------------------------------------------------------------------------- + /*! + * \brief Face boundary is discretized so that each its segment to correspond to + * an edge of MA + */ + class SMESHUtils_EXPORT Boundary + { + public: + + Boundary( std::size_t nbEdges ): _pointsPerEdge( nbEdges ) {} + BndPoints& getPoints( std::size_t iEdge ) { return _pointsPerEdge[ iEdge ]; } + std::size_t nbEdges() const { return _pointsPerEdge.size(); } + + bool getPoint( std::size_t iEdge, std::size_t iSeg, double u, BoundaryPoint& bp ) const; + + bool getBranchPoint( const std::size_t iEdge, double u, BranchPoint& p ) const; + + bool getBranchPoint( const BoundaryPoint& bp, BranchPoint& p ) const; + + bool isConcaveSegment( std::size_t iEdge, std::size_t iSeg ) const; + + bool moveToClosestEdgeEnd( BoundaryPoint& bp ) const; + + private: + std::vector< BndPoints > _pointsPerEdge; + }; + + //------------------------------------------------------------------------------------- + /*! + * \brief Point on FACE boundary + */ + struct SMESHUtils_EXPORT BoundaryPoint + { + std::size_t _edgeIndex; // index of an EDGE in a sequence passed to MedialAxis() + double _param; // parameter of this EDGE + }; + //------------------------------------------------------------------------------------- + /*! + * \brief Medial axis (MA) is defined as the loci of centres of locally + * maximal balls inside 2D representation of a face. This class + * implements a piecewise approximation of MA. + */ + class SMESHUtils_EXPORT MedialAxis + { + public: + MedialAxis(const TopoDS_Face& face, + const std::vector< TopoDS_Edge >& edges, + const double minSegLen, + const bool ignoreCorners = false ); + std::size_t nbBranches() const { return _nbBranches; } + const Branch* getBranch(size_t i) const; + const std::vector< const BranchEnd* >& getBranchPoints() const { return _branchPnt; } + const Boundary& getBoundary() const { return _boundary; } + + void getPoints( const Branch* branch, std::vector< gp_XY >& points) const; + Adaptor3d_Curve* make3DCurve(const Branch& branch) const; + + private: + + private: + TopoDS_Face _face; + TVD _vd; + std::vector< Branch > _branch; + std::size_t _nbBranches; // removed branches ignored + std::vector< const BranchEnd* > _branchPnt; + Boundary _boundary; + double _scale[2]; + }; + +} + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_Mesh.hxx b/src/3rdParty/salomesmesh/inc/SMESH_Mesh.hxx index 629c4185df89..6a5550386144 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_Mesh.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_Mesh.hxx @@ -1,49 +1,55 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMESH : implementaion of SMESH idl descriptions + // File : SMESH_Mesh.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESH/SMESH_Mesh.hxx,v 1.18.2.3 2008/11/27 12:25:15 abd Exp $ // #ifndef _SMESH_MESH_HXX_ #define _SMESH_MESH_HXX_ #include "SMESH_SMESH.hxx" -#include "SMESH_Hypothesis.hxx" - -#include "SMESHDS_Mesh.hxx" -#include "SMESHDS_Command.hxx" #include "SMDSAbs_ElementType.hxx" +#include "SMESHDS_Command.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_ComputeError.hxx" +#include "SMESH_Controls.hxx" +#include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" #include #include #include -#include #include +#include + + +#ifdef WIN32 +#pragma warning(disable:4251) // Warning DLL Interface ... +#pragma warning(disable:4290) // Warning Exception ... +#endif class SMESH_Gen; class SMESHDS_Document; @@ -55,17 +61,20 @@ class SMESH_subMesh; class SMESH_HypoFilter; class TopoDS_Solid; +typedef std::list TListOfInt; +typedef std::list TListOfListOfInt; + class SMESH_EXPORT SMESH_Mesh { -public: - SMESH_Mesh(int theLocalId, - int theStudyId, - SMESH_Gen* theGen, - bool theIsEmbeddedMode, - SMESHDS_Document* theDocument); - + public: + SMESH_Mesh(int theLocalId, + int theStudyId, + SMESH_Gen* theGen, + bool theIsEmbeddedMode, + SMESHDS_Document* theDocument); + virtual ~SMESH_Mesh(); - + /*! * \brief Set geometry to be meshed */ @@ -78,7 +87,7 @@ public: * \brief Return true if there is a geometry to be meshed, not PseudoShape() */ bool HasShapeToMesh() const { return _isShapeToMesh; } - /*! + /*! * \brief Return diagonal size of bounding box of shape to mesh. */ double GetShapeDiagonalSize() const; @@ -92,37 +101,46 @@ public: */ static const TopoDS_Solid& PseudoShape(); + /*! + * \brief Load mesh from study file + */ + void Load(); /*! * \brief Remove all nodes and elements */ void Clear(); - - /*! + /*! * \brief Remove all nodes and elements of indicated shape */ void ClearSubMesh(const int theShapeId); - int UNVToMesh(const char* theFileName); /*! * consult DriverMED_R_SMESHDS_Mesh::ReadStatus for returned value */ + int UNVToMesh(const char* theFileName); + int MEDToMesh(const char* theFileName, const char* theMeshName); int STLToMesh(const char* theFileName); int DATToMesh(const char* theFileName); + int CGNSToMesh(const char* theFileName, const int theMeshIndex, std::string& theMeshName); + + SMESH_ComputeErrorPtr GMFToMesh(const char* theFileName, + bool theMakeRequiredGroups = true ); + SMESH_Hypothesis::Hypothesis_Status - AddHypothesis(const TopoDS_Shape & aSubShape, int anHypId) - throw(SMESH_Exception); + AddHypothesis(const TopoDS_Shape & aSubShape, int anHypId, std::string* error=0) + throw(SALOME_Exception); SMESH_Hypothesis::Hypothesis_Status RemoveHypothesis(const TopoDS_Shape & aSubShape, int anHypId) - throw(SMESH_Exception); + throw(SALOME_Exception); const std::list & GetHypothesisList(const TopoDS_Shape & aSubShape) const - throw(SMESH_Exception); + throw(SALOME_Exception); const SMESH_Hypothesis * GetHypothesis(const TopoDS_Shape & aSubShape, const SMESH_HypoFilter& aFilter, @@ -131,44 +149,64 @@ public: int GetHypotheses(const TopoDS_Shape & aSubShape, const SMESH_HypoFilter& aFilter, - std::list & aHypList, - const bool andAncestors) const; + std::list< const SMESHDS_Hypothesis * >& aHypList, + const bool andAncestors, + std::list< TopoDS_Shape > * assignedTo=0) const; + + const SMESH_Hypothesis * GetHypothesis(const SMESH_subMesh * aSubMesh, + const SMESH_HypoFilter& aFilter, + const bool andAncestors, + TopoDS_Shape* assignedTo=0) const; + + int GetHypotheses(const SMESH_subMesh * aSubMesh, + const SMESH_HypoFilter& aFilter, + std::list< const SMESHDS_Hypothesis * >& aHypList, + const bool andAncestors, + std::list< TopoDS_Shape > * assignedTo=0) const; + + SMESH_Hypothesis * GetHypothesis(const int aHypID) const; - const std::list & GetLog() throw(SMESH_Exception); + const std::list & GetLog() throw(SALOME_Exception); - void ClearLog() throw(SMESH_Exception); + void ClearLog() throw(SALOME_Exception); - int GetId() { return _id; } + int GetId() const { return _id; } + bool MeshExists( int meshId ) const; + + SMESH_Mesh* FindMesh( int meshId ) const; + SMESHDS_Mesh * GetMeshDS() { return _myMeshDS; } + + const SMESHDS_Mesh * GetMeshDS() const { return _myMeshDS; } SMESH_Gen *GetGen() { return _gen; } - + SMESH_subMesh *GetSubMesh(const TopoDS_Shape & aSubShape) - throw(SMESH_Exception); + throw(SALOME_Exception); SMESH_subMesh *GetSubMeshContaining(const TopoDS_Shape & aSubShape) const - throw(SMESH_Exception); + throw(SALOME_Exception); SMESH_subMesh *GetSubMeshContaining(const int aShapeID) const - throw(SMESH_Exception); + throw(SALOME_Exception); /*! * \brief Return submeshes of groups containing the given subshape */ std::list GetGroupSubMeshesContaining(const TopoDS_Shape & shape) const - throw(SMESH_Exception); + throw(SALOME_Exception); /*! * \brief Say all submeshes that theChangedHyp has been modified */ void NotifySubMeshesHypothesisModification(const SMESH_Hypothesis* theChangedHyp); - const std::list < SMESH_subMesh * >& - GetSubMeshUsingHypothesis(SMESHDS_Hypothesis * anHyp) throw(SMESH_Exception); + // const std::list < SMESH_subMesh * >& + // GetSubMeshUsingHypothesis(SMESHDS_Hypothesis * anHyp) throw(SALOME_Exception); /*! * \brief Return True if anHyp is used to mesh aSubShape */ bool IsUsedHypothesis(SMESHDS_Hypothesis * anHyp, - const SMESH_subMesh * aSubMesh); + const SMESH_subMesh * aSubMesh); /*! * \brief check if a hypothesis alowing notconform mesh is present */ @@ -181,9 +219,24 @@ public: */ const TopTools_ListOfShape& GetAncestors(const TopoDS_Shape& theSubShape) const; - void SetAutoColor(bool theAutoColor) throw(SMESH_Exception); + void SetAutoColor(bool theAutoColor) throw(SALOME_Exception); - bool GetAutoColor() throw(SMESH_Exception); + bool GetAutoColor() throw(SALOME_Exception); + + /*! + * \brief Set the flag meaning that the mesh has been edited "manually". + * It is to set to false after Clear() and to set to true by MeshEditor + */ + void SetIsModified(bool isModified); + + bool GetIsModified() const { return _isModified; } + + /*! + * \brief Return true if the mesh has been edited since a total re-compute + * and those modifications may prevent successful partial re-compute. + * As a side effect reset _isModified flag if mesh is empty + */ + bool HasModificationsToDiscard() const; /*! * \brief Return data map of descendant to ancestor shapes @@ -196,49 +249,70 @@ public: */ bool HasDuplicatedGroupNamesMED(); - void ExportMED(const char *file, - const char* theMeshName = NULL, - bool theAutoGroups = true, - int theVersion = 0) - throw(SMESH_Exception); - - void ExportDAT(const char *file) throw(SMESH_Exception); - void ExportUNV(const char *file) throw(SMESH_Exception); - void ExportSTL(const char *file, const bool isascii) throw(SMESH_Exception); - - int NbNodes() throw(SMESH_Exception); - - int NbEdges(SMDSAbs_ElementOrder order = ORDER_ANY) throw(SMESH_Exception); + void ExportMED(const char * theFile, + const char* theMeshName = NULL, + bool theAutoGroups = true, + int theVersion = 0, + const SMESHDS_Mesh* theMeshPart = 0, + bool theAutoDimension = false, + bool theAddODOnVertices = false) + throw(SALOME_Exception); + + void ExportDAT(const char * file, + const SMESHDS_Mesh* meshPart = 0) throw(SALOME_Exception); + void ExportUNV(const char * file, + const SMESHDS_Mesh* meshPart = 0) throw(SALOME_Exception); + void ExportSTL(const char * file, + const bool isascii, + const SMESHDS_Mesh* meshPart = 0) throw(SALOME_Exception); + void ExportCGNS(const char * file, + const SMESHDS_Mesh* mesh, + const char * meshName = 0); + void ExportGMF(const char * file, + const SMESHDS_Mesh* mesh, + bool withRequiredGroups = true ); + void ExportSAUV(const char *file, + const char* theMeshName = NULL, + bool theAutoGroups = true) throw(SALOME_Exception); + + double GetComputeProgress() const; + + int NbNodes() const throw(SALOME_Exception); + int Nb0DElements() const throw(SALOME_Exception); + int NbBalls() const throw(SALOME_Exception); + + int NbEdges(SMDSAbs_ElementOrder order = ORDER_ANY) const throw(SALOME_Exception); + + int NbFaces(SMDSAbs_ElementOrder order = ORDER_ANY) const throw(SALOME_Exception); + int NbTriangles(SMDSAbs_ElementOrder order = ORDER_ANY) const throw(SALOME_Exception); + int NbQuadrangles(SMDSAbs_ElementOrder order = ORDER_ANY) const throw(SALOME_Exception); + int NbBiQuadQuadrangles() const throw(SALOME_Exception); + int NbBiQuadTriangles() const throw(SALOME_Exception); + int NbPolygons(SMDSAbs_ElementOrder order = ORDER_ANY) const throw(SALOME_Exception); + + int NbVolumes(SMDSAbs_ElementOrder order = ORDER_ANY) const throw(SALOME_Exception); + int NbTetras(SMDSAbs_ElementOrder order = ORDER_ANY) const throw(SALOME_Exception); + int NbHexas(SMDSAbs_ElementOrder order = ORDER_ANY) const throw(SALOME_Exception); + int NbTriQuadraticHexas() const throw(SALOME_Exception); + int NbPyramids(SMDSAbs_ElementOrder order = ORDER_ANY) const throw(SALOME_Exception); + int NbPrisms(SMDSAbs_ElementOrder order = ORDER_ANY) const throw(SALOME_Exception); + int NbHexagonalPrisms() const throw(SALOME_Exception); + int NbPolyhedrons() const throw(SALOME_Exception); + + int NbSubMesh() const throw(SALOME_Exception); - int NbFaces(SMDSAbs_ElementOrder order = ORDER_ANY) throw(SMESH_Exception); - - int NbTriangles(SMDSAbs_ElementOrder order = ORDER_ANY) throw(SMESH_Exception); - - int NbQuadrangles(SMDSAbs_ElementOrder order = ORDER_ANY) throw(SMESH_Exception); + int NbGroup() const { return _mapGroup.size(); } - int NbPolygons() throw(SMESH_Exception); - - int NbVolumes(SMDSAbs_ElementOrder order = ORDER_ANY) throw(SMESH_Exception); - - int NbTetras(SMDSAbs_ElementOrder order = ORDER_ANY) throw(SMESH_Exception); - - int NbHexas(SMDSAbs_ElementOrder order = ORDER_ANY) throw(SMESH_Exception); - - int NbPyramids(SMDSAbs_ElementOrder order = ORDER_ANY) throw(SMESH_Exception); + int NbMeshes() const; // nb meshes in the Study - int NbPrisms(SMDSAbs_ElementOrder order = ORDER_ANY) throw(SMESH_Exception); - - int NbPolyhedrons() throw(SMESH_Exception); - - int NbSubMesh() throw(SMESH_Exception); - - int NbGroup() const { return _mapGroup.size(); } - SMESH_Group* AddGroup (const SMDSAbs_ElementType theType, - const char* theName, - int& theId, - const TopoDS_Shape& theShape=TopoDS_Shape()); - + const char* theName, + int& theId, + const TopoDS_Shape& theShape=TopoDS_Shape(), + const SMESH_PredicatePtr& thePredicate=SMESH_PredicatePtr()); + + SMESH_Group* AddGroup (SMESHDS_GroupBase* groupDS) throw(SALOME_Exception); + typedef boost::shared_ptr< SMDS_Iterator > GroupIteratorPtr; GroupIteratorPtr GetGroups() const; @@ -246,40 +320,76 @@ public: SMESH_Group* GetGroup (const int theGroupID); - void RemoveGroup (const int theGroupID); + bool RemoveGroup (const int theGroupID); SMESH_Group* ConvertToStandalone ( int theGroupID ); + struct TCallUp // callback from SMESH to SMESH_I level + { + virtual void RemoveGroup (const int theGroupID)=0; + virtual void HypothesisModified ()=0; + virtual void Load ()=0; + virtual ~TCallUp() {} + }; + void SetCallUp( TCallUp * upCaller ); + + bool SynchronizeGroups(); + + SMDSAbs_ElementType GetElementType( const int id, const bool iselem ); - // - + void ClearMeshOrder(); + void SetMeshOrder(const TListOfListOfInt& theOrder ); + const TListOfListOfInt& GetMeshOrder() const; + + // sort submeshes according to stored mesh order + bool SortByMeshOrder(std::vector& theListToSort) const; + + // return true if given order of sub-meshes is OK + bool IsOrderOK( const SMESH_subMesh* smBefore, + const SMESH_subMesh* smAfter ) const; + ostream& Dump(ostream & save); private: + + void fillAncestorsMap(const TopoDS_Shape& theShape); + void getAncestorsSubMeshes(const TopoDS_Shape& theSubShape, + std::vector< SMESH_subMesh* >& theSubMeshes) const; protected: int _id; // id given by creator (unique within the creator instance) int _studyId; - int _idDoc; // id given by SMESHDS_Document int _groupId; // id generator for group objects int _nbSubShapes; // initial nb of subshapes in the shape to mesh bool _isShapeToMesh;// set to true when a shape is given (only once) - std::list _subMeshesUsingHypothesisList; SMESHDS_Document * _myDocument; SMESHDS_Mesh * _myMeshDS; - std::map _mapSubMesh; - std::map _mapGroup; SMESH_Gen * _gen; + std::map _mapGroup; + class SubMeshHolder; + SubMeshHolder* _subMeshHolder; + bool _isAutoColor; + bool _isModified; //!< modified since last total re-compute, issue 0020693 double _shapeDiagonal; //!< diagonal size of bounding box of shape to mesh - + TopTools_IndexedDataMapOfShapeListOfShape _mapAncestors; + mutable std::vector _ancestorSubMeshes; // to speed up GetHypothes[ei]s() + + TListOfListOfInt _mySubMeshOrder; + + // Struct calling methods at CORBA API implementation level, used to + // 1) make an upper level (SMESH_I) be consistent with a lower one (SMESH) + // when group removal is invoked by hyp modification (issue 0020918) + // 2) to forget not loaded mesh data at hyp modification + TCallUp* _callUp; + protected: - SMESH_Mesh() {}; + SMESH_Mesh(); SMESH_Mesh(const SMESH_Mesh&) {}; }; diff --git a/src/3rdParty/salomesmesh/inc/SMESH_MeshAlgos.hxx b/src/3rdParty/salomesmesh/inc/SMESH_MeshAlgos.hxx new file mode 100644 index 000000000000..9b860a6ab115 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMESH_MeshAlgos.hxx @@ -0,0 +1,200 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SMESH_MeshAlgos.hxx +// Created : Tue Apr 30 18:00:36 2013 +// Author : Edward AGAPOV (eap) + +// This file holds some low level algorithms extracted from SMESH_MeshEditor +// to make them accessible from Controls package + + +#ifndef __SMESH_MeshAlgos_HXX__ +#define __SMESH_MeshAlgos_HXX__ + +#include "SMESH_Utils.hxx" + +#include "SMDSAbs_ElementType.hxx" +#include "SMDS_ElemIterator.hxx" +#include "SMESH_TypeDefs.hxx" + +#include +#include + +class gp_Pnt; +class gp_Ax1; +class SMDS_MeshNode; +class SMDS_MeshElement; +class SMDS_Mesh; + +//======================================================================= +/*! + * \brief Searcher for the node closest to a point + */ +//======================================================================= + +struct SMESHUtils_EXPORT SMESH_NodeSearcher +{ + virtual const SMDS_MeshNode* FindClosestTo( const gp_Pnt& pnt ) = 0; + virtual void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt ) = 0; + virtual int FindNearPoint(const gp_Pnt& point, + const double tolerance, + std::vector< const SMDS_MeshNode* >& foundNodes) = 0; +}; + +//======================================================================= +/*! + * \brief Searcher for elements + */ +//======================================================================= + +struct SMESHUtils_EXPORT SMESH_ElementSearcher +{ + /*! + * \brief Find elements of given type where the given point is IN or ON. + * Returns nb of found elements and elements them-selves. + * + * 'ALL' type means elements of any type excluding nodes and 0D elements + */ + virtual int FindElementsByPoint(const gp_Pnt& point, + SMDSAbs_ElementType type, + std::vector< const SMDS_MeshElement* >& foundElems) = 0; + /*! + * \brief Return an element most close to the given point + */ + virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt& point, + SMDSAbs_ElementType type) = 0; + /*! + * \brief Return elements possibly intersecting the line + */ + virtual void GetElementsNearLine( const gp_Ax1& line, + SMDSAbs_ElementType type, + std::vector< const SMDS_MeshElement* >& foundElems) = 0; + /*! + * \brief Find out if the given point is out of closed 2D mesh. + */ + virtual TopAbs_State GetPointState(const gp_Pnt& point) = 0; + virtual ~SMESH_ElementSearcher(); +}; + +namespace SMESH_MeshAlgos +{ + /*! + * \brief Return true if the point is IN or ON of the element + */ + SMESHUtils_EXPORT + bool IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol ); + + SMESHUtils_EXPORT + double GetDistance( const SMDS_MeshElement* elem, const gp_Pnt& point ); + + SMESHUtils_EXPORT + double GetDistance( const SMDS_MeshEdge* edge, const gp_Pnt& point ); + + SMESHUtils_EXPORT + double GetDistance( const SMDS_MeshFace* face, const gp_Pnt& point ); + + SMESHUtils_EXPORT + double GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point ); + + SMESHUtils_EXPORT + void GetBarycentricCoords( const gp_XY& point, + const gp_XY& t0, const gp_XY& t1, const gp_XY& t2, + double & bc0, double & bc1); + + /*! + * Return a face having linked nodes n1 and n2 and which is + * - not in avoidSet, + * - in elemSet provided that !elemSet.empty() + * i1 and i2 optionally returns indices of n1 and n2 + */ + SMESHUtils_EXPORT + const SMDS_MeshElement* FindFaceInSet(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const TIDSortedElemSet& elemSet, + const TIDSortedElemSet& avoidSet, + int* i1=0, + int* i2=0); + /*! + * \brief Calculate normal of a mesh face + */ + SMESHUtils_EXPORT + bool FaceNormal(const SMDS_MeshElement* F, gp_XYZ& normal, bool normalized=true); + + /*! + * \brief Return nodes common to two elements + */ + SMESHUtils_EXPORT + std::vector< const SMDS_MeshNode*> GetCommonNodes(const SMDS_MeshElement* e1, + const SMDS_MeshElement* e2); + + /*! + * \brief Return SMESH_NodeSearcher. The caller is responsible for deleteing it + */ + SMESHUtils_EXPORT + SMESH_NodeSearcher* GetNodeSearcher( SMDS_Mesh& mesh ); + + /*! + * \brief Return SMESH_ElementSearcher. The caller is responsible for deleting it + */ + SMESHUtils_EXPORT + SMESH_ElementSearcher* GetElementSearcher( SMDS_Mesh& mesh, + double tolerance=-1.); + SMESHUtils_EXPORT + SMESH_ElementSearcher* GetElementSearcher( SMDS_Mesh& mesh, + SMDS_ElemIteratorPtr elemIt, + double tolerance=-1. ); + + + + typedef std::vector TFreeBorder; + typedef std::vector TFreeBorderVec; + struct TFreeBorderPart + { + int _border; // border index within a TFreeBorderVec + int _node1; // node index within the border-th TFreeBorder + int _node2; + int _nodeLast; + }; + typedef std::vector TCoincidentGroup; + typedef std::vector TCoincidentGroupVec; + struct CoincidentFreeBorders + { + TFreeBorderVec _borders; // nodes of all free borders + TCoincidentGroupVec _coincidentGroups; // groups of coincident parts of borders + }; + + /*! + * Returns TFreeBorder's coincident within the given tolerance. + * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent + * to free borders being compared is used. + * + * (Implemented in ./SMESH_FreeBorders.cxx) + */ + SMESHUtils_EXPORT + void FindCoincidentFreeBorders(SMDS_Mesh& mesh, + double tolerance, + CoincidentFreeBorders & foundFreeBordes); + + +} // SMESH_MeshAlgos + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_MeshEditor.hxx b/src/3rdParty/salomesmesh/inc/SMESH_MeshEditor.hxx index 9f766cbd5e16..f9a0b51ac5ac 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_MeshEditor.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_MeshEditor.hxx @@ -1,25 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses + // File : SMESH_MeshEditor.hxx // Created : Mon Apr 12 14:56:19 2004 // Author : Edward AGAPOV (eap) @@ -28,21 +28,22 @@ #ifndef SMESH_MeshEditor_HeaderFile #define SMESH_MeshEditor_HeaderFile -#include "Standard_Version.hxx" - #include "SMESH_SMESH.hxx" #include "SMDS_MeshElement.hxx" #include "SMESH_Controls.hxx" #include "SMESH_Mesh.hxx" -#include "SMESH_SequenceOfElemPtr.hxx" -#include "SMESH_SequenceOfNode.hxx" +#include "SMESH_TypeDefs.hxx" +#include "SMESH_ComputeError.hxx" + +#include #include #include #include #include +#include class SMDS_MeshFace; class SMDS_MeshNode; @@ -50,74 +51,82 @@ class gp_Ax1; class gp_Vec; class gp_Pnt; class SMESH_MesherHelper; +class SMESH_NodeSearcher; +// ============================================================ +/*! + * \brief Editor of a mesh + */ +// ============================================================ -typedef std::map > TElemOfElemListMap; -typedef std::map TNodeNodeMap; +class SMESH_EXPORT SMESH_MeshEditor +{ +public: - //!< Set of elements sorted by ID, to be used to assure predictability of edition -typedef std::set< const SMDS_MeshElement*, TIDCompare > TIDSortedElemSet; + SMESH_MeshEditor( SMESH_Mesh* theMesh ); -typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink; + SMESH_Mesh * GetMesh() { return myMesh; } + SMESHDS_Mesh * GetMeshDS() { return myMesh->GetMeshDS(); } + const SMESH_SequenceOfElemPtr& GetLastCreatedNodes() const { return myLastCreatedNodes; } + const SMESH_SequenceOfElemPtr& GetLastCreatedElems() const { return myLastCreatedElems; } + void ClearLastCreated(); + SMESH_ComputeErrorPtr & GetError() { return myError; } -//======================================================================= -/*! - * \brief A sorted pair of nodes - */ -//======================================================================= + // -------------------------------------------------------------------------------- + struct ElemFeatures //!< Features of element to create + { + SMDSAbs_ElementType myType; + bool myIsPoly, myIsQuad; + int myID; + double myBallDiameter; + std::vector myPolyhedQuantities; -struct SMESH_TLink: public NLink -{ - SMESH_TLink(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2 ):NLink( n1, n2 ) - { if ( n1->GetID() < n2->GetID() ) std::swap( first, second ); } - SMESH_TLink(const NLink& link ):NLink( link ) - { if ( first->GetID() < second->GetID() ) std::swap( first, second ); } -}; + SMESH_EXPORT ElemFeatures( SMDSAbs_ElementType type=SMDSAbs_All, bool isPoly=false, bool isQuad=false ) + :myType( type ), myIsPoly(isPoly), myIsQuad(isQuad), myID(-1), myBallDiameter(0) {} -// ============================================================ -/*! - * \brief Searcher for the node closest to point - */ -// ============================================================ + SMESH_EXPORT ElemFeatures& Init( SMDSAbs_ElementType type, bool isPoly=false, bool isQuad=false ) + { myType = type; myIsPoly = isPoly; myIsQuad = isQuad; return *this; } -struct SMESH_NodeSearcher -{ - virtual const SMDS_MeshNode* FindClosestTo( const gp_Pnt& pnt ) = 0; -}; + SMESH_EXPORT ElemFeatures& Init( const SMDS_MeshElement* elem, bool basicOnly=true ); -// ============================================================ -/*! - * \brief Editor of a mesh - */ -// ============================================================ + SMESH_EXPORT ElemFeatures& Init( double diameter ) + { myType = SMDSAbs_Ball; myBallDiameter = diameter; return *this; } -class SMESH_EXPORT SMESH_MeshEditor { + SMESH_EXPORT ElemFeatures& Init( std::vector& quanities, bool isQuad=false ) + { myType = SMDSAbs_Volume; myIsPoly = 1; myIsQuad = isQuad; + myPolyhedQuantities.swap( quanities ); return *this; } -public: + SMESH_EXPORT ElemFeatures& Init( const std::vector& quanities, bool isQuad=false ) + { myType = SMDSAbs_Volume; myIsPoly = 1; myIsQuad = isQuad; + myPolyhedQuantities = quanities; return *this; } - SMESH_MeshEditor( SMESH_Mesh* theMesh ); + SMESH_EXPORT ElemFeatures& SetPoly(bool isPoly) { myIsPoly = isPoly; return *this; } + SMESH_EXPORT ElemFeatures& SetQuad(bool isQuad) { myIsQuad = isQuad; return *this; } + SMESH_EXPORT ElemFeatures& SetID (int ID) { myID = ID; return *this; } + }; /*! * \brief Add element */ SMDS_MeshElement* AddElement(const std::vector & nodes, - const SMDSAbs_ElementType type, - const bool isPoly, - const int ID = 0); + const ElemFeatures& features); /*! * \brief Add element */ - SMDS_MeshElement* AddElement(const std::vector & nodeIDs, - const SMDSAbs_ElementType type, - const bool isPoly, - const int ID = 0); + SMDS_MeshElement* AddElement(const std::vector & nodeIDs, + const ElemFeatures& features); - bool Remove (const std::list< int >& theElemIDs, const bool isNodes); + int Remove (const std::list< int >& theElemIDs, const bool isNodes); // Remove a node or an element. // Modify a compute state of sub-meshes which become empty + void Create0DElementsOnAllNodes( const TIDSortedElemSet& elements, + TIDSortedElemSet& all0DElems); + // Create 0D elements on all nodes of the given object except those + // nodes on which a 0D element already exists. \a all0DElems returns + // all 0D elements found or created on nodes of \a elements + bool InverseDiag (const SMDS_MeshElement * theTria1, const SMDS_MeshElement * theTria2 ); // Replace two neighbour triangles with ones built on the same 4 nodes @@ -139,6 +148,17 @@ public: bool Reorient (const SMDS_MeshElement * theElement); // Reverse theElement orientation + int Reorient2D (TIDSortedElemSet & theFaces, + const gp_Dir& theDirection, + const SMDS_MeshElement * theFace); + // Reverse theFaces whose orientation to be same as that of theFace + // oriented according to theDirection. Return nb of reoriented faces + + int Reorient2DBy3D (TIDSortedElemSet & theFaces, + TIDSortedElemSet & theVolumes, + const bool theOutsideNormal); + // Reorient faces basing on orientation of adjacent volumes. + // Return nb of reoriented faces /*! * \brief Fuse neighbour triangles into quadrangles. @@ -146,40 +166,81 @@ public: * \param theCriterion - Is used to choose a neighbour to fuse with. * \param theMaxAngle - Is a max angle between element normals at which fusion * is still performed; theMaxAngle is mesured in radians. - * \retval bool - Success or not. + * \return bool - Success or not. */ bool TriToQuad (TIDSortedElemSet & theElems, SMESH::Controls::NumericalFunctorPtr theCriterion, const double theMaxAngle); - /*! * \brief Split quadrangles into triangles. * \param theElems - The faces to be splitted. * \param theCriterion - Is used to choose a diagonal for splitting. - * \retval bool - Success or not. + * \return bool - Success or not. */ bool QuadToTri (TIDSortedElemSet & theElems, SMESH::Controls::NumericalFunctorPtr theCriterion); - /*! * \brief Split quadrangles into triangles. * \param theElems - The faces to be splitted. * \param the13Diag - Is used to choose a diagonal for splitting. - * \retval bool - Success or not. + * \return bool - Success or not. */ bool QuadToTri (TIDSortedElemSet & theElems, const bool the13Diag); + /*! + * \brief Split each of given quadrangles into 4 triangles. + * \param theElems - The faces to be splitted. If empty all faces are split. + */ + void QuadTo4Tri (TIDSortedElemSet & theElems); /*! * \brief Find better diagonal for splitting. * \param theQuad - The face to find better splitting of. * \param theCriterion - Is used to choose a diagonal for splitting. - * \retval int - 1 for 1-3 diagonal, 2 for 2-4, -1 - for errors. + * \return int - 1 for 1-3 diagonal, 2 for 2-4, -1 - for errors. */ int BestSplit (const SMDS_MeshElement* theQuad, SMESH::Controls::NumericalFunctorPtr theCriterion); + typedef std::map < const SMDS_MeshElement*, int, TIDCompare > TFacetOfElem; + + //!<2nd arg of SplitVolumes() + enum SplitVolumToTetraFlags { HEXA_TO_5 = 1, // split into tetrahedra + HEXA_TO_6, + HEXA_TO_24, + HEXA_TO_2_PRISMS, // split into prisms + HEXA_TO_4_PRISMS }; + /*! + * \brief Split volumic elements into tetrahedra or prisms. + * If facet ID < 0, element is split into tetrahedra, + * else a hexahedron is split into prisms so that the given facet is + * split into triangles + */ + void SplitVolumes (const TFacetOfElem & theElems, const int theMethodFlags); + + /*! + * \brief For hexahedra that will be split into prisms, finds facets to + * split into triangles + * \param [in,out] theHexas - the hexahedra + * \param [in] theFacetNormal - facet normal + * \param [out] theFacets - the hexahedra and found facet IDs + */ + void GetHexaFacetsToSplit( TIDSortedElemSet& theHexas, + const gp_Ax1& theFacetNormal, + TFacetOfElem & theFacets); + + /*! + * \brief Split bi-quadratic elements into linear ones without creation of additional nodes + * - bi-quadratic triangle will be split into 3 linear quadrangles; + * - bi-quadratic quadrangle will be split into 4 linear quadrangles; + * - tri-quadratic hexahedron will be split into 8 linear hexahedra; + * Quadratic elements of lower dimension adjacent to the split bi-quadratic element + * will be split in order to keep the mesh conformal. + * \param elems - elements to split + */ + void SplitBiQuadraticIntoLinear(TIDSortedElemSet& theElems); + enum SmoothMethod { LAPLACIAN = 0, CENTROIDAL }; void Smooth (TIDSortedElemSet & theElements, @@ -197,9 +258,16 @@ public: // If the2D, smoothing is performed using UV parameters of nodes // on geometrical faces + typedef TIDTypeCompare TElemSort; + typedef std::map < const SMDS_MeshElement*, + std::list, TElemSort > TTElemOfElemListMap; + typedef std::map > TNodeOfNodeListMap; + typedef TNodeOfNodeListMap::iterator TNodeOfNodeListMapItr; + typedef std::vector TVecOfNnlmiMap; + typedef std::map TElemOfVecOfNnlmiMap; typedef std::auto_ptr< std::list > PGroupIDs; - PGroupIDs RotationSweep (TIDSortedElemSet & theElements, + PGroupIDs RotationSweep (TIDSortedElemSet theElements[2], const gp_Ax1& theAxis, const double theAngle, const int theNbSteps, @@ -210,70 +278,131 @@ public: // by theAngle by theNbSteps /*! - * Auxilary flag for advanced extrusion. + * Flags of extrusion. * BOUNDARY: create or not boundary for result of extrusion * SEW: try to use existing nodes or create new nodes in any case + * GROUPS: to create groups + * BY_AVG_NORMAL: step size is measured along average normal to elements, + * else step size is measured along average normal of any element + * USE_INPUT_ELEMS_ONLY: to use only input elements to compute extrusion direction + * for ExtrusionByNormal() */ enum ExtrusionFlags { EXTRUSION_FLAG_BOUNDARY = 0x01, - EXTRUSION_FLAG_SEW = 0x02 + EXTRUSION_FLAG_SEW = 0x02, + EXTRUSION_FLAG_GROUPS = 0x04, + EXTRUSION_FLAG_BY_AVG_NORMAL = 0x08, + EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY = 0x10 }; - + /*! - * special structire for control of extrusion functionality + * Generator of nodes for extrusion functionality */ - struct ExtrusParam { - gp_Dir myDir; // direction of extrusion + class SMESH_EXPORT ExtrusParam { + gp_Dir myDir; // direction of extrusion Handle(TColStd_HSequenceOfReal) mySteps; // magnitudes for each step - SMESH_SequenceOfNode myNodes; // nodes for using in sewing + SMESH_SequenceOfNode myNodes; // nodes for using in sewing + int myFlags; // see ExtrusionFlags + double myTolerance; // tolerance for sewing nodes + const TIDSortedElemSet* myElemsToUse; // elements to use for extrusion by normal + + int (ExtrusParam::*myMakeNodesFun)(SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes); + + public: + ExtrusParam( const gp_Vec& theStep, + const int theNbSteps, + const int theFlags = 0, + const double theTolerance = 1e-6); + ExtrusParam( const gp_Dir& theDir, + Handle(TColStd_HSequenceOfReal) theSteps, + const int theFlags = 0, + const double theTolerance = 1e-6); + ExtrusParam( const double theStep, + const int theNbSteps, + const int theFlags, + const int theDim); // for extrusion by normal + + SMESH_SequenceOfNode& ChangeNodes() { return myNodes; } + int& Flags() { return myFlags; } + bool ToMakeBoundary() const { return myFlags & EXTRUSION_FLAG_BOUNDARY; } + bool ToMakeGroups() const { return myFlags & EXTRUSION_FLAG_GROUPS; } + bool ToUseInpElemsOnly() const { return myFlags & EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY; } + int NbSteps() const { return mySteps->Length(); } + + // stores elements to use for extrusion by normal, depending on + // state of EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY flag + void SetElementsToUse( const TIDSortedElemSet& elems ); + + // creates nodes and returns number of nodes added in \a newNodes + int MakeNodes( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes) + { + return (this->*myMakeNodesFun)( mesh, srcNode, newNodes, makeMediumNodes ); + } + private: + + int makeNodesByDir( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes); + int makeNodesByDirAndSew( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes); + int makeNodesByNormal2D( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes); + int makeNodesByNormal1D( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes); + // step iteration + void beginStepIter( bool withMediumNodes ); + bool moreSteps(); + double nextStep(); + std::vector< double > myCurSteps; + bool myWithMediumNodes; + int myNextStep; }; - /*! - * Create new node in the mesh with given coordinates - * (auxilary for advanced extrusion) - */ - const SMDS_MeshNode* CreateNode(const double x, - const double y, - const double z, - const double tolnode, - SMESH_SequenceOfNode& aNodes); - /*! * Generate new elements by extrusion of theElements * It is a method used in .idl file. All functionality * is implemented in the next method (see below) which - * is used in the cuurent method. - * param theElems - list of elements for extrusion - * param newElemsMap returns history of extrusion - * param theFlags set flags for performing extrusion (see description + * is used in the current method. + * @param theElems - list of elements for extrusion + * @param newElemsMap returns history of extrusion + * @param theFlags set flags for performing extrusion (see description * of enum ExtrusionFlags for additional information) - * param theTolerance - uses for comparing locations of nodes if flag + * @param theTolerance - uses for comparing locations of nodes if flag * EXTRUSION_FLAG_SEW is set */ - PGroupIDs ExtrusionSweep (TIDSortedElemSet & theElems, - const gp_Vec& theStep, - const int theNbSteps, - TElemOfElemListMap& newElemsMap, - const bool theMakeGroups, - const int theFlags = EXTRUSION_FLAG_BOUNDARY, - const double theTolerance = 1.e-6); + PGroupIDs ExtrusionSweep (TIDSortedElemSet theElems[2], + const gp_Vec& theStep, + const int theNbSteps, + TTElemOfElemListMap& newElemsMap, + const int theFlags, + const double theTolerance = 1.e-6); /*! * Generate new elements by extrusion of theElements - * param theElems - list of elements for extrusion - * param newElemsMap returns history of extrusion - * param theFlags set flags for performing extrusion (see description + * @param theElems - list of elements for extrusion + * @param newElemsMap returns history of extrusion + * @param theFlags set flags for performing extrusion (see description * of enum ExtrusionFlags for additional information) - * param theTolerance - uses for comparing locations of nodes if flag + * @param theTolerance - uses for comparing locations of nodes if flag * EXTRUSION_FLAG_SEW is set - * param theParams - special structure for manage of extrusion + * @param theParams - special structure for manage of extrusion */ - PGroupIDs ExtrusionSweep (TIDSortedElemSet & theElems, - ExtrusParam& theParams, - TElemOfElemListMap& newElemsMap, - const bool theMakeGroups, - const int theFlags, - const double theTolerance); + PGroupIDs ExtrusionSweep (TIDSortedElemSet theElems[2], + ExtrusParam& theParams, + TTElemOfElemListMap& newElemsMap); // Generate new elements by extrusion of theElements @@ -289,11 +418,21 @@ public: EXTR_CANT_GET_TANGENT }; - Extrusion_Error ExtrusionAlongTrack (TIDSortedElemSet & theElements, + Extrusion_Error ExtrusionAlongTrack (TIDSortedElemSet theElements[2], SMESH_subMesh* theTrackPattern, const SMDS_MeshNode* theNodeStart, const bool theHasAngles, std::list& theAngles, + const bool theLinearVariation, + const bool theHasRefPoint, + const gp_Pnt& theRefPoint, + const bool theMakeGroups); + Extrusion_Error ExtrusionAlongTrack (TIDSortedElemSet theElements[2], + SMESH_Mesh* theTrackPattern, + const SMDS_MeshNode* theNodeStart, + const bool theHasAngles, + std::list& theAngles, + const bool theLinearVariation, const bool theHasRefPoint, const gp_Pnt& theRefPoint, const bool theMakeGroups); @@ -309,31 +448,21 @@ public: typedef std::list< std::list< const SMDS_MeshNode* > > TListOfListOfNodes; - void FindCoincidentNodes (std::set & theNodes, - const double theTolerance, - TListOfListOfNodes & theGroupsOfNodes); + void FindCoincidentNodes (TIDSortedNodeSet & theNodes, + const double theTolerance, + TListOfListOfNodes & theGroupsOfNodes, + bool theSeparateCornersAndMedium); // Return list of group of nodes close to each other within theTolerance. // Search among theNodes or in the whole mesh if theNodes is empty. - /*! - * \brief Return SMESH_NodeSearcher - */ - SMESH_NodeSearcher* GetNodeSearcher(); - - int SimplifyFace (const std::vector faceNodes, - std::vector& poly_nodes, - std::vector& quantities) const; - // Split face, defined by , into several faces by repeating nodes. - // Is used by MergeNodes() - void MergeNodes (TListOfListOfNodes & theNodeGroups); // In each group, the cdr of nodes are substituted by the first one // in all elements. typedef std::list< std::list< int > > TListOfListOfElementsID; - void FindEqualElements(std::set & theElements, - TListOfListOfElementsID & theGroupsOfElementsID); + void FindEqualElements(TIDSortedElemSet & theElements, + TListOfListOfElementsID & theGroupsOfElementsID); // Return list of group of elements build on the same nodes. // Search among theElements or in the whole mesh if theElements is empty. @@ -344,6 +473,12 @@ public: // Remove all but one of elements built on the same nodes. // Return nb of successfully merged groups. + int SimplifyFace (const std::vector& faceNodes, + std::vector& poly_nodes, + std::vector& quantities) const; + // Split face, defined by , into several faces by repeating nodes. + // Is used by MergeNodes() + static bool CheckFreeBorderNodes(const SMDS_MeshNode* theNode1, const SMDS_MeshNode* theNode2, const SMDS_MeshNode* theNode3 = 0); @@ -429,25 +564,21 @@ public: // insert theNodesToInsert into all volumes, containing link // theBetweenNode1 - theBetweenNode2, between theBetweenNode1 and theBetweenNode2. - void ConvertToQuadratic(const bool theForce3d); - //converts all mesh to quadratic one, deletes old elements, replacing - //them with quadratic ones with the same id. + void ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad); + void ConvertToQuadratic(const bool theForce3d, + TIDSortedElemSet& theElements, const bool theToBiQuad); + // Converts all mesh to quadratic or bi-quadratic one, deletes old elements, + // replacing them with quadratic or bi-quadratic ones with the same id. + // If theForce3d = 1; this results in the medium node lying at the + // middle of the line segments connecting start and end node of a mesh element. + // If theForce3d = 0; this results in the medium node lying at the + // geometrical edge from which the mesh element is built. bool ConvertFromQuadratic(); - //converts all mesh from quadratic to ordinary ones, deletes old quadratic elements, replacing - //them with ordinary mesh elements with the same id. - - -// static int SortQuadNodes (const SMDS_Mesh * theMesh, -// int theNodeIds[] ); -// // Set 4 nodes of a quadrangle face in a good order. -// // Swap 1<->2 or 2<->3 nodes and correspondingly return -// // 1 or 2 else 0. -// -// static bool SortHexaNodes (const SMDS_Mesh * theMesh, -// int theNodeIds[] ); -// // Set 8 nodes of a hexahedron in a good order. -// // Return success status + void ConvertFromQuadratic(TIDSortedElemSet& theElements); + // Converts all mesh from quadratic to ordinary ones, deletes old quadratic elements, replacing + // them with ordinary mesh elements with the same id. + // Returns true in case of success, false otherwise. static void AddToSameGroups (const SMDS_MeshElement* elemToAdd, const SMDS_MeshElement* elemInGroups, @@ -463,6 +594,11 @@ public: SMESHDS_Mesh * aMesh); // replace elemToRm by elemToAdd in the all groups + static void ReplaceElemInGroups (const SMDS_MeshElement* elemToRm, + const std::vector& elemToAdd, + SMESHDS_Mesh * aMesh); + // replace elemToRm by elemToAdd in the all groups + /*! * \brief Return nodes linked to the given one in elements of the type */ @@ -470,15 +606,6 @@ public: TIDSortedElemSet & linkedNodes, SMDSAbs_ElementType type = SMDSAbs_All ); - static const SMDS_MeshElement* - FindFaceInSet(const SMDS_MeshNode* n1, - const SMDS_MeshNode* n2, - const TIDSortedElemSet& elemSet, - const TIDSortedElemSet& avoidSet); - // Return a face having linked nodes n1 and n2 and which is - // - not in avoidSet, - // - in elemSet provided that !elemSet.empty() - /*! * \brief Find corresponding nodes in two sets of faces * \param theSide1 - first face set @@ -488,21 +615,21 @@ public: * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1 * \param nReplaceMap - output map of corresponding nodes - * \retval Sew_Error - is a success or not + * \return Sew_Error - is a success or not */ static Sew_Error FindMatchingNodes(std::set& theSide1, std::set& theSide2, - const SMDS_MeshNode* theFirstNode1, - const SMDS_MeshNode* theFirstNode2, - const SMDS_MeshNode* theSecondNode1, - const SMDS_MeshNode* theSecondNode2, - TNodeNodeMap & nReplaceMap); + const SMDS_MeshNode* theFirstNode1, + const SMDS_MeshNode* theFirstNode2, + const SMDS_MeshNode* theSecondNode1, + const SMDS_MeshNode* theSecondNode2, + TNodeNodeMap & theNodeReplaceMap); /*! * \brief Returns true if given node is medium * \param n - node to check * \param typeToCheck - type of elements containing the node to ask about node status - * \retval bool - check result + * \return bool - check result */ static bool IsMedium(const SMDS_MeshNode* node, const SMDSAbs_ElementType typeToCheck = SMDSAbs_All); @@ -511,22 +638,62 @@ public: // Return an index of the shape theElem is on // or zero if a shape not found - SMESH_Mesh * GetMesh() { return myMesh; } - - SMESHDS_Mesh * GetMeshDS() { return myMesh->GetMeshDS(); } + void DoubleElements( const TIDSortedElemSet& theElements ); - const SMESH_SequenceOfElemPtr& GetLastCreatedNodes() const { return myLastCreatedNodes; } - - const SMESH_SequenceOfElemPtr& GetLastCreatedElems() const { return myLastCreatedElems; } - bool DoubleNodes( const std::list< int >& theListOfNodes, const std::list< int >& theListOfModifiedElems ); + + bool DoubleNodes( const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + const TIDSortedElemSet& theAffectedElems ); + + bool AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + const TopoDS_Shape& theShape, + TIDSortedElemSet& theAffectedElems); + + bool DoubleNodesInRegion( const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + const TopoDS_Shape& theShape ); + + double OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2); -private: + bool DoubleNodesOnGroupBoundaries( const std::vector& theElems, + bool createJointElems, + bool onAllBoundaries); + + bool CreateFlatElementsOnFacesGroups( const std::vector& theElems ); + + void CreateHoleSkin(double radius, + const TopoDS_Shape& theShape, + SMESH_NodeSearcher* theNodeSearcher, + const char* groupName, + std::vector& nodesCoords, + std::vector >& listOfListOfNodes); + + /*! + * \brief Generated skin mesh (containing 2D cells) from 3D mesh + * The created 2D mesh elements based on nodes of free faces of boundary volumes + * \return TRUE if operation has been completed successfully, FALSE otherwise + */ + bool Make2DMeshFrom3D(); + + enum Bnd_Dimension { BND_2DFROM3D, BND_1DFROM3D, BND_1DFROM2D }; + + int MakeBoundaryMesh(const TIDSortedElemSet& elements, + Bnd_Dimension dimension, + SMESH_Group* group = 0, + SMESH_Mesh* targetMesh = 0, + bool toCopyElements = false, + bool toCopyExistingBondary = false, + bool toAddExistingBondary = false, + bool aroundElements = false); + + private: /*! * \brief Convert elements contained in a submesh to quadratic - * \retval int - nb of checked elements + * \return int - nb of checked elements */ int convertElemToQuadratic(SMESHDS_SubMesh * theSm, SMESH_MesherHelper& theHelper, @@ -534,7 +701,7 @@ private: /*! * \brief Convert quadratic elements to linear ones and remove quadratic nodes - * \retval int - nb of checked elements + * \return nb of checked elements */ int removeQuadElem( SMESHDS_SubMesh * theSm, SMDS_ElemIteratorPtr theItr, @@ -544,25 +711,21 @@ private: * \param nodeGens - nodes making corresponding myLastCreatedNodes * \param elemGens - elements making corresponding myLastCreatedElems * \param postfix - to append to names of new groups + * \param targetMesh - mesh to create groups in + * \param topPresent - is there "top" elements that are created by sweeping */ PGroupIDs generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, const SMESH_SequenceOfElemPtr& elemGens, const std::string& postfix, - SMESH_Mesh* targetMesh=0); - - - typedef std::map > TNodeOfNodeListMap; - typedef TNodeOfNodeListMap::iterator TNodeOfNodeListMapItr; - typedef std::vector TVecOfNnlmiMap; - typedef std::map TElemOfVecOfNnlmiMap; - + SMESH_Mesh* targetMesh=0, + const bool topPresent=true); /*! * \brief Create elements by sweeping an element - * \param elem - element to sweep - * \param newNodesItVec - nodes generated from each node of the element - * \param newElems - generated elements - * \param nbSteps - number of sweeping steps - * \param srcElements - to append elem for each generated element + * \param elem - element to sweep + * \param newNodesItVec - nodes generated from each node of the element + * \param newElems - generated elements + * \param nbSteps - number of sweeping steps + * \param srcElements - to append elem for each generated element */ void sweepElement(const SMDS_MeshElement* elem, const std::vector & newNodesItVec, @@ -572,33 +735,69 @@ private: /*! * \brief Create 1D and 2D elements around swept elements - * \param mapNewNodes - source nodes and ones generated from them - * \param newElemsMap - source elements and ones generated from them - * \param elemNewNodesMap - nodes generated from each node of each element - * \param elemSet - all swept elements - * \param nbSteps - number of sweeping steps - * \param srcElements - to append elem for each generated element + * \param mapNewNodes - source nodes and ones generated from them + * \param newElemsMap - source elements and ones generated from them + * \param elemNewNodesMap - nodes generated from each node of each element + * \param elemSet - all swept elements + * \param nbSteps - number of sweeping steps + * \param srcElements - to append elem for each generated element */ void makeWalls (TNodeOfNodeListMap & mapNewNodes, - TElemOfElemListMap & newElemsMap, + TTElemOfElemListMap & newElemsMap, TElemOfVecOfNnlmiMap & elemNewNodesMap, TIDSortedElemSet& elemSet, const int nbSteps, SMESH_SequenceOfElemPtr& srcElements); -private: - SMESH_Mesh * myMesh; + struct SMESH_MeshEditor_PathPoint + { + gp_Pnt myPnt; + gp_Dir myTgt; + double myAngle, myPrm; + + SMESH_MeshEditor_PathPoint(): myPnt(99., 99., 99.), myTgt(1.,0.,0.), myAngle(0), myPrm(0) {} + void SetPnt (const gp_Pnt& aP3D) { myPnt =aP3D; } + void SetTangent (const gp_Dir& aTgt) { myTgt =aTgt; } + void SetAngle (const double& aBeta) { myAngle=aBeta; } + void SetParameter(const double& aPrm) { myPrm =aPrm; } + const gp_Pnt& Pnt ()const { return myPnt; } + const gp_Dir& Tangent ()const { return myTgt; } + double Angle ()const { return myAngle; } + double Parameter ()const { return myPrm; } + }; + Extrusion_Error MakeEdgePathPoints(std::list& aPrms, + const TopoDS_Edge& aTrackEdge, + bool aFirstIsStart, + std::list& aLPP); + Extrusion_Error MakeExtrElements(TIDSortedElemSet theElements[2], + std::list& theFullList, + const bool theHasAngles, + std::list& theAngles, + const bool theLinearVariation, + const bool theHasRefPoint, + const gp_Pnt& theRefPoint, + const bool theMakeGroups); + void LinearAngleVariation(const int NbSteps, + std::list& theAngles); + + bool doubleNodes( SMESHDS_Mesh* theMeshDS, + const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + TNodeNodeMap& theNodeNodeMap, + const bool theIsDoubleElem ); + + void copyPosition( const SMDS_MeshNode* from, + const SMDS_MeshNode* to ); - /*! - * Sequence for keeping nodes created during last operation - */ - SMESH_SequenceOfElemPtr myLastCreatedNodes; +private: - /*! - * Sequence for keeping elements created during last operation - */ - SMESH_SequenceOfElemPtr myLastCreatedElems; + SMESH_Mesh * myMesh; + + // Nodes and elements created during last operation + SMESH_SequenceOfElemPtr myLastCreatedNodes, myLastCreatedElems; + // Description of error/warning occured during last operation + SMESH_ComputeErrorPtr myError; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_MeshVSLink.hxx b/src/3rdParty/salomesmesh/inc/SMESH_MeshVSLink.hxx index be22e06af661..383a38c26c67 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_MeshVSLink.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_MeshVSLink.hxx @@ -1,162 +1,158 @@ -// SMESH SMESH_MeshVSLink : Connection of SMESH with MeshVS from OCC -// -// 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 : SMESH_MeshVSLink.cxx -// Created : Mon Dec 1 09:00:00 2008 -// Author : Sioutis Fotios -// Module : SMESH - -#ifndef _SMESH_MeshVSLink_HeaderFile -#define _SMESH_MeshVSLink_HeaderFile - -#ifndef _Standard_HeaderFile -#include -#endif -#ifndef _Handle_SMESH_MeshVSLink_HeaderFile -#include -#endif -#ifndef _TColStd_PackedMapOfInteger_HeaderFile -#include -#endif -#ifndef _TColStd_HArray2OfInteger_HeaderFile -#include -#endif -#ifndef _TColStd_HArray2OfReal_HeaderFile -#include -#endif -#ifndef _MeshVS_DataSource3D_HeaderFile -#include -#endif -#ifndef _Standard_Boolean_HeaderFile -#include -#endif -#ifndef _Standard_Integer_HeaderFile -#include -#endif -#ifndef _MeshVS_EntityType_HeaderFile -#include -#endif -#ifndef _Standard_Address_HeaderFile -#include -#endif -#ifndef _TColStd_HArray1OfInteger_HeaderFile -#include -#endif -#ifndef _Standard_Real_HeaderFile -#include -#endif -#ifndef _SMESH_Mesh_HeaderFile -#include -#endif -#ifndef _Standard_Version_HeaderFile -#include -#endif - -#if OCC_VERSION_HEX >= 0x070000 -DEFINE_STANDARD_HANDLE(SMESH_MeshVSLink, MeshVS_DataSource3D) -#endif -class SMESH_MeshVSLink : public MeshVS_DataSource3D { - - public: - // Methods PUBLIC - // - - //! Constructor
- Standard_EXPORT SMESH_MeshVSLink(const SMESH_Mesh *aMesh); - - //Not implemented yet - /* - - Standard_EXPORT Standard_Boolean GetNodeNormal(const Standard_Integer ranknode,const Standard_Integer ElementId,Standard_Real& nx,Standard_Real& ny,Standard_Real& nz) const; - Standard_EXPORT Standard_Boolean GetNormalsByElement(const Standard_Integer Id,const Standard_Boolean IsNodal,const Standard_Integer MaxNodes,Handle(TColStd_HArray1OfReal)& Normals) const; - Standard_EXPORT void GetAllGroups(TColStd_PackedMapOfInteger& Ids) const; - Standard_EXPORT Standard_Boolean GetGroup(const Standard_Integer Id,MeshVS_EntityType& Type,TColStd_PackedMapOfInteger& Ids) const; - Standard_EXPORT Standard_Address GetGroupAddr(const Standard_Integer ID) const; - Standard_EXPORT Standard_Boolean IsAdvancedSelectionEnabled() const; - Standard_EXPORT Bnd_Box GetBoundingBox() const; - Standard_EXPORT Standard_Boolean GetDetectedEntities(const Handle(MeshVS_Mesh)& Prs,const Standard_Real X,const Standard_Real Y,const Standard_Real aTol,Handle(TColStd_HPackedMapOfInteger)& Nodes,Handle(TColStd_HPackedMapOfInteger)& Elements) ; - Standard_EXPORT Standard_Boolean GetDetectedEntities(const Handle(MeshVS_Mesh)& Prs,const Standard_Real XMin,const Standard_Real YMin,const Standard_Real XMax,const Standard_Real YMax,const Standard_Real aTol,Handle(TColStd_HPackedMapOfInteger)& Nodes,Handle(TColStd_HPackedMapOfInteger)& Elements) ; - Standard_EXPORT Standard_Boolean GetDetectedEntities(const Handle(MeshVS_Mesh)& Prs,const TColgp_Array1OfPnt2d& Polyline,const Bnd_Box2d& aBox,const Standard_Real aTol,Handle(TColStd_HPackedMapOfInteger)& Nodes,Handle(TColStd_HPackedMapOfInteger)& Elements) ; - Standard_EXPORT Standard_Boolean GetDetectedEntities(const Handle(MeshVS_Mesh)& Prs,Handle(TColStd_HPackedMapOfInteger)& Nodes,Handle(TColStd_HPackedMapOfInteger)& Elements) ; - */ - - //! Returns geometry information about node ( if IsElement is False ) or element ( IsElement is True )
- //! by co-ordinates. For element this method must return all its nodes co-ordinates in the strict order: X, Y, Z and
- //! with nodes order is the same as in wire bounding the face or link. NbNodes is number of nodes of element.
- //! It is recommended to return 1 for node. Type is an element type.
- Standard_EXPORT Standard_Boolean GetGeom(const Standard_Integer ID,const Standard_Boolean IsElement,TColStd_Array1OfReal& Coords,Standard_Integer& NbNodes,MeshVS_EntityType& Type) const; - - Standard_EXPORT Standard_Boolean Get3DGeom(const Standard_Integer ID,Standard_Integer& NbNodes,Handle(MeshVS_HArray1OfSequenceOfInteger)& Data) const; - - //! This method is similar to GetGeom, but returns only element or node type. This method is provided for
- //! a fine performance.
- Standard_EXPORT Standard_Boolean GetGeomType(const Standard_Integer ID,const Standard_Boolean IsElement,MeshVS_EntityType& Type) const; - - //! This method returns by number an address of any entity which represents element or node data structure.
- Standard_EXPORT Standard_Address GetAddr(const Standard_Integer ID,const Standard_Boolean IsElement) const; - - //! This method returns information about what node this element consist of.
- Standard_EXPORT /*virtual*/ Standard_Boolean GetNodesByElement(const Standard_Integer ID,TColStd_Array1OfInteger& NodeIDs,Standard_Integer& NbNodes) const; - - //! This method returns map of all nodes the object consist of.
- Standard_EXPORT const TColStd_PackedMapOfInteger& GetAllNodes() const; - - //! This method returns map of all elements the object consist of.
- Standard_EXPORT const TColStd_PackedMapOfInteger& GetAllElements() const; - - //! This method calculates normal of face, which is using for correct reflection presentation.
- //! There is default method, for advance reflection this method can be redefined.
- Standard_EXPORT Standard_Boolean GetNormal(const Standard_Integer Id,const Standard_Integer Max,Standard_Real& nx,Standard_Real& ny,Standard_Real& nz) const; - - //! This method returns map of all groups the object contains.
- Standard_EXPORT void GetAllGroups(TColStd_PackedMapOfInteger& Ids) const; - - // Type management - // -#if OCC_VERSION_HEX >= 0x070000 - DEFINE_STANDARD_RTTIEXT(SMESH_MeshVSLink,MeshVS_DataSource3D) -#else - Standard_EXPORT const Handle(Standard_Type)& DynamicType() const; -#endif - - protected: - // Methods PROTECTED - // - - // Fields PROTECTED - // - - private: - // Methods PRIVATE - // - - // Fields PRIVATE - // - SMESH_Mesh *myMesh; - TColStd_PackedMapOfInteger myNodes; - TColStd_PackedMapOfInteger myElements; - TColStd_PackedMapOfInteger myGroups; -}; - -// other Inline functions and methods (like "C++: function call" methods) -// - -#endif +// SMESH SMESH_MeshVSLink : Connection of SMESH with MeshVS from OCC +// +// 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 : SMESH_MeshVSLink.cxx +// Created : Mon Dec 1 09:00:00 2008 +// Author : Sioutis Fotios +// Module : SMESH + +#ifndef _SMESH_MeshVSLink_HeaderFile +#define _SMESH_MeshVSLink_HeaderFile + +#ifndef _Standard_HeaderFile +#include +#endif +#ifndef _TColStd_PackedMapOfInteger_HeaderFile +#include +#endif +#ifndef _TColStd_HArray2OfInteger_HeaderFile +#include +#endif +#ifndef _TColStd_HArray2OfReal_HeaderFile +#include +#endif +#ifndef _MeshVS_DataSource3D_HeaderFile +#include +#endif +#ifndef _Standard_Boolean_HeaderFile +#include +#endif +#ifndef _Standard_Integer_HeaderFile +#include +#endif +#ifndef _MeshVS_EntityType_HeaderFile +#include +#endif +#ifndef _Standard_Address_HeaderFile +#include +#endif +#ifndef _TColStd_HArray1OfInteger_HeaderFile +#include +#endif +#ifndef _Standard_Real_HeaderFile +#include +#endif +#ifndef _SMESH_Mesh_HeaderFile +#include +#endif +#ifndef _Standard_Version_HeaderFile +#include +#endif + +#if OCC_VERSION_HEX >= 0x070000 +DEFINE_STANDARD_HANDLE(SMESH_MeshVSLink, MeshVS_DataSource3D) +#endif +class SMESH_MeshVSLink : public MeshVS_DataSource3D { + + public: + // Methods PUBLIC + // + + //! Constructor
+ Standard_EXPORT SMESH_MeshVSLink(const SMESH_Mesh *aMesh); + + //Not implemented yet + /* + + Standard_EXPORT Standard_Boolean GetNodeNormal(const Standard_Integer ranknode,const Standard_Integer ElementId,Standard_Real& nx,Standard_Real& ny,Standard_Real& nz) const; + Standard_EXPORT Standard_Boolean GetNormalsByElement(const Standard_Integer Id,const Standard_Boolean IsNodal,const Standard_Integer MaxNodes,Handle(TColStd_HArray1OfReal)& Normals) const; + Standard_EXPORT void GetAllGroups(TColStd_PackedMapOfInteger& Ids) const; + Standard_EXPORT Standard_Boolean GetGroup(const Standard_Integer Id,MeshVS_EntityType& Type,TColStd_PackedMapOfInteger& Ids) const; + Standard_EXPORT Standard_Address GetGroupAddr(const Standard_Integer ID) const; + Standard_EXPORT Standard_Boolean IsAdvancedSelectionEnabled() const; + Standard_EXPORT Bnd_Box GetBoundingBox() const; + Standard_EXPORT Standard_Boolean GetDetectedEntities(const Handle(MeshVS_Mesh)& Prs,const Standard_Real X,const Standard_Real Y,const Standard_Real aTol,Handle(TColStd_HPackedMapOfInteger)& Nodes,Handle(TColStd_HPackedMapOfInteger)& Elements) ; + Standard_EXPORT Standard_Boolean GetDetectedEntities(const Handle(MeshVS_Mesh)& Prs,const Standard_Real XMin,const Standard_Real YMin,const Standard_Real XMax,const Standard_Real YMax,const Standard_Real aTol,Handle(TColStd_HPackedMapOfInteger)& Nodes,Handle(TColStd_HPackedMapOfInteger)& Elements) ; + Standard_EXPORT Standard_Boolean GetDetectedEntities(const Handle(MeshVS_Mesh)& Prs,const TColgp_Array1OfPnt2d& Polyline,const Bnd_Box2d& aBox,const Standard_Real aTol,Handle(TColStd_HPackedMapOfInteger)& Nodes,Handle(TColStd_HPackedMapOfInteger)& Elements) ; + Standard_EXPORT Standard_Boolean GetDetectedEntities(const Handle(MeshVS_Mesh)& Prs,Handle(TColStd_HPackedMapOfInteger)& Nodes,Handle(TColStd_HPackedMapOfInteger)& Elements) ; + */ + + //! Returns geometry information about node ( if IsElement is False ) or element ( IsElement is True )
+ //! by co-ordinates. For element this method must return all its nodes co-ordinates in the strict order: X, Y, Z and
+ //! with nodes order is the same as in wire bounding the face or link. NbNodes is number of nodes of element.
+ //! It is recommended to return 1 for node. Type is an element type.
+ Standard_EXPORT Standard_Boolean GetGeom(const Standard_Integer ID,const Standard_Boolean IsElement,TColStd_Array1OfReal& Coords,Standard_Integer& NbNodes,MeshVS_EntityType& Type) const; + + Standard_EXPORT Standard_Boolean Get3DGeom(const Standard_Integer ID,Standard_Integer& NbNodes,Handle(MeshVS_HArray1OfSequenceOfInteger)& Data) const; + + //! This method is similar to GetGeom, but returns only element or node type. This method is provided for
+ //! a fine performance.
+ Standard_EXPORT Standard_Boolean GetGeomType(const Standard_Integer ID,const Standard_Boolean IsElement,MeshVS_EntityType& Type) const; + + //! This method returns by number an address of any entity which represents element or node data structure.
+ Standard_EXPORT Standard_Address GetAddr(const Standard_Integer ID,const Standard_Boolean IsElement) const; + + //! This method returns information about what node this element consist of.
+ Standard_EXPORT /*virtual*/ Standard_Boolean GetNodesByElement(const Standard_Integer ID,TColStd_Array1OfInteger& NodeIDs,Standard_Integer& NbNodes) const; + + //! This method returns map of all nodes the object consist of.
+ Standard_EXPORT const TColStd_PackedMapOfInteger& GetAllNodes() const; + + //! This method returns map of all elements the object consist of.
+ Standard_EXPORT const TColStd_PackedMapOfInteger& GetAllElements() const; + + //! This method calculates normal of face, which is using for correct reflection presentation.
+ //! There is default method, for advance reflection this method can be redefined.
+ Standard_EXPORT Standard_Boolean GetNormal(const Standard_Integer Id,const Standard_Integer Max,Standard_Real& nx,Standard_Real& ny,Standard_Real& nz) const; + + //! This method returns map of all groups the object contains.
+ Standard_EXPORT void GetAllGroups(TColStd_PackedMapOfInteger& Ids) const; + + // Type management + // +#if OCC_VERSION_HEX >= 0x070000 + DEFINE_STANDARD_RTTIEXT(SMESH_MeshVSLink,MeshVS_DataSource3D) +#else + Standard_EXPORT const Handle(Standard_Type)& DynamicType() const; +#endif + + protected: + // Methods PROTECTED + // + + // Fields PROTECTED + // + + private: + // Methods PRIVATE + // + + // Fields PRIVATE + // + SMESH_Mesh *myMesh; + TColStd_PackedMapOfInteger myNodes; + TColStd_PackedMapOfInteger myElements; + TColStd_PackedMapOfInteger myGroups; +}; +#include +// other Inline functions and methods (like "C++: function call" methods) +// +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_MeshVSLink.ixx b/src/3rdParty/salomesmesh/inc/SMESH_MeshVSLink.ixx index 1e7d6fe93e1b..e9eec6cb73f9 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_MeshVSLink.ixx +++ b/src/3rdParty/salomesmesh/inc/SMESH_MeshVSLink.ixx @@ -1,77 +1,43 @@ -// SMESH SMESH_MeshVSLink : Connection of SMESH with MeshVS from OCC -// -// 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 : SMESH_MeshVSLink.cxx -// Created : Mon Dec 1 09:00:00 2008 -// Author : Sioutis Fotios -// Module : SMESH - -#include - -#ifndef _Standard_TypeMismatch_HeaderFile -#include -#endif - -#ifndef _Standard_Version_HeaderFile -#include -#endif - -#if OCC_VERSION_HEX < 0x070000 -Standard_EXPORT Handle_Standard_Type& SMESH_MeshVSLink_Type_() -{ - static Handle_Standard_Type aType1 = STANDARD_TYPE(MeshVS_DataSource3D); - static Handle_Standard_Type aType2 = STANDARD_TYPE(MeshVS_DataSource); - static Handle_Standard_Type aType3 = STANDARD_TYPE(MMgt_TShared); - static Handle_Standard_Type aType4 = STANDARD_TYPE(Standard_Transient); - - - static Handle_Standard_Transient _Ancestors[]= {aType1,aType2,aType3,aType4,NULL}; - static Handle_Standard_Type _aType = new Standard_Type("SMESH_MeshVSLink", - sizeof(SMESH_MeshVSLink), - 1, - (Standard_Address)_Ancestors, - (Standard_Address)NULL); - - return _aType; -} - - -// DownCast method -// allow safe downcasting -// -const Handle(SMESH_MeshVSLink) Handle(SMESH_MeshVSLink)::DownCast(const Handle(Standard_Transient)& AnObject) -{ - Handle(SMESH_MeshVSLink) _anOtherObject; - - if (!AnObject.IsNull()) { - if (AnObject->IsKind(STANDARD_TYPE(SMESH_MeshVSLink))) { - _anOtherObject = Handle(SMESH_MeshVSLink)((Handle(SMESH_MeshVSLink)&)AnObject); - } - } - - return _anOtherObject ; -} - -const Handle(Standard_Type)& SMESH_MeshVSLink::DynamicType() const -{ - return STANDARD_TYPE(SMESH_MeshVSLink) ; -} -#endif +// SMESH SMESH_MeshVSLink : Connection of SMESH with MeshVS from OCC +// +// 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 : SMESH_MeshVSLink.cxx +// Created : Mon Dec 1 09:00:00 2008 +// Author : Sioutis Fotios +// Module : SMESH + +// #include + +// #ifndef _Standard_TypeMismatch_HeaderFile +// #include +// #endif + +#ifndef _Standard_Version_HeaderFile +#include +#endif + +#if OCC_VERSION_HEX < 0x070000 + +const Handle(Standard_Type)& SMESH_MeshVSLink::DynamicType() const +{ + return STANDARD_TYPE(SMESH_MeshVSLink) ; +} + diff --git a/src/3rdParty/salomesmesh/inc/SMESH_MesherHelper.hxx b/src/3rdParty/salomesmesh/inc/SMESH_MesherHelper.hxx index 733cfa4a436e..fdf863f033e9 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_MesherHelper.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_MesherHelper.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File: SMESH_MesherHelper.hxx // Created: 15.02.06 14:48:09 // Author: Sergey KUUL @@ -32,68 +33,113 @@ #include #include +#include +#include #include #include #include #include +#include + +class GeomAPI_ProjectPointOnSurf; +class GeomAPI_ProjectPointOnCurve; +class SMESH_ProxyMesh; + +typedef std::map TLinkNodeMap; +typedef std::map::iterator ItTLinkNode; + +typedef SMDS_Iterator PShapeIterator; +typedef boost::shared_ptr< PShapeIterator > PShapeIteratorPtr; + +typedef std::vector TNodeColumn; +typedef std::map< double, TNodeColumn > TParam2ColumnMap; -typedef std::pair NLink; -typedef std::map NLinkNodeMap; -typedef std::map::iterator ItNLinkNode; +typedef gp_XY (*xyFunPtr)(const gp_XY& uv1, const gp_XY& uv2); +//======================================================================= /*! - * \brief It helps meshers to add elements + * \brief It helps meshers to add elements and provides other utilities * - * It allow meshers not to care about creation of medium nodes + * - It allows meshers not to care about creation of medium nodes * when filling a quadratic mesh. Helper does it itself. - * It defines degree of elements to create when IsQuadraticSubMesh() + * It defines order of elements to create when IsQuadraticSubMesh() * is called. + * - It provides information on a shape it is initialized with: + * periodicity, presence of singularities etc. + * - ... */ - -typedef std::vector TNodeColumn; -typedef std::map< double, TNodeColumn > TParam2ColumnMap; +//======================================================================= class SMESH_EXPORT SMESH_MesherHelper { -public: + public: // ---------- PUBLIC UTILITIES ---------- /*! - * \brief Returns true if given node is medium - * \param n - node to check - * \param typeToCheck - type of elements containing the node to ask about node status + * \brief Returns true if all elements of a sub-mesh are of same shape + * \param smDS - sub-mesh to check elements of + * \param shape - expected shape of elements + * \param nullSubMeshRes - result value for the case of smDS == NULL * \retval bool - check result */ - static bool IsMedium(const SMDS_MeshNode* node, - const SMDSAbs_ElementType typeToCheck = SMDSAbs_All); + static bool IsSameElemGeometry(const SMESHDS_SubMesh* smDS, + SMDSAbs_GeometryType shape, + const bool nullSubMeshRes = true); /*! * \brief Load nodes bound to face into a map of node columns * \param theParam2ColumnMap - map of node columns to fill * \param theFace - the face on which nodes are searched for - * \param theBaseEdge - the edge nodes of which are columns' bases + * \param theBaseSide - the edges holding nodes on which columns' bases * \param theMesh - the mesh containing nodes * \retval bool - false if something is wrong * * The key of the map is a normalized parameter of each - * base node on theBaseEdge. + * base node on theBaseSide. Edges in theBaseSide must be sequenced. * This method works in supposition that nodes on the face - * forms a rectangular grid and elements can be quardrangles or triangles + * forms a structured grid and elements can be quardrangles or triangles + */ + static bool LoadNodeColumns(TParam2ColumnMap & theParam2ColumnMap, + const TopoDS_Face& theFace, + const std::list& theBaseSide, + SMESHDS_Mesh* theMesh, + SMESH_ProxyMesh* theProxyMesh=0); + /*! + * \brief Variant of LoadNodeColumns() above with theBaseSide given by one edge */ static bool LoadNodeColumns(TParam2ColumnMap & theParam2ColumnMap, const TopoDS_Face& theFace, const TopoDS_Edge& theBaseEdge, - SMESHDS_Mesh* theMesh); + SMESHDS_Mesh* theMesh, + SMESH_ProxyMesh* theProxyMesh=0); + /*! + * \brief Return true if 2D mesh on FACE is structured + */ + static bool IsStructured( SMESH_subMesh* faceSM ); + + /*! + * \brief Return true if 2D mesh on FACE is distored + */ + static bool IsDistorted2D( SMESH_subMesh* faceSM, bool checkUV=false ); + + /*! + * \brief Returns true if given node is medium + * \param n - node to check + * \param typeToCheck - type of elements containing the node to ask about node status + * \retval bool - check result + */ + static bool IsMedium(const SMDS_MeshNode* node, + const SMDSAbs_ElementType typeToCheck = SMDSAbs_All); /*! * \brief Return support shape of a node * \param node - the node * \param meshDS - mesh DS * \retval TopoDS_Shape - found support shape + * \sa SMESH_Algo::VertexNode( const TopoDS_Vertex&, SMESHDS_Mesh* ) */ - static const TopoDS_Shape& GetSubShapeByNode(const SMDS_MeshNode* node, - SMESHDS_Mesh* meshDS) - { return meshDS->IndexToShape( node->GetPosition()->GetShapeId() ); } + static TopoDS_Shape GetSubShapeByNode(const SMDS_MeshNode* node, + const SMESHDS_Mesh* meshDS); /*! * \brief Return a valid node index, fixing the given one if necessary @@ -101,18 +147,100 @@ public: * \param nbNodes - total nb of nodes * \retval int - valid node index */ - static int WrapIndex(const int ind, const int nbNodes) { - if ( ind < 0 ) return nbNodes + ind % nbNodes; - if ( ind >= nbNodes ) return ind % nbNodes; - return ind; + static inline int WrapIndex(int ind, const int nbNodes) { + return (( ind %= nbNodes ) < 0 ) ? ind + nbNodes : ind; } + /*! + * \brief Return UV of a point inside a quadrilateral FACE by it's + * normalized parameters within a unit quadrangle and the + * corresponding projections on sub-shapes of the real-world FACE. + * The used calculation method is called Trans-Finite Interpolation (TFI). + * \param x,y - normalized parameters that should be in range [0,1] + * \param a0,a1,a2,a3 - UV of VERTEXes of the FACE == projections on VERTEXes + * \param p0,p1,p2,p3 - UV of the point projections on EDGEs of the FACE + * \return gp_XY - UV of the point on the FACE + * + * Y ^ Order of those UV in the FACE is as follows. + * | + * a3 p2 a2 + * o---x-----o + * | : | + * | :UV | + * p3 x...O.....x p1 + * | : | + * o---x-----o ----> X + * a0 p0 a1 + */ + inline static gp_XY calcTFI(double x, double y, + const gp_XY& a0,const gp_XY& a1,const gp_XY& a2,const gp_XY& a3, + const gp_XY& p0,const gp_XY& p1,const gp_XY& p2,const gp_XY& p3); + + /*! + * \brief Same as "gp_XY calcTFI(...)" but in 3D + */ + inline static gp_XYZ calcTFI(double x, double y, + const gp_XYZ& a0,const gp_XYZ& a1,const gp_XYZ& a2,const gp_XYZ& a3, + const gp_XYZ& p0,const gp_XYZ& p1,const gp_XYZ& p2,const gp_XYZ& p3); + /*! + * \brief Count nb of sub-shapes + * \param shape - the shape + * \param type - the type of sub-shapes to count + * \param ignoreSame - if true, use map not to count same shapes, esle use explorer + * \retval int - the calculated number + */ + static int Count(const TopoDS_Shape& shape, + const TopAbs_ShapeEnum type, + const bool ignoreSame); + /*! * \brief Return number of unique ancestors of the shape */ static int NbAncestors(const TopoDS_Shape& shape, const SMESH_Mesh& mesh, TopAbs_ShapeEnum ancestorType=TopAbs_SHAPE); + /*! + * \brief Return iterator on ancestors of the given type + */ + static PShapeIteratorPtr GetAncestors(const TopoDS_Shape& shape, + const SMESH_Mesh& mesh, + TopAbs_ShapeEnum ancestorType); + /*! + * \brief Find a common ancestor, of the given type, of two shapes + */ + static TopoDS_Shape GetCommonAncestor(const TopoDS_Shape& shape1, + const TopoDS_Shape& shape2, + const SMESH_Mesh& mesh, + TopAbs_ShapeEnum ancestorType); + /*! + * \brief Return orientation of sub-shape in the main shape + */ + static TopAbs_Orientation GetSubShapeOri(const TopoDS_Shape& shape, + const TopoDS_Shape& subShape); + + static bool IsSubShape( const TopoDS_Shape& shape, const TopoDS_Shape& mainShape ); + + static bool IsSubShape( const TopoDS_Shape& shape, SMESH_Mesh* aMesh ); + + static bool IsBlock( const TopoDS_Shape& shape ); + + static double MaxTolerance( const TopoDS_Shape& shape ); + + static double GetAngle( const TopoDS_Edge & E1, const TopoDS_Edge & E2, + const TopoDS_Face & F, const TopoDS_Vertex & V, + gp_Vec* faceNormal=0); + + static bool IsClosedEdge( const TopoDS_Edge& anEdge ); + + static TopoDS_Vertex IthVertex( const bool is2nd, TopoDS_Edge anEdge, const bool CumOri=true ); + + static TopAbs_ShapeEnum GetGroupType(const TopoDS_Shape& group, + const bool avoidCompound=false); + + static TopoDS_Shape GetShapeOfHypothesis( const SMESHDS_Hypothesis * hyp, + const TopoDS_Shape& shape, + SMESH_Mesh* mesh); + public: // ---------- PUBLIC INSTANCE METHODS ---------- @@ -120,31 +248,59 @@ public: // constructor SMESH_MesherHelper(SMESH_Mesh& theMesh); - SMESH_Mesh* GetMesh() const { return myMesh; } + SMESH_Gen* GetGen() const { return GetMesh()->GetGen(); } + + SMESH_Mesh* GetMesh() const { return myMesh; } SMESHDS_Mesh* GetMeshDS() const { return GetMesh()->GetMeshDS(); } /*! * Check submesh for given shape: if all elements on this shape are quadratic, - * quadratic elements will be created. Also fill myNLinkNodeMap + * quadratic elements will be created. Also fill myTLinkNodeMap */ bool IsQuadraticSubMesh(const TopoDS_Shape& theShape); + /*! * \brief Set order of elements to create without calling IsQuadraticSubMesh() */ void SetIsQuadratic(const bool theBuildQuadratic) { myCreateQuadratic = theBuildQuadratic; } + + /*! + * \brief Set myCreateBiQuadratic flag + */ + void SetIsBiQuadratic(const bool theBuildBiQuadratic) + { myCreateBiQuadratic = theBuildBiQuadratic; } + /*! * \brief Return myCreateQuadratic flag */ bool GetIsQuadratic() const { return myCreateQuadratic; } + /* + * \brief Find out elements orientation on a geometrical face + */ + bool IsReversedSubMesh (const TopoDS_Face& theFace); + + /*! + * \brief Return myCreateBiQuadratic flag + */ + bool GetIsBiQuadratic() const { return myCreateBiQuadratic; } + + /*! + * \brief Move medium nodes of faces and volumes to fix distorted elements + * \param error - container of fixed distorted elements + * \param volumeOnly - fix nodes on geom faces or not if the shape is solid + */ + void FixQuadraticElements(SMESH_ComputeErrorPtr& error, bool volumeOnly=true); + /*! * \brief To set created elements on the shape set by IsQuadraticSubMesh() * or the next methods. By defaul elements are set on the shape if * a mesh has no shape to be meshed */ - void SetElementsOnShape(bool toSet) { mySetElemOnShape = toSet; } + bool SetElementsOnShape(bool toSet) + { bool res = mySetElemOnShape; mySetElemOnShape = toSet; return res; } /*! * \brief Set shape to make elements on without calling IsQuadraticSubMesh() @@ -159,12 +315,12 @@ public: /*! * \brief Return the shape set by IsQuadraticSubMesh() or SetSubShape() */ - TopoDS_Shape GetSubShape() const { return myShape; } + const TopoDS_Shape& GetSubShape() const { return myShape; } /*! - * Creates a node + * Creates a node (!Note ID before u=0.,v0.) */ - SMDS_MeshNode* AddNode(double x, double y, double z, int ID = 0); + SMDS_MeshNode* AddNode(double x, double y, double z, int ID = 0, double u=0., double v=0.); /*! * Creates quadratic or linear edge */ @@ -179,25 +335,31 @@ public: const SMDS_MeshNode* n2, const SMDS_MeshNode* n3, const int id=0, - const bool force3d = false); + const bool force3d = false); /*! - * Creates quadratic or linear quadrangle + * Creates bi-quadratic, quadratic or linear quadrangle */ SMDS_MeshFace* AddFace(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshNode* n3, const SMDS_MeshNode* n4, const int id = 0, - const bool force3d = false); + const bool force3d = false); + /*! + * Creates polygon, with additional nodes in quadratic mesh + */ + SMDS_MeshFace* AddPolygonalFace (const std::vector& nodes, + const int id = 0, + const bool force3d = false); /*! - * Creates quadratic or linear tetraahedron + * Creates quadratic or linear tetrahedron */ SMDS_MeshVolume* AddVolume(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshNode* n3, const SMDS_MeshNode* n4, const int id = 0, - const bool force3d = true); + const bool force3d = true); /*! * Creates quadratic or linear pyramid */ @@ -207,7 +369,7 @@ public: const SMDS_MeshNode* n4, const SMDS_MeshNode* n5, const int id = 0, - const bool force3d = true); + const bool force3d = true); /*! * Creates quadratic or linear pentahedron */ @@ -218,9 +380,23 @@ public: const SMDS_MeshNode* n5, const SMDS_MeshNode* n6, const int id = 0, - const bool force3d = true); + const bool force3d = true); + /*! + * Creates bi-quadratic, quadratic or linear hexahedron + */ + SMDS_MeshVolume* AddVolume(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n3, + const SMDS_MeshNode* n4, + const SMDS_MeshNode* n5, + const SMDS_MeshNode* n6, + const SMDS_MeshNode* n7, + const SMDS_MeshNode* n8, + const int id = 0, + bool force3d = true); + /*! - * Creates quadratic or linear hexahedron + * Creates LINEAR!!!!!!!!! octahedron */ SMDS_MeshVolume* AddVolume(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, @@ -230,38 +406,150 @@ public: const SMDS_MeshNode* n6, const SMDS_MeshNode* n7, const SMDS_MeshNode* n8, + const SMDS_MeshNode* n9, + const SMDS_MeshNode* n10, + const SMDS_MeshNode* n11, + const SMDS_MeshNode* n12, const int id = 0, - bool force3d = true); + bool force3d = true); + + /*! + * Creates polyhedron. In quadratic mesh, adds medium nodes + */ + SMDS_MeshVolume* AddPolyhedralVolume (const std::vector& nodes, + const std::vector& quantities, + const int ID=0, + const bool force3d = true); + /*! + * \brief Enables fixing node parameters on EDGEs and FACEs by + * GetNodeU(...,check=true), GetNodeUV(...,check=true), CheckNodeUV() and + * CheckNodeU() in case if a node lies on a shape set via SetSubShape(). + * Default is False + */ + void ToFixNodeParameters(bool toFix); + /*! * \brief Return U of the given node on the edge */ double GetNodeU(const TopoDS_Edge& theEdge, - const SMDS_MeshNode* theNode); + const SMDS_MeshNode* theNode, + const SMDS_MeshNode* inEdgeNode=0, + bool* check=0) const; /*! * \brief Return node UV on face - * \param inFaceNode - a node of element being created located inside a face + * \param inFaceNode - a node of element being created located inside a face + * \param check - if provided, returns result of UV check that it enforces */ gp_XY GetNodeUV(const TopoDS_Face& F, const SMDS_MeshNode* n, - const SMDS_MeshNode* inFaceNode=0) const; + const SMDS_MeshNode* inFaceNode=0, + bool* check=0) const; + /*! + * \brief Check and fix node UV on a face + * \param force - check even if checks of other nodes on this face passed OK + * \param distXYZ - returns result distance and point coordinates + * \retval bool - false if UV is bad and could not be fixed + */ + bool CheckNodeUV(const TopoDS_Face& F, + const SMDS_MeshNode* n, + gp_XY& uv, + const double tol, + const bool force=false, + double distXYZ[4]=0) const; + /*! + * \brief Check and fix node U on an edge + * \param force - check even if checks of other nodes on this edge passed OK + * \param distXYZ - returns result distance and point coordinates + * \retval bool - false if U is bad and could not be fixed + */ + bool CheckNodeU(const TopoDS_Edge& E, + const SMDS_MeshNode* n, + double& u, + const double tol, + const bool force=false, + double distXYZ[4]=0) const; + /*! + * \brief Return middle UV taking in account surface period + */ + static gp_XY GetMiddleUV(const Handle(Geom_Surface)& surface, + const gp_XY& uv1, + const gp_XY& uv2); + /*! + * \brief Return UV for the central node of a biquadratic triangle + */ + static gp_XY GetCenterUV(const gp_XY& uv1, + const gp_XY& uv2, + const gp_XY& uv3, + const gp_XY& uv12, + const gp_XY& uv23, + const gp_XY& uv31, + bool * isBadTria=0); + /*! + * \brief Define a pointer to wrapper over a function of gp_XY class, + * suitable to pass as xyFunPtr to ApplyIn2D(). + * For exaple gp_XY_FunPtr(Added) defines pointer gp_XY_Added to function + * calling gp_XY::Added(gp_XY), which is to be used like following + * ApplyIn2D(surf, uv1, uv2, gp_XY_Added) + */ +#define gp_XY_FunPtr(meth) \ + static gp_XY __gpXY_##meth (const gp_XY& uv1, const gp_XY& uv2) { return uv1.meth( uv2 ); } \ + static xyFunPtr gp_XY_##meth = & __gpXY_##meth + + /*! + * \brief Perform given operation on two 2d points in parameric space of given surface. + * It takes into account period of the surface. Use gp_XY_FunPtr macro + * to easily define pointer to function of gp_XY class. + */ + static gp_XY ApplyIn2D(Handle(Geom_Surface) surface, + const gp_XY& uv1, + const gp_XY& uv2, + xyFunPtr fun, + const bool resultInPeriod=true); + + /*! + * \brief Move node positions on a FACE within surface period + * \param [in] face - the FACE + * \param [inout] uv - node positions to adjust + * \param [in] nbUV - nb of \a uv + */ + void AdjustByPeriod( const TopoDS_Face& face, gp_XY uv[], const int nbUV ); + /*! * \brief Check if inFaceNode argument is necessary for call GetNodeUV(F,..) - * \retval bool - return true if the face is periodic - * - * if F is Null, answer about subshape set through IsQuadraticSubMesh() or - * SetSubShape() + * \retval bool - return true if the face is periodic + * + * If F is Null, answer about subshape set through IsQuadraticSubMesh() or + * SetSubShape() */ bool GetNodeUVneedInFaceNode(const TopoDS_Face& F = TopoDS_Face()) const; + /*! + * \brief Return projector intitialized by given face without location, which is returned + */ + GeomAPI_ProjectPointOnSurf& GetProjector(const TopoDS_Face& F, + TopLoc_Location& loc, + double tol=0 ) const; + /*! + * \brief Return a cached ShapeAnalysis_Surface of a FACE + */ + Handle(ShapeAnalysis_Surface) GetSurface(const TopoDS_Face& F ) const; + /*! * \brief Check if shape is a degenerated edge or it's vertex - * \param subShape - edge or vertex index in SMESHDS - * \retval bool - true if subShape is a degenerated shape - * - * It works only if IsQuadraticSubMesh() or SetSubShape() has been called + * \param subShape - edge or vertex index in SMESHDS + * \retval bool - true if subShape is a degenerated shape + * + * It works only if IsQuadraticSubMesh() or SetSubShape() has been called */ bool IsDegenShape(const int subShape) const { return myDegenShapeIds.find( subShape ) != myDegenShapeIds.end(); } + /*! + * \brief Check if the shape set through IsQuadraticSubMesh() or SetSubShape() + * has a degenerated edges + * \retval bool - true if it has + */ + bool HasDegeneratedEdges() const { return !myDegenShapeIds.empty(); } + /*! * \brief Check if shape is a seam edge or it's vertex * \param subShape - edge or vertex index in SMESHDS @@ -296,13 +584,20 @@ public: { return IsRealSeam( GetMeshDS()->ShapeToIndex( subShape)); } /*! * \brief Check if the shape set through IsQuadraticSubMesh() or SetSubShape() - * has a seam edge - * \retval bool - true if it has + * has a seam edge, i.e. an edge that has two parametric representations + * on a surface + * \retval bool - true if it has */ bool HasSeam() const { return !mySeamShapeIds.empty(); } + /*! + * \brief Check if the shape set through IsQuadraticSubMesh() or SetSubShape() + * has a seam edge that encounters twice in a wire + * \retval bool - true if it has + */ + bool HasRealSeam() const { return HasSeam() && ( *mySeamShapeIds.begin() < 0 ); } /*! * \brief Return index of periodic parametric direction of a closed face - * \retval int - 1 for U, 2 for V direction + * \retval int - 1 for U, 2 for V direction */ int GetPeriodicIndex() const { return myParIndex; } /*! @@ -310,28 +605,74 @@ public: */ double GetOtherParam(const double param) const; - /** - * Special function for search or creation medium node + /*! + * \brief Return existing or create new medium nodes between given ones + * \param force3d - true means node creation at the middle between the + * two given nodes, else node position is found on its + * supporting geometrical shape, if any. + * \param expectedSupport - shape type corresponding to element being created + * , e.g TopAbs_EDGE if SMDSAbs_Edge is created + * basing on \a n1 and \a n2 */ const SMDS_MeshNode* GetMediumNode(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, - const bool force3d); - /*! - * Auxilary function for filling myNLinkNodeMap - */ - void AddNLinkNode(const SMDS_MeshNode* n1, + const bool force3d, + TopAbs_ShapeEnum expectedSupport=TopAbs_SHAPE); + /*! + * \brief Return existing or create a new central node for a quardilateral + * quadratic face given its 8 nodes. + * \param force3d - true means node creation in between the given nodes, + * else node position is found on a geometrical face if any. + */ + const SMDS_MeshNode* GetCentralNode(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n3, + const SMDS_MeshNode* n4, + const SMDS_MeshNode* n12, + const SMDS_MeshNode* n23, + const SMDS_MeshNode* n34, + const SMDS_MeshNode* n41, + bool force3d); + /*! + * \brief Return existing or create a new central node for a + * quadratic triangle given its 6 nodes. + * \param force3d - true means node creation in between the given nodes, + * else node position is found on a geometrical face if any. + */ + const SMDS_MeshNode* GetCentralNode(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n3, + const SMDS_MeshNode* n12, + const SMDS_MeshNode* n23, + const SMDS_MeshNode* n31, + bool force3d); + /*! + * \brief Return index and type of the shape (EDGE or FACE only) to set a medium node on + */ + std::pair GetMediumPos(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const bool useCurSubShape=false, + TopAbs_ShapeEnum expectedSupport=TopAbs_SHAPE); + /*! + * \brief Add a link in my data structure + */ + void AddTLinkNode(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshNode* n12); - /** - * Auxilary function for filling myNLinkNodeMap + /*! + * \brief Add many links in my data structure */ - void AddNLinkNodeMap(const NLinkNodeMap& aMap) - { myNLinkNodeMap.insert(aMap.begin(), aMap.end()); } + void AddTLinkNodeMap(const TLinkNodeMap& aMap) + { myTLinkNodeMap.insert(aMap.begin(), aMap.end()); } + + bool AddTLinks(const SMDS_MeshEdge* edge); + bool AddTLinks(const SMDS_MeshFace* face); + bool AddTLinks(const SMDS_MeshVolume* vol); /** - * Returns myNLinkNodeMap + * Returns myTLinkNodeMap */ - const NLinkNodeMap& GetNLinkNodeMap() const { return myNLinkNodeMap; } + const TLinkNodeMap& GetTLinkNodeMap() const { return myTLinkNodeMap; } /** * Check mesh without geometry for: if all elements on this shape are quadratic, @@ -341,38 +682,101 @@ public: enum MType{ LINEAR, QUADRATIC, COMP }; MType IsQuadraticMesh(); -protected: + virtual ~SMESH_MesherHelper(); + + protected: /*! * \brief Select UV on either of 2 pcurves of a seam edge, closest to the given UV - * \param uv1 - UV on the seam - * \param uv2 - UV within a face - * \retval gp_Pnt2d - selected UV + * \param uv1 - UV on the seam + * \param uv2 - UV within a face + * \retval gp_Pnt2d - selected UV */ - gp_Pnt2d GetUVOnSeam( const gp_Pnt2d& uv1, const gp_Pnt2d& uv2 ) const; + gp_Pnt2d getUVOnSeam( const gp_Pnt2d& uv1, const gp_Pnt2d& uv2 ) const; + + const SMDS_MeshNode* getMediumNodeOnComposedWire(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + bool force3d); + + double getFaceMaxTol( const TopoDS_Shape& face ) const; private: // Forbiden copy constructor - SMESH_MesherHelper (const SMESH_MesherHelper& theOther) {}; + SMESH_MesherHelper (const SMESH_MesherHelper& theOther); - // special map for using during creation of quadratic elements - NLinkNodeMap myNLinkNodeMap; + // key of a map of bi-quadratic face to it's central node + struct TBiQuad: public std::pair > + { + TBiQuad(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n3, + const SMDS_MeshNode* n4=0) + { + TIDSortedNodeSet s; + s.insert(n1); + s.insert(n2); + s.insert(n3); + if ( n4 ) s.insert(n4); + TIDSortedNodeSet::iterator n = s.begin(); + first = (*n++)->GetID(); + second.first = (*n++)->GetID(); + second.second = (*n++)->GetID(); + } + }; + + // maps used during creation of quadratic elements + TLinkNodeMap myTLinkNodeMap; // medium nodes on links + std::map< TBiQuad, const SMDS_MeshNode* > myMapWithCentralNode; // central nodes of faces std::set< int > myDegenShapeIds; std::set< int > mySeamShapeIds; - double myPar1, myPar2; // bounds of a closed periodic surface - int myParIndex; // bounds' index (1-U, 2-V) + double myPar1[2], myPar2[2]; // U and V bounds of a closed periodic surface + int myParIndex; // bounds' index (1-U, 2-V, 3-both) + + std::map< int, double > myFaceMaxTol; + + typedef std::map< int, Handle(ShapeAnalysis_Surface)> TID2Surface; + typedef std::map< int, GeomAPI_ProjectPointOnSurf* > TID2ProjectorOnSurf; + typedef std::map< int, GeomAPI_ProjectPointOnCurve* > TID2ProjectorOnCurve; + mutable TID2Surface myFace2Surface; + TID2ProjectorOnSurf myFace2Projector; + TID2ProjectorOnCurve myEdge2Projector; TopoDS_Shape myShape; SMESH_Mesh* myMesh; int myShapeID; - // to create quadratic elements bool myCreateQuadratic; + bool myCreateBiQuadratic; bool mySetElemOnShape; + bool myFixNodeParameters; + std::map< int,bool > myNodePosShapesValidity; + bool toCheckPosOnShape(int shapeID ) const; + void setPosOnShapeValidity(int shapeID, bool ok ) const; }; +//======================================================================= +inline gp_XY +SMESH_MesherHelper::calcTFI(double x, double y, + const gp_XY& a0,const gp_XY& a1,const gp_XY& a2,const gp_XY& a3, + const gp_XY& p0,const gp_XY& p1,const gp_XY& p2,const gp_XY& p3) +{ + return + ((1 - y) * p0 + x * p1 + y * p2 + (1 - x) * p3 ) - + ((1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3); +} +//======================================================================= +inline gp_XYZ +SMESH_MesherHelper::calcTFI(double x, double y, + const gp_XYZ& a0,const gp_XYZ& a1,const gp_XYZ& a2,const gp_XYZ& a3, + const gp_XYZ& p0,const gp_XYZ& p1,const gp_XYZ& p2,const gp_XYZ& p3) +{ + return + ((1 - y) * p0 + x * p1 + y * p2 + (1 - x) * p3 ) - + ((1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3); +} +//======================================================================= #endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_Octree.hxx b/src/3rdParty/salomesmesh/inc/SMESH_Octree.hxx index 1d40b39e6309..d99081d75a30 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_Octree.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_Octree.hxx @@ -1,99 +1,75 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMESH_Octree : global Octree implementation -// File : SMESH_Octree.hxx -// Created : Tue Jan 16 16:00:00 2007 -// Author : Nicolas Geimer & Aurélien Motteux (OCC) -// Module : SMESH + +// SMESH SMESH_Octree : Octree implementation +// File : SMESH_Octree.hxx +// Created : Tue Jan 16 16:00:00 2007 +// Author : Nicolas Geimer & Aurélien Motteux (OCC) +// Module : SMESH // #ifndef _SMESH_OCTREE_HXX_ #define _SMESH_OCTREE_HXX_ +#include "SMESH_Utils.hxx" +#include "SMESH_tree.hxx" #include -class SMESH_Octree { - +//================================================================================ +/*! + * \brief 3D tree of anything. + * Methods to implement in a descendant are: + * - Bnd_B3d* buildRootBox(); // box of the whole tree + * - descendant* newChild() const; // a new child instance + * - void buildChildrenData(); // Fill in data of the children + */ +class SMESHUtils_EXPORT SMESH_Octree : public SMESH_Tree< Bnd_B3d, 8 > +{ public: - // Constructor - SMESH_Octree (const int maxLevel = -1, const double minBoxSize = 0.); - - // Destructor - virtual ~SMESH_Octree (); - - // Tell if Octree is a leaf or not (has to be implemented in inherited classes) - virtual const bool isLeaf() = 0; - - // Compute the Octree - void Compute(); - - // Set the maximal level of the Octree - void setMaxLevel(const int maxLevel); - - // Set the minimal size of the Box - void setMinBoxSize(const double minBoxSize){myMinBoxSize = minBoxSize;}; - - // Set the bounding box of the Octree - void setBox(const Bnd_B3d* box); - - // Set box to the 3d Bounding Box of the Octree - void getBox(Bnd_B3d & box); + typedef SMESH_Tree< Bnd_B3d, 8> TBaseTree; - // Compute the bigger dimension of the box - static double maxSize(const Bnd_B3d* box); + // Constructor. limit must be provided at tree root construction. + // limit will be deleted by SMESH_Octree + SMESH_Octree (SMESH_TreeLimit* limit=0); + virtual ~SMESH_Octree() {}; - // Return its level - int level() const { return myLevel; } + // Compute the bigger dimension of my box + double maxSize() const; -protected: - // Constructor for children (has to be implemented in inherited classes) - virtual SMESH_Octree* allocateOctreeChild() = 0; + // Return index of a child the given point is in + inline static int getChildIndex(double x, double y, double z, const gp_XYZ& boxMiddle); - // Build the 8 children boxes - void buildChildren(); + protected: - // Build the data in the 8 children (has to be implemented in inherited classes) - virtual void buildChildrenData() = 0; - - // members - - // Box of the Octree - Bnd_B3d* myBox; - - // Array of 8 Octree children - SMESH_Octree** myChildren; - - // Point the father, set to NULL for the level 0 - SMESH_Octree* myFather; - - // Level of the Octree - int myLevel; - - // MaxLevel of the Octree - int myMaxLevel; + // Allocate a bndbox according to childIndex. childIndex is zero based + virtual Bnd_B3d* newChildBox(int childIndex) const; +}; - // Minimal size of the Box - double myMinBoxSize; +//================================================================================ +/*! + * \brief Return index of a child the given point is in + */ +inline int SMESH_Octree::getChildIndex(double x, double y, double z, const gp_XYZ& mid) +{ + return (x > mid.X()) + ( y > mid.Y())*2 + (z > mid.Z())*4; +} - // Tell us if the Octree is a leaf or not (-1 if not initialized) - int myIsLeaf; -}; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_OctreeNode.hxx b/src/3rdParty/salomesmesh/inc/SMESH_OctreeNode.hxx index 6a3b0cb39a1e..2cd22a3c544d 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_OctreeNode.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_OctreeNode.hxx @@ -1,87 +1,101 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH_OctreeNode : Octree with Nodes set // inherites global class SMESH_Octree -// // File : SMESH_OctreeNode.hxx // Created : Tue Jan 16 16:00:00 2007 -// Author : Nicolas Geimer & Aurélien Motteux (OCC) +// Author : Nicolas Geimer & Aurelien Motteux (OCC) // Module : SMESH - +// #ifndef _SMESH_OCTREENODE_HXX_ #define _SMESH_OCTREENODE_HXX_ +#include "SMDS_ElemIterator.hxx" +#include "SMDS_MeshNode.hxx" #include "SMESH_Octree.hxx" +#include "SMESH_Utils.hxx" + +#include #include #include - -#include "SMDS_ElemIterator.hxx" +#include +#include //forward declaration class SMDS_MeshNode; class SMESH_OctreeNode; -typedef SMDS_Iterator SMESH_OctreeNodeIterator; -typedef boost::shared_ptr SMESH_OctreeNodeIteratorPtr; +typedef SMDS_Iterator SMESH_OctreeNodeIterator; +typedef boost::shared_ptr SMESH_OctreeNodeIteratorPtr; +typedef std::set< const SMDS_MeshNode*, TIDCompare > TIDSortedNodeSet; -class SMESH_OctreeNode : public SMESH_Octree{ - -public: +class SMESHUtils_EXPORT SMESH_OctreeNode : public SMESH_Octree +{ + public: // Constructor - SMESH_OctreeNode (const std::set& theNodes, const int maxLevel = -1, + SMESH_OctreeNode (const TIDSortedNodeSet& theNodes, const int maxLevel = 8, const int maxNbNodes = 5, const double minBoxSize = 0.); -//============================= -/*! - * \brief Empty destructor - */ -//============================= + // destructor virtual ~SMESH_OctreeNode () {}; - // Tells us if SMESH_OctreeNode is a leaf or not (-1 = not initialiazed) - virtual const bool isLeaf(); - // Tells us if Node is inside the current box with the precision "precision" - virtual const bool isInside(const SMDS_MeshNode * Node, const double precision = 0.); + virtual const bool isInside(const gp_XYZ& p, const double precision = 0.); // Return in Result a list of Nodes potentials to be near Node - void NodesAround(const SMDS_MeshNode * Node, - std::list* Result, - const double precision = 0.); + void NodesAround(const SMDS_MeshNode * node, + std::list* result, + const double precision = 0.); + + // Return in dist2Nodes nodes mapped to their square distance from Node + bool NodesAround(const gp_XYZ& point, + std::map& dist2Nodes, + double precision); + + // Return a list of Nodes close to a point + void NodesAround(const gp_XYZ& point, + std::vector& nodes, + double precision); // Return in theGroupsOfNodes a list of group of nodes close to each other within theTolerance // Search for all the nodes in nodes - void FindCoincidentNodes ( std::set* nodes, + void FindCoincidentNodes ( TIDSortedNodeSet* nodes, const double theTolerance, std::list< std::list< const SMDS_MeshNode*> >* theGroupsOfNodes); // Static method that return in theGroupsOfNodes a list of group of nodes close to each other within // theTolerance search for all the nodes in nodes - static void FindCoincidentNodes ( std::set nodes, + static void FindCoincidentNodes ( TIDSortedNodeSet& nodes, std::list< std::list< const SMDS_MeshNode*> >* theGroupsOfNodes, - const double theTolerance = 0.00001, const int maxLevel = -1, + const double theTolerance = 0.00001, + const int maxLevel = -1, const int maxNbNodes = 5); + /*! + * \brief Update data according to node movement + */ + void UpdateByMoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt ); /*! * \brief Return iterator over children */ @@ -93,40 +107,39 @@ public: /*! * \brief Return nb nodes in a tree */ - int NbNodes() const { return myNbNodes; } + int NbNodes() const { return myNodes.size(); } protected: -//============================= -/*! - * \brief Empty constructor - */ -//============================= - SMESH_OctreeNode (){}; + struct Limit : public SMESH_TreeLimit + { + int myMaxNbNodes; + Limit(int maxLevel, double minSize, int maxNbNodes) + :SMESH_TreeLimit(maxLevel, minSize), myMaxNbNodes(maxNbNodes) {} + }; + + int getMaxNbNodes() const; + + SMESH_OctreeNode(); + + // Compute the bounding box of the whole set of nodes myNodes + virtual Bnd_B3d* buildRootBox(); // Shares the father's data with each of his child virtual void buildChildrenData(); - // Compute the bounding box of the whole set of nodes myNodes (only used for OctreeNode level 0) - void computeBoxForFather(); - // Construct an empty SMESH_OctreeNode used by SMESH_Octree::buildChildren() - virtual SMESH_Octree* allocateOctreeChild(); + virtual SMESH_Octree* newChild() const; // Return in result a list of nodes closed to Node and remove it from SetOfNodes - void FindCoincidentNodes( const SMDS_MeshNode * Node, - std::set* SetOfNodes, + void FindCoincidentNodes( const SMDS_MeshNode * Node, + TIDSortedNodeSet* SetOfNodes, std::list* Result, - const double precision); - - // The max number of nodes a leaf box can contain - int myMaxNbNodes; + const double precision); // The set of nodes inside the box of the Octree (Empty if Octree is not a leaf) - std::set myNodes; + TIDSortedNodeSet myNodes; - // The number of nodes I have inside the box - int myNbNodes; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_Pattern.hxx b/src/3rdParty/salomesmesh/inc/SMESH_Pattern.hxx index b13c7033ae17..67c9093ea5c8 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_Pattern.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_Pattern.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : SMESH_Pattern.hxx // Created : Mon Aug 2 10:30:00 2004 // Author : Edward AGAPOV (eap) @@ -34,16 +35,12 @@ #include #include -#include +#include #include #include #include #include -#ifdef __BORLANDC__ -#include -#endif - class SMDS_MeshElement; class SMDS_MeshFace; class SMDS_MeshVolume; @@ -51,12 +48,8 @@ class SMDS_MeshNode; class SMESH_Mesh; class SMESHDS_SubMesh; class TopoDS_Shell; -class TopoDS_Vertex; class TopoDS_Face; - -#ifndef __BORLANDC__ class TopoDS_Edge; -#endif // // Class allowing meshing by mapping of pre-defined patterns: it generates @@ -77,7 +70,8 @@ class SMESH_EXPORT SMESH_Pattern { bool Load (SMESH_Mesh* theMesh, const TopoDS_Face& theFace, - bool theProject = false); + bool theProject = false, + TopoDS_Vertex the1stVertex=TopoDS_Vertex()); // Create a pattern from the mesh built on . // ==true makes override nodes positions // on computed by mesher @@ -197,7 +191,9 @@ class SMESH_EXPORT SMESH_Pattern { // Apply(mesh_face) ERR_APPLF_BAD_FACE_GEOM, // bad face geometry // MakeMesh - ERR_MAKEM_NOT_COMPUTED // mapping failed + ERR_MAKEM_NOT_COMPUTED, // mapping failed + //Unexpected error + ERR_UNEXPECTED // Unexpected of the pattern mapping alorithm }; ErrorCode GetErrorCode() const { return myErrorCode; } @@ -248,8 +244,7 @@ private: }; friend std::ostream & operator <<(std::ostream & OS, const TPoint& p); - bool setErrorCode( const ErrorCode theErrorCode ) - { myErrorCode = theErrorCode; return myErrorCode == ERR_OK; } + bool setErrorCode( const ErrorCode theErrorCode ); // set ErrorCode and return true if it is Ok bool setShapeToMesh(const TopoDS_Shape& theShape); @@ -299,7 +294,7 @@ private: const TListOfEdgesList::iterator& theFromWire, const TListOfEdgesList::iterator& theToWire, const int theFirstEdgeID, - std::list< std::list< TPoint* > >& theEdgesPointsList ); + std::list< std::list< TPoint* > >& theEdgesPointsList ); // sort wires in theWireList from theFromWire until theToWire, // the wires are set in the order to correspond to the order // of boundaries; after sorting, edges in the wires are put @@ -339,6 +334,12 @@ private: void clearMesh(SMESH_Mesh* theMesh) const; // clear mesh elements existing on myShape in theMesh + bool findExistingNodes( SMESH_Mesh* mesh, + const TopoDS_Shape& S, + const std::list< TPoint* > & points, + std::vector< const SMDS_MeshNode* > & nodes); + // fills nodes vector with nodes existing on a given shape + static SMESHDS_SubMesh * getSubmeshWithElements(SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); // return submesh containing elements bound to theShape in theMesh @@ -361,7 +362,7 @@ private: // all functions assure that shapes are indexed so that first go // ordered vertices, then ordered edge, then faces and maybe a shell TopTools_IndexedMapOfOrientedShape myShapeIDMap; - std::map< int, std::list< TPoint* > > myShapeIDToPointsMap; + std::map< int, std::list< TPoint*> > myShapeIDToPointsMap; // for the 2d case: // nb of key-points in each of pattern boundaries diff --git a/src/3rdParty/salomesmesh/inc/SMESH_ProxyMesh.hxx b/src/3rdParty/salomesmesh/inc/SMESH_ProxyMesh.hxx new file mode 100644 index 000000000000..03d3f2b1bd5b --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMESH_ProxyMesh.hxx @@ -0,0 +1,183 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 : SMESH_ProxyMesh.hxx +// Created : Thu Dec 2 10:05:35 2010 +// Author : Edward AGAPOV (eap) + +#ifndef __SMESH_ProxyMesh_HXX__ +#define __SMESH_ProxyMesh_HXX__ + +#include "SMESH_SMESH.hxx" + +#include "SMDS_MeshElement.hxx" +#include "SMESHDS_SubMesh.hxx" +#include "SMESH_TypeDefs.hxx" + +#include + +#include +#include +#include + +class SMDS_MeshNode; +class SMESHDS_Mesh; +class SMESH_Mesh; + +/*! + * \brief Container of xD mesh elements substituting other ones in the + * input mesh of an (x+1)D algorithm + */ +class SMESH_EXPORT SMESH_ProxyMesh +{ +public: + + typedef boost::shared_ptr Ptr; + + typedef std::map TN2NMap; + + //-------------------------------------------------------------------------------- + /*! + * \brief Proxy sub-mesh + */ + class SMESH_EXPORT SubMesh : public SMESHDS_SubMesh + { + public: + + const TN2NMap* GetNodeNodeMap() const { return _n2n; } + const SMDS_MeshNode* GetProxyNode( const SMDS_MeshNode* n ) const; + const UVPtStructVec& GetUVPtStructVec() const { return _uvPtStructVec; } + virtual void AddElement(const SMDS_MeshElement * e); + virtual int NbElements() const; + virtual int NbNodes() const; + virtual SMDS_ElemIteratorPtr GetElements() const; + virtual SMDS_NodeIteratorPtr GetNodes() const; + virtual void Clear(); + virtual bool Contains(const SMDS_MeshElement * ME) const; + + template< class ITERATOR > + void ChangeElements( ITERATOR it, ITERATOR end ) + { + // change SubMesh contents without deleting tmp elements + // for which the caller is responsible + _elements.assign( it, end ); + } + SubMesh(int index=0):SMESHDS_SubMesh(0,index),_n2n(0) {} + virtual ~SubMesh() { Clear(); } + + protected: + std::vector _elements; + TN2NMap* _n2n; + UVPtStructVec _uvPtStructVec; // for SubMesh of EDGE + friend class SMESH_ProxyMesh; + }; + //-------------------------------------------------------------------------------- + // Public interface + + SMESH_ProxyMesh(); + SMESH_ProxyMesh(std::vector& components); + SMESH_ProxyMesh(const SMESH_Mesh& mesh) { _mesh = &mesh; } + virtual ~SMESH_ProxyMesh(); + + // Returns the submesh of a shape; it can be a proxy sub-mesh + const SMESHDS_SubMesh* GetSubMesh(const TopoDS_Shape& shape) const; + + // Returns the proxy sub-mesh of a shape; it can be NULL + const SubMesh* GetProxySubMesh(const TopoDS_Shape& shape) const; + + // Returns the proxy node of a node; the input node is returned if no proxy exists + const SMDS_MeshNode* GetProxyNode( const SMDS_MeshNode* node ) const; + + // Returns number of proxy sub-meshes + int NbProxySubMeshes() const; + + // Returns iterator on all faces of the mesh taking into account substitutions. + // To be used in case of mesh without shape + SMDS_ElemIteratorPtr GetFaces() const; + + // Returns iterator on all faces on the face taking into account substitutions + SMDS_ElemIteratorPtr GetFaces(const TopoDS_Shape& face) const; + + // Return total nb of faces taking into account substitutions + int NbFaces() const; + + bool IsTemporary(const SMDS_MeshElement* elem ) const; + + + + SMESH_Mesh* GetMesh() const { return const_cast( _mesh ); } + + SMESHDS_Mesh* GetMeshDS() const; + + //-------------------------------------------------------------------------------- + // Interface for descendants + protected: + + void setMesh(const SMESH_Mesh& mesh) { _mesh = &mesh; } + + int shapeIndex(const TopoDS_Shape& shape) const; + + virtual SubMesh* newSubmesh(int index=0) const { return new SubMesh(index); } + + // returns a proxy sub-mesh; zero index is for the case of mesh w/o shape + SubMesh* findProxySubMesh(int shapeIndex=0) const; + + // returns a proxy sub-mesh; it is created if not yet exists + SubMesh* getProxySubMesh(int shapeIndex); + + // returns a proxy sub-mesh; it is created if not yet exists + SubMesh* getProxySubMesh(const TopoDS_Shape& shape=TopoDS_Shape()); + + // move proxy sub-mesh from other proxy mesh to this, returns true if sub-mesh found + bool takeProxySubMesh( const TopoDS_Shape& shape, SMESH_ProxyMesh* proxyMesh ); + + // move tmp elements residing the _mesh from other proxy mesh to this + void takeTmpElemsInMesh( SMESH_ProxyMesh* proxyMesh ); + + // removes tmp element from the _mesh + void removeTmpElement( const SMDS_MeshElement* elem ); + + // stores tmp element residing the _mesh + void storeTmpElement( const SMDS_MeshElement* elem ); + + // store node-node correspondence + void setNode2Node(const SMDS_MeshNode* srcNode, + const SMDS_MeshNode* proxyNode, + const SubMesh* subMesh); + + // types of elements needed to implement NbFaces() and GetFaces(); + // if _allowedTypes is empty, only elements from _subMeshes are returned, + // else elements of _mesh filtered using allowedTypes are additionally returned + std::vector< SMDSAbs_EntityType> _allowedTypes; + + private: + + const SMESH_Mesh* _mesh; + + // proxy sub-meshes; index in vector == shapeIndex(shape) + std::vector< SubMesh* > _subMeshes; + + // tmp elements residing the _mesh, to be deleted at destruction + std::set< const SMDS_MeshElement* > _elemsInMesh; + + // Complex submesh used to iterate over elements in other sub-meshes + mutable SubMesh _subContainer; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_Quadtree.hxx b/src/3rdParty/salomesmesh/inc/SMESH_Quadtree.hxx new file mode 100644 index 000000000000..0117529e4403 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMESH_Quadtree.hxx @@ -0,0 +1,73 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH_Quadtree : Quartree implementation +// File : SMESH_Quadtree.hxx +// Module : SMESH +// +#ifndef _SMESH_Quadtree_HXX_ +#define _SMESH_Quadtree_HXX_ + +#include "SMESH_Utils.hxx" +#include "SMESH_tree.hxx" +#include + +/*! + * \brief 2D tree of anything. + * Methods to implement in a descendant are: + * - Bnd_B2d* buildRootBox(); // box of the whole tree + * - descendant* newChild() const; // a new child instance + * - void buildChildrenData(); // Fill in data of the children + */ +class SMESHUtils_EXPORT SMESH_Quadtree : public SMESH_Tree< Bnd_B2d, 4 > +{ +public: + typedef SMESH_Tree< Bnd_B2d, 4> TBaseTree; + + // Constructor. limit must be provided at tree root construction. + // limit will be deleted by SMESH_Quadtree + SMESH_Quadtree (SMESH_TreeLimit* limit=0); + + // Compute the bigger dimension of my box + double maxSize() const; + + // Return index of a child the given point is in + //inline int getChildIndex(double x, double y, const gp_XY& boxMiddle)const; + + protected: + + // Allocate a bndbox according to childIndex. childIndex is zero based + virtual Bnd_B2d* newChildBox(int childIndex) const; +}; + +//================================================================================ +/*! + * \brief Return index of a child the given point is in + */ +//================================================================================ + +// inline int SMESH_Quadtree::getChildIndex(double x, double y, const gp_XY& mid) const +// { +// return (x > mid.X()) + ( y > mid.Y())*2 + (z > mid.Z())*4; +// } + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_SMDS.hxx b/src/3rdParty/salomesmesh/inc/SMESH_SMDS.hxx index 97a1b63ff14f..9e55e313f428 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_SMDS.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_SMDS.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : SMESH_SMDS.hxx // Author : Alexander A. BORODIN // Module : SMESH @@ -26,7 +27,7 @@ #ifndef _SMESH_SMDS_HXX_ #define _SMESH_SMDS_HXX_ -#ifdef WNT +#ifdef WIN32 #if defined SMDS_EXPORTS #define SMDS_EXPORT __declspec( dllexport ) #else diff --git a/src/3rdParty/salomesmesh/inc/SMESH_SMESH.hxx b/src/3rdParty/salomesmesh/inc/SMESH_SMESH.hxx index 249fc6a85538..1094aed0dfdd 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_SMESH.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_SMESH.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : SMESH_SMESH.hxx // Author : Alexander A. BORODIN // Module : SMESH @@ -26,8 +27,8 @@ #ifndef _SMESH_SMESH_HXX_ #define _SMESH_SMESH_HXX_ -#ifdef WNT - #if defined SMESH_EXPORTS +#ifdef WIN32 + #if defined SMESHimpl_EXPORTS #define SMESH_EXPORT __declspec( dllexport ) #else #define SMESH_EXPORT __declspec( dllimport ) diff --git a/src/3rdParty/salomesmesh/inc/SMESH_SMESHDS.hxx b/src/3rdParty/salomesmesh/inc/SMESH_SMESHDS.hxx index 4e45bbfaaf42..bbd85c6ec98a 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_SMESHDS.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_SMESHDS.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : SMESH_SMESHDS.hxx // Author : Alexander A. BORODIN // Module : SMESH @@ -26,7 +27,7 @@ #ifndef _SMESH_SMESHDS_HXX_ #define _SMESH_SMESHDS_HXX_ -#ifdef WNT +#ifdef WIN32 #if defined SMESHDS_EXPORTS #define SMESHDS_EXPORT __declspec( dllexport ) #else diff --git a/src/3rdParty/salomesmesh/inc/SMESH_StdMeshers.hxx b/src/3rdParty/salomesmesh/inc/SMESH_StdMeshers.hxx index be440c1bd35a..88c712d448f4 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_StdMeshers.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_StdMeshers.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : SMESH_StdMeshers.hxx // Author : Alexander BORODIN // Module : SMESH @@ -27,8 +28,8 @@ #ifndef _SMESH_StdMeshers_HXX_ #define _SMESH_StdMeshers_HXX_ -#ifdef WNT - #if defined STDMESHERS_EXPORTS +#ifdef WIN32 + #if defined STDMESHERS_EXPORTS || defined StdMeshers_EXPORTS #define STDMESHERS_EXPORT __declspec( dllexport ) #else #define STDMESHERS_EXPORT __declspec( dllimport ) diff --git a/src/3rdParty/salomesmesh/inc/SMESH_TryCatch.hxx b/src/3rdParty/salomesmesh/inc/SMESH_TryCatch.hxx new file mode 100644 index 000000000000..bf2a8a73ccde --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMESH_TryCatch.hxx @@ -0,0 +1,109 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SMESH_TryCatch.hxx +// Created : Mon Dec 17 15:43:38 2012 +// Author : Edward AGAPOV (eap) + +#ifndef __SMESH_TryCatch_HXX__ +#define __SMESH_TryCatch_HXX__ + +#include "SMESH_Comment.hxx" +#include "SMESH_ComputeError.hxx" +#include "SMESH_Utils.hxx" + +#include +#include +#include +#include +#include + +// IMPORTANT: include this file _after_ OCC ones, else OCC_CATCH_SIGNALS can be undefined! + +#ifndef OCC_CATCH_SIGNALS +#define OCC_CATCH_SIGNALS +#endif + +// Define macros to catch and convert some of possible exceptions into text or SALOME_Exception + +//------------------------------------------------------------------------------------- +#define SMESH_TRY \ + try { \ + OCC_CATCH_SIGNALS \ + +//------------------------------------------------------------------------------------- +// A macro to add a custom catch clause to SMESH_CATCH +// To add your own catch close, define SMY_OWN_CATCH macro before including this file. +#ifndef SMY_OWN_CATCH +#define SMY_OWN_CATCH +#endif + +//------------------------------------------------------------------------------------- +// A macro allowing to retrieve a result returned by onExceptionFun +#define SMESH_CAUGHT + +//------------------------------------------------------------------------------------- +// A macro makes description of a caught exception and calls onExceptionFun(const char*). +// Two onExceptionFun() are defined here: SMESH::throwSalomeEx() and SMESH::doNothing(). +// To add your own catch close, define SMY_OWN_CATCH macro before including this file. + +#define SMESH_CATCH( onExceptionFun ) \ + } \ + catch (Standard_Failure& ex) \ + { \ + SMESH_Comment text("OCCT Exception: "); \ + text << ": " << ex.DynamicType()->Name(); \ + if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) \ + text << ": " << ex.GetMessageString(); \ + SMESH_CAUGHT onExceptionFun( text ); \ + } \ + catch ( ::SMESH_ComputeError& ce ) \ + { \ + if ( !ce.myComment.empty() ) \ + SMESH_CAUGHT onExceptionFun( ce.myComment.c_str() ); \ + else if ( ce.IsCommon() ) \ + SMESH_CAUGHT onExceptionFun( ce.CommonName().c_str() ); \ + else \ + SMESH_CAUGHT onExceptionFun \ + (SMESH_Comment("SMESH_ComputeError: ") << ce.myName ); \ + } \ + catch ( const std::exception& ex) \ + { \ + SMESH_CAUGHT onExceptionFun( ex.what() ); \ + } \ + \ + SMY_OWN_CATCH \ + \ + catch (...) \ + { \ + SMESH_CAUGHT onExceptionFun("Unknown Exception caught"); \ + } + +//------------------------------------------------------------------------------------- +// Functions that can be used as an argument of SMESH_CATCH + +namespace SMESH +{ + SMESHUtils_EXPORT void throwSalomeEx(const char* txt); + SMESHUtils_EXPORT void doNothing(const char* txt); +} + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_TypeDefs.hxx b/src/3rdParty/salomesmesh/inc/SMESH_TypeDefs.hxx new file mode 100644 index 000000000000..afef61b906c5 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMESH_TypeDefs.hxx @@ -0,0 +1,204 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SMESH_TypeDefs.hxx +// Created : Thu Jan 27 18:38:33 2011 +// Author : Edward AGAPOV (eap) + + +#ifndef __SMESH_TypeDefs_HXX__ +#define __SMESH_TypeDefs_HXX__ + +#include "SMESH_Utils.hxx" + +#include "SMDS_MeshNode.hxx" + +#include +#include + +#include +#include +#include +#include + +typedef std::map, TIDCompare > TElemOfElemListMap; +typedef std::map, TIDCompare > TElemOfNodeListMap; +typedef std::map TNodeNodeMap; + +//!< Set of elements sorted by ID, to be used to assure predictability of edition +typedef std::set< const SMDS_MeshElement*, TIDCompare > TIDSortedElemSet; +typedef std::set< const SMDS_MeshNode*, TIDCompare > TIDSortedNodeSet; + +typedef std::pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink; + +struct FaceQuadStruct; // defined in StdMeshers_Quadrangle_2D.hxx +typedef boost::shared_ptr TFaceQuadStructPtr; + + +namespace SMESHUtils +{ + /*! + * \brief Enforce freeing memory allocated by std::vector + */ + template + void FreeVector(TVECTOR& vec) + { + TVECTOR v2; + vec.swap( v2 ); + } + template + void CompactVector(TVECTOR& vec) + { + TVECTOR v2( vec ); + vec.swap( v2 ); + } + /*! + * \brief Auto pointer + */ + template + struct Deleter + { + TOBJ* _obj; + Deleter( TOBJ* obj = (TOBJ*)NULL ): _obj( obj ) {} + ~Deleter() { delete _obj; _obj = 0; } + private: + Deleter( const Deleter& ); + }; + /*! + * \brief Auto pointer to array + */ + template + struct ArrayDeleter + { + TOBJ* _obj; + ArrayDeleter( TOBJ* obj ): _obj( obj ) {} + ~ArrayDeleter() { delete [] _obj; _obj = 0; } + private: + ArrayDeleter( const ArrayDeleter& ); + }; +} + +//======================================================================= +/*! + * \brief A sorted pair of nodes + */ +//======================================================================= + +struct SMESH_TLink: public NLink +{ + SMESH_TLink(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2 ):NLink( n1, n2 ) + { if ( n1->GetID() < n2->GetID() ) std::swap( first, second ); } + SMESH_TLink(const NLink& link ):NLink( link ) + { if ( first->GetID() < second->GetID() ) std::swap( first, second ); } + const SMDS_MeshNode* node1() const { return first; } + const SMDS_MeshNode* node2() const { return second; } +}; + +//======================================================================= +/*! + * \brief SMESH_TLink knowing its orientation + */ +//======================================================================= + +struct SMESH_OrientedLink: public SMESH_TLink +{ + bool _reversed; + SMESH_OrientedLink(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2 ) + : SMESH_TLink( n1, n2 ), _reversed( n1 != node1() ) {} +}; + +//------------------------------------------ +/*! + * \brief SMDS_MeshNode -> gp_XYZ convertor + */ +//------------------------------------------ +struct SMESH_TNodeXYZ : public gp_XYZ +{ + const SMDS_MeshNode* _node; + double _xyz[3]; + SMESH_TNodeXYZ( const SMDS_MeshElement* e=0):gp_XYZ(0,0,0),_node(0) + { + Set(e); + } + bool Set( const SMDS_MeshElement* e=0 ) + { + if (e) { + assert( e->GetType() == SMDSAbs_Node ); + _node = static_cast(e); + _node->GetXYZ(_xyz); // - thread safe getting coords + SetCoord( _xyz[0], _xyz[1], _xyz[2] ); + return true; + } + return false; + } + double Distance(const SMDS_MeshNode* n) const { return (SMESH_TNodeXYZ( n )-*this).Modulus(); } + double SquareDistance(const SMDS_MeshNode* n) const { return (SMESH_TNodeXYZ( n )-*this).SquareModulus(); } + bool operator==(const SMESH_TNodeXYZ& other) const { return _node == other._node; } +}; + +//-------------------------------------------------- +/*! + * \brief Data of a node generated on FACE boundary + */ +//-------------------------------------------------- +typedef struct uvPtStruct +{ + double param; + double normParam; + double u, v; // original 2d parameter + double x, y; // 2d parameter, normalized [0,1] + const SMDS_MeshNode * node; + + uvPtStruct(): node(NULL) {} + + inline gp_XY UV() const { return gp_XY( u, v ); } + + struct NodeAccessor // accessor to iterate on nodes in UVPtStructVec + { + static const SMDS_MeshNode* value(std::vector< uvPtStruct >::const_iterator it) + { return it->node; } + }; +} UVPtStruct; + +typedef std::vector< UVPtStruct > UVPtStructVec; + +// -------------------------------------------------------------------------------- +// class SMESH_SequenceOfElemPtr +#include + +class SMDS_MeshElement; + +typedef const SMDS_MeshElement* SMDS_MeshElementPtr; + +DEFINE_SEQUENCE (SMESH_SequenceOfElemPtr, SMESH_BaseCollectionElemPtr, SMDS_MeshElementPtr) + + +// -------------------------------------------------------------------------------- +// class SMESH_SequenceOfNode +typedef const SMDS_MeshNode* SMDS_MeshNodePtr; + +DEFINE_SEQUENCE(SMESH_SequenceOfNode, + SMESH_BaseCollectionNodePtr, SMDS_MeshNodePtr) + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_Utils.hxx b/src/3rdParty/salomesmesh/inc/SMESH_Utils.hxx new file mode 100755 index 000000000000..6e3d7958a390 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMESH_Utils.hxx @@ -0,0 +1,40 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SMESH_Utils.hxx +// Author : Alexander A. BORODIN +// Module : SMESH +// +#ifndef _SMESH_Utils_hxx_ +#define _SMESH_Utils_hxx_ + +#ifdef WIN32 + #if defined SMESHUtils_EXPORTS + #define SMESHUtils_EXPORT __declspec( dllexport ) + #else + #define SMESHUtils_EXPORT __declspec( dllimport ) + #endif +#else + #define SMESHUtils_EXPORT +#endif + +#endif diff --git a/src/3rdParty/salomesmesh/inc/SMESH_subMesh.hxx b/src/3rdParty/salomesmesh/inc/SMESH_subMesh.hxx index 823593844b1b..249784c08119 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_subMesh.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_subMesh.hxx @@ -1,29 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMESH : implementaion of SMESH idl descriptions + // File : SMESH_subMesh.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESH/SMESH_subMesh.hxx,v 1.12.2.3 2008/11/27 12:25:15 abd Exp $ // #ifndef _SMESH_SUBMESH_HXX_ #define _SMESH_SUBMESH_HXX_ @@ -34,8 +33,9 @@ #include "SMESHDS_SubMesh.hxx" #include "SMESH_Hypothesis.hxx" #include "SMESH_ComputeError.hxx" +#include "SMESH_Algo.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" #include @@ -47,7 +47,7 @@ class SMESH_Hypothesis; class SMESH_Algo; class SMESH_Gen; class SMESH_subMeshEventListener; -struct SMESH_subMeshEventListenerData; +class SMESH_subMeshEventListenerData; class SMESH_subMesh; typedef SMESH_subMeshEventListener EventListener; @@ -59,28 +59,37 @@ typedef boost::shared_ptr< SMDS_Iterator > SMESH_subMeshIterator class SMESH_EXPORT SMESH_subMesh { public: - SMESH_subMesh(int Id, SMESH_Mesh * father, SMESHDS_Mesh * meshDS, - const TopoDS_Shape & aSubShape); + SMESH_subMesh(int Id, + SMESH_Mesh * father, + SMESHDS_Mesh * meshDS, + const TopoDS_Shape & aSubShape); virtual ~ SMESH_subMesh(); - int GetId() const; + int GetId() const; // == meshDS->ShapeToIndex( aSubShape ) SMESH_Mesh* GetFather() { return _father; } - SMESHDS_SubMesh * GetSubMeshDS(); + SMESHDS_SubMesh * GetSubMeshDS(); + const SMESHDS_SubMesh * GetSubMeshDS() const; SMESHDS_SubMesh* CreateSubMeshDS(); // Explicit SMESHDS_SubMesh creation method, required for persistence mechanism SMESH_subMesh *GetFirstToCompute(); + SMESH_Algo* GetAlgo() const; + const std::map < int, SMESH_subMesh * >& DependsOn(); - //const map < int, SMESH_subMesh * >&Dependants(); + bool DependsOn( const SMESH_subMesh* other ) const; /*! - * \brief Return iterator on the submeshes this one depends on + * \brief Return iterator on the sub-meshes this one depends on. By default + * most simple sub-meshes go first. */ SMESH_subMeshIteratorPtr getDependsOnIterator(const bool includeSelf, - const bool complexShapeFirst); + const bool complexShapeFirst=false) const; + + const std::vector< SMESH_subMesh * > & GetAncestors() const; + void ClearAncestors(); const TopoDS_Shape & GetSubShape() const; @@ -88,11 +97,11 @@ class SMESH_EXPORT SMESH_subMesh { NOT_READY, READY_TO_COMPUTE, COMPUTE_OK, FAILED_TO_COMPUTE - }; + }; enum algo_state { NO_ALGO, MISSING_HYP, HYP_OK - }; + }; enum algo_event { ADD_HYP , ADD_ALGO, @@ -100,13 +109,13 @@ class SMESH_EXPORT SMESH_subMesh ADD_FATHER_HYP , ADD_FATHER_ALGO, REMOVE_FATHER_HYP, REMOVE_FATHER_ALGO, MODIF_HYP - }; + }; enum compute_event { - MODIF_ALGO_STATE, COMPUTE, - CLEAN, SUBMESH_COMPUTED, SUBMESH_RESTORED, + MODIF_ALGO_STATE, COMPUTE, COMPUTE_SUBMESH, COMPUTE_CANCELED, + CLEAN, SUBMESH_COMPUTED, SUBMESH_RESTORED, SUBMESH_LOADED, MESH_ENTITY_REMOVED, CHECK_COMPUTE_STATE - }; + }; enum event_type { ALGO_EVENT, COMPUTE_EVENT @@ -123,7 +132,7 @@ class SMESH_EXPORT SMESH_subMesh * \param where - the submesh to store the listener and it's data * * The method remembers the submesh \awhere it puts the listener in order to delete - * them when HYP_OK algo_state is lost + * it when HYP_OK algo_state is lost * After being set, event listener is notified on each event of \awhere submesh. */ void SetEventListener(EventListener* listener, @@ -133,9 +142,22 @@ class SMESH_EXPORT SMESH_subMesh /*! * \brief Return an event listener data * \param listener - the listener whose data is + * \param myOwn - if \c true, returns a listener set by this sub-mesh, + * else returns a listener listening to events of this sub-mesh * \retval EventListenerData* - found data, maybe NULL */ - EventListenerData* GetEventListenerData(EventListener* listener) const; + EventListenerData* GetEventListenerData(EventListener* listener, + const bool myOwn=false) const; + + /*! + * \brief Return an event listener data + * \param listenerName - the listener name + * \param myOwn - if \c true, returns a listener set by this sub-mesh, + * else returns a listener listening to events of this sub-mesh + * \retval EventListenerData* - found data, maybe NULL + */ + EventListenerData* GetEventListenerData(const std::string& listenerName, + const bool myOwn=false) const; /*! * \brief Unregister the listener and delete it and it's data @@ -146,9 +168,17 @@ class SMESH_EXPORT SMESH_subMesh protected: //!< event listeners to notify - std::map< EventListener*, EventListenerData* > myEventListeners; + std::map< EventListener*, EventListenerData* > _eventListeners; + //!< event listeners to delete when HYP_OK algo_state is lost - std::list< std::pair< SMESH_subMesh*, EventListener* > > myOwnListeners; + struct OwnListenerData { + SMESH_subMesh* mySubMesh; + int myMeshID; // id of mySubMesh->GetFather() + int mySubMeshID; + EventListener* myListener; + OwnListenerData( SMESH_subMesh* sm=0, EventListener* el=0); + }; + std::list< OwnListenerData > _ownListeners; /*! * \brief Sets an event listener and its data to a submesh @@ -157,7 +187,7 @@ protected: * * After being set, event listener is notified on each event of a submesh. */ - void SetEventListener(EventListener* listener, EventListenerData* data); + void setEventListener(EventListener* listener, EventListenerData* data); /*! * \brief Notify stored event listeners on the occured event @@ -165,16 +195,22 @@ protected: * \param eventType - algo_event or compute_event * \param hyp - hypothesis, if eventType is algo_event */ - void NotifyListenersOnEvent( const int event, + void notifyListenersOnEvent( const int event, const event_type eventType, SMESH_Hypothesis* hyp = 0); /*! * \brief Delete event listeners depending on algo of this submesh */ - void DeleteOwnListeners(); + void deleteOwnListeners(); - // ================================================================== + /*! + * \brief loads dependent meshes on SUBMESH_LOADED event + */ + void loadDependentMeshes(); + + // END: Members to track non hierarchical dependencies between submeshes + // ===================================================================== public: @@ -182,15 +218,18 @@ public: AlgoStateEngine(int event, SMESH_Hypothesis * anHyp); SMESH_Hypothesis::Hypothesis_Status - SubMeshesAlgoStateEngine(int event, SMESH_Hypothesis * anHyp); + SubMeshesAlgoStateEngine(int event, SMESH_Hypothesis * anHyp, bool exitOnFatal=false); - int GetAlgoState() const { return _algoState; } - int GetComputeState() const { return _computeState; }; - SMESH_ComputeErrorPtr& GetComputeError() { return _computeError; } + algo_state GetAlgoState() const { return _algoState; } + compute_state GetComputeState() const { return _computeState; } + SMESH_ComputeErrorPtr& GetComputeError() { return _computeError; } void DumpAlgoState(bool isMain); bool ComputeStateEngine(int event); + void ComputeSubMeshStateEngine(int event, const bool includeSelf=false); + + bool Evaluate(MapShapeNbElems& aResMap); bool IsConform(const SMESH_Algo* theAlgo); // check if a conform mesh will be produced by the Algo @@ -216,52 +255,56 @@ public: bool IsEmpty() const; bool IsMeshComputed() const; - // check if _subMeshDS contains mesh elements + // check if _subMeshDS contains mesh elements unless _alwaysComputed==true /*! * \brief Allow algo->Compute() if a subshape of lower dim is meshed but * none mesh entity is bound to it */ void SetIsAlwaysComputed(bool isAlCo); - bool IsAlwaysComputed() { return _alwaysComputed; } + bool SubMeshesComputed(bool * isFailedToCompute=0) const; + + int GetComputeCost() const; + // how costly is to compute this sub-mesh + /*! + * \brief Find common submeshes (based on shared subshapes with other + * \param theOther submesh to check + * \param theCommonIds set of common submesh IDs + * NOTE: this method does not cleat set before collect common IDs + */ + bool FindIntersection( const SMESH_subMesh * theOther, + std::set& theSetOfCommon ) const; + protected: // ================================================================== - void InsertDependence(const TopoDS_Shape aSubShape); - - bool SubMeshesComputed(); + void insertDependence(const TopoDS_Shape aShape, TopAbs_ShapeEnum aSubType ); - bool SubMeshesReady(); - - void RemoveSubMeshElementsAndNodes(); - void UpdateDependantsState(const compute_event theEvent); - void UpdateSubMeshState(const compute_state theState); - void ComputeSubMeshStateEngine(int event); - void CleanDependants(); - void CleanDependsOn(); - void SetAlgoState(int state); + void removeSubMeshElementsAndNodes(); + void updateDependantsState(const compute_event theEvent); + void updateSubMeshState(const compute_state theState); + void cleanDependants(); + void cleanDependsOn( SMESH_Algo* algoRequiringCleaning=0 ); + void setAlgoState(algo_state state); /*! * \brief Return a shape containing all sub-shapes of the MainShape that can be * meshed at once along with _subShape */ - TopoDS_Shape GetCollection(SMESH_Gen * theGen, + TopoDS_Shape getCollection(SMESH_Gen * theGen, SMESH_Algo* theAlgo, - bool & theSubComputed); - - /*! - * \brief Apply theAlgo to all subshapes in theCollection - */ - bool ApplyToCollection (SMESH_Algo* theAlgo, - const TopoDS_Shape& theCollection); - + bool & theSubComputed, + bool & theSubFailed, + std::vector& theSubs); /*! * \brief Update compute_state by _computeError * \retval bool - false if there are errors */ - bool CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& theShape=TopoDS_Shape()); + bool checkComputeError(SMESH_Algo* theAlgo, + const bool theComputeOK, + const TopoDS_Shape& theShape=TopoDS_Shape()); /*! * \brief Return a hypothesis attached to theShape. @@ -270,10 +313,11 @@ protected: * is returned; else an applicable ones having theHypType * is returned */ - const SMESH_Hypothesis* GetSimilarAttached(const TopoDS_Shape& theShape, + const SMESH_Hypothesis* getSimilarAttached(const TopoDS_Shape& theShape, const SMESH_Hypothesis * theHyp, const int theHypType = 0); // + int computeCost() const; protected: @@ -283,13 +327,17 @@ protected: int _Id; std::map < int, SMESH_subMesh * >_mapDepend; - bool _dependenceAnalysed; + bool _dependenceAnalysed; + std::vector< SMESH_subMesh * > _ancestors; - int _algoState; - int _computeState; + SMESH_Algo * _algo; // the algorithm found by last *StateEngine() call + algo_state _algoState; + compute_state _computeState; SMESH_ComputeErrorPtr _computeError; + int _computeCost; // how costly is to compute this sub-mesh + int _realComputeCost; // _computeCost depending on presence of needed hypotheses - // allow algo->Compute() if a subshape of lower dim is meshed but + // allow algo->Compute() if a sub-shape of lower dim is meshed but // none mesh entity is bound to it. Eg StdMeshers_CompositeSegment_1D can // mesh several edges as a whole and leave some of them without mesh entities bool _alwaysComputed; diff --git a/src/3rdParty/salomesmesh/inc/SMESH_subMeshEventListener.hxx b/src/3rdParty/salomesmesh/inc/SMESH_subMeshEventListener.hxx index 4673452fc347..d5bfe5cfcaf9 100644 --- a/src/3rdParty/salomesmesh/inc/SMESH_subMeshEventListener.hxx +++ b/src/3rdParty/salomesmesh/inc/SMESH_subMeshEventListener.hxx @@ -1,28 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMESH : implementaion of SMESH idl descriptions -// File : SMESH_subMeshEventListener.hxx -// Created : Mon Nov 13 10:45:49 2006 -// Author : Edward AGAPOV (eap) + +// File : SMESH_subMeshEventListener.hxx +// Created : Mon Nov 13 10:45:49 2006 +// Author : Edward AGAPOV (eap) // #ifndef SMESH_subMeshEventListener_HeaderFile #define SMESH_subMeshEventListener_HeaderFile @@ -30,6 +30,7 @@ #include "SMESH_SMESH.hxx" #include +#include class SMESH_subMesh; class SMESH_Hypothesis; @@ -41,12 +42,22 @@ struct SMESH_subMeshEventListenerData; */ // ------------------------------------------------------------------ -class SMESH_EXPORT SMESH_subMeshEventListener { +class SMESH_EXPORT SMESH_subMeshEventListener +{ bool myIsDeletable; //!< if true, it will be deleted by SMESH_subMesh -public: - SMESH_subMeshEventListener(bool isDeletable):myIsDeletable(isDeletable) {} - virtual ~SMESH_subMeshEventListener() {}; - bool IsDeletable() const { return myIsDeletable; } + mutable std::set myBusySM; //!< to avoid infinite recursion via events + const char* myName; //!< identifier + friend class SMESH_subMesh; + + public: + SMESH_subMeshEventListener(bool isDeletable, const char* name) + :myIsDeletable(isDeletable), myName(name) {} + virtual ~SMESH_subMeshEventListener() {} + bool IsDeletable() const { return myIsDeletable; } + const char* GetName() const { return myName; } + virtual void BeforeDelete(SMESH_subMesh* subMesh, + SMESH_subMeshEventListenerData* data) + {} /*! * \brief Do something on a certain event * \param event - algo_event or compute_event itself (of SMESH_subMesh) @@ -55,9 +66,9 @@ public: * \param data - listener data stored in the subMesh * \param hyp - hypothesis, if eventType is algo_event * - * The base implementation translates CLEAN event to the subMesh stored - * in the listener data. Also it sends SUBMESH_COMPUTED event in case of - * successful COMPUTE event. + * The base implementation (see SMESH_subMesh.cxx) translates CLEAN event + * to the subMeshes stored in the listener data. Also it sends SUBMESH_COMPUTED + * event in case of successful COMPUTE event. */ virtual void ProcessEvent(const int event, const int eventType, @@ -76,10 +87,13 @@ struct SMESH_subMeshEventListenerData { bool myIsDeletable; //!< if true, it will be deleted by SMESH_subMesh int myType; //!< to recognize data type - std::list mySubMeshes; //!< generally: submeshes depending - // on the one storing this data + std::list mySubMeshes; /* generally: submeshes depending + on the one storing this data; + !! they are used to track intermesh + dependencies at mesh loading as well !! */ public: SMESH_subMeshEventListenerData(bool isDeletable):myIsDeletable(isDeletable) {} + virtual ~SMESH_subMeshEventListenerData() {} bool IsDeletable() const { return myIsDeletable; } /*! diff --git a/src/3rdParty/salomesmesh/inc/SMESH_tree.hxx b/src/3rdParty/salomesmesh/inc/SMESH_tree.hxx new file mode 100644 index 000000000000..eb7b2b864886 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/SMESH_tree.hxx @@ -0,0 +1,278 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH_Tree : tree implementation +// File : SMESH_Tree.hxx +// Created : Tue Jan 16 16:00:00 2007 +// Author : Nicolas Geimer & Aurélien Motteux (OCC) +// Module : SMESH +// +#ifndef _SMESH_Tree_HXX_ +#define _SMESH_Tree_HXX_ + +#include "SMESH_Utils.hxx" + +//================================================================================ +// Data limiting the tree height +struct SMESH_TreeLimit { + // MaxLevel of the Tree + int myMaxLevel; + // Minimal size of the Box + double myMinBoxSize; + + // Default: + // maxLevel-> 8^8 = 16777216 terminal trees at most + // minSize -> box size not checked + SMESH_TreeLimit(int maxLevel=8, double minSize=0.):myMaxLevel(maxLevel),myMinBoxSize(minSize) {} + virtual ~SMESH_TreeLimit() {} // it can be inherited +}; + +//================================================================================ +/*! + * \brief Base class for 2D and 3D trees + */ +//================================================================================ + +template< class BND_BOX, + int NB_CHILDREN> +class SMESH_Tree +{ + public: + + typedef BND_BOX box_type; + + // Constructor. limit must be provided at tree root construction. + // limit will be deleted by SMESH_Tree + SMESH_Tree (SMESH_TreeLimit* limit=0); + + // Destructor + virtual ~SMESH_Tree (); + + // Compute the Tree. Must be called by constructor of inheriting class + void compute(); + + // Tell if Tree is a leaf or not. + // An inheriting class can influence it via myIsLeaf protected field + bool isLeaf() const; + + // Return its level + int level() const { return myLevel; } + + // Return Bounding Box of the Tree + const box_type* getBox() const { return myBox; } + + // Return height of the tree, full or from this level to topest leaf + int getHeight(const bool full=true) const; + + static int nbChildren() { return NB_CHILDREN; } + + // Compute the biggest dimension of my box + virtual double maxSize() const = 0; + +protected: + // Return box of the whole tree + virtual box_type* buildRootBox() = 0; + + // Allocate a child + virtual SMESH_Tree* newChild() const = 0; + + // Allocate a bndbox according to childIndex. childIndex is zero based + virtual box_type* newChildBox(int childIndex) const = 0; + + // Fill in data of the children + virtual void buildChildrenData() = 0; + + // members + + // Array of children + SMESH_Tree** myChildren; + + // Point the father, NULL for the level 0 + SMESH_Tree* myFather; + + // Tell us if the Tree is a leaf or not + bool myIsLeaf; + + // Tree limit + const SMESH_TreeLimit* myLimit; + + // Bounding box of a tree + box_type* myBox; + + // Level of the Tree + int myLevel; + + // Build the children recursively + void buildChildren(); +}; + +//=========================================================================== +/*! + * Constructor. limit must be provided at tree root construction. + * limit will be deleted by SMESH_Tree. + */ +//=========================================================================== + +template< class BND_BOX, int NB_CHILDREN> +SMESH_Tree::SMESH_Tree (SMESH_TreeLimit* limit): + myChildren(0), + myFather(0), + myIsLeaf( false ), + myLimit( limit ), + myLevel(0), + myBox(0) +{ + //if ( !myLimit ) myLimit = new SMESH_TreeLimit(); +} + +//================================================================================ +/*! + * \brief Compute the Tree + */ +//================================================================================ + +template< class BND_BOX, int NB_CHILDREN> +void SMESH_Tree::compute() +{ + if ( myLevel==0 ) + { + if ( !myLimit ) myLimit = new SMESH_TreeLimit(); + myBox = buildRootBox(); + if ( myLimit->myMinBoxSize > 0. && maxSize() <= myLimit->myMinBoxSize ) + myIsLeaf = true; + else + buildChildren(); + } +} + +//====================================== +/*! + * \brief SMESH_Tree Destructor + */ +//====================================== + +template< class BND_BOX, int NB_CHILDREN> +SMESH_Tree::~SMESH_Tree () +{ + if ( myChildren ) + { + if ( !isLeaf() ) + { + for(int i = 0; i +void SMESH_Tree::buildChildren() +{ + if ( isLeaf() ) return; + + myChildren = new SMESH_Tree*[NB_CHILDREN]; + + // get the whole model size + double rootSize = 0; + { + SMESH_Tree* root = this; + while ( root->myLevel > 0 ) + root = root->myFather; + rootSize = root->maxSize(); + } + for (int i = 0; i < NB_CHILDREN; i++) + { + // The child is of the same type than its father (For instance, a SMESH_OctreeNode) + // We allocate the memory we need for the child + myChildren[i] = newChild(); + // and we assign to him its box. + myChildren[i]->myFather = this; + if (myChildren[i]->myLimit) + delete myChildren[i]->myLimit; + myChildren[i]->myLimit = myLimit; + myChildren[i]->myLevel = myLevel + 1; + myChildren[i]->myBox = newChildBox( i ); + myChildren[i]->myBox->Enlarge( rootSize * 1e-10 ); + if ( myLimit->myMinBoxSize > 0. && myChildren[i]->maxSize() <= myLimit->myMinBoxSize ) + myChildren[i]->myIsLeaf = true; + } + + // After building the NB_CHILDREN boxes, we put the data into the children. + buildChildrenData(); + + //After we pass to the next level of the Tree + for (int i = 0; ibuildChildren(); +} + +//================================================================================ +/*! + * \brief Tell if Tree is a leaf or not + * An inheriting class can influence it via myIsLeaf protected field + */ +//================================================================================ + +template< class BND_BOX, int NB_CHILDREN> +bool SMESH_Tree::isLeaf() const +{ + return myIsLeaf || ((myLimit->myMaxLevel > 0) ? (level() >= myLimit->myMaxLevel) : false ); +} + +//================================================================================ +/*! + * \brief Return height of the tree, full or from this level to topest leaf + */ +//================================================================================ + +template< class BND_BOX, int NB_CHILDREN> +int SMESH_Tree::getHeight(const bool full) const +{ + if ( full && myFather ) + return myFather->getHeight( true ); + + if ( isLeaf() ) + return 1; + + int heigth = 0; + for (int i = 0; igetHeight( false ); + if ( h > heigth ) + heigth = h; + } + return heigth + 1; +} + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Adaptive1D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Adaptive1D.hxx new file mode 100644 index 000000000000..291a22f879e8 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Adaptive1D.hxx @@ -0,0 +1,90 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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_Adaptive1D.hxx +// Module : SMESH +// +#ifndef _StdMeshers_Adaptive1D_HXX_ +#define _StdMeshers_Adaptive1D_HXX_ + +#include "SMESH_StdMeshers.hxx" + +#include "StdMeshers_Regular_1D.hxx" + +#include "Utils_SALOME_Exception.hxx" + +/*! + * \brief Adaptive 1D hypothesis + */ +class STDMESHERS_EXPORT StdMeshers_Adaptive1D : public SMESH_Hypothesis +{ + public: + StdMeshers_Adaptive1D(int hypId, int studyId, SMESH_Gen * gen); + ~StdMeshers_Adaptive1D(); + + /*! + * Sets minimal allowed segment length + */ + void SetMinSize( double minSegLen ) throw (SALOME_Exception); + double GetMinSize() const { return myMinSize; } + + /*! + * Sets maximal allowed segment length + */ + void SetMaxSize( double maxSegLen ) throw (SALOME_Exception); + double GetMaxSize() const { return myMaxSize; } + + /*! + * Sets parameter value, + * i.e. a maximal allowed distance between a segment and an edge. + */ + void SetDeflection(double value) throw(SALOME_Exception); + double GetDeflection() const { return myDeflection; } + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + + /*! + * \brief Initialize deflection value 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 + */ + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + + /*! + * \brief Initialize my parameter values by default parameters. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0); + + /*! + * \brief Returns an algorithm that works using this hypothesis + */ + SMESH_Algo* GetAlgo() const; + +protected: + + double myMinSize, myMaxSize, myDeflection; + SMESH_Algo* myAlgo; // StdMeshers_AdaptiveAlgo_1D implemented in cxx file +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Arithmetic1D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Arithmetic1D.hxx index 639c8ba019d5..9d00419fbc68 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_Arithmetic1D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Arithmetic1D.hxx @@ -1,37 +1,41 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Arithmetic1D.hxx // Author : Damien COQUERET, OCC // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_Arithmetic1D.hxx,v 1.7.2.1 2008/11/27 13:03:50 abd Exp $ // #ifndef _SMESH_ARITHMETIC1D_HXX_ #define _SMESH_ARITHMETIC1D_HXX_ + + #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" + +#include class STDMESHERS_EXPORT StdMeshers_Arithmetic1D: public SMESH_Hypothesis @@ -40,10 +44,18 @@ public: StdMeshers_Arithmetic1D(int hypId, int studyId, SMESH_Gen* gen); virtual ~StdMeshers_Arithmetic1D(); - void SetLength(double length, bool isStartLength) throw(SMESH_Exception); + void SetLength(double length, bool isStartLength) throw(SALOME_Exception); double GetLength(bool isStartLength) const; + void SetReversedEdges( std::vector& ids); + + void SetObjectEntry( const char* entry ) { _objEntry = entry; } + + const char* GetObjectEntry() { return _objEntry.c_str(); } + + const std::vector& GetReversedEdges() const { return _edgeIDs; } + virtual std::ostream & SaveTo(std::ostream & save); virtual std::istream & LoadFrom(std::istream & load); friend std::ostream& operator << (std::ostream & save, StdMeshers_Arithmetic1D & hyp); @@ -57,7 +69,7 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ @@ -65,6 +77,8 @@ public: protected: double _begLength, _endLength; + std::vector _edgeIDs; + std::string _objEntry; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_AutomaticLength.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_AutomaticLength.hxx index 236dc0ae2d81..79a9d7a2a92e 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_AutomaticLength.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_AutomaticLength.hxx @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_AutomaticLength.hxx // Author : Edward AGAPOV, OCC // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_AutomaticLength.hxx,v 1.5.2.1 2008/11/27 13:03:49 abd Exp $ // #ifndef _SMESH_AutomaticLength_HXX_ #define _SMESH_AutomaticLength_HXX_ @@ -31,7 +31,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" #include @@ -56,13 +56,13 @@ public: * \brief Computes segment for a given edge */ double GetLength(const SMESH_Mesh* aMesh, const TopoDS_Shape& anEdge) - throw(SMESH_Exception); + throw(SALOME_Exception); /*! * \brief Computes segment length for an edge of given length */ double GetLength(const SMESH_Mesh* aMesh, const double edgeLength) - throw(SMESH_Exception); + throw(SALOME_Exception); /*! * \brief Set Fineness @@ -75,7 +75,7 @@ public: * is divided by (0.5 + 4.5 x theFineness) */ void SetFineness(double theFineness) - throw(SMESH_Exception); + throw(SALOME_Exception); /*! * \brief Return mesh Fineness diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_CartesianParameters3D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_CartesianParameters3D.hxx new file mode 100644 index 000000000000..befb9afd8e8f --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_CartesianParameters3D.hxx @@ -0,0 +1,177 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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_CartesianParameters3D.hxx +// Author : Edward AGAPOV +// Module : SMESH +// +#ifndef _SMESH_CartesianParameters3D_HXX_ +#define _SMESH_CartesianParameters3D_HXX_ + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_Hypothesis.hxx" +#include "Utils_SALOME_Exception.hxx" + +#include + +class SMESH_Gen; +class Bnd_Box; + +// ========================================================= +/*! + * This hypothesis specifies + * - Definition of the Cartesian grid + * - Size threshold + */ +// ========================================================= + +class STDMESHERS_EXPORT StdMeshers_CartesianParameters3D: public SMESH_Hypothesis +{ +public: + // Constructor + StdMeshers_CartesianParameters3D( int hypId, int studyId, SMESH_Gen * gen ); + + /*! + * Sets coordinates of node positions along an axis (countered from 0) + */ + void SetGrid(std::vector& xNodes, int axis) throw ( SALOME_Exception ); + /*! + * Return coordinates of node positions along the three axes + */ + void GetGrid(std::vector& xNodes, int axis) const throw ( SALOME_Exception ); + + /*! + * \brief Set grid spacing along the three axes + * \param spaceFunctions - functions defining spacing values at given point on axis + * \param internalPoints - points dividing a grid into parts along each direction + * + * Parameter t of spaceFunction f(t) is a position [0,1] withing bounding box of + * the shape to mesh + */ + void SetGridSpacing(std::vector& spaceFunctions, + std::vector& internalPoints, + const int axis) throw ( SALOME_Exception ); + + void GetGridSpacing(std::vector& spaceFunctions, + std::vector& internalPoints, + const int axis) const throw ( SALOME_Exception ); + + bool IsGridBySpacing(const int axis) const throw ( SALOME_Exception ); + + /*! + * Set/unset a fixed point, at which a node will be created provided that grid + * is defined by spacing in all directions + */ + void SetFixedPoint(const double p[3], bool toUnset); + bool GetFixedPoint(double p[3]) const; + + /*! + * \brief Computes node coordinates by spacing functions + * \param x0 - lower coordinate + * \param x1 - upper coordinate + * \param spaceFuns - space functions + * \param points - internal points + * \param coords - the computed coordinates + */ + static void ComputeCoordinates(const double x0, + const double x1, + std::vector& spaceFuns, + std::vector& points, + std::vector& coords, + const std::string& axis, + const double* xForced=0) throw (SALOME_Exception); + /*! + * Return coordinates of node positions along the three axes. + * If the grid is defined by spacing functions, the coordinates are computed + */ + void GetCoordinates(std::vector& xNodes, + std::vector& yNodes, + std::vector& zNodes, + const Bnd_Box& bndBox) const throw ( SALOME_Exception ); + + /*! + * \brief Set custom direction of axes + */ + void SetAxisDirs(const double* the9DirComps) throw ( SALOME_Exception ); + const double* GetAxisDirs() const { return _axisDirs; } + /*! + * \brief Returns axes at which number of hexahedra is maximal + */ + static void ComputeOptimalAxesDirs(const TopoDS_Shape& shape, + const bool isOrthogonal, + double dirCoords[9]); + /*! + * Set size threshold. A polyhedral cell got by cutting an initial + * hexahedron by geometry boundary is considered small and is removed if + * it's size is \athreshold times less than the size of the initial hexahedron. + */ + void SetSizeThreshold(const double threshold) throw ( SALOME_Exception ); + /*! + * \brief Return size threshold + */ + double GetSizeThreshold() const; + + /*! + * \brief Enables implementation of geometrical edges into the mesh. If this feature + * is disabled, sharp edges of the shape are lost ("smoothed") in the mesh if + * they don't coincide with the grid lines + */ + void SetToAddEdges(bool toAdd); + bool GetToAddEdges() const; + + /*! + * \brief Return true if parameters are well defined + */ + bool IsDefined() const; + + /*! + * \brief Persistence methods + */ + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + + /*! + * \brief Initialize my parameter values by the mesh built on the geometry + */ + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + + /*! + * \brief Initialize my parameter values by default parameters. + */ + virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0); + + protected: + + std::vector _coords[3]; + std::vector _spaceFunctions[3]; + std::vector _internalPoints[3]; + + double _axisDirs [9]; + double _fixedPoint[3]; + + double _sizeThreshold; + bool _toAddEdges; +}; + +#endif + diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Cartesian_3D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Cartesian_3D.hxx new file mode 100644 index 000000000000..552d7fc168b3 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Cartesian_3D.hxx @@ -0,0 +1,64 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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_Cartesian_3D.hxx +// Module : SMESH +// +#ifndef _SMESH_Cartesian_3D_HXX_ +#define _SMESH_Cartesian_3D_HXX_ + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_Algo.hxx" + +/*! + * \brief A 3D algorithm generating 3D structured Cartesian mesh in the + * internal part of a solid shape and polyhedral volumes near the shape boundary. + * + * Issue 0021336 + */ +class StdMeshers_CartesianParameters3D; + +class STDMESHERS_EXPORT StdMeshers_Cartesian_3D : public SMESH_3D_Algo +{ +public: + StdMeshers_Cartesian_3D(int hypId, int studyId, SMESH_Gen* gen); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + Hypothesis_Status& aStatus); + + virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + + virtual void SetEventListener(SMESH_subMesh* subMesh); + + private: + + void setSubmeshesComputed(SMESH_Mesh& aMesh, const TopoDS_Shape& theShape ); + + const StdMeshers_CartesianParameters3D* _hyp; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_CompositeHexa_3D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_CompositeHexa_3D.hxx index 09b687fc17f9..e3347383ceeb 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_CompositeHexa_3D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_CompositeHexa_3D.hxx @@ -1,39 +1,37 @@ -// SMESH SMESH : implementaion of SMESH idl descriptions +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// 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 +// 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, or (at your option) any later version. // +// 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 +// + +// SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_CompositeBlock_3D.hxx // Module : SMESH - +// #ifndef _SMESH_CompositeSegment_1D_HXX_ #define _SMESH_CompositeSegment_1D_HXX_ #include "SMESH_StdMeshers.hxx" -#include "SMESH_3D_Algo.hxx" +#include "SMESH_Algo.hxx" class SMESH_Mesh; class StdMeshers_FaceSide; class TopoDS_Edge; class TopoDS_Face; +struct _QuadFaceGrid; /*! * \brief Computes hexahedral mesh on a box with composite sides @@ -48,14 +46,26 @@ public: //virtual ~StdMeshers_CompositeHexa_3D(); virtual bool Compute(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape); + const TopoDS_Shape& aShape); + + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); virtual bool CheckHypothesis(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, Hypothesis_Status& aStatus); private: - // private fields + + bool findBoxFaces( const TopoDS_Shape& shape, + std::list< _QuadFaceGrid >& boxFaceContainer, + SMESH_Mesh& mesh, + _QuadFaceGrid * & fBottom, + _QuadFaceGrid * & fTop, + _QuadFaceGrid * & fFront, + _QuadFaceGrid * & fBack, + _QuadFaceGrid * & fLeft, + _QuadFaceGrid * & fRight); }; #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_CompositeSegment_1D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_CompositeSegment_1D.hxx index b18b4262ca93..12e08a5a1fb7 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_CompositeSegment_1D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_CompositeSegment_1D.hxx @@ -1,28 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_CompositeSegment_1D.hxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_CompositeSegment_1D.hxx,v 1.2.2.1 2008/11/27 13:03:49 abd Exp $ // #ifndef _SMESH_CompositeSegment_1D_HXX_ #define _SMESH_CompositeSegment_1D_HXX_ @@ -40,10 +40,9 @@ class STDMESHERS_EXPORT StdMeshers_CompositeSegment_1D: public StdMeshers_Regula { public: StdMeshers_CompositeSegment_1D(int hypId, int studyId, SMESH_Gen* gen); - virtual ~StdMeshers_CompositeSegment_1D(); virtual bool Compute(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape); + const TopoDS_Shape& aShape); /*! * \brief Sets event listener to submeshes if necessary * \param subMesh - submesh where algo is set @@ -61,8 +60,11 @@ public: const TopoDS_Face& aFace, const bool ignoreMeshed); -protected: - SMESH_subMeshEventListener* _EventListener; + /*! + * \brief Returns algo type name + */ + static std::string AlgoName(); + }; #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Deflection1D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Deflection1D.hxx index 6ad69973deca..c1b8a7a1f83b 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_Deflection1D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Deflection1D.hxx @@ -1,28 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH StdMeshers : implementaion of SMESH idl descriptions // File : StdMeshers_Deflection1D.hxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_Deflection1D.hxx,v 1.7.2.1 2008/11/27 13:03:50 abd Exp $ // #ifndef _StdMeshers_Deflection1D_HXX_ #define _StdMeshers_Deflection1D_HXX_ @@ -30,7 +30,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" class STDMESHERS_EXPORT StdMeshers_Deflection1D:public SMESH_Hypothesis { @@ -38,7 +38,7 @@ class STDMESHERS_EXPORT StdMeshers_Deflection1D:public SMESH_Hypothesis StdMeshers_Deflection1D(int hypId, int studyId, SMESH_Gen * gen); virtual ~ StdMeshers_Deflection1D(); - void SetDeflection(double value) throw(SMESH_Exception); + void SetDeflection(double value) throw(SALOME_Exception); double GetDeflection() const; @@ -55,13 +55,13 @@ class STDMESHERS_EXPORT StdMeshers_Deflection1D:public SMESH_Hypothesis */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0); - protected: +protected: double _value; }; diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Distribution.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Distribution.hxx index baad1667a0d0..261d702645b1 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_Distribution.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Distribution.hxx @@ -1,29 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH StdMeshers : implementaion of point distribution algorithm // File : StdMeshers_Distribution.hxx // Author : Alexandre SOLOVYOV // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_Distribution.hxx,v 1.4.2.2 2008/11/27 13:03:49 abd Exp $ +// $Header$ // #ifndef _STD_MESHERS_DISTRIBUTION_HXX_ #define _STD_MESHERS_DISTRIBUTION_HXX_ @@ -36,7 +37,8 @@ #include #include - +namespace StdMeshers +{ class STDMESHERS_EXPORT Function { public: @@ -102,16 +104,16 @@ private: STDMESHERS_EXPORT bool buildDistribution( const Function& f, - const double start, const double end, - const int nbSeg, - std::vector& data, - const double eps ); + const double start, const double end, + const int nbSeg, + std::vector& data, + const double eps ); STDMESHERS_EXPORT bool buildDistribution( const TCollection_AsciiString& f, const int conv, const double start, const double end, - const int nbSeg, std::vector& data, const double eps ); + const int nbSeg, std::vector& data, const double eps ); STDMESHERS_EXPORT bool buildDistribution( const std::vector& f, const int conv, const double start, const double end, - const int nbSeg, std::vector& data, const double eps ); - + const int nbSeg, std::vector& data, const double eps ); +} #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_FaceSide.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_FaceSide.hxx index d99237868bc4..485081af0e6a 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_FaceSide.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_FaceSide.hxx @@ -1,25 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMESH : implementaion of SMESH idl descriptions + // File : StdMeshers_FaceSide.hxx // Created : Wed Jan 31 18:41:25 2007 // Author : Edward AGAPOV (eap) @@ -28,14 +28,16 @@ #ifndef StdMeshers_FaceSide_HeaderFile #define StdMeshers_FaceSide_HeaderFile -#include +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_ProxyMesh.hxx" + +#include +#include #include +#include #include -#include -#include - -#include "SMESH_StdMeshers.hxx" -#include "SMESH_Algo.hxx" +#include #include #include @@ -46,26 +48,12 @@ class SMESH_Mesh; class Adaptor2d_Curve2d; class Adaptor3d_Curve; class BRepAdaptor_CompCurve; -class TopoDS_Face; struct SMESH_ComputeError; - -typedef struct uvPtStruct -{ - double param; - //int curvIndex; - double normParam; - double u; // original 2d parameter - double v; - double x; // 2d parameter, normalized [0,1] - double y; - const SMDS_MeshNode * node; -} UVPtStruct; - class StdMeshers_FaceSide; + +typedef boost::shared_ptr< SMESH_ComputeError > TError; typedef boost::shared_ptr< StdMeshers_FaceSide > StdMeshers_FaceSidePtr; -typedef boost::shared_ptr< uvPtStruct > UVPtStructPtr; -typedef std::vector< StdMeshers_FaceSidePtr > TSideVector; -typedef boost::shared_ptr< SMESH_ComputeError > TError; +typedef std::vector< StdMeshers_FaceSidePtr > TSideVector; //================================================================================ /*! @@ -80,64 +68,151 @@ public: /*! * \brief Wrap one edge */ - StdMeshers_FaceSide(const TopoDS_Face& theFace, - const TopoDS_Edge& theEdge, - SMESH_Mesh* theMesh, - const bool theIsForward, - const bool theIgnoreMediumNodes); + StdMeshers_FaceSide(const TopoDS_Face& theFace, + const TopoDS_Edge& theEdge, + SMESH_Mesh* theMesh, + const bool theIsForward, + const bool theIgnoreMediumNodes, + SMESH_ProxyMesh::Ptr theProxyMesh = SMESH_ProxyMesh::Ptr()); /*! * \brief Wrap several edges. Edges must be properly ordered and oriented. */ - StdMeshers_FaceSide(const TopoDS_Face& theFace, + StdMeshers_FaceSide(const TopoDS_Face& theFace, std::list& theEdges, - SMESH_Mesh* theMesh, - const bool theIsForward, - const bool theIgnoreMediumNodes); + SMESH_Mesh* theMesh, + const bool theIsForward, + const bool theIgnoreMediumNodes, + SMESH_ProxyMesh::Ptr theProxyMesh = SMESH_ProxyMesh::Ptr()); + /*! + * \brief Simulate a side from a vertex using data from other FaceSide + */ + StdMeshers_FaceSide(const StdMeshers_FaceSide* theSide, + const SMDS_MeshNode* theNode, + const gp_Pnt2d* thePnt2d1, + const gp_Pnt2d* thePnt2d2=NULL, + const Handle(Geom2d_Curve)& theC2d=NULL, + const double theUFirst=0., + const double theULast=1.); + /*! + * \brief Create a side from an UVPtStructVec + */ + StdMeshers_FaceSide(UVPtStructVec& theSideNodes, + const TopoDS_Face& theFace = TopoDS_Face()); + + // static "consrtuctors" + static StdMeshers_FaceSidePtr New(const TopoDS_Face& Face, + const TopoDS_Edge& Edge, + SMESH_Mesh* Mesh, + const bool IsForward, + const bool IgnoreMediumNodes, + SMESH_ProxyMesh::Ptr ProxyMesh = SMESH_ProxyMesh::Ptr()) + { return StdMeshers_FaceSidePtr + ( new StdMeshers_FaceSide( Face,Edge,Mesh,IsForward,IgnoreMediumNodes,ProxyMesh )); + } + static StdMeshers_FaceSidePtr New (const TopoDS_Face& Face, + std::list& Edges, + SMESH_Mesh* Mesh, + const bool IsForward, + const bool IgnoreMediumNodes, + SMESH_ProxyMesh::Ptr ProxyMesh = SMESH_ProxyMesh::Ptr()) + { return StdMeshers_FaceSidePtr + ( new StdMeshers_FaceSide( Face,Edges,Mesh,IsForward,IgnoreMediumNodes,ProxyMesh )); + } + static StdMeshers_FaceSidePtr New (const StdMeshers_FaceSide* Side, + const SMDS_MeshNode* Node, + const gp_Pnt2d* Pnt2d1, + const gp_Pnt2d* Pnt2d2=NULL, + const Handle(Geom2d_Curve)& C2d=NULL, + const double UFirst=0., + const double ULast=1.) + { return StdMeshers_FaceSidePtr + ( new StdMeshers_FaceSide( Side,Node,Pnt2d1,Pnt2d2,C2d,UFirst,ULast )); + } + static StdMeshers_FaceSidePtr New (UVPtStructVec& theSideNodes, + const TopoDS_Face& theFace = TopoDS_Face()) + { + return StdMeshers_FaceSidePtr( new StdMeshers_FaceSide( theSideNodes, theFace )); + } /*! * \brief Return wires of a face as StdMeshers_FaceSide's */ - static TSideVector GetFaceWires(const TopoDS_Face& theFace, - SMESH_Mesh & theMesh, - const bool theIgnoreMediumNodes, - TError & theError); - + static TSideVector GetFaceWires(const TopoDS_Face& theFace, + SMESH_Mesh & theMesh, + const bool theIgnoreMediumNodes, + TError & theError, + SMESH_ProxyMesh::Ptr theProxyMesh = SMESH_ProxyMesh::Ptr(), + const bool theCheckVertexNodes=true); /*! * \brief Change orientation of side geometry */ void Reverse(); /*! - * \brief Return nb nodes on edges and vertices (+1 to be == GetUVPtStruct().size() ) + * \brief Make ignore medium nodes + */ + void SetIgnoreMediumNodes(bool toIgnore); + + /*! + * \brief Return nb nodes on edges and vertices (+1 to be == GetUVPtStruct().size() ). + * Call it with update == true if mesh of this side can be recomputed + * since creation of this side */ - int NbPoints() const { return myNbPonits; } + int NbPoints(const bool update = false) const; /*! * \brief Return nb edges + * Call it with update == true if mesh of this side can be recomputed + * since creation of this side */ - int NbSegments() const { return myNbSegments; } + int NbSegments(const bool update = false) const; /*! * \brief Return mesh */ - SMESH_Mesh* GetMesh() const { return myMesh; } + SMESH_Mesh* GetMesh() const { return myProxyMesh->GetMesh(); } /*! - * \brief Return true if there vertices without nodes + * \brief Return true if there are vertices without nodes */ bool MissVertexNode() const { return myMissingVertexNodes; } + /*! * \brief Return detailed data on nodes * \param isXConst - true if normalized parameter X is constant * \param constValue - constant parameter value * - * Missing nodes are allowed only on internal vertices + * Missing nodes are allowed only on internal vertices. + * For a closed side, the 1st point repeats at end */ - const std::vector& GetUVPtStruct(bool isXConst =0, double constValue =0) const; + const UVPtStructVec& GetUVPtStruct(bool isXConst =0, double constValue =0) const; /*! * \brief Simulates detailed data on nodes * \param isXConst - true if normalized parameter X is constant * \param constValue - constant parameter value */ - const std::vector& SimulateUVPtStruct(int nbSeg, - bool isXConst = 0, - double constValue = 0) const; + const UVPtStructVec& SimulateUVPtStruct(int nbSeg, + bool isXConst = 0, + double constValue = 0) const; + /*! + * \brief Return nodes in the order they encounter while walking along + * the while side or a specified EDGE. + * For a closed side, the 1st point repeats at end + */ + std::vector GetOrderedNodes(int iE=-1) const; + + /*! + * \brief Return nodes of the i-th EDGE. + * Nodes moved to other geometry by MergeNodes() are also returned. + * \retval bool - is OK + */ + bool GetEdgeNodes(const size_t i, + std::vector& nodes, + bool inlude1stVertex=true, + bool inludeLastVertex=true) const; + + /*! + * \brief Return a node from the i-th VERTEX (count starts from zero) + * Nodes moved to other geometry by MergeNodes() are also returned. + */ + const SMDS_MeshNode* VertexNode(std::size_t i, bool* isMoved = 0) const; + /*! * \brief Return edge and parameter on edge by normalized parameter */ @@ -146,6 +221,10 @@ public: * \brief Return UV by normalized parameter */ gp_Pnt2d Value2d(double U) const; + /*! + * \brief Return XYZ by normalized parameter + */ + gp_Pnt Value3d(double U) const; /*! * \brief Creates a Adaptor2d_Curve2d to be used in SMESH_Block */ @@ -159,25 +238,25 @@ public: */ int NbEdges() const { return myEdge.size(); } /*! - * \brief Return i-th wrapped edge (count starts from zero) + * \brief Return i-th edge (count starts from zero) */ const TopoDS_Edge& Edge(int i) const { return myEdge[i]; } /*! - * \brief Return 1st vertex of the i-the edge (count starts from zero) + * \brief Return all edges */ - inline TopoDS_Vertex FirstVertex(int i=0) const; + const std::vector& Edges() const { return myEdge; } /*! - * \brief Return last vertex of the i-the edge (count starts from zero) + * \brief Return 1st vertex of the i-th edge (count starts from zero) */ - inline TopoDS_Vertex LastVertex(int i=-1) const; + TopoDS_Vertex FirstVertex(int i=0) const; /*! - * \brief Return first normalized parameter of the i-the edge (count starts from zero) + * \brief Return last vertex of the i-th edge (count starts from zero) */ - inline double FirstParameter(int i) const; + TopoDS_Vertex LastVertex(int i=-1) const; /*! - * \brief Return ast normalized parameter of the i-the edge (count starts from zero) + * \brief Return \c true if the chain of EDGEs is closed */ - inline double LastParameter(int i) const; + bool IsClosed() const; /*! * \brief Return side length */ @@ -191,17 +270,61 @@ public: void dump(const char* msg=0) const; + /*! + * \brief Return ID of i-th wrapped edge (count starts from zero) + */ + inline int EdgeID(int i) const; + /*! + * \brief Return p-curve of i-th wrapped edge (count starts from zero) + */ + inline Handle(Geom2d_Curve) Curve2d(int i) const; + /*! + * \brief Return first normalized parameter of the i-th edge (count starts from zero) + */ + inline double FirstParameter(int i) const; + /*! + * \brief Return last normalized parameter of the i-th edge (count starts from zero) + */ + inline double LastParameter(int i) const; + /*! + * \brief Return first parameter of the i-th edge (count starts from zero). + * EDGE orientation is taken into account + */ + inline double FirstU(int i) const; + /*! + * \brief Return last parameter of the i-th edge (count starts from zero). + * EDGE orientation is taken into account + */ + inline double LastU(int i) const; + /*! + * \brief Return length of i-th wrapped edge (count starts from zero) + */ + inline double EdgeLength(int i) const; + /*! + * \brief Return orientation of i-th wrapped edge (count starts from zero) + */ + inline bool IsReversed(int i) const; protected: + + void reverseProxySubmesh( const TopoDS_Edge& E ); + + // DON't FORGET to update Reverse() when adding one more vector! + TopoDS_Face myFace; std::vector myPoints, myFalsePoints; std::vector myEdge; + std::vector myEdgeID; std::vector myC2d; + std::vector myC3dAdaptor; std::vector myFirst, myLast; std::vector myNormPar; + std::vector myEdgeLength; + std::vector myIsUniform; double myLength; int myNbPonits, myNbSegments; - SMESH_Mesh* myMesh; + SMESH_ProxyMesh::Ptr myProxyMesh; bool myMissingVertexNodes, myIgnoreMediumNodes; + gp_Pnt2d myDefaultPnt2d; }; @@ -239,46 +362,90 @@ inline double StdMeshers_FaceSide::Parameter(double U, TopoDS_Edge & edge) const //================================================================================ /*! - * \brief Return 1st vertex of the i-the edge + * \brief Return first normalized parameter of the i-th edge */ //================================================================================ -inline TopoDS_Vertex StdMeshers_FaceSide::FirstVertex(int i) const +inline double StdMeshers_FaceSide::FirstParameter(int i) const { - return i < static_cast(myEdge.size()) ? TopExp::FirstVertex( myEdge[i], 1 ) : TopoDS_Vertex(); + return i==0 ? 0. : i<(int)myNormPar.size() ? myNormPar[i-1] : 1.; } //================================================================================ /*! - * \brief Return last vertex of the i-the edge + * \brief Return ast normalized parameter of the i-th edge */ //================================================================================ -inline TopoDS_Vertex StdMeshers_FaceSide::LastVertex(int i) const +inline double StdMeshers_FaceSide::LastParameter(int i) const { - return i<0 ? TopExp::LastVertex( myEdge.back(), 1) : i(myEdge.size()) ? TopExp::LastVertex( myEdge[i], 1 ) : TopoDS_Vertex(); + return i < (int)myNormPar.size() ? myNormPar[i] : 1; } //================================================================================ /*! - * \brief Return first normalized parameter of the i-the edge + * \brief Return first parameter of the i-th edge */ //================================================================================ -inline double StdMeshers_FaceSide::FirstParameter(int i) const +inline double StdMeshers_FaceSide::FirstU(int i) const { - return i==0 ? 0. : i(myNormPar.size()) ? myNormPar[i-1] : 1.; + return myFirst[ i % myFirst.size() ]; } //================================================================================ /*! - * \brief Return ast normalized parameter of the i-the edge + * \brief Return last parameter of the i-th edge */ //================================================================================ -inline double StdMeshers_FaceSide::LastParameter(int i) const +inline double StdMeshers_FaceSide::LastU(int i) const +{ + return myLast[ i % myLast.size() ]; +} + +//================================================================================ + /*! + * \brief Return ID of i-th wrapped edge (count starts from zero) + */ +//================================================================================ + +inline int StdMeshers_FaceSide::EdgeID(int i) const +{ + return myEdgeID[ i % myEdgeID.size() ]; +} + +//================================================================================ +/*! + * \brief Return p-curve of i-th wrapped edge (count starts from zero) + */ +//================================================================================ + +inline Handle(Geom2d_Curve) StdMeshers_FaceSide::Curve2d(int i) const +{ + return myC2d[ i % myC2d.size() ]; +} + +//================================================================================ +/*! + * \brief Return length of i-th wrapped edge (count starts from zero) + */ + //================================================================================ + +inline double StdMeshers_FaceSide::EdgeLength(int i) const +{ + return myEdgeLength[ i % myEdgeLength.size() ]; +} + +//================================================================================ +/*! + * \brief Return orientation of i-th wrapped edge (count starts from zero) + */ + //================================================================================ + +inline bool StdMeshers_FaceSide::IsReversed(int i) const { - return i(myNormPar.size()) ? myNormPar[i] : 1; + return myFirst[i] > myLast[i]; } #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_FixedPoints1D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_FixedPoints1D.hxx new file mode 100644 index 000000000000..23f5aa428bea --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_FixedPoints1D.hxx @@ -0,0 +1,88 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// File : StdMeshers_FixedPoints1D.hxx +// Author : Damien COQUERET, OCC +// Module : SMESH +// +#ifndef _SMESH_FIXEDPOINTS1D_HXX_ +#define _SMESH_FIXEDPOINTS1D_HXX_ + + + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_Hypothesis.hxx" +#include "Utils_SALOME_Exception.hxx" + +#include + +class STDMESHERS_EXPORT StdMeshers_FixedPoints1D: + public SMESH_Hypothesis +{ +public: + StdMeshers_FixedPoints1D(int hypId, int studyId, SMESH_Gen* gen); + virtual ~StdMeshers_FixedPoints1D(); + + void SetPoints(std::vector& listParams) + throw(SALOME_Exception); + + void SetNbSegments(std::vector& listNbSeg) + throw(SALOME_Exception); + + const std::vector& GetPoints() const { return _params; } + + const std::vector& GetNbSegments() const { return _nbsegs; } + + void SetReversedEdges( std::vector& ids); + + void SetObjectEntry( const char* entry ) { _objEntry = entry; } + + const char* GetObjectEntry() { return _objEntry.c_str(); } + + const std::vector& GetReversedEdges() const { return _edgeIDs; } + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + friend std::ostream& operator << (std::ostream & save, StdMeshers_FixedPoints1D & hyp); + friend std::istream& operator >> (std::istream & load, StdMeshers_FixedPoints1D & hyp); + + /*! + * \brief Initialize start and end length 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 + */ + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + + /*! + * \brief Initialize my parameter values by default parameters. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0); + +protected: + std::vector _params; + std::vector _nbsegs; + std::vector _edgeIDs; + std::string _objEntry; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Geometric1D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Geometric1D.hxx new file mode 100644 index 000000000000..33f505734047 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Geometric1D.hxx @@ -0,0 +1,67 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// File : StdMeshers_Geometric1D.hxx +// Module : SMESH +// +#ifndef _SMESH_Geometric1D_HXX_ +#define _SMESH_Geometric1D_HXX_ + +#include "SMESH_StdMeshers.hxx" + +#include "StdMeshers_Reversible1D.hxx" +#include "Utils_SALOME_Exception.hxx" + +class STDMESHERS_EXPORT StdMeshers_Geometric1D: public StdMeshers_Reversible1D +{ +public: + StdMeshers_Geometric1D(int hypId, int studyId, SMESH_Gen* gen); + + void SetStartLength(double length) throw(SALOME_Exception); + void SetCommonRatio(double factor) throw(SALOME_Exception); + + double GetStartLength() const; + double GetCommonRatio() const; + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + + /*! + * \brief Initialize start and end length 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 + */ + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + + /*! + * \brief Initialize my parameter values by default parameters. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0); + +protected: + double _begLength, _ratio; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_HexaFromSkin_3D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_HexaFromSkin_3D.hxx new file mode 100644 index 000000000000..82ff85872f02 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_HexaFromSkin_3D.hxx @@ -0,0 +1,54 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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_HexaFromSkin_3D.hxx +// Created : Wed Jan 27 12:23:21 2010 +// Author : Edward AGAPOV (eap) +// +#ifndef __StdMeshers_HexaFromSkin_3D_HXX__ +#define __StdMeshers_HexaFromSkin_3D_HXX__ + +#include "SMESH_StdMeshers.hxx" +#include "SMESH_Algo.hxx" + +/*! + * \brief Alorithm generating hexahedral mesh from 2D skin of block + */ + +class STDMESHERS_EXPORT StdMeshers_HexaFromSkin_3D : public SMESH_3D_Algo +{ +public: + StdMeshers_HexaFromSkin_3D(int hypId, int studyId, SMESH_Gen* gen); + virtual ~StdMeshers_HexaFromSkin_3D(); + + virtual bool Compute(SMESH_Mesh & aMesh, SMESH_MesherHelper* aHelper); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + Hypothesis_Status& aStatus); + + virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + + virtual bool Evaluate(SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Hexa_3D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Hexa_3D.hxx index 5032417ae3e4..52b581a56c50 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_Hexa_3D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Hexa_3D.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Hexa_3D.hxx // Moved here from SMESH_Hexa_3D.hxx @@ -30,42 +31,15 @@ #include "SMESH_StdMeshers.hxx" -#include "SMESH_3D_Algo.hxx" -#include "SMESH_Mesh.hxx" -#include "StdMeshers_Quadrangle_2D.hxx" -#include "SMESH_Exception.hxx" - -#include "SMESH_MesherHelper.hxx" - +#include "SMESH_Algo.hxx" #if OCC_VERSION_HEX < 0x070000 -class TopTools_IndexedMapOfShape; #endif -typedef struct point3Dstruct -{ - const SMDS_MeshNode * node; -} Point3DStruct; -typedef double Pt3[3]; +class StdMeshers_ViscousLayers; +class SMESH_MesherHelper; -typedef struct conv2dstruct -{ - double a1; // X = a1*x + b1*y + c1 - double b1; // Y = a2*x + b2*y + c2 - double c1; // a1, b1 a2, b2 in {-1,0,1} - double a2; // c1, c2 in {0,1} - double b2; - double c2; - int ia; // I = ia*i + ib*j + ic - int ib; - int ic; - int ja; // J = ja*i + jb*j + jc - int jb; - int jc; -} Conv2DStruct; - -class STDMESHERS_EXPORT StdMeshers_Hexa_3D: - public SMESH_3D_Algo +class STDMESHERS_EXPORT StdMeshers_Hexa_3D : public SMESH_3D_Algo { public: StdMeshers_Hexa_3D(int hypId, int studyId, SMESH_Gen* gen); @@ -75,45 +49,18 @@ public: const TopoDS_Shape& aShape, SMESH_Hypothesis::Hypothesis_Status& aStatus); - virtual bool Compute(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape) - /*throw (SMESH_Exception)*/; - - static TopoDS_Vertex OppositeVertex(const TopoDS_Vertex& aVertex, - const TopTools_IndexedMapOfShape& aQuads0Vertices, - FaceQuadStruct* aQuads[6]); + virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); -protected: - TopoDS_Edge - EdgeNotInFace(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape, - const TopoDS_Face& aFace, - const TopoDS_Vertex& aVertex, - const TopTools_IndexedDataMapOfShapeListOfShape& MS); + virtual bool Compute(SMESH_Mesh & aMesh, SMESH_MesherHelper* aHelper); - int GetFaceIndex(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape, - const std::vector& meshFaces, - const TopoDS_Vertex& V0, - const TopoDS_Vertex& V1, - const TopoDS_Vertex& V2, - const TopoDS_Vertex& V3); + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); - void GetConv2DCoefs(const faceQuadStruct& quad, - const TopoDS_Shape& aShape, - const TopoDS_Vertex& V0, - const TopoDS_Vertex& V1, - const TopoDS_Vertex& V2, - const TopoDS_Vertex& V3, - Conv2DStruct& conv); + static bool IsApplicable(const TopoDS_Shape & aShape, bool toCheckAll); - void GetPoint(Pt3 p, - int i, int j, int k, - int nbx, int nby, int nbz, - Point3DStruct *np, - const SMESHDS_Mesh* meshDS); + protected: - bool ClearAndReturn(FaceQuadStruct* theQuads[6], const bool res); + const StdMeshers_ViscousLayers* _viscousLayersHyp; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_ImportSource.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_ImportSource.hxx new file mode 100644 index 000000000000..cb1db4440b8d --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_ImportSource.hxx @@ -0,0 +1,100 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH StdMeshers : implementaion of SMESH idl descriptions +// File : StdMeshers_ImportSource1D.hxx +// Module : SMESH +// +#ifndef _StdMeshers_ImportSource_HXX_ +#define _StdMeshers_ImportSource_HXX_ + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_Hypothesis.hxx" +#include "Utils_SALOME_Exception.hxx" + +#include +#include + +class SMESH_Group; +class SMESHDS_Mesh; +class SMESH_subMesh; + +//============================================================================== +/*! + * \brief Stores groups to import elements from + */ +//============================================================================== + +class STDMESHERS_EXPORT StdMeshers_ImportSource1D : public SMESH_Hypothesis +{ + public: + StdMeshers_ImportSource1D(int hypId, int studyId, SMESH_Gen * gen); + virtual ~ StdMeshers_ImportSource1D(); + + void SetGroups(const std::vector& groups); + const std::vector& GetGroups(bool loaded=false) const; + + void SetCopySourceMesh(bool toCopyMesh, bool toCopyGroups); + void GetCopySourceMesh(bool& toCopyMesh, bool& toCopyGroups) const; + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0); + virtual bool DataDependOnParams() const { return true; } + void RestoreGroups(const std::vector& groups); + + void StoreResultGroups(const std::vector& groups, + const SMESHDS_Mesh& srcMesh, + const SMESHDS_Mesh& tgtMesh); + std::vector* GetResultGroups(const SMESHDS_Mesh& srcMesh, + const SMESHDS_Mesh& tgtMesh); + + std::vector GetSourceMeshes() const; + std::vector GetSourceSubMeshes(const SMESH_Mesh* srcMesh) const; + +private: + + std::vector _groups; + bool _toCopyMesh, _toCopyGroups; + + // groups imported using this hypothesis + typedef std::map< std::pair, std::vector > TResGroupMap; + TResGroupMap _resultGroups; + std::vector _resultGroupsStorage; // persistent representation of _resultGroups + + void resultGroupsToIntVec(); +}; + +//============================================================================== +/*! + * \brief Redefines name and dimension of inherited StdMeshers_ImportSource1D + */ +//============================================================================== + +class STDMESHERS_EXPORT StdMeshers_ImportSource2D : public StdMeshers_ImportSource1D +{ + public: + StdMeshers_ImportSource2D(int hypId, int studyId, SMESH_Gen * gen); +}; +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Import_1D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Import_1D.hxx new file mode 100644 index 000000000000..487499cbd033 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Import_1D.hxx @@ -0,0 +1,81 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// Module : SMESH +// +#ifndef _SMESH_Import_1D_HXX_ +#define _SMESH_Import_1D_HXX_ + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_Algo.hxx" +#include "SMDS_MeshElement.hxx" + +class StdMeshers_ImportSource1D; + +/*! + * \brief Copy elements from other the mesh + */ +class STDMESHERS_EXPORT StdMeshers_Import_1D: public SMESH_1D_Algo +{ +public: + StdMeshers_Import_1D(int hypId, int studyId, SMESH_Gen* gen); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus); + + virtual bool Compute (SMESH_Mesh & aMesh, const TopoDS_Shape & aShape); + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + + virtual void SetEventListener(SMESH_subMesh* subMesh); + virtual void SubmeshRestored(SMESH_subMesh* subMesh); + + // internal utilities + + typedef std::map TNodeNodeMap; + typedef std::map TElemElemMap; + + static void getMaps(const SMESH_Mesh* srcMesh, + SMESH_Mesh* tgtMesh, + TNodeNodeMap*& n2n, + TElemElemMap*& e2e); + + static void importMesh(const SMESH_Mesh* srcMesh, + SMESH_Mesh & tgtMesh, + StdMeshers_ImportSource1D* srcHyp, + const TopoDS_Shape& tgtShape); + + static void setEventListener( SMESH_subMesh* subMesh, + StdMeshers_ImportSource1D* sourceHyp ); + + static SMESH_subMesh* getSubMeshOfCopiedMesh( SMESH_Mesh& tgtMesh, + SMESH_Mesh& srcMesh ); + + private: + + StdMeshers_ImportSource1D* _sourceHyp; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Import_1D2D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Import_1D2D.hxx new file mode 100644 index 000000000000..fb8b244ab741 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Import_1D2D.hxx @@ -0,0 +1,60 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// Module : SMESH +// +#ifndef _SMESH_Import_2D_HXX_ +#define _SMESH_Import_2D_HXX_ + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_Algo.hxx" +#include "SMDS_MeshElement.hxx" + +class StdMeshers_ImportSource1D; + +/*! + * \brief Copy elements from other the mesh + */ +class STDMESHERS_EXPORT StdMeshers_Import_1D2D: public SMESH_2D_Algo +{ +public: + StdMeshers_Import_1D2D(int hypId, int studyId, SMESH_Gen* gen); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus); + + virtual bool Compute (SMESH_Mesh & aMesh, const TopoDS_Shape & aShape); + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + + virtual void SetEventListener(SMESH_subMesh* subMesh); + virtual void SubmeshRestored(SMESH_subMesh* subMesh); + + private: + + StdMeshers_ImportSource1D* _sourceHyp; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_LayerDistribution.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_LayerDistribution.hxx index cfef8fbda9ce..c2a77c08d342 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_LayerDistribution.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_LayerDistribution.hxx @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : idl implementation based on 'SMESH' unit's calsses // File : StdMeshers_LayerDistribution.hxx // Author : Edward AGAPOV // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_LayerDistribution.hxx,v 1.2.2.1 2008/11/27 13:03:50 abd Exp $ // #ifndef _SMESH_LayerDistribution_HXX_ #define _SMESH_LayerDistribution_HXX_ @@ -31,7 +31,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" #include @@ -60,7 +60,7 @@ public: * \param hyp1D - 1D hypothesis */ void SetLayerDistribution(SMESH_Hypothesis* hyp1D) - throw ( SMESH_Exception ); + throw ( SALOME_Exception ); /*! * \brief Returns 1D hypothesis specifying distribution of layers @@ -83,7 +83,7 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_LayerDistribution2D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_LayerDistribution2D.hxx new file mode 100644 index 000000000000..1049c68dd6ef --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_LayerDistribution2D.hxx @@ -0,0 +1,53 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_LayerDistribution2D.hxx +// Author : Edward AGAPOV +// Module : SMESH +// +#ifndef _SMESH_LayerDistribution2D_HXX_ +#define _SMESH_LayerDistribution2D_HXX_ + +#include "StdMeshers_LayerDistribution.hxx" + + +// ========================================================= +// ========================================================= +/*! + * This hypothesis is used by "Radial quadrangle" algorithm. + * It specifies 1D hypothesis defining distribution of segments + * between the internal and the external surfaces. + */ +// ========================================================= +// ========================================================= + +class STDMESHERS_EXPORT StdMeshers_LayerDistribution2D + :public StdMeshers_LayerDistribution +{ +public: + // Constructor + StdMeshers_LayerDistribution2D(int hypId, int studyId, SMESH_Gen* gen); + // Destructor + virtual ~StdMeshers_LayerDistribution2D(); + +}; + +#endif + diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_LengthFromEdges.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_LengthFromEdges.hxx index 7703079876d7..714042cf9769 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_LengthFromEdges.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_LengthFromEdges.hxx @@ -1,30 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_LengthFromEdges.hxx // Moved here from SMESH_LengthFromEdges.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_LengthFromEdges.hxx,v 1.8.2.1 2008/11/27 13:03:50 abd Exp $ // #ifndef _SMESH_LENGTHFROMEDGES_HXX_ #define _SMESH_LENGTHFROMEDGES_HXX_ @@ -32,7 +32,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" class STDMESHERS_EXPORT StdMeshers_LengthFromEdges: public SMESH_Hypothesis @@ -42,7 +42,7 @@ public: virtual ~StdMeshers_LengthFromEdges(); void SetMode(int mode) - throw (SMESH_Exception); + throw (SALOME_Exception); int GetMode(); @@ -61,7 +61,7 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_LocalLength.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_LocalLength.hxx index cbbf995a39fa..41b019109d45 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_LocalLength.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_LocalLength.hxx @@ -1,30 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_LocalLength.hxx // Moved here from SMESH_LocalLength.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_LocalLength.hxx,v 1.8.2.1 2008/11/27 13:03:49 abd Exp $ // #ifndef _SMESH_LOCALLENGTH_HXX_ #define _SMESH_LOCALLENGTH_HXX_ @@ -32,7 +32,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" class STDMESHERS_EXPORT StdMeshers_LocalLength: public SMESH_Hypothesis { @@ -40,8 +40,8 @@ class STDMESHERS_EXPORT StdMeshers_LocalLength: public SMESH_Hypothesis StdMeshers_LocalLength(int hypId, int studyId, SMESH_Gen * gen); virtual ~ StdMeshers_LocalLength(); - void SetLength(double length) throw(SMESH_Exception); - void SetPrecision(double precision) throw(SMESH_Exception); + void SetLength(double length) throw(SALOME_Exception); + void SetPrecision(double precision) throw(SALOME_Exception); double GetLength() const; double GetPrecision() const; @@ -59,7 +59,7 @@ class STDMESHERS_EXPORT StdMeshers_LocalLength: public SMESH_Hypothesis */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_MEFISTO_2D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_MEFISTO_2D.hxx index 8b0d0a964a91..a1ece4b72f17 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_MEFISTO_2D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_MEFISTO_2D.hxx @@ -1,37 +1,37 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_MEFISTO_2D.hxx // Moved here from SMESH_MEFISTO_2D.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_MEFISTO_2D.hxx,v 1.9.2.2 2008/11/27 13:03:49 abd Exp $ // #ifndef _StdMeshers_MEFISTO_2D_HXX_ #define _StdMeshers_MEFISTO_2D_HXX_ #include "SMESH_StdMeshers.hxx" -#include "SMESH_2D_Algo.hxx" +#include "SMESH_Algo.hxx" class TopoDS_Face; class StdMeshers_MaxElementArea; @@ -55,25 +55,28 @@ public: SMESH_Hypothesis::Hypothesis_Status& aStatus); virtual bool Compute(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape); + const TopoDS_Shape& aShape); + + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); typedef boost::shared_ptr< StdMeshers_FaceSide> StdMeshers_FaceSidePtr; typedef std::vector< StdMeshers_FaceSidePtr > TWireVector; bool LoadPoints(TWireVector & wires, - R2* uvslf, - std::vector< const SMDS_MeshNode*>& mefistoToDS, + R2* uvslf, + std::vector< const SMDS_MeshNode*>& mefistoToDS, double scalex, double scaley); void ComputeScaleOnFace(SMESH_Mesh& aMesh, - const TopoDS_Face& aFace, - double& scalex, - double& scaley); + const TopoDS_Face& aFace, + double& scalex, + double& scaley); void StoreResult (Z nbst, R2* uvst, Z nbt, Z* nust, - std::vector< const SMDS_MeshNode*>& mefistoToDS, + std::vector< const SMDS_MeshNode*>& mefistoToDS, double scalex, double scaley); - + protected: double _edgeLength; double _maxElementArea; @@ -82,7 +85,7 @@ protected: std::list myNodesOnCommonV; - SMESH_MesherHelper* myTool; // tool for working with quadratic elements + SMESH_MesherHelper* _helper; // tool for working with quadratic elements }; #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_MaxElementArea.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_MaxElementArea.hxx index ae2c34c77f1e..cdf19e997ba3 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_MaxElementArea.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_MaxElementArea.hxx @@ -1,30 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_MaxElementArea.hxx // Moved here from SMESH_MaxElementArea.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_MaxElementArea.hxx,v 1.8.2.1 2008/11/27 13:03:49 abd Exp $ // #ifndef _SMESH_MAXELEMENTAREA_HXX_ #define _SMESH_MAXELEMENTAREA_HXX_ @@ -32,7 +32,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" class STDMESHERS_EXPORT StdMeshers_MaxElementArea:public SMESH_Hypothesis { @@ -40,7 +40,7 @@ public: StdMeshers_MaxElementArea(int hypId, int studyId, SMESH_Gen * gen); virtual ~ StdMeshers_MaxElementArea(); - void SetMaxArea(double maxArea) throw(SMESH_Exception); + void SetMaxArea(double maxArea) throw(SALOME_Exception); double GetMaxArea() const; @@ -57,7 +57,7 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_MaxElementVolume.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_MaxElementVolume.hxx index e9dacb23709b..cff8162822f8 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_MaxElementVolume.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_MaxElementVolume.hxx @@ -1,30 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_MaxElementVolume.hxx // Moved here from SMESH_MaxElementVolume.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_MaxElementVolume.hxx,v 1.8.2.1 2008/11/27 13:03:49 abd Exp $ // #ifndef _SMESH_MAXELEMENTVOLUME_HXX_ #define _SMESH_MAXELEMENTVOLUME_HXX_ @@ -32,7 +32,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" class STDMESHERS_EXPORT StdMeshers_MaxElementVolume: public SMESH_Hypothesis @@ -42,7 +42,7 @@ public: virtual ~StdMeshers_MaxElementVolume(); void SetMaxVolume(double maxVolume) - throw (SMESH_Exception); + throw (SALOME_Exception); double GetMaxVolume() const; @@ -59,7 +59,7 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_MaxLength.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_MaxLength.hxx index ead29f2aa9f4..6edd2e19eee0 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_MaxLength.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_MaxLength.hxx @@ -1,34 +1,33 @@ -// SMESH SMESH : implementaion of SMESH idl descriptions +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 // -// 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 +// +// SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_MaxLength.hxx // Module : SMESH - +// #ifndef _SMESH_MaxLength_HXX_ #define _SMESH_MaxLength_HXX_ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" class STDMESHERS_EXPORT StdMeshers_MaxLength: public SMESH_Hypothesis { @@ -36,7 +35,7 @@ class STDMESHERS_EXPORT StdMeshers_MaxLength: public SMESH_Hypothesis StdMeshers_MaxLength(int hypId, int studyId, SMESH_Gen * gen); virtual ~ StdMeshers_MaxLength(); - void SetLength(double length) throw(SMESH_Exception); + void SetLength(double length) throw(SALOME_Exception); double GetLength() const; bool HavePreestimatedLength() const { return _preestimated > 0.; } diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_NotConformAllowed.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_NotConformAllowed.hxx index 371ed82e5977..4a57c4eb0424 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_NotConformAllowed.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_NotConformAllowed.hxx @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH StdMeshers : implementaion of SMESH idl descriptions // File : StdMeshers_NotConformAllowed.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_NotConformAllowed.hxx,v 1.8.2.1 2008/11/27 13:03:50 abd Exp $ // #ifndef _StdMeshers_NotConformAllowed_HXX_ #define _StdMeshers_NotConformAllowed_HXX_ @@ -31,7 +31,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" class STDMESHERS_EXPORT StdMeshers_NotConformAllowed: public SMESH_Hypothesis @@ -55,7 +55,7 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_NumberOfLayers.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_NumberOfLayers.hxx index fad0c69eba4e..0a8bb43356d1 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_NumberOfLayers.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_NumberOfLayers.hxx @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : idl implementation based on 'SMESH' unit's calsses // File : StdMeshers_NumberOfLayers.hxx // Author : Edward AGAPOV // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_NumberOfLayers.hxx,v 1.2.2.1 2008/11/27 13:03:50 abd Exp $ // #ifndef _SMESH_NumberOfLayers_HXX_ #define _SMESH_NumberOfLayers_HXX_ @@ -31,7 +31,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" class SMESH_Gen; @@ -54,7 +54,7 @@ public: virtual ~StdMeshers_NumberOfLayers(); // Sets parameter value - void SetNumberOfLayers(int numberOfLayers) throw ( SMESH_Exception ); + void SetNumberOfLayers(int numberOfLayers) throw ( SALOME_Exception ); // Returns parameter value int GetNumberOfLayers() const; @@ -74,7 +74,7 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_NumberOfLayers2D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_NumberOfLayers2D.hxx new file mode 100644 index 000000000000..d0257cecbc25 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_NumberOfLayers2D.hxx @@ -0,0 +1,52 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_NumberOfLayers2D.hxx +// Author : Edward AGAPOV +// Module : SMESH +// +#ifndef _SMESH_NumberOfLayers2D_HXX_ +#define _SMESH_NumberOfLayers2D_HXX_ + +#include "StdMeshers_NumberOfLayers.hxx" + + +// ========================================================= +// ========================================================= +/*! + * This hypothesis is used by "Radial quadrangle" algorithm. + * It specifies number of segments between the internal + * and the external surfaces. + */ +// ========================================================= +// ========================================================= + +class STDMESHERS_EXPORT StdMeshers_NumberOfLayers2D + : public StdMeshers_NumberOfLayers +{ +public: + // Constructor + StdMeshers_NumberOfLayers2D(int hypId, int studyId, SMESH_Gen* gen); + // Destructor + virtual ~StdMeshers_NumberOfLayers2D(); +}; + +#endif + diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_NumberOfSegments.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_NumberOfSegments.hxx index 73aa841e6c97..e09417eab007 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_NumberOfSegments.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_NumberOfSegments.hxx @@ -1,30 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_NumberOfSegments.hxx // Moved here from SMESH_NumberOfSegments.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_NumberOfSegments.hxx,v 1.12.2.1 2008/11/27 13:03:50 abd Exp $ // #ifndef _SMESH_NUMBEROFSEGMENTS_HXX_ #define _SMESH_NUMBEROFSEGMENTS_HXX_ @@ -32,7 +32,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" #include /*! @@ -49,15 +49,15 @@ public: virtual ~StdMeshers_NumberOfSegments(); // Builds point distribution according to passed function - const std::vector& BuildDistributionExpr( const char*, int, int ) throw ( SMESH_Exception ); - const std::vector& BuildDistributionTab( const std::vector&, int, int ) throw ( SMESH_Exception ); + const std::vector& BuildDistributionExpr( const char*, int, int ) throw ( SALOME_Exception ); + const std::vector& BuildDistributionTab( const std::vector&, int, int ) throw ( SALOME_Exception ); /*! * \brief Set the number of segments * \param segmentsNumber - must be greater than zero */ void SetNumberOfSegments(int segmentsNumber) - throw (SMESH_Exception); + throw (SALOME_Exception); /*! * \brief Get the number of segments @@ -79,7 +79,7 @@ public: * \brief Set distribution type */ void SetDistrType(DistrType typ) - throw (SMESH_Exception); + throw (SALOME_Exception); /*! * \brief Get distribution type @@ -90,19 +90,19 @@ public: * \brief Set scale factor for scale distribution * \param scaleFactor - positive value different from 1 * - * Throws SMESH_Exception if distribution type is not DT_Scale, + * Throws SALOME_Exception if distribution type is not DT_Scale, * or scaleFactor is not a positive value different from 1 */ virtual void SetScaleFactor(double scaleFactor) - throw (SMESH_Exception); + throw (SALOME_Exception); /*! * \brief Get scale factor for scale distribution * - * Throws SMESH_Exception if distribution type is not DT_Scale + * Throws SALOME_Exception if distribution type is not DT_Scale */ double GetScaleFactor() const - throw (SMESH_Exception); + throw (SALOME_Exception); /*! * \brief Set table function for distribution DT_TabFunc @@ -111,36 +111,45 @@ public: * must be even. The parameters must be in range [0,1] and sorted in * increase order. The values of function must be positive. * - * Throws SMESH_Exception if distribution type is not DT_TabFunc + * Throws SALOME_Exception if distribution type is not DT_TabFunc */ void SetTableFunction(const std::vector& table) - throw (SMESH_Exception); + throw (SALOME_Exception); /*! * \brief Get table function for distribution DT_TabFunc * - * Throws SMESH_Exception if distribution type is not DT_TabFunc + * Throws SALOME_Exception if distribution type is not DT_TabFunc */ const std::vector& GetTableFunction() const - throw (SMESH_Exception); + throw (SALOME_Exception); /*! * \brief Set expression function for distribution DT_ExprFunc * \param expr - string containing the expression of the function * f(t), e.g. "sin(t)" * - * Throws SMESH_Exception if distribution type is not DT_ExprFunc + * Throws SALOME_Exception if distribution type is not DT_ExprFunc */ void SetExpressionFunction( const char* expr) - throw (SMESH_Exception); + throw (SALOME_Exception); /*! * \brief Get expression function for distribution DT_ExprFunc * - * Throws SMESH_Exception if distribution type is not DT_ExprFunc + * Throws SALOME_Exception if distribution type is not DT_ExprFunc */ const char* GetExpressionFunction() const - throw (SMESH_Exception); + throw (SALOME_Exception); + + /*! + * \brief Checks validity of the expression of the function f(t), e.g. "sin(t)". + * In case of validity returns a cleaned expression + * \param convMode - 0 for "Exponent mode", 1 for "Cut negative mode" + */ + static std::string CheckExpressionFunction( const std::string& expr, + const int convMode) + throw (SALOME_Exception); /*! * \brief Set conversion mode. When it is 0, it means "exponent mode": @@ -149,19 +158,26 @@ public: * F(t), where F(t0)=f(t0), if f(t0)>=0, otherwise F(t0) = 0. * This mode is sensible only when function distribution is used (DT_TabFunc or DT_ExprFunc) * - * Throws SMESH_Exception if distribution type is not functional + * Throws SALOME_Exception if distribution type is not functional */ void SetConversionMode( int conv ) - throw (SMESH_Exception); + throw (SALOME_Exception); /*! * \brief Returns conversion mode * - * Throws SMESH_Exception if distribution type is not functional + * Throws SALOME_Exception if distribution type is not functional */ int ConversionMode() const - throw (SMESH_Exception); + throw (SALOME_Exception); + void SetReversedEdges( std::vector& ids); + + void SetObjectEntry( const char* entry ) { _objEntry = entry; } + + const char* GetObjectEntry() { return _objEntry.c_str(); } + + const std::vector& GetReversedEdges() const { return _edgeIDs; } /*! * \brief Initialize number of segments by the mesh built on the geometry @@ -171,7 +187,7 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ @@ -189,6 +205,8 @@ protected: std::vector _table, _distr; //!< the table for DT_TabFunc, a sequence of pairs of numbers std::string _func; //!< the expression of the function for DT_ExprFunc int _convMode; //!< flag of conversion mode: 0=exponent, 1=cut negative + std::vector _edgeIDs; //!< list of reversed edges ids + std::string _objEntry; //!< Entry of the main object to reverse edges }; #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Penta_3D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Penta_3D.hxx index 9ca4b3d2bdb9..32e1bcd5627b 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_Penta_3D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Penta_3D.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH StdMeshers : implementaion of SMESH idl descriptions // File : StdMeshers_Penta_3D.hxx // Module : SMESH @@ -35,13 +36,14 @@ // class StdMeshers_SMESHBlock // //////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include #include #include -#include -#include -#include -#include +#include "SMESH_Algo.hxx" #include "SMESH_Block.hxx" #include "SMESH_ComputeError.hxx" #include "SMESH_MesherHelper.hxx" @@ -57,26 +59,26 @@ public: void Load (const TopoDS_Shell& theShell); void Load (const TopoDS_Shell& theShell, - const TopoDS_Vertex& theV000, - const TopoDS_Vertex& theV001); + const TopoDS_Vertex& theV000, + const TopoDS_Vertex& theV001); void ComputeParameters(const gp_Pnt& thePnt, - gp_XYZ& theXYZ); + gp_XYZ& theXYZ); void ComputeParameters(const gp_Pnt& thePnt, - const TopoDS_Shape& theShape, - gp_XYZ& theXYZ); + const TopoDS_Shape& theShape, + gp_XYZ& theXYZ); void ComputeParameters(const double& theU, - const TopoDS_Shape& theShape, - gp_XYZ& theXYZ); + const TopoDS_Shape& theShape, + gp_XYZ& theXYZ); void Point(const gp_XYZ& theParams, - gp_Pnt& thePnt); + gp_Pnt& thePnt); void Point(const gp_XYZ& theParams, - const TopoDS_Shape& theShape, - gp_Pnt& thePnt); + const TopoDS_Shape& theShape, + gp_Pnt& thePnt); int ShapeID(const TopoDS_Shape& theShape); @@ -204,6 +206,9 @@ class STDMESHERS_EXPORT StdMeshers_Penta_3D { // The key of theIJNodes map is a normalized parameter of each // 0-the node on theBaseEdge. + bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + protected: // methods @@ -213,23 +218,23 @@ class STDMESHERS_EXPORT StdMeshers_Penta_3D { void MakeNodes(); - double SetHorizEdgeXYZ(const gp_XYZ& aBNXYZ, - const int aFaceID, + double SetHorizEdgeXYZ(const gp_XYZ& aBNXYZ, + const int aFaceID, std::vector*& aCol1, std::vector*& aCol2); void ShapeSupportID(const bool theIsUpperLayer, - const SMESH_Block::TShapeID theBNSSID, - SMESH_Block::TShapeID& theSSID); + const SMESH_Block::TShapeID theBNSSID, + SMESH_Block::TShapeID& theSSID); void FindNodeOnShape(const TopoDS_Shape& aS, - const gp_XYZ& aParams, + const gp_XYZ& aParams, const int z, - StdMeshers_TNode& aTN); + StdMeshers_TNode& aTN); void CreateNode(const bool theIsUpperLayer, - const gp_XYZ& aParams, - StdMeshers_TNode& aTN); + const gp_XYZ& aParams, + StdMeshers_TNode& aTN); void ClearMeshOnFxy1(); @@ -262,7 +267,7 @@ class STDMESHERS_EXPORT StdMeshers_Penta_3D { std::map < int, int > myConnectingMap; // std::vector myWallNodesMaps; // nodes on a face - std::vector myShapeXYZ; // point on each sub-shape + std::vector myShapeXYZ; // point on each sub-shape bool myCreateQuadratic; SMESH_MesherHelper* myTool; // tool building quadratic elements diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_PolygonPerFace_2D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_PolygonPerFace_2D.hxx new file mode 100644 index 000000000000..5a6a60422d4d --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_PolygonPerFace_2D.hxx @@ -0,0 +1,47 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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_PolygonPerFace_2D.hxx +// Module : SMESH +// +#ifndef _SMESH_PolygonPerFace_2D_HXX_ +#define _SMESH_PolygonPerFace_2D_HXX_ + +#include "SMESH_StdMeshers.hxx" +#include "SMESH_Algo.hxx" + +class STDMESHERS_EXPORT StdMeshers_PolygonPerFace_2D: public SMESH_2D_Algo +{ + public: + StdMeshers_PolygonPerFace_2D(int hypId, int studyId, SMESH_Gen* gen); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus); + + virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Prism_3D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Prism_3D.hxx index 86fa1845eecf..708a92ca9226 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_Prism_3D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Prism_3D.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Prism_3D.hxx // Module : SMESH @@ -28,77 +29,104 @@ #include "SMESH_StdMeshers.hxx" -#include "SMESH_3D_Algo.hxx" -#include "SMDS_TypeOfPosition.hxx" #include "SMDS_MeshNode.hxx" +#include "SMDS_TypeOfPosition.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_Algo.hxx" #include "SMESH_Block.hxx" +#include "SMESH_Comment.hxx" #include "SMESH_Mesh.hxx" -#include "SMESHDS_Mesh.hxx" -#include "SMESH_subMesh.hxx" #include "SMESH_MesherHelper.hxx" -#include "SMESH_Comment.hxx" - -#include +#include "SMESH_TypeDefs.hxx" +#include "SMESH_subMesh.hxx" +#include #include #include -#include #include #include +#include +#include #include +#include +namespace Prism_3D +{ + struct TNode; + struct TPrismTopo; +} +namespace StdMeshers_ProjectionUtils +{ + class TrsfFinder3D; +} class SMESHDS_SubMesh; class TopoDS_Edge; -class TopoDS_Faces; -struct TNode; - -//typedef std::map TNodeNodeMap; -typedef std::vector TNodeColumn; +typedef TopTools_IndexedMapOfOrientedShape TBlockShapes; +typedef std::vector TNodeColumn; +typedef std::map< double, TNodeColumn > TParam2ColumnMap; +typedef std::map< double, TNodeColumn >::const_iterator TParam2ColumnIt; // map of bottom nodes to the column of nodes above them // (the column includes the bottom nodes) -typedef std::map< TNode, TNodeColumn > TNode2ColumnMap; -typedef std::map< double, TNodeColumn > TParam2ColumnMap; -typedef std::map< double, TNodeColumn >::const_iterator TParam2ColumnIt; - -typedef TopTools_IndexedMapOfOrientedShape TBlockShapes; +typedef std::map< Prism_3D::TNode, TNodeColumn > TNode2ColumnMap; -// =============================================== -/*! - * \brief Structure containing node relative data - */ -// =============================================== -struct TNode +namespace Prism_3D { - const SMDS_MeshNode* myNode; - gp_XYZ myParams; - - gp_XYZ GetCoords() const { return gp_XYZ( myNode->X(), myNode->Y(), myNode->Z() ); } - gp_XYZ GetParams() const { return myParams; } - gp_XYZ& ChangeParams() { return myParams; } - bool HasParams() const { return myParams.X() >= 0.0; } - SMDS_TypeOfPosition GetPositionType() const - { return myNode ? myNode->GetPosition()->GetTypeOfPosition() : SMDS_TOP_UNSPEC; } - bool IsNeighbor( const TNode& other ) const; - - TNode(const SMDS_MeshNode* node = 0): myNode(node), myParams(-1,-1,-1) {} - bool operator < (const TNode& other) const { return myNode->GetID() < other.myNode->GetID(); } -}; + // =============================================== + /*! + * \brief Structure containing node relative data + */ + struct TNode + { + const SMDS_MeshNode* myNode; + mutable gp_XYZ myParams; + + gp_XYZ GetCoords() const { return gp_XYZ( myNode->X(), myNode->Y(), myNode->Z() ); } + gp_XYZ GetParams() const { return myParams; } + gp_XYZ& ChangeParams() const { return myParams; } + bool HasParams() const { return myParams.X() >= 0.0; } + SMDS_TypeOfPosition GetPositionType() const + { return myNode ? myNode->GetPosition()->GetTypeOfPosition() : SMDS_TOP_UNSPEC; } + bool IsNeighbor( const TNode& other ) const; + + TNode(const SMDS_MeshNode* node = 0): myNode(node), myParams(-1,-1,-1) {} + bool operator < (const TNode& other) const { return myNode->GetID() < other.myNode->GetID(); } + }; + // =============================================== + /*! + * \brief Topological data of the prism + */ + typedef std::list< TFaceQuadStructPtr > TQuadList; + + struct TPrismTopo + { + TopoDS_Shape myShape3D; + TopoDS_Face myBottom; + TopoDS_Face myTop; + std::list< TopoDS_Edge > myBottomEdges; + std::vector< TQuadList> myWallQuads; // wall sides can be vertically composite + std::vector< int > myRightQuadIndex; // index of right neighbour wall quad + std::list< int > myNbEdgesInWires; + + bool myNotQuadOnTop; + + void Clear(); + void SetUpsideDown(); + }; +} // =============================================================== /*! * \brief Tool analyzing and giving access to a prism geometry * treating it like a block, i.e. the four side faces are * emulated by division/uniting of missing/excess faces. - * It also manage associations between block subshapes and a mesh. + * It also manage associations between block sub-shapes and a mesh. */ -// =============================================================== - class STDMESHERS_EXPORT StdMeshers_PrismAsBlock: public SMESH_Block { -public: + public: /*! * \brief Constructor. Initialization is needed */ @@ -108,20 +136,22 @@ public: /*! * \brief Initialization. - * \param helper - helper loaded with mesh and 3D shape - * \param shape3D - a closed shell or solid - * \retval bool - false if a mesh or a shape are KO - * - * Analyse shape geometry and mesh. - * If there are triangles on one of faces, it becomes 'bottom' + * \param helper - helper loaded with mesh and 3D shape + * \param prism - prism topology + * \retval bool - false if a mesh or a shape are KO */ - bool Init(SMESH_MesherHelper* helper, const TopoDS_Shape& shape3D); + bool Init(SMESH_MesherHelper* helper, const Prism_3D::TPrismTopo& prism); /*! * \brief Return problem description */ SMESH_ComputeErrorPtr GetError() const { return myError; } + /*! + * \brief Free allocated memory + */ + void Clear(); + /*! * \brief Return number of nodes on every vertical edge * \retval int - number of nodes including end nodes @@ -141,16 +171,27 @@ public: * \brief Return TParam2ColumnMap for a base edge * \param baseEdgeID - base edge SMESHDS Index * \param isReverse - columns in-block orientation - * \retval const TParam2ColumnMap& - map + * \retval const TParam2ColumnMap* - map */ - const TParam2ColumnMap& GetParam2ColumnMap(const int baseEdgeID, - bool & isReverse) + const TParam2ColumnMap* GetParam2ColumnMap(const int baseEdgeID, + bool & isReverse) const { - std::pair< TParam2ColumnMap*, bool > & col_frw = - myShapeIndex2ColumnMap[ baseEdgeID ]; + std::map< int, std::pair< TParam2ColumnMap*, bool > >::const_iterator i_mo = + myShapeIndex2ColumnMap.find( baseEdgeID ); + if ( i_mo == myShapeIndex2ColumnMap.end() ) return 0; + + const std::pair< TParam2ColumnMap*, bool >& col_frw = i_mo->second; isReverse = !col_frw.second; - return * col_frw.first; + return col_frw.first; } + + /*! + * \brief Return transformations to get coordinates of nodes of each internal layer + * by nodes of the bottom. Layer is a set of nodes at a certain step + * from bottom to top. + */ + bool GetLayersTransformation(std::vector & trsf, + const Prism_3D::TPrismTopo& prism) const; /*! * \brief Return pointer to mesh @@ -190,7 +231,7 @@ public: /*! * \brief Return in-block ID of a shape - * \param shape - block subshape + * \param shape - block sub-shape * \retval int - ID or zero if the shape has no ID */ int ShapeID(const TopoDS_Shape& shape) const @@ -208,19 +249,6 @@ public: const TParam2ColumnMap& columnsMap, const TopoDS_Edge & bottomEdge, const int sideFaceID); - /*! - * \brief Find wall faces by bottom edges - * \param mesh - the mesh - * \param mainShape - the prism - * \param bottomFace - the bottom face - * \param bottomEdges - edges bounding the bottom face - * \param wallFaces - faces list to fill in - */ - static bool GetWallFaces( SMESH_Mesh* mesh, - const TopoDS_Shape & mainShape, - const TopoDS_Shape & bottomFace, - const std::list< TopoDS_Edge >& bottomEdges, - std::list< TopoDS_Face >& wallFaces); private: @@ -235,39 +263,45 @@ private: // -------------------------------------------------------------------- class TSideFace: public Adaptor3d_Surface { + typedef boost::shared_ptr PSurface; + int myID; //!< in-block ID // map used to find out real UV by it's normalized UV TParam2ColumnMap* myParamToColumnMap; - BRepAdaptor_Surface mySurface; + PSurface mySurface; TopoDS_Edge myBaseEdge; + map< int, PSurface > myShapeID2Surf; // first and last normalized params and orientaion for each component or it-self - std::vector< std::pair< double, double> > myParams; + std::vector< std::pair< double, double> > myParams; // select my columns in myParamToColumnMap bool myIsForward; std::vector< TSideFace* > myComponents; - SMESH_MesherHelper * myHelper; + SMESH_MesherHelper myHelper; public: - TSideFace( SMESH_MesherHelper* helper, - const int faceID, - const TopoDS_Face& face, - const TopoDS_Edge& baseEdge, - TParam2ColumnMap* columnsMap, - const double first = 0.0, - const double last = 1.0); - TSideFace( const std::vector< TSideFace* >& components, + TSideFace( SMESH_Mesh& mesh, + const int faceID, + const Prism_3D::TQuadList& quadList, + const TopoDS_Edge& baseEdge, + TParam2ColumnMap* columnsMap, + const double first = 0.0, + const double last = 1.0); + TSideFace( SMESH_Mesh& mesh, + const std::vector< TSideFace* >& components, const std::vector< std::pair< double, double> > & params); TSideFace( const TSideFace& other ); ~TSideFace(); bool IsComplex() const { return ( NbComponents() > 0 || myParams[0].first != 0. || myParams[0].second != 1. ); } int FaceID() const { return myID; } + SMESH_Mesh* GetMesh() const { return myHelper.GetMesh(); } TParam2ColumnMap* GetColumns() const { return myParamToColumnMap; } - gp_XY GetNodeUV(const TopoDS_Face& F, const SMDS_MeshNode* n) const - { return myHelper->GetNodeUV( F, n ); } + gp_XY GetNodeUV(const TopoDS_Face& F, const SMDS_MeshNode* n, const SMDS_MeshNode* n2=0) const + { return ((SMESH_MesherHelper&) myHelper).SetSubShape(F), myHelper.GetNodeUV( F, n, n2 ); } const TopoDS_Edge & BaseEdge() const { return myBaseEdge; } int ColumnHeight() const { if ( NbComponents() ) return GetComponent(0)->GetColumns()->begin()->second.size(); else return GetColumns()->begin()->second.size(); } double GetColumns(const double U, TParam2ColumnIt & col1, TParam2ColumnIt& col2 ) const; + void GetNodesAtZ(const int Z, std::map& nodes ) const; int NbComponents() const { return myComponents.size(); } TSideFace* GetComponent(const int i) const { return myComponents.at( i ); } void SetComponent(const int i, TSideFace* c) @@ -284,6 +318,8 @@ private: int InsertSubShapes( TBlockShapes& shapeMap ) const; // redefine Adaptor methods gp_Pnt Value(const Standard_Real U,const Standard_Real V) const; + // debug + void dumpNodes(int nbNodes) const; }; // -------------------------------------------------------------------- @@ -299,6 +335,8 @@ private: gp_Pnt Value(const Standard_Real U) const; Standard_Real FirstParameter() const { return 0; } Standard_Real LastParameter() const { return 1; } + // debug + void dumpNodes(int nbNodes) const; }; // -------------------------------------------------------------------- @@ -316,6 +354,8 @@ private: gp_Pnt Value(const Standard_Real U) const; Standard_Real FirstParameter() const { return 0; } Standard_Real LastParameter() const { return 1; } + // debug + void dumpNodes(int nbNodes) const; }; // -------------------------------------------------------------------- @@ -325,32 +365,28 @@ private: // -------------------------------------------------------------------- class STDMESHERS_EXPORT TPCurveOnHorFaceAdaptor: public Adaptor2d_Curve2d { - const TSideFace* mySide; - int myZ; - TopoDS_Face myFace; + std::map< double, gp_XY > myUVmap; // normalized parameter to UV on a horizontal face public: TPCurveOnHorFaceAdaptor( const TSideFace* sideFace, const bool isTop, - const TopoDS_Face& horFace) - : mySide(sideFace), myZ(isTop ? mySide->ColumnHeight() - 1 : 0 ), myFace(horFace) {} + const TopoDS_Face& horFace); gp_Pnt2d Value(const Standard_Real U) const; Standard_Real FirstParameter() const { return 0; } Standard_Real LastParameter() const { return 1; } }; - // -------------------------------------------------------------------- - bool myNotQuadOnTop; - SMESH_MesherHelper* myHelper; - TBlockShapes myShapeIDMap; + bool myNotQuadOnTop; + SMESH_MesherHelper* myHelper; + TBlockShapes myShapeIDMap; + SMESH_ComputeErrorPtr myError; // container of 4 side faces - TSideFace* mySide; + TSideFace* mySide; // node columns for each base edge - std::vector< TParam2ColumnMap > myParam2ColumnMaps; + std::vector< TParam2ColumnMap > myParam2ColumnMaps; // to find a column for a node by edge SMESHDS Index std::map< int, std::pair< TParam2ColumnMap*, bool > > myShapeIndex2ColumnMap; - SMESH_ComputeErrorPtr myError; /*! * \brief store error and comment and then return ( error == COMPERR_OK ) */ @@ -358,15 +394,54 @@ private: myError = SMESH_ComputeError::New(error,comment); return myError->IsOK(); } - //std::vector< SMESH_subMesh* > mySubMeshesVec; // submesh by in-block id + /*! + * \brief Prints a script creating a normal grid on the prism side + */ + void faceGridToPythonDump(const SMESH_Block::TShapeID face, + const int nb=10); + +}; // class StdMeshers_PrismAsBlock + +// =============================================== +/*! + * \brief Tool building internal nodes in a prism + */ +struct StdMeshers_Sweeper +{ + std::vector< TNodeColumn* > myBndColumns; // boundary nodes + std::vector< TNodeColumn* > myIntColumns; // internal nodes + + bool ComputeNodes( SMESH_MesherHelper& helper, + const double tol, + const bool allowHighBndError ); + +private: + + gp_XYZ bndPoint( int iP, int z ) const + { return SMESH_TNodeXYZ( (*myBndColumns[ iP ])[ z ]); } + + gp_XYZ intPoint( int iP, int z ) const + { return SMESH_TNodeXYZ( (*myIntColumns[ iP ])[ z ]); } + + static bool projectIntPoints(const std::vector< gp_XYZ >& fromBndPoints, + const std::vector< gp_XYZ >& toBndPoints, + const std::vector< gp_XYZ >& fromIntPoints, + std::vector< gp_XYZ >& toIntPoints, + StdMeshers_ProjectionUtils::TrsfFinder3D& trsf, + std::vector< gp_XYZ > * bndError); + + static void applyBoundaryError(const std::vector< gp_XYZ >& bndPoints, + const std::vector< gp_XYZ >& bndError1, + const std::vector< gp_XYZ >& bndError2, + const double r, + std::vector< gp_XYZ >& toIntPoints, + std::vector< double >& int2BndDist); }; -// ============================================= +// =============================================== /*! * \brief Algo building prisms on a prism shape */ -// ============================================= - class STDMESHERS_EXPORT StdMeshers_Prism_3D: public SMESH_3D_Algo { public: @@ -379,6 +454,9 @@ public: virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + /*! * \brief Enable removal of quadrangles from the bottom face and * triangles creation there by projection from the top @@ -395,9 +473,40 @@ public: * \param helper - helper initialized by mesh and shape to add prisms to */ static void AddPrisms( std::vector & nodeColumns, - SMESH_MesherHelper* helper); + SMESH_MesherHelper* helper); -private: + static bool IsApplicable(const TopoDS_Shape & aShape, bool toCheckAll); + + private: + + /*! + * \brief Analyse shape geometry and mesh. + * If there are triangles on one of faces, it becomes 'bottom' + */ + bool initPrism(Prism_3D::TPrismTopo& thePrism, + const TopoDS_Shape& theSolid, + const bool selectBottom = true); + + /*! + * \brief Fill thePrism.myWallQuads and thePrism.myTopEdges + */ + bool getWallFaces( Prism_3D::TPrismTopo& thePrism, + const int totalNbFaces); + + /*! + * \brief Compute mesh on a SOLID + */ + bool compute(const Prism_3D::TPrismTopo& thePrism); + + /*! + * \brief Compute 2D mesh on walls FACEs of a prism + */ + bool computeWalls(const Prism_3D::TPrismTopo& thePrism); + + /*! + * \brief Returns a source EDGE of propagation to a given EDGE + */ + TopoDS_Edge findPropagationSource( const TopoDS_Edge& E ); /*! * \brief Find correspondence between bottom and top nodes. @@ -405,35 +514,69 @@ private: * and projection is possible and allowed, perform the projection * \retval bool - is a success or not */ - bool assocOrProjBottom2Top(); + bool assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf, + const Prism_3D::TPrismTopo& thePrism); /*! * \brief Remove quadrangles from the top face and - * create triangles there by projection from the bottom + * create triangles there by projection from the bottom * \retval bool - a success or not */ - bool projectBottomToTop(); + bool projectBottomToTop( const gp_Trsf & bottomToTopTrsf, + const Prism_3D::TPrismTopo& thePrism ); + + /*! + * \brief Compute tolerance to pass to StdMeshers_Sweeper + */ + double getSweepTolerance( const Prism_3D::TPrismTopo& thePrism ); + + /*! + * \brief Defines if it's safe to use the block approach + */ + bool isSimpleBottom( const Prism_3D::TPrismTopo& thePrism ); /*! - * \brief Set projection coordinates of a node to a face and it's subshapes + * \brief Project mesh faces from a source FACE of one prism to + * a source FACE of another prism + * \retval bool - a success or not + */ + bool project2dMesh(const TopoDS_Face& source, const TopoDS_Face& target); + + /*! + * \brief Set projection coordinates of a node to a face and it's sub-shapes * \param faceID - the face given by in-block ID * \param params - node normalized parameters * \retval bool - is a success */ bool setFaceAndEdgesXYZ( const int faceID, const gp_XYZ& params, int z ); + /*! + * \brief If (!isOK), sets the error to a sub-mesh of a current SOLID + */ + bool toSM( bool isOK ); + + /*! + * \brief Return index of a shape + */ + int shapeID( const TopoDS_Shape& S ); + private: bool myProjectTriangles; + bool mySetErrorToSM; + bool myUseBlock; StdMeshers_PrismAsBlock myBlock; SMESH_MesherHelper* myHelper; - std::vector myShapeXYZ; // point on each sub-shape + std::vector myShapeXYZ; // point on each sub-shape of the block // map of bottom nodes to the column of nodes above them // (the column includes the bottom node) TNode2ColumnMap myBotToColumnMap; -}; + + TopTools_IndexedMapOfShape* myPropagChains; + +}; // class StdMeshers_Prism_3D #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionSource1D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionSource1D.hxx index e3b7ca46ea08..9f40bd8762c2 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionSource1D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionSource1D.hxx @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : idl implementation based on 'SMESH' unit's calsses // File : StdMeshers_ProjectionSource1D.hxx // Author : Edward AGAPOV // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_ProjectionSource1D.hxx,v 1.2.2.1 2008/11/27 13:03:49 abd Exp $ // #ifndef _SMESH_ProjectionSource1D_HXX_ #define _SMESH_ProjectionSource1D_HXX_ @@ -31,7 +31,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" #include @@ -57,7 +57,7 @@ public: * Sets source to take a mesh pattern from */ void SetSourceEdge(const TopoDS_Shape& edge) - throw ( SMESH_Exception ); + throw ( SALOME_Exception ); /*! * Returns the source edge or a group containing edges @@ -86,7 +86,7 @@ public: */ void SetVertexAssociation(const TopoDS_Shape& sourceVertex, const TopoDS_Shape& targetVertex) - throw ( SMESH_Exception ); + throw ( SALOME_Exception ); /*! * Returns the vertex associated with the target vertex. @@ -137,7 +137,7 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionSource2D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionSource2D.hxx index 1ea4f9eee34b..7f02586d2c35 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionSource2D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionSource2D.hxx @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : idl implementation based on 'SMESH' unit's calsses // File : StdMeshers_ProjectionSource2D.hxx // Author : Edward AGAPOV // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_ProjectionSource2D.hxx,v 1.2.2.1 2008/11/27 13:03:49 abd Exp $ // #ifndef _SMESH_ProjectionSource2D_HXX_ #define _SMESH_ProjectionSource2D_HXX_ @@ -31,7 +31,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" #include @@ -57,7 +57,7 @@ public: * Sets a source to take a mesh pattern from */ void SetSourceFace(const TopoDS_Shape& face) - throw ( SMESH_Exception ); + throw ( SALOME_Exception ); /*! * Returns the source face or a group containing faces @@ -89,21 +89,21 @@ public: const TopoDS_Shape& sourceVertex2, const TopoDS_Shape& targetVertex1, const TopoDS_Shape& targetVertex2) - throw ( SMESH_Exception ); + throw ( SALOME_Exception ); /*! * Returns the -th source vertex associated with the -th target vertex. * Result may be nil if association not set. * Valid indices are 1 and 2 */ - TopoDS_Vertex GetSourceVertex(int i) const throw ( SMESH_Exception ); + TopoDS_Vertex GetSourceVertex(int i) const throw ( SALOME_Exception ); /*! * Returns the -th target vertex associated with the -th source vertex. * Result may be nil if association not set. * Valid indices are 1 and 2 */ - TopoDS_Vertex GetTargetVertex(int i) const throw ( SMESH_Exception ); + TopoDS_Vertex GetTargetVertex(int i) const throw ( SALOME_Exception ); /*! * \brief Test if vertex association defined diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionSource3D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionSource3D.hxx index 011e2bdcbd98..53c7ac75934d 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionSource3D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionSource3D.hxx @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : idl implementation based on 'SMESH' unit's calsses // File : StdMeshers_ProjectionSource3D.hxx // Author : Edward AGAPOV // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_ProjectionSource3D.hxx,v 1.2.2.1 2008/11/27 13:03:50 abd Exp $ // #ifndef _SMESH_ProjectionSource3D_HXX_ #define _SMESH_ProjectionSource3D_HXX_ @@ -31,7 +31,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" #include @@ -57,7 +57,7 @@ public: * Sets a source to take a mesh pattern from */ void SetSource3DShape(const TopoDS_Shape& shape) - throw ( SMESH_Exception ); + throw ( SALOME_Exception ); /*! * Returns the source shape @@ -83,19 +83,19 @@ public: const TopoDS_Shape& sourceVertex2, const TopoDS_Shape& targetVertex1, const TopoDS_Shape& targetVertex2) - throw ( SMESH_Exception ); + throw ( SALOME_Exception ); /*! * Returns the -th source vertex associated with the -th target vertex. * Result may be nil if association not set. */ - TopoDS_Vertex GetSourceVertex(int i) const throw ( SMESH_Exception ); + TopoDS_Vertex GetSourceVertex(int i) const throw ( SALOME_Exception ); /*! * Returns the -th target vertex associated with the -th source vertex. * Result may be nil if association not set. */ - TopoDS_Vertex GetTargetVertex(int i) const throw ( SMESH_Exception ); + TopoDS_Vertex GetTargetVertex(int i) const throw ( SALOME_Exception ); /*! * \brief Test if vertex association defined @@ -139,7 +139,7 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionUtils.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionUtils.hxx index 3184ac3422f5..56cfd2aee5f5 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionUtils.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_ProjectionUtils.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : idl implementation based on 'SMESH' unit's calsses // File : StdMeshers_ProjectionUtils.hxx // Created : Thu Oct 26 15:37:24 2006 @@ -29,189 +30,257 @@ #include "SMESH_StdMeshers.hxx" +#include "SMDS_MeshElement.hxx" + #include #include #include -#include #include +#include +#include +#include +#include #include #include -class TopoDS_Shape; class SMDS_MeshNode; -class SMESH_Mesh; +class SMESH_Algo; class SMESH_Hypothesis; +class SMESH_Mesh; class SMESH_subMesh; +class TopTools_IndexedMapOfShape; +class TopoDS_Shape; /*! - * \brief Class encapsulating methods common to Projection algorithms + * \brief Struct used instead of a sole TopTools_DataMapOfShapeShape to avoid + * problems with bidirectional bindings */ -class StdMeshers_ProjectionUtils +struct StdMeshers_ShapeShapeBiDirectionMap { - public: + TopTools_DataMapOfShapeShape _map1to2, _map2to1; + + enum EAssocType { + UNDEF, INIT_VERTEX, PROPAGATION, PARTNER, CLOSE_VERTEX, COMMON_VERTEX, FEW_EF }; + EAssocType _assocType; - typedef TopTools_DataMapOfShapeShape TShapeShapeMap; + // convention: s1 - target, s2 - source + bool Bind( const TopoDS_Shape& s1, const TopoDS_Shape& s2 ) + { _map1to2.Bind( s1, s2 ); return _map2to1.Bind( s2, s1 ); } + bool IsBound( const TopoDS_Shape& s, const bool isShape2=false ) const + { return (isShape2 ? _map2to1 : _map1to2).IsBound( s ); } + bool IsEmpty() const { return _map1to2.IsEmpty(); } + int Extent() const { return _map1to2.Extent(); } + void Clear() { _map1to2.Clear(); _map2to1.Clear(); } + const TopoDS_Shape& operator()( const TopoDS_Shape& s, const bool isShape2=false ) const + { // if we get a Standard_NoSuchObject here, it means that the calling code + // passes incorrect isShape2 + return (isShape2 ? _map2to1 : _map1to2)( s ); + } + StdMeshers_ShapeShapeBiDirectionMap() : _assocType( UNDEF ) {} + void SetAssocType( EAssocType type ) { if ( _assocType == UNDEF ) _assocType = type; } +}; + +/*! + * \brief Methods common to Projection algorithms + */ +namespace StdMeshers_ProjectionUtils +{ + typedef StdMeshers_ShapeShapeBiDirectionMap TShapeShapeMap; typedef TopTools_IndexedDataMapOfShapeListOfShape TAncestorMap; - typedef std::map TNodeNodeMap; + typedef std::map TNodeNodeMap; + + + /*! + * \brief Finds transformation beween two sets of 2D points using + * a least square approximation + */ + class TrsfFinder2D + { + gp_GTrsf2d _trsf; + gp_XY _srcOrig; + public: + TrsfFinder2D(): _srcOrig(0,0) {} + void Set( const gp_GTrsf2d& t ) { _trsf = t; } // it's an alternative to Solve() + + bool Solve( const std::vector< gp_XY >& srcPnts, + const std::vector< gp_XY >& tgtPnts ); + + gp_XY Transform( const gp_Pnt2d& srcUV ) const; + + bool IsIdentity() const { return ( _trsf.Form() == gp_Identity ); } + }; /*! - * \brief Looks for association of all subshapes of two shapes - * \param theShape1 - shape 1 - * \param theMesh1 - mesh built on shape 1 - * \param theShape2 - shape 2 - * \param theMesh2 - mesh built on shape 2 - * \param theAssociation - association map to be filled that may - * contain association of one or two pairs of vertices - * \retval bool - true if association found + * \brief Finds transformation beween two sets of 3D points using + * a least square approximation */ - static bool FindSubShapeAssociation(const TopoDS_Shape& theShape1, - SMESH_Mesh* theMesh1, - const TopoDS_Shape& theShape2, - SMESH_Mesh* theMesh2, - TShapeShapeMap & theAssociationMap); + class TrsfFinder3D + { + gp_GTrsf _trsf; + gp_XYZ _srcOrig; + public: + TrsfFinder3D(): _srcOrig(0,0,0) {} + + void Set( const gp_GTrsf& t ) { _trsf = t; } // it's an alternative to Solve() + + bool Solve( const std::vector< gp_XYZ > & srcPnts, + const std::vector< gp_XYZ > & tgtPnts ); + + gp_XYZ Transform( const gp_Pnt& srcP ) const; + + gp_XYZ TransformVec( const gp_Vec& v ) const; + + bool IsIdentity() const { return ( _trsf.Form() == gp_Identity ); } + + bool Invert(); + }; + + /*! + * \brief Looks for association of all sub-shapes of two shapes + * \param theShape1 - shape 1 + * \param theMesh1 - mesh built on shape 1 + * \param theShape2 - shape 2 + * \param theMesh2 - mesh built on shape 2 + * \param theAssociation - association map to be filled that may + * contain association of one or two pairs of vertices + * \retval bool - true if association found + */ + bool FindSubShapeAssociation(const TopoDS_Shape& theShape1, + SMESH_Mesh* theMesh1, + const TopoDS_Shape& theShape2, + SMESH_Mesh* theMesh2, + TShapeShapeMap & theAssociationMap); /*! * \brief Find association of edges of faces - * \param face1 - face 1 - * \param VV1 - vertices of face 1 - * \param face2 - face 2 - * \param VV2 - vertices of face 2 associated with oned of face 1 - * \param edges1 - out list of edges of face 1 - * \param edges2 - out list of edges of face 2 - * \retval int - nb of edges in an outer wire in a success case, else zero - */ - static int FindFaceAssociation(const TopoDS_Face& face1, - TopoDS_Vertex VV1[2], - const TopoDS_Face& face2, - TopoDS_Vertex VV2[2], - std::list< TopoDS_Edge > & edges1, - std::list< TopoDS_Edge > & edges2); + * \param face1 - face 1 + * \param VV1 - vertices of face 1 + * \param face2 - face 2 + * \param VV2 - vertices of face 2 associated with oned of face 1 + * \param edges1 - out list of edges of face 1 + * \param edges2 - out list of edges of face 2 + * \param isClosenessAssoc - is association starting by VERTEX closeness + * \retval int - nb of edges in an outer wire in a success case, else zero + */ + int FindFaceAssociation(const TopoDS_Face& face1, + TopoDS_Vertex VV1[2], + const TopoDS_Face& face2, + TopoDS_Vertex VV2[2], + std::list< TopoDS_Edge > & edges1, + std::list< TopoDS_Edge > & edges2, + const bool isClosenessAssoc=false); /*! * \brief Insert vertex association defined by a hypothesis into a map - * \param theHyp - hypothesis - * \param theAssociationMap - association map - * \param theTargetShape - the shape theHyp assigned to + * \param theHyp - hypothesis + * \param theAssociationMap - association map + * \param theTargetShape - the shape theHyp assigned to */ - static void InitVertexAssociation( const SMESH_Hypothesis* theHyp, - TShapeShapeMap & theAssociationMap, - const TopoDS_Shape& theTargetShape); + void InitVertexAssociation( const SMESH_Hypothesis* theHyp, + TShapeShapeMap & theAssociationMap); /*! * \brief Inserts association theShape1 <-> theShape2 to TShapeShapeMap - * \param theShape1 - shape 1 - * \param theShape2 - shape 2 - * \param theAssociationMap - association map - * \param theBidirectional - if false, inserts theShape1 -> theShape2 association - * \retval bool - true if there was no association for these shapes before + * \param theShape1 - target shape + * \param theShape2 - source shape + * \param theAssociationMap - association map + * \param theBidirectional - if false, inserts theShape1 -> theShape2 association + * \retval bool - true if there was no association for these shapes before */ - static bool InsertAssociation( const TopoDS_Shape& theShape1, - const TopoDS_Shape& theShape2, - TShapeShapeMap & theAssociationMap, - const bool theBidirectional=true); - - static bool IsSubShape( const TopoDS_Shape& shape, SMESH_Mesh* aMesh ); - - static bool IsSubShape( const TopoDS_Shape& shape, const TopoDS_Shape& mainShape ); + bool InsertAssociation( const TopoDS_Shape& theShape1, // target + const TopoDS_Shape& theShape2, // source + TShapeShapeMap & theAssociationMap); /*! * \brief Finds an edge by its vertices in a main shape of the mesh */ - static TopoDS_Edge GetEdgeByVertices( SMESH_Mesh* aMesh, - const TopoDS_Vertex& V1, - const TopoDS_Vertex& V2); - + TopoDS_Edge GetEdgeByVertices( SMESH_Mesh* aMesh, + const TopoDS_Vertex& V1, + const TopoDS_Vertex& V2); + /*! * \brief Return another face sharing an edge * \param edgeToFaces - data map of descendants to ancestors */ - static TopoDS_Face GetNextFace( const TAncestorMap& edgeToFaces, - const TopoDS_Edge& edge, - const TopoDS_Face& face); + TopoDS_Face GetNextFace( const TAncestorMap& edgeToFaces, + const TopoDS_Edge& edge, + const TopoDS_Face& face); /*! * \brief Return other vertex of an edge */ - static TopoDS_Vertex GetNextVertex(const TopoDS_Edge& edge, - const TopoDS_Vertex& vertex); + TopoDS_Vertex GetNextVertex(const TopoDS_Edge& edge, + const TopoDS_Vertex& vertex); /*! * \brief Return an oriented propagation edge - * \param aMesh - mesh - * \param fromEdge - start edge for propagation - * \retval pair - propagation step and found edge + * \param aMesh - mesh + * \param fromEdge - start edge for propagation + * \param chain - return, if provided, a propagation chain passed till + * anEdge; if anEdge.IsNull() then a full propagation chain is returned + * \retval pair - propagation step and found edge */ - static std::pair GetPropagationEdge( SMESH_Mesh* aMesh, - const TopoDS_Edge& anEdge, - const TopoDS_Edge& fromEdge); + std::pair GetPropagationEdge( SMESH_Mesh* aMesh, + const TopoDS_Edge& anEdge, + const TopoDS_Edge& fromEdge, + TopTools_IndexedMapOfShape* chain=0); /*! * \brief Find corresponding nodes on two faces - * \param face1 - the first face - * \param mesh1 - mesh containing elements on the first face - * \param face2 - the second face - * \param mesh2 - mesh containing elements on the second face - * \param assocMap - map associating subshapes of the faces - * \param nodeIn2OutMap - map containing found matching nodes - * \retval bool - is a success - */ - static bool FindMatchingNodesOnFaces( const TopoDS_Face& face1, - SMESH_Mesh* mesh1, - const TopoDS_Face& face2, - SMESH_Mesh* mesh2, - const TShapeShapeMap & assocMap, - TNodeNodeMap & nodeIn2OutMap); - /*! - * \brief Check if the first and last vertices of an edge are the same - * \param anEdge - the edge to check - * \retval bool - true if same + * \param face1 - the first face + * \param mesh1 - mesh containing elements on the first face + * \param face2 - the second face + * \param mesh2 - mesh containing elements on the second face + * \param assocMap - map associating sub-shapes of the faces + * \param nodeIn2OutMap - map containing found matching nodes + * \retval bool - is a success */ - static bool IsClosedEdge( const TopoDS_Edge& anEdge ); - + bool FindMatchingNodesOnFaces( const TopoDS_Face& face1, + SMESH_Mesh* mesh1, + const TopoDS_Face& face2, + SMESH_Mesh* mesh2, + const TShapeShapeMap & assocMap, + TNodeNodeMap & nodeIn2OutMap); /*! - * \brief Return any subshape of a face belonging to the outer wire - * \param face - the face - * \param type - type of subshape to return - * \retval TopoDS_Shape - the found subshape + * \brief Return any sub-shape of a face belonging to the outer wire + * \param face - the face + * \param type - type of sub-shape to return + * \retval TopoDS_Shape - the found sub-shape */ - static TopoDS_Shape OuterShape( const TopoDS_Face& face, - TopAbs_ShapeEnum type); + TopoDS_Shape OuterShape( const TopoDS_Face& face, + TopAbs_ShapeEnum type); /*! * \brief Check that submeshis is computed and try to compute it if is not - * \param sm - submesh to compute - * \param iterationNb - int used to stop infinite recursive call - * \retval bool - true if computed + * \param sm - submesh to compute + * \param iterationNb - int used to stop infinite recursive call + * \retval bool - true if computed */ - static bool MakeComputed(SMESH_subMesh * sm, const int iterationNb = 0); + bool MakeComputed(SMESH_subMesh * sm, const int iterationNb = 0); /*! - * \brief Count nb of subshapes - * \param shape - the shape - * \param type - the type of subshapes to count - * \param ignoreSame - if true, use map not to count same shapes, esle use explorer - * \retval int - the calculated number + * \brief Returns an error message to show in case if MakeComputed( sm ) fails. */ - static int Count(const TopoDS_Shape& shape, - const TopAbs_ShapeEnum type, - const bool ignoreSame); + std::string SourceNotComputedError( SMESH_subMesh * sm = 0, + SMESH_Algo* projAlgo=0); /*! * \brief Set event listeners to submesh with projection algo - * \param subMesh - submesh with projection algo - * \param srcShape - source shape - * \param srcMesh - source mesh + * \param subMesh - submesh with projection algo + * \param srcShape - source shape + * \param srcMesh - source mesh */ - static void SetEventListener(SMESH_subMesh* subMesh, - TopoDS_Shape srcShape, - SMESH_Mesh* srcMesh); + void SetEventListener(SMESH_subMesh* subMesh, + TopoDS_Shape srcShape, + SMESH_Mesh* srcMesh); /*! - * \brief Return true if edge is a boundary of edgeContainer + * \brief Return a boundary EDGE (or all boundary EDGEs) of edgeContainer */ - static bool IsBoundaryEdge(const TopoDS_Edge& edge, - const TopoDS_Shape& edgeContainer, - SMESH_Mesh& mesh); + TopoDS_Edge GetBoundaryEdge(const TopoDS_Shape& edgeContainer, + const SMESH_Mesh& mesh, + std::list< TopoDS_Edge >* allBndEdges = 0 ); }; #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_1D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_1D.hxx index 52f76e17043f..55b2dbca7436 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_1D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_1D.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Projection_1D.hxx // Module : SMESH @@ -29,7 +30,7 @@ #include "SMESH_StdMeshers.hxx" -#include "SMESH_1D_Algo.hxx" +#include "SMESH_Algo.hxx" class StdMeshers_ProjectionSource1D; @@ -46,6 +47,9 @@ public: virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + /*! * \brief Sets a default event listener to submesh of the source edge * \param whenSetToSubMesh - submesh where algo is set diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_1D2D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_1D2D.hxx new file mode 100644 index 000000000000..6465a0acea36 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_1D2D.hxx @@ -0,0 +1,52 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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_Projection_1D2D.hxx +// Module : SMESH +// +#ifndef _SMESH_Projection_1D2D_HXX_ +#define _SMESH_Projection_1D2D_HXX_ + +#include "StdMeshers_Projection_2D.hxx" + +class STDMESHERS_EXPORT StdMeshers_Projection_1D2D: public StdMeshers_Projection_2D +{ +public: + StdMeshers_Projection_1D2D(int hypId, int studyId, SMESH_Gen* gen); + + virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + /*! + * \brief Sets a default event listener to submesh of the source face + * \param whenSetToSubMesh - submesh where algo is set + * + * After being set, event listener is notified on each event of a submesh. + * This method is called when a submesh gets HYP_OK algo_state. + * Arranges that CLEAN event is translated from source submesh to + * the whenSetToSubMesh submesh. + */ + virtual void SetEventListener(SMESH_subMesh* whenSetToSubMesh); +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_2D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_2D.hxx index 2619a0fb5157..c1586a7adb1e 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_2D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_2D.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Projection_2D.hxx // Module : SMESH @@ -28,7 +29,8 @@ #include "SMESH_StdMeshers.hxx" -#include "SMESH_2D_Algo.hxx" +#include "SMESH_Algo.hxx" +#include "StdMeshers_ProjectionUtils.hxx" class StdMeshers_ProjectionSource2D; @@ -44,6 +46,9 @@ public: virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + /*! * \brief Sets a default event listener to submesh of the source face * \param whenSetToSubMesh - submesh where algo is set @@ -54,10 +59,13 @@ public: * the whenSetToSubMesh submesh. */ virtual void SetEventListener(SMESH_subMesh* whenSetToSubMesh); + + + protected: -protected: + const StdMeshers_ProjectionSource2D* _sourceHypo; - const StdMeshers_ProjectionSource2D* _sourceHypo; + StdMeshers_ProjectionUtils::TNodeNodeMap _src2tgtNodes; }; diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_3D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_3D.hxx index 7f4200ef42d8..27e177348c0c 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_3D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Projection_3D.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Projection_3D.hxx // Module : SMESH @@ -28,7 +29,7 @@ #include "SMESH_StdMeshers.hxx" -#include "SMESH_3D_Algo.hxx" +#include "SMESH_Algo.hxx" class StdMeshers_ProjectionSource3D; @@ -44,6 +45,9 @@ public: virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + /*! * \brief Sets a default event listener to submesh of the source shape * \param whenSetToSubMesh - submesh where algo is set @@ -53,7 +57,9 @@ public: */ virtual void SetEventListener(SMESH_subMesh* whenSetToSubMesh); -protected: + static bool IsApplicable(const TopoDS_Shape & aShape, bool toCheckAll); + + protected: const StdMeshers_ProjectionSource3D* _sourceHypo; diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Propagation.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Propagation.hxx index fc69cccf8323..90d04334aa76 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_Propagation.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Propagation.hxx @@ -1,28 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Propagation.hxx // Module : SMESH - +// #ifndef _SMESH_PROPAGATION_HXX_ #define _SMESH_PROPAGATION_HXX_ @@ -30,10 +31,11 @@ #include "SMESH_Hypothesis.hxx" #include "SMESH_subMeshEventListener.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" #include +class SMESH_HypoFilter; // ======================================================================= /*! @@ -41,7 +43,7 @@ */ // ======================================================================= -class STDMESHERS_EXPORT StdMeshers_Propagation:public SMESH_Hypothesis +class STDMESHERS_EXPORT StdMeshers_Propagation : public SMESH_Hypothesis { public: StdMeshers_Propagation(int hypId, int studyId, SMESH_Gen * gen); @@ -49,10 +51,14 @@ class STDMESHERS_EXPORT StdMeshers_Propagation:public SMESH_Hypothesis virtual std::ostream & SaveTo(std::ostream & save); virtual std::istream & LoadFrom(std::istream & load); - friend std::ostream & operator <<(std::ostream & save, StdMeshers_Propagation & hyp); - friend std::istream & operator >>(std::istream & load, StdMeshers_Propagation & hyp); - static std::string GetName (); + static std::string GetName(); + + /*! + * \brief Returns a filter selecting both StdMeshers_Propagation and + * StdMeshers_PropagOfDistribution hypotheses + */ + static const SMESH_HypoFilter& GetFilter(); /*! * \brief Set EventListener managing propagation of hypotheses @@ -68,7 +74,9 @@ class STDMESHERS_EXPORT StdMeshers_Propagation:public SMESH_Hypothesis * \param theEdge - edge to which hypotheses are propagated * \retval TopoDS_Edge - source edge, also passing orientation */ - static TopoDS_Edge GetPropagationSource(SMESH_Mesh& theMesh, const TopoDS_Shape& theEdge); + static TopoDS_Edge GetPropagationSource(SMESH_Mesh& theMesh, + const TopoDS_Shape& theEdge, + bool& isPropagOfDistribution ); /*! * \brief Initialize my parameter values by the mesh built on the geometry @@ -87,4 +95,19 @@ class STDMESHERS_EXPORT StdMeshers_Propagation:public SMESH_Hypothesis virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0); }; + +// ======================================================================= +/*! + * \brief Propagation Of Distribution hypothesis + */ +// ======================================================================= + +class STDMESHERS_EXPORT StdMeshers_PropagOfDistribution: public StdMeshers_Propagation +{ + public: + StdMeshers_PropagOfDistribution(int hypId, int studyId, SMESH_Gen * gen); + + static std::string GetName(); +}; + #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_QuadFromMedialAxis_1D2D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_QuadFromMedialAxis_1D2D.hxx new file mode 100644 index 000000000000..aec59a2d7247 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_QuadFromMedialAxis_1D2D.hxx @@ -0,0 +1,69 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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_QuadFromMedialAxis_1D2D.hxx +// Created : Wed Jun 3 17:22:35 2015 +// Author : Edward AGAPOV (eap) + + +#ifndef __StdMeshers_QuadFromMedialAxis_1D2D_HXX__ +#define __StdMeshers_QuadFromMedialAxis_1D2D_HXX__ + +#include "StdMeshers_Quadrangle_2D.hxx" + +#include + +/*! + * \brief Quadrangle mesher using Medial Axis + */ +class STDMESHERS_EXPORT StdMeshers_QuadFromMedialAxis_1D2D: public StdMeshers_Quadrangle_2D +{ + public: + StdMeshers_QuadFromMedialAxis_1D2D(int hypId, int studyId, SMESH_Gen* gen); + virtual ~StdMeshers_QuadFromMedialAxis_1D2D(); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + Hypothesis_Status& aStatus); + + virtual bool Compute(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape); + + virtual bool Evaluate(SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + + virtual void SetEventListener(SMESH_subMesh* subMesh); + + static bool IsApplicable(const TopoDS_Shape & aShape, bool toCheckAll); + + class Algo1D; + + private: + + bool computeQuads( SMESH_MesherHelper& theHelper, + FaceQuadStruct::Ptr theQuad); + + Algo1D* _regular1D; + const SMESHDS_Hypothesis* _hyp2D; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_QuadToTriaAdaptor.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_QuadToTriaAdaptor.hxx index 02fe44321d47..d5aae1963929 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_QuadToTriaAdaptor.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_QuadToTriaAdaptor.hxx @@ -1,78 +1,98 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 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, or (at your option) any later version. // -// 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. // -// 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 // -// 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 // -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// SMESH SMESH : implementaion of SMESH idl descriptions + // File : StdMeshers_QuadToTriaAdaptor.hxx // Module : SMESH // #ifndef _SMESH_QuadToTriaAdaptor_HXX_ #define _SMESH_QuadToTriaAdaptor_HXX_ -#include -#include -#include +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_ProxyMesh.hxx" #include #include - -#include +class SMESH_Mesh; +class SMESH_ElementSearcher; +class SMDS_MeshElement; +class SMDS_MeshNode; +class SMDS_MeshFace; +// class Handle_TColgp_HArray1OfPnt; +// class Handle_TColgp_HArray1OfVec; +class gp_Pnt; +class gp_Vec; + + +#include #include #include -class STDMESHERS_EXPORT StdMeshers_QuadToTriaAdaptor +#include + +/*! + * \brief "Transforms" quadrilateral faces into triangular ones by creation of pyramids + */ +class STDMESHERS_EXPORT StdMeshers_QuadToTriaAdaptor : public SMESH_ProxyMesh { public: - StdMeshers_QuadToTriaAdaptor(); ~StdMeshers_QuadToTriaAdaptor(); - bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + bool Compute(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_ProxyMesh* aProxyMesh=0); bool Compute(SMESH_Mesh& aMesh); - const std::list* GetTriangles(const SMDS_MeshElement* aFace); + const TopoDS_Shape& GetShape() const { return myShape; } protected: - //bool CheckDegenerate(const SMDS_MeshElement* aFace); - int Preparation(const SMDS_MeshElement* face, - Handle(TColgp_HArray1OfPnt)& PN, - Handle(TColgp_HArray1OfVec)& VN, + Handle_TColgp_HArray1OfPnt& PN, + Handle_TColgp_HArray1OfVec& VN, std::vector& FNodes, - gp_Pnt& PC, gp_Vec& VNorm); + gp_Pnt& PC, gp_Vec& VNorm, + const SMDS_MeshElement** volumes=0); bool CheckIntersection(const gp_Pnt& P, const gp_Pnt& PC, gp_Pnt& Pint, SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, - const TopoDS_Shape& NotCheckedFace); + const SMDS_MeshElement* NotCheckedFace); - bool Compute2ndPart(SMESH_Mesh& aMesh); + bool Compute2ndPart(SMESH_Mesh& aMesh, + const std::vector& pyramids); - typedef std::map< const SMDS_MeshElement*, const SMDS_MeshElement*, TIDCompare > TF2PyramMap; - std::map< const SMDS_MeshElement*, std::list > myResMap; - TF2PyramMap myMapFPyram; - std::list< const SMDS_MeshNode* > myDegNodes; + void MergePiramids( const SMDS_MeshElement* PrmI, + const SMDS_MeshElement* PrmJ, + std::set & nodesToMove); + + void MergeAdjacent(const SMDS_MeshElement* PrmI, + std::set& nodesToMove); + + TopoDS_Shape myShape; + std::set myRemovedTrias; + std::list< const SMDS_MeshNode* > myDegNodes; + const SMESH_ElementSearcher* myElemSearcher; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_QuadrangleParams.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_QuadrangleParams.hxx new file mode 100644 index 000000000000..088161516504 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_QuadrangleParams.hxx @@ -0,0 +1,91 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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_QuadrangleParams.hxx +// Author : Sergey KUUL, OCC +// Module : SMESH + +#ifndef _SMESH_QUADRANGLEPARAMS_HXX_ +#define _SMESH_QUADRANGLEPARAMS_HXX_ + +#include "SMESH_StdMeshers.hxx" +#include "SMESH_Hypothesis.hxx" + +#include + +#include +#include + +enum StdMeshers_QuadType + { + QUAD_STANDARD, + QUAD_TRIANGLE_PREF, + QUAD_QUADRANGLE_PREF, + QUAD_QUADRANGLE_PREF_REVERSED, + QUAD_REDUCED, + QUAD_NB_TYPES + }; + +class STDMESHERS_EXPORT StdMeshers_QuadrangleParams: public SMESH_Hypothesis +{ +public: + StdMeshers_QuadrangleParams(int hypId, int studyId, SMESH_Gen* gen); + virtual ~StdMeshers_QuadrangleParams(); + + void SetTriaVertex (int id); + int GetTriaVertex() const { return _triaVertexID; } + + void SetObjectEntry (const char* entry) { _objEntry = entry; } + const char* GetObjectEntry() { return _objEntry.c_str(); } + + void SetQuadType (StdMeshers_QuadType type); + StdMeshers_QuadType GetQuadType() const { return _quadType; } + + void SetEnforcedNodes( const std::vector< TopoDS_Shape >& shapes, + const std::vector< gp_Pnt >& points ); + void GetEnforcedNodes( std::vector< TopoDS_Shape >& shapes, + std::vector< gp_Pnt >& points ) const; + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + + /*! + * \brief Initialize start and end length 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 + */ + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, + const TopoDS_Shape& theShape); + + /*! + * \brief Initialize my parameter values by default parameters. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByDefaults(const TDefaults& dflts, + const SMESH_Mesh* theMesh=0); + +protected: + int _triaVertexID; + std::string _objEntry; + StdMeshers_QuadType _quadType; + std::vector< TopoDS_Shape > _enforcedVertices; + std::vector< gp_Pnt > _enforcedPoints; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_QuadranglePreference.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_QuadranglePreference.hxx index c8f87758d115..6abddcc2f500 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_QuadranglePreference.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_QuadranglePreference.hxx @@ -1,28 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH StdMeshers : implementaion of SMESH idl descriptions // File : StdMeshers_QuadranglePreference.hxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_QuadranglePreference.hxx,v 1.4.2.1 2008/11/27 13:03:49 abd Exp $ // #ifndef _StdMeshers_QuadranglePreference_HXX_ #define _StdMeshers_QuadranglePreference_HXX_ @@ -30,7 +30,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" /*! * \brief Hypothesis for StdMeshers_Quadrangle_2D, forcing construction @@ -46,8 +46,6 @@ class STDMESHERS_EXPORT StdMeshers_QuadranglePreference:public SMESH_Hypothesis virtual std::ostream & SaveTo(std::ostream & save); virtual std::istream & LoadFrom(std::istream & load); - friend std::ostream & operator <<(std::ostream & save, StdMeshers_QuadranglePreference & hyp); - friend std::istream & operator >>(std::istream & load, StdMeshers_QuadranglePreference & hyp); /*! * \brief Initialize my parameter values by the mesh built on the geometry @@ -59,7 +57,7 @@ class STDMESHERS_EXPORT StdMeshers_QuadranglePreference:public SMESH_Hypothesis */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Quadrangle_2D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Quadrangle_2D.hxx index 74cf8cf43464..460a5e4ab7fb 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_Quadrangle_2D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Quadrangle_2D.hxx @@ -1,117 +1,259 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Quadrangle_2D.hxx // Moved here from SMESH_Quadrangle_2D.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_Quadrangle_2D.hxx,v 1.12.2.4 2008/11/27 13:03:50 abd Exp $ -// + #ifndef _SMESH_QUADRANGLE_2D_HXX_ #define _SMESH_QUADRANGLE_2D_HXX_ +#include "SMESH_Algo.hxx" +#include "SMESH_ProxyMesh.hxx" #include "SMESH_StdMeshers.hxx" +#include "StdMeshers_FaceSide.hxx" +#include "StdMeshers_QuadrangleParams.hxx" -#include "SMESH_2D_Algo.hxx" -#include "SMESH_Exception.hxx" +#include +#include +class SMDS_MeshNode; class SMESH_Mesh; class SMESH_MesherHelper; -class StdMeshers_FaceSide; -class SMDS_MeshNode; +class SMESH_ProxyMesh; struct uvPtStruct; -enum TSideID { BOTTOM_SIDE=0, RIGHT_SIDE, TOP_SIDE, LEFT_SIDE, NB_SIDES }; + +enum TSideID { QUAD_BOTTOM_SIDE=0, QUAD_RIGHT_SIDE, QUAD_TOP_SIDE, QUAD_LEFT_SIDE, NB_QUAD_SIDES }; typedef uvPtStruct UVPtStruct; -typedef struct faceQuadStruct +struct FaceQuadStruct { - std::vector< StdMeshers_FaceSide*> side; - bool isEdgeOut[4]; // true, if an edge has more nodes, than the opposite - UVPtStruct* uv_grid; - ~faceQuadStruct(); -} FaceQuadStruct; + struct Side // a side of FaceQuadStruct + { + struct Contact // contact of two sides + { + int point; // index of a grid point of this side where two sides meat + Side* other_side; + int other_point; + }; + StdMeshers_FaceSidePtr grid; + int from, to; // indices of grid points used by the quad + int di; // +1 or -1 depending on IsReversed() + std::set forced_nodes; // indices of forced grid points + std::vector contacts; // contacts with sides of other quads + int nbNodeOut; // nb of missing nodes on an opposite shorter side + + Side(StdMeshers_FaceSidePtr theGrid = StdMeshers_FaceSidePtr()); + Side& operator=(const Side& otherSide); + operator StdMeshers_FaceSidePtr() { return grid; } + operator const StdMeshers_FaceSidePtr() const { return grid; } + void AddContact( int ip, Side* side, int iop ); + int ToSideIndex( int quadNodeIndex ) const; + int ToQuadIndex( int sideNodeIndex ) const; + bool IsForced( int nodeIndex ) const; + bool IsReversed() const { return nbNodeOut ? false : to < from; } + bool Reverse(bool keepGrid); + int NbPoints() const { return Abs( to - from ); } + double Param( int nodeIndex ) const; + double Length( int from=-1, int to=-1) const; + gp_XY Value2d( double x ) const; + const UVPtStruct& First() const { return GetUVPtStruct()[ from ]; } + const UVPtStruct& Last() const { + return GetUVPtStruct()[ to-nbNodeOut-(IsReversed() ? -1 : +1)]; + } + // some sortcuts + const vector& GetUVPtStruct(bool isXConst=0, double constValue=0) const + { return nbNodeOut ? + grid->SimulateUVPtStruct( NbPoints()-nbNodeOut-1, isXConst, constValue ) : + grid->GetUVPtStruct( isXConst, constValue ); + } + }; + struct SideIterator // iterator on UVPtStruct of a Side + { + const UVPtStruct *uvPtr, *uvEnd; + int dPtr, counter; + SideIterator(): uvPtr(0), uvEnd(0), dPtr(0), counter(0) {} + void Init( const Side& side ) { + dPtr = counter = 0; + uvPtr = uvEnd = 0; + if ( side.NbPoints() > 0 ) { + uvPtr = & side.First(); + uvEnd = & side.Last(); + dPtr = ( uvEnd > uvPtr ) ? +1 : -1; + uvEnd += dPtr; + } + } + bool More() const { return uvPtr != uvEnd; } + void Next() { uvPtr += dPtr; ++counter; } + UVPtStruct& UVPt() const { return (UVPtStruct&) *uvPtr; } + UVPtStruct& operator[](int i) { return (UVPtStruct&) uvPtr[ i*dPtr]; } + int Count() const { return counter; } + }; + + std::vector< Side > side; + std::vector< UVPtStruct> uv_grid; + int iSize, jSize; + TopoDS_Face face; + Bnd_B2d uv_box; + std::string name; // to ease debugging + + FaceQuadStruct ( const TopoDS_Face& F = TopoDS_Face(), const std::string& nm="main" ); + UVPtStruct& UVPt( int i, int j ) { return uv_grid[ i + j * iSize ]; } + double& U( int i, int j ) { return UVPt( i, j ).u; } + double& V( int i, int j ) { return UVPt( i, j ).v; } + void shift ( size_t nb, bool keepUnitOri, bool keepGrid=false ); + int & nbNodeOut( int iSide ) { return side[ iSide ].nbNodeOut; } + bool findCell ( const gp_XY& uv, int & i, int & j ); + bool isNear ( const gp_XY& uv, int & i, int & j, int nbLoops=1 ); + bool isEqual ( const gp_XY& uv, int i, int j ); + void normPa2IJ( double x, double y, int & i, int & j ); + void updateUV ( const gp_XY& uv, int i, int j, bool isVertical ); + + typedef boost::shared_ptr Ptr; +}; class STDMESHERS_EXPORT StdMeshers_Quadrangle_2D: public SMESH_2D_Algo { -public: + public: StdMeshers_Quadrangle_2D(int hypId, int studyId, SMESH_Gen* gen); virtual ~StdMeshers_Quadrangle_2D(); - virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, - SMESH_Hypothesis::Hypothesis_Status& aStatus); - - virtual bool Compute(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape); - - FaceQuadStruct* CheckAnd2Dcompute(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape, - const bool CreateQuadratic); - -protected: - - FaceQuadStruct* CheckNbEdges(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape); - - bool SetNormalizedGrid(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape, - FaceQuadStruct*& quad); - - void SplitQuad(SMESHDS_Mesh *theMeshDS, - const int theFaceID, - const SMDS_MeshNode* theNode1, - const SMDS_MeshNode* theNode2, - const SMDS_MeshNode* theNode3, - const SMDS_MeshNode* theNode4); - - /** - * Special function for creation only quandrangle faces - */ - bool ComputeQuadPref(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape, - FaceQuadStruct* quad); - - UVPtStruct* LoadEdgePoints2(SMESH_Mesh& aMesh, - const TopoDS_Face& F, const TopoDS_Edge& E, - bool IsReverse); - - UVPtStruct* LoadEdgePoints(SMESH_Mesh& aMesh, - const TopoDS_Face& F, const TopoDS_Edge& E, - double first, double last); - - UVPtStruct* MakeEdgePoints(SMESH_Mesh& aMesh, - const TopoDS_Face& F, const TopoDS_Edge& E, - double first, double last, int nb_segm); - - // true if QuadranglePreference hypothesis is assigned that forces - // construction of quadrangles if the number of nodes on opposite edges - // is not the same in the case where the global number of nodes on edges is even - bool myQuadranglePreference; + Hypothesis_Status& aStatus); + + virtual bool Compute(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape); + + virtual bool Evaluate(SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + + FaceQuadStruct::Ptr CheckAnd2Dcompute(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + const bool CreateQuadratic); + + FaceQuadStruct::Ptr CheckNbEdges(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + const bool considerMesh=false); + + static bool IsApplicable(const TopoDS_Shape & aShape, bool toCheckAll); + + protected: + + bool checkNbEdgesForEvaluate(SMESH_Mesh& aMesh, + const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap, + std::vector& aNbNodes, + bool& IsQuadratic); + + bool setNormalizedGrid(FaceQuadStruct::Ptr quad); + + void splitQuadFace(SMESHDS_Mesh * theMeshDS, + const int theFaceID, + const SMDS_MeshNode* theNode1, + const SMDS_MeshNode* theNode2, + const SMDS_MeshNode* theNode3, + const SMDS_MeshNode* theNode4); + bool computeQuadDominant(SMESH_Mesh& aMesh, + const TopoDS_Face& aFace); + + bool computeQuadDominant(SMESH_Mesh& aMesh, + const TopoDS_Face& aFace, + FaceQuadStruct::Ptr quad); + + bool computeQuadPref(SMESH_Mesh& aMesh, + const TopoDS_Face& aFace, + FaceQuadStruct::Ptr quad); + + bool computeTriangles(SMESH_Mesh& aMesh, + const TopoDS_Face& aFace, + FaceQuadStruct::Ptr quad); + + bool evaluateQuadPref(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + std::vector& aNbNodes, + MapShapeNbElems& aResMap, + bool isQuadratic); + + bool computeReduced (SMESH_Mesh& aMesh, + const TopoDS_Face& aFace, + FaceQuadStruct::Ptr quad); + + void updateDegenUV(FaceQuadStruct::Ptr quad); + + void smooth (FaceQuadStruct::Ptr quad); + + bool check(); + + int getCorners(const TopoDS_Face& theFace, + SMESH_Mesh & theMesh, + std::list& theWire, + std::vector& theVertices, + int & theNbDegenEdges, + const bool considerMesh); + + bool getEnforcedUV(); + + bool addEnforcedNodes(); + + int splitQuad(FaceQuadStruct::Ptr quad, int i, int j); + + void shiftQuad(FaceQuadStruct::Ptr& quad, const int num ); + + typedef std::map< StdMeshers_FaceSidePtr, std::vector< FaceQuadStruct::Ptr > > TQuadsBySide; + void updateSideUV( FaceQuadStruct::Side& side, + int iForced, + const TQuadsBySide& quads, + int * iNext=NULL); + + + protected: // Fields + + bool myQuadranglePreference; bool myTrianglePreference; + int myTriaVertexID; + bool myNeedSmooth, myCheckOri; + const StdMeshers_QuadrangleParams* myParams; + StdMeshers_QuadType myQuadType; + + SMESH_MesherHelper* myHelper; + SMESH_ProxyMesh::Ptr myProxyMesh; + std::list< FaceQuadStruct::Ptr > myQuadList; + + struct ForcedPoint + { + gp_XY uv; + gp_XYZ xyz; + TopoDS_Vertex vertex; + const SMDS_MeshNode* node; - - SMESH_MesherHelper* myTool; // tool for working with quadratic elements + double U() const { return uv.X(); } + double V() const { return uv.Y(); } + operator const gp_XY& () { return uv; } + }; + std::vector< ForcedPoint > myForcedPnts; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_QuadraticMesh.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_QuadraticMesh.hxx index f0308fe2e0b1..7b2d826ea90d 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_QuadraticMesh.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_QuadraticMesh.hxx @@ -1,28 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH StdMeshers : implementaion of SMESH idl descriptions // File : StdMeshers_QuadraticMesh.hxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_QuadraticMesh.hxx,v 1.4.2.1 2008/11/27 13:03:50 abd Exp $ // #ifndef _StdMeshers_QuadraticMesh_HXX_ #define _StdMeshers_QuadraticMesh_HXX_ @@ -30,7 +30,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" /*! * \brief Hypothesis for StdMeshers_Regular_1D, forcing construction of quadratic edges. @@ -61,7 +61,7 @@ class STDMESHERS_EXPORT StdMeshers_QuadraticMesh:public SMESH_Hypothesis */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_RadialPrism_3D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_RadialPrism_3D.hxx index d0c783522165..9f1ac2a103c8 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_RadialPrism_3D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_RadialPrism_3D.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_RadialPrism_3D.hxx // Module : SMESH @@ -28,7 +29,7 @@ #include "SMESH_StdMeshers.hxx" -#include "SMESH_3D_Algo.hxx" +#include "SMESH_Algo.hxx" #include "SMDS_MeshNode.hxx" #include @@ -51,6 +52,11 @@ public: virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + + static bool IsApplicable(const TopoDS_Shape & aShape, bool toCheckAll); + protected: typedef std::vector TNodeColumn; diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_RadialQuadrangle_1D2D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_RadialQuadrangle_1D2D.hxx new file mode 100644 index 000000000000..9275b85f9f10 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_RadialQuadrangle_1D2D.hxx @@ -0,0 +1,78 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// File : StdMeshers_RadialQuadrangle_1D2D.hxx +// Module : SMESH +// +#ifndef _SMESH_RadialQuadrangle_1D2D_HXX_ +#define _SMESH_RadialQuadrangle_1D2D_HXX_ + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_Algo.hxx" + +#include + +#include + +class StdMeshers_NumberOfLayers; +class StdMeshers_LayerDistribution; +class SMESH_MesherHelper; +class gp_Pnt; + +class STDMESHERS_EXPORT StdMeshers_RadialQuadrangle_1D2D: public SMESH_2D_Algo +{ +public: + StdMeshers_RadialQuadrangle_1D2D(int hypId, int studyId, SMESH_Gen* gen); + virtual ~StdMeshers_RadialQuadrangle_1D2D(); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus); + + virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + /*! + * \brief Allow algo to do something after persistent restoration + * \param subMesh - restored submesh + * + * This method is called only if a submesh has HYP_OK algo_state. + */ + virtual void SubmeshRestored(SMESH_subMesh* subMesh); + + static bool IsApplicable(const TopoDS_Shape & aShape, bool toCheckAll); + +protected: + + bool computeLayerPositions(const gp_Pnt& p1, + const gp_Pnt& p2, + const TopoDS_Edge& linEdge=TopoDS_Edge(), + bool* linEdgeComputed = 0); + + + const StdMeshers_NumberOfLayers* myNbLayerHypo; + const StdMeshers_LayerDistribution* myDistributionHypo; + SMESH_MesherHelper* myHelper; + std::vector< double > myLayerPositions; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Regular_1D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Regular_1D.hxx index 7df8e45338f8..0f270b9c8872 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_Regular_1D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Regular_1D.hxx @@ -1,40 +1,43 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Regular_1D.hxx // Moved here from SMESH_Regular_1D.hxx // Author : Paul RASCLE, EDF // Module : SMESH - +// #ifndef _SMESH_REGULAR_1D_HXX_ #define _SMESH_REGULAR_1D_HXX_ #include "SMESH_StdMeshers.hxx" -#include "SMESH_1D_Algo.hxx" +#include "SMESH_Algo.hxx" class Adaptor3d_Curve; -class TopoDS_Vertex; +class StdMeshers_Adaptive1D; +class StdMeshers_FixedPoints1D; class StdMeshers_SegmentLengthAroundVertex; +class TopoDS_Vertex; class STDMESHERS_EXPORT StdMeshers_Regular_1D: public SMESH_1D_Algo { @@ -47,7 +50,12 @@ public: SMESH_Hypothesis::Hypothesis_Status& aStatus); virtual bool Compute(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape); + const TopoDS_Shape& aShape); + + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + + virtual void CancelCompute(); virtual const std::list & GetUsedHypothesis(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, const bool=true); @@ -94,7 +102,7 @@ protected: StdMeshers_SegmentLengthAroundVertex* getVertexHyp(SMESH_Mesh & theMesh, const TopoDS_Vertex & theV); - enum HypothesisType { LOCAL_LENGTH, MAX_LENGTH, NB_SEGMENTS, BEG_END_LENGTH, DEFLECTION, ARITHMETIC_1D, NONE }; + enum HypothesisType { LOCAL_LENGTH, MAX_LENGTH, NB_SEGMENTS, BEG_END_LENGTH, DEFLECTION, ARITHMETIC_1D, FIXED_POINTS_1D, ADAPTIVE, GEOMETRIC_1D, NONE }; enum ValueIndex { SCALE_FACTOR_IND = 0, @@ -105,9 +113,9 @@ protected: }; enum IValueIndex { - NB_SEGMENTS_IND = 0, - DISTR_TYPE_IND = 1, - CONV_MODE_IND = 2 + NB_SEGMENTS_IND = 0, + DISTR_TYPE_IND = 1, + CONV_MODE_IND = 2 }; enum VValueIndex { @@ -120,14 +128,19 @@ protected: HypothesisType _hypType; + const StdMeshers_FixedPoints1D* _fpHyp; + const StdMeshers_Adaptive1D* _adaptiveHyp; + double _value[2]; int _ivalue[3]; std::vector _vvalue[1]; std::string _svalue[1]; + std::vector _revEdgesIDs; // a source of propagated hypothesis, is set by CheckHypothesis() // always called before Compute() TopoDS_Shape _mainEdge; + bool _isPropagOfDistribution; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_Reversible1D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_Reversible1D.hxx new file mode 100644 index 000000000000..2e7a8bb907b4 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_Reversible1D.hxx @@ -0,0 +1,59 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// File : StdMeshers_Reversible1D.hxx +// Module : SMESH +// +#ifndef _SMESH_Reversible1D_HXX_ +#define _SMESH_Reversible1D_HXX_ + +#include "SMESH_StdMeshers.hxx" +#include "SMESH_Hypothesis.hxx" + +#include + +/*! + * \brief A base of reversible 1D hypotheses + */ +class STDMESHERS_EXPORT StdMeshers_Reversible1D : public SMESH_Hypothesis +{ +public: + StdMeshers_Reversible1D(int hypId, int studyId, SMESH_Gen* gen); + + void SetReversedEdges( const std::vector& ids); + + void SetObjectEntry( const char* entry ) { _objEntry = entry; } + + const char* GetObjectEntry() { return _objEntry.c_str(); } + + const std::vector& GetReversedEdges() const { return _edgeIDs; } + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + +protected: + std::vector _edgeIDs; + std::string _objEntry; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_SegmentAroundVertex_0D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_SegmentAroundVertex_0D.hxx index 4054a715d5c3..6fe0982c0c60 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_SegmentAroundVertex_0D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_SegmentAroundVertex_0D.hxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_SegmentAroundVertex_0D.hxx // Module : SMESH @@ -28,7 +29,7 @@ #include "SMESH_StdMeshers.hxx" -#include "SMESH_0D_Algo.hxx" +#include "SMESH_Algo.hxx" /*! * \brief Algorithm existing in order just to enable assignation of @@ -46,6 +47,8 @@ public: virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); }; #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_SegmentLengthAroundVertex.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_SegmentLengthAroundVertex.hxx index ca567952486f..580d1eeb8320 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_SegmentLengthAroundVertex.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_SegmentLengthAroundVertex.hxx @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_SegmentLengthAroundVertex.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_SegmentLengthAroundVertex.hxx,v 1.2.2.1 2008/11/27 13:03:50 abd Exp $ // #ifndef _SMESH_SegmentLengthAroundVertex_HXX_ #define _SMESH_SegmentLengthAroundVertex_HXX_ @@ -31,7 +31,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" /*! * \brief This hypothesis specifies length of segments adjacent to the vertex the @@ -43,7 +43,7 @@ class STDMESHERS_EXPORT StdMeshers_SegmentLengthAroundVertex:public SMESH_Hypoth StdMeshers_SegmentLengthAroundVertex(int hypId, int studyId, SMESH_Gen * gen); virtual ~ StdMeshers_SegmentLengthAroundVertex(); - void SetLength(double length) throw(SMESH_Exception); + void SetLength(double length) throw(SALOME_Exception); double GetLength() const; @@ -60,7 +60,7 @@ class STDMESHERS_EXPORT StdMeshers_SegmentLengthAroundVertex:public SMESH_Hypoth */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_StartEndLength.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_StartEndLength.hxx index 1794fc0409bb..82f9096beaba 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_StartEndLength.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_StartEndLength.hxx @@ -1,28 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH StdMeshers : implementaion of SMESH idl descriptions // File : StdMeshers_StartEndLength.hxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_StartEndLength.hxx,v 1.7.2.1 2008/11/27 13:03:50 abd Exp $ // #ifndef _STDMESHERS_STARTENDLENGTH_HXX_ #define _STDMESHERS_STARTENDLENGTH_HXX_ @@ -30,7 +30,9 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" + +#include class STDMESHERS_EXPORT StdMeshers_StartEndLength:public SMESH_Hypothesis { @@ -38,9 +40,17 @@ class STDMESHERS_EXPORT StdMeshers_StartEndLength:public SMESH_Hypothesis StdMeshers_StartEndLength(int hypId, int studyId, SMESH_Gen * gen); virtual ~ StdMeshers_StartEndLength(); - void SetLength(double length, bool isStartLength) throw(SMESH_Exception); + void SetLength(double length, bool isStartLength) throw(SALOME_Exception); double GetLength(bool isStartLength) const; + + void SetReversedEdges( std::vector& ids); + + const std::vector& GetReversedEdges() const { return _edgeIDs; } + + void SetObjectEntry( const char* entry ) { _objEntry = entry; } + + const char* GetObjectEntry() { return _objEntry.c_str(); } virtual std::ostream & SaveTo(std::ostream & save); virtual std::istream & LoadFrom(std::istream & load); @@ -56,7 +66,7 @@ class STDMESHERS_EXPORT StdMeshers_StartEndLength:public SMESH_Hypothesis */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - /*! + /*! * \brief Initialize my parameter values by default parameters. * \retval bool - true if parameter values have been successfully defined */ @@ -64,6 +74,8 @@ class STDMESHERS_EXPORT StdMeshers_StartEndLength:public SMESH_Hypothesis protected: double _begLength, _endLength; + std::vector _edgeIDs; + std::string _objEntry; }; #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_UseExisting_1D2D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_UseExisting_1D2D.hxx index 6d5a5e495be4..91337a917aa6 100644 --- a/src/3rdParty/salomesmesh/inc/StdMeshers_UseExisting_1D2D.hxx +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_UseExisting_1D2D.hxx @@ -1,24 +1,22 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 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, or (at your option) any later version. // -// 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. // -// 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 // -// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_UseExisting_1D2D.hxx // Module : SMESH @@ -28,8 +26,7 @@ #include "SMESH_StdMeshers.hxx" -#include "SMESH_1D_Algo.hxx" -#include "SMESH_2D_Algo.hxx" +#include "SMESH_Algo.hxx" /*! * \brief 1D and 2D algorithms doing nothing to allow mesh generation @@ -46,6 +43,8 @@ public: virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); }; class STDMESHERS_EXPORT StdMeshers_UseExisting_1D: public SMESH_1D_Algo @@ -59,6 +58,8 @@ public: virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); }; #endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_ViscousLayers.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_ViscousLayers.hxx new file mode 100644 index 000000000000..661ab8ab1194 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_ViscousLayers.hxx @@ -0,0 +1,131 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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_ViscousLayers.hxx +// Created : Wed Dec 1 15:15:34 2010 +// Author : Edward AGAPOV (eap) + +#ifndef __StdMeshers_ViscousLayers_HXX__ +#define __StdMeshers_ViscousLayers_HXX__ + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_Hypothesis.hxx" +#include "SMESH_ProxyMesh.hxx" +#include "SMESH_ComputeError.hxx" + +#include + +/*! + * \brief Hypothesis defining parameters of viscous layers + */ +class STDMESHERS_EXPORT StdMeshers_ViscousLayers : public SMESH_Hypothesis +{ +public: + StdMeshers_ViscousLayers(int hypId, int studyId, SMESH_Gen* gen); + + // Set boundary shapes (faces in 3D, edges in 2D) either to exclude from + // treatment or to make the Viscous Layers on + void SetBndShapes(const std::vector& shapeIds, bool toIgnore); + std::vector GetBndShapes() const { return _shapeIds; } + bool IsToIgnoreShapes() const { return _isToIgnoreShapes; } + + // Set total thickness of layers of prisms + void SetTotalThickness(double thickness); + double GetTotalThickness() const { return _thickness; } + + // Set number of layers of prisms + void SetNumberLayers(int nb); + int GetNumberLayers() const { return _nbLayers; } + + // Set factor (>1.0) of growth of layer thickness towards inside of mesh + void SetStretchFactor(double factor); + double GetStretchFactor() const { return _stretchFactor; } + + // Method of computing node translation + enum ExtrusionMethod { + // node is translated along normal to a surface with possible further smoothing + SURF_OFFSET_SMOOTH, + // node is translated along the average normal of surrounding faces till + // intersection with a neighbor face translated along its own normal + // by the layers thickness + FACE_OFFSET, + // node is translated along the average normal of surrounding faces + // by the layers thickness + NODE_OFFSET + }; + void SetMethod( ExtrusionMethod how ); + ExtrusionMethod GetMethod() const { return _method; } + + // Computes temporary 2D mesh to be used by 3D algorithm. + // Return SMESH_ProxyMesh for each SOLID in theShape + SMESH_ProxyMesh::Ptr Compute(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + const bool toMakeN2NMap=false) const; + + // Checks compatibility of assigned StdMeshers_ViscousLayers hypotheses + static SMESH_ComputeErrorPtr + CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus); + + // Checks if viscous layers should be constructed on a shape + bool IsShapeWithLayers(int shapeIndex) const; + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & 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 + */ + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + + /*! + * \brief Initialize my parameter values by default parameters. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0) + { return false; } + + static const char* GetHypType() { return "ViscousLayers"; } + + private: + + std::vector _shapeIds; + bool _isToIgnoreShapes; + int _nbLayers; + double _thickness; + double _stretchFactor; + ExtrusionMethod _method; +}; + +class SMESH_subMesh; +namespace VISCOUS_3D +{ + // sets a sub-mesh event listener to clear sub-meshes of sub-shapes of + // the main shape when sub-mesh of the main shape is cleared, + // for example to clear sub-meshes of FACEs when sub-mesh of a SOLID + // is cleared + void ToClearSubWithMain( SMESH_subMesh* sub, const TopoDS_Shape& main); +} + +#endif diff --git a/src/3rdParty/salomesmesh/inc/StdMeshers_ViscousLayers2D.hxx b/src/3rdParty/salomesmesh/inc/StdMeshers_ViscousLayers2D.hxx new file mode 100644 index 000000000000..e508f173e6b8 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/StdMeshers_ViscousLayers2D.hxx @@ -0,0 +1,78 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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_ViscousLayers2D.hxx +// Created : 23 Jul 2012 +// Author : Edward AGAPOV (eap) + +#ifndef __StdMeshers_ViscousLayers2D_HXX__ +#define __StdMeshers_ViscousLayers2D_HXX__ + +#include "StdMeshers_ViscousLayers.hxx" + +class TopoDS_Face; + +/*! + * \brief Hypothesis defining parameters of viscous layers + */ +class STDMESHERS_EXPORT StdMeshers_ViscousLayers2D : public StdMeshers_ViscousLayers +{ +public: + StdMeshers_ViscousLayers2D(int hypId, int studyId, SMESH_Gen* gen); + /*! + * \brief Computes temporary 2D mesh to be used by 2D algorithm. + * Return SMESH_ProxyMesh for the given FACE, or NULL in case of error + */ + static SMESH_ProxyMesh::Ptr Compute(SMESH_Mesh& theMesh, + const TopoDS_Face& theShape); + /*! + * \brief At study restoration, restore event listeners used to clear an inferior + * dim sub-mesh modified by viscous layers + */ + void RestoreListeners() const; + + /*! + * \brief Checks compatibility of assigned StdMeshers_ViscousLayers2D hypotheses + */ + static SMESH_ComputeErrorPtr CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + Hypothesis_Status& aStatus); + /*! + * \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); + + /*! + * \brief Initialize my parameter values by default parameters. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0) + { return false; } + + static const char* GetHypType() { return "ViscousLayers2D"; } + + private: +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/UNV164_Structure.hxx b/src/3rdParty/salomesmesh/inc/UNV164_Structure.hxx new file mode 100644 index 000000000000..2dab980215fa --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/UNV164_Structure.hxx @@ -0,0 +1,94 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +#ifndef UNV164_Structure_HeaderFile +#define UNV164_Structure_HeaderFile + +// Universal Dataset Number: 164 +// Name: Units +// Status: Current +// Owner: General +// Revision Date: 19-AUG-1987 +// ----------------------------------------------------------------------- + +// Record 1: FORMAT(I10,20A1,I10) +// Field 1 -- units code +// = 1 - SI: Meter (newton) +// = 2 - BG: Foot (pound f) +// = 3 - MG: Meter (kilogram f) +// = 4 - BA: Foot (poundal) +// = 5 - MM: mm (milli newton) +// = 6 - CM: cm (centi newton) +// = 7 - IN: Inch (pound f) +// = 8 - GM: mm (kilogram f) +// = 9 - US: USER_DEFINED +// = 10- MN: mm (newton) +// Field 2 -- units description (used for +// documentation only) +// Field 3 -- temperature mode +// = 1 - absolute +// = 2 - relative +// Record 2: FORMAT(3D25.17) +// Unit factors for converting universal file units to SI. +// To convert from universal file units to SI divide by +// the appropriate factor listed below. +// Field 1 -- length +// Field 2 -- force +// Field 3 -- temperature +// Field 4 -- temperature offset + +// Example: + +// -1 +// 164 +// 2Foot (pound f) 2 +// 3.28083989501312334D+00 2.24808943099710480D-01 1.79999999999999999D+00 +// 4.59670000000000002D+02 +// -1 + +#include "SMESH_DriverUNV.hxx" + +#include + +namespace UNV164 +{ + enum { LENGTH_FACTOR, FORCE_FACTOR, TEMP_FACTOR, TEMP_OFFSET }; + + struct MESHDRIVERUNV_EXPORT TRecord + { + int units_code; + std::string units_description; + int temp_mode; + double factors[4]; + TRecord(); + }; + + MESHDRIVERUNV_EXPORT void + Read(std::ifstream& in_stream, TRecord& theUnitsRecord); + + MESHDRIVERUNV_EXPORT void + Write(std::ofstream& out_stream ); + +}; + + +#endif diff --git a/src/3rdParty/salomesmesh/inc/UNV2411_Structure.hxx b/src/3rdParty/salomesmesh/inc/UNV2411_Structure.hxx index 07195860ea16..2b518a9aa159 100644 --- a/src/3rdParty/salomesmesh/inc/UNV2411_Structure.hxx +++ b/src/3rdParty/salomesmesh/inc/UNV2411_Structure.hxx @@ -1,44 +1,47 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #ifndef UNV2411_Structure_HeaderFile #define UNV2411_Structure_HeaderFile #include "SMESH_DriverUNV.hxx" -#include -#include +#include +#include namespace UNV2411{ + typedef int TNodeLab; // type of node label + struct MESHDRIVERUNV_EXPORT TRecord{ TRecord(); + TNodeLab label; int exp_coord_sys_num; // export coordinate system number int disp_coord_sys_num; // displacement coordinate system number int color; // color double coord[3]; // node coordinates in the part coordinate system }; - typedef int TNodeLab; // type of node label - typedef std::map TDataSet; + typedef std::vector TDataSet; MESHDRIVERUNV_EXPORT void Read(std::ifstream& in_stream, TDataSet& theDataSet); diff --git a/src/3rdParty/salomesmesh/inc/UNV2412_Structure.hxx b/src/3rdParty/salomesmesh/inc/UNV2412_Structure.hxx index 5c6a532f1aa6..1ef8a38e091d 100644 --- a/src/3rdParty/salomesmesh/inc/UNV2412_Structure.hxx +++ b/src/3rdParty/salomesmesh/inc/UNV2412_Structure.hxx @@ -1,41 +1,43 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #ifndef UNV2412_Structure_HeaderFile #define UNV2412_Structure_HeaderFile #include "SMESH_DriverUNV.hxx" -#include #include -#include - +#include namespace UNV2412{ typedef std::vector TNodeLabels; // Nodal connectivities + typedef int TElementLab; // type of element label - struct MESHDRIVERUNV_EXPORT TRecord{ + struct MESHDRIVERUNV_EXPORT TRecord + { TRecord(); + TElementLab label; int fe_descriptor_id; // FE descriptor id int phys_prop_tab_num; // physical property table number int mat_prop_tab_num; // material property table number @@ -48,8 +50,7 @@ namespace UNV2412{ int beam_aft_end; // beam aft-end cross section number }; - typedef int TElementLab; // type of element label - typedef std::map TDataSet; + typedef std::vector TDataSet; MESHDRIVERUNV_EXPORT void Read(std::ifstream& in_stream, TDataSet& theDataSet); diff --git a/src/3rdParty/salomesmesh/inc/UNV2417_Structure.hxx b/src/3rdParty/salomesmesh/inc/UNV2417_Structure.hxx index 2f7999012504..5e155c780652 100644 --- a/src/3rdParty/salomesmesh/inc/UNV2417_Structure.hxx +++ b/src/3rdParty/salomesmesh/inc/UNV2417_Structure.hxx @@ -1,31 +1,32 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #ifndef UNV2417_Structure_HeaderFile #define UNV2417_Structure_HeaderFile #include #include -#include -#include +#include +#include namespace UNV2417{ diff --git a/src/3rdParty/salomesmesh/inc/UNV2420_Structure.hxx b/src/3rdParty/salomesmesh/inc/UNV2420_Structure.hxx new file mode 100644 index 000000000000..60dd28afe256 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/UNV2420_Structure.hxx @@ -0,0 +1,119 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +#ifndef UNV2420_Structure_HeaderFile +#define UNV2420_Structure_HeaderFile + +// Name: Coordinate Systems +// ----------------------------------------------------------------------- + +// Record 1: FORMAT (1I10) +// Field 1 -- Part UID + +// Record 2: FORMAT (40A2) +// Field 1 -- Part Name + +// Record 3: FORMAT (3I10) +// Field 1 -- Coordinate System Label +// Field 2 -- Coordinate System Type +// = 0, Cartesian +// = 1, Cylindrical +// = 2, Spherical +// Field 3 -- Coordinate System Color + +// Record 4: FORMAT (40A2) +// Field 1 -- Coordinate System Name + +// Record 5: FORMAT (1P3D25.16) +// Field 1-3 -- Transformation Matrix Row 1 + +// Record 6: FORMAT (1P3D25.16) +// Field 1-3 -- Transformation Matrix Row 2 + +// Record 7: FORMAT (1P3D25.16) +// Field 1-3 -- Transformation Matrix Row 3 + +// Record 8: FORMAT (1P3D25.16) +// Field 1-3 -- Transformation Matrix Row 4 + +// Records 3 thru 8 are repeated for each Coordinate System in the Part. + +// Example: +// -1 +// 2420 +// 100 +// Untitled +// 6 1 15 +// FEMAP Global Cylindrical (6) +// 1.0000000000000000E+0 0.0000000000000000E+0 0.0000000000000000E+0 +// 0.0000000000000000E+0 1.0000000000000000E+0 0.0000000000000000E+0 +// 0.0000000000000000E+0 0.0000000000000000E+0 1.0000000000000000E+0 +// 0.0000000000000000E+0 0.0000000000000000E+0 0.0000000000000000E+0 +// 7 2 15 +// Coordinate System 4 +// 1.0000000000000000E+0 0.0000000000000000E+0 0.0000000000000000E+0 +// 0.0000000000000000E+0 1.0000000000000000E+0 0.0000000000000000E+0 +// 0.0000000000000000E+0 0.0000000000000000E+0 1.0000000000000000E+0 +// 0.0000000000000000E+0 0.0000000000000000E+0 0.0000000000000000E+0 +// -1 + +#include "SMESH_DriverUNV.hxx" + +#include +#include + +namespace UNV2420 +{ + enum { Cartesian=0, Cylindrical, Spherical }; + + typedef int TCSLabel; // type of coord system label + + struct MESHDRIVERUNV_EXPORT TRecord + { + TCSLabel coord_sys_label; + int coord_sys_type; // { Cartesian=0, Cylindrical, Spherical } + int coord_sys_color; + std::string coord_sys_name; + double matrix[4][3]; + + bool isIdentityMatrix() const; + void ApplyMatrix ( double* coords ) const; + static void FromCylindricalCS( double* coords ); + static void FromSphericalCS ( double* coords ); + }; + + typedef std::vector TDataSet; + + MESHDRIVERUNV_EXPORT void + Read(std::ifstream& in_stream, + std::string& part_name, // can re-store a mesh name + TDataSet& theDataSet); + + MESHDRIVERUNV_EXPORT void + Write(std::ofstream& out_stream, + const std::string& part_name); // can store a mesh name + // const TDataSet& theDataSet); + +}; + + +#endif diff --git a/src/3rdParty/salomesmesh/inc/UNV_Utilities.hxx b/src/3rdParty/salomesmesh/inc/UNV_Utilities.hxx index 41666c84e702..413ccfa5a254 100644 --- a/src/3rdParty/salomesmesh/inc/UNV_Utilities.hxx +++ b/src/3rdParty/salomesmesh/inc/UNV_Utilities.hxx @@ -1,31 +1,32 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #ifndef MED_Utilities_HeaderFile #define MED_Utilities_HeaderFile #include "SMESH_DriverUNV.hxx" -#include -#include +#include +#include #include #include #include @@ -33,13 +34,17 @@ #include namespace UNV{ + using namespace std; + + const size_t theMaxLineLen = 82; // 80 for text + 2 for "\r\n" + class MESHDRIVERUNV_EXPORT PrefixPrinter{ static int myCounter; public: PrefixPrinter(); ~PrefixPrinter(); - static std::string GetPrefix(); + static string GetPrefix(); }; /** @@ -51,23 +56,30 @@ namespace UNV{ { assert (in_file.good()); assert (!ds_name.empty()); - + std::string olds, news; - - while(true){ + + in_file.seekg(0); + while(true) + { in_file >> olds >> news; /* * a "-1" followed by a number means the beginning of a dataset * stop combing at the end of the file */ - while( ((olds != "-1") || (news == "-1") ) && !in_file.eof() ){ - olds = news; - in_file >> news; + while( ((olds != "-1") || (news == "-1"))) + { + olds = news; + in_file >> news; + + if ( in_file.eof() || in_file.fail() ) + { + in_file.clear(); + return false; + } } - if(in_file.eof()) - return false; if (news == ds_name) - return true; + return true; } // should never end up here return false; @@ -89,7 +101,7 @@ namespace UNV{ if(position != std::string::npos){ number.replace(position, 1, "e"); } - return std::atof (number.c_str()); + return atof (number.c_str()); } /** @@ -110,6 +122,24 @@ namespace UNV{ return (olds == " -1"); } + /*! + * \brief reads a whole line + * \param in_stream - source stream + * \param next - if true, first reads the current line up to the end + * which is necessary after reading using >> operator + * \retval std::string - the result line + */ + inline std::string read_line(std::ifstream& in_stream, const bool next=true) + { + std::string resLine; + std::getline( in_stream, resLine ); + if ( next ) + std::getline( in_stream, resLine ); + + if ( resLine.size() > 0 && resLine[ resLine.size()-1 ] == '\r' ) + resLine.resize( resLine.size()-1 ); + return resLine; + } }; diff --git a/src/3rdParty/salomesmesh/inc/Utils_ExceptHandlers.hxx b/src/3rdParty/salomesmesh/inc/Utils_ExceptHandlers.hxx new file mode 100644 index 000000000000..6cf1c56c05d5 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/Utils_ExceptHandlers.hxx @@ -0,0 +1,89 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// KERNEL Utils : common utils for KERNEL +// File : Utils_ExceptHandlers.hxx +// Author : Oksana Tchebanova +// Module : KERNEL +// $Header: +// +#ifndef Utils_ExceptHandlers_HeaderFile +#define Utils_ExceptHandlers_HeaderFile + +#include "SALOME_Utils.hxx" + +#include + +typedef void (*PVF)(); + +class UTILS_EXPORT Unexpect { //save / retrieve unexpected exceptions treatment + PVF old; + public : +#ifndef WIN32 + Unexpect( PVF f ) + { old = std::set_unexpected(f); } + ~Unexpect() { std::set_unexpected(old); } +#else + Unexpect( PVF f ) + { old = ::set_unexpected(f); } + ~Unexpect() { ::set_unexpected(old); } +#endif +}; + +class UTILS_EXPORT Terminate {//save / retrieve terminate function + + PVF old; + public : +#ifndef WIN32 + Terminate( PVF f ) + { old = std::set_terminate(f); } + ~Terminate() { std::set_terminate(old); } +#else + Terminate( PVF f ) + { old = ::set_terminate(f); } + ~Terminate() { ::set_terminate(old); } +#endif +}; + +#define UNEXPECT_CATCH(FuncName, ExceptionConstructor) \ +inline void FuncName () {\ + throw ExceptionConstructor (); \ +} +//Example of the usage + +// void DTC_NotFound () { +// throw (SALOME_DataTypeCatalog::NotFound()); +// } +// or the same : +// +// UNEXPECT_CATCH( DTC_NotFound , SALOME_DataTypeCatalog::NotFound) +// in the function body : +// .... +// Unexpect aCatch(DTC_NotFound) // redefinition of the unexpect exceptions handler +// .... + + +//Definitions : +UTILS_EXPORT extern void SalomeException(); +UTILS_EXPORT extern void SALOME_SalomeException(); + +#endif diff --git a/src/3rdParty/salomesmesh/inc/Utils_Mutex.hxx b/src/3rdParty/salomesmesh/inc/Utils_Mutex.hxx new file mode 100644 index 000000000000..d80df1707f91 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/Utils_Mutex.hxx @@ -0,0 +1,62 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SALOME Utils : general SALOME's definitions and tools +// File: Utils_Mutex.hxx +// Author: Sergey ANIKIN +// Module : SALOME +// $Header$ +// +#ifndef Utils_Mutex_HeaderFile +#define Utils_Mutex_HeaderFile + +#include "SALOME_Utils.hxx" + +#include + +class UTILS_EXPORT Utils_Mutex +{ +public: + Utils_Mutex(); + ~Utils_Mutex(); + + void lock(); + void unlock(); + +private: + pthread_mutex_t myMutex; + pthread_mutex_t myHelperMutex; + pthread_t myThread; + int myCount; +}; + +class UTILS_EXPORT Utils_Locker +{ +public: + Utils_Locker( Utils_Mutex* ); + virtual ~Utils_Locker(); + +private: + Utils_Mutex* myMutex; +}; + +#endif diff --git a/src/3rdParty/salomesmesh/inc/Utils_SALOME_Exception.hxx b/src/3rdParty/salomesmesh/inc/Utils_SALOME_Exception.hxx new file mode 100644 index 000000000000..da31a40f5bfc --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/Utils_SALOME_Exception.hxx @@ -0,0 +1,85 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SALOME Utils : general SALOME's definitions and tools +// File : Utils_SALOME_Exception.hxx +// Author : Antoine YESSAYAN, EDF +// Module : SALOME +// $Header$ +// +#if !defined( __Utils_SALOME_Exception_hxx__ ) +#define __Utils_SALOME_Exception_hxx__ + +//#include "SALOME_Utils.hxx" + +# include +# include + +#ifdef LOCALIZED +#undef LOCALIZED +#endif +#if defined(_DEBUG_) || defined(_DEBUG) +# define LOCALIZED(message) #message , __FILE__ , __LINE__ +#else +# define LOCALIZED(message) #message +#endif + +//swig tool on Linux doesn't pass defines from header SALOME_Utils.hxx +//therefore (temporary solution) defines are placed below + +#ifdef WIN32 +# if defined UTILS_EXPORTS || defined OpUtil_EXPORTS +# define UTILS_EXPORT __declspec( dllexport ) +# else +# define UTILS_EXPORT __declspec( dllimport ) +# undef LOCALIZED +# define LOCALIZED(message) #message +# endif +#else +# define UTILS_EXPORT +#endif + +class SALOME_Exception; + +UTILS_EXPORT std::ostream& operator<<( std::ostream&, const SALOME_Exception& ); + +UTILS_EXPORT const char *makeText( const char *text, const char *fileName, const unsigned int lineNumber ); + +class UTILS_EXPORT SALOME_Exception : public std::exception +{ + +private : + SALOME_Exception( void ); + +protected : + const char* _text ; // non constant pointer but read only char variable + +public : + SALOME_Exception( const char *text, const char *fileName=0, const unsigned int lineNumber=0 ); + SALOME_Exception( const SALOME_Exception &ex ); + virtual ~SALOME_Exception() throw (); + UTILS_EXPORT friend std::ostream & operator<<( std::ostream &os , const SALOME_Exception &ex ); + virtual const char *what( void ) const throw () ; +} ; + + +#endif /* #if !defined( __Utils_SALOME_Exception_hxx__ ) */ diff --git a/src/3rdParty/salomesmesh/inc/aptrte.h b/src/3rdParty/salomesmesh/inc/aptrte.h index c563d15d4e07..6f1dc7bc48b9 100644 --- a/src/3rdParty/salomesmesh/inc/aptrte.h +++ b/src/3rdParty/salomesmesh/inc/aptrte.h @@ -1,24 +1,22 @@ // SMESH MEFISTO2 : algorithm for meshing // -// Copyright (C) 2006 Laboratoire J.-L. Lions UPMC Paris +// Copyright (C) 2006-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// 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 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, or (at your option) any later version. // -// 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.ann.jussieu.fr/~perronne or email Perronnet@ann.jussieu.fr +// 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 : aptrte.h // Author : Alain PERRONNET @@ -48,7 +46,7 @@ #include #endif -#ifdef WNT +#ifdef WIN32 #if defined MEFISTO2D_EXPORTS #define MEFISTO2D_EXPORT __declspec( dllexport ) #else @@ -58,12 +56,13 @@ #define MEFISTO2D_EXPORT #endif + MEFISTO2D_EXPORT void aptrte( Z nutysu, R aretmx, - Z nblf, Z *nudslf, R2 *uvslf, - Z nbpti, R2 *uvpti, - Z & nbst, R2 * & uvst, Z & nbt, Z * & nust, - Z & ierr ); + Z nblf, Z *nudslf, R2 *uvslf, + Z nbpti, R2 *uvpti, + Z & nbst, R2 * & uvst, Z & nbt, Z * & nust, + Z & ierr ); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // but : appel de la triangulation par un arbre-4 recouvrant // ----- de triangles equilateraux @@ -108,8 +107,7 @@ MEFISTO2D_EXPORT // auteur : Alain Perronnet Analyse Numerique Paris UPMC decembre 2001 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#if defined(WIN32) && defined(DFORTRAN) - +#if WIN32 & DFORTRAN #define tempscpu TEMPSCPU #define deltacpu DELTACPU #define insoar INSOAR @@ -126,58 +124,45 @@ MEFISTO2D_EXPORT #define nusotr NUSOTR #define qutr2d QUTR2D #define surtd2 SURTD2 - #define qualitetrte QUALITETRTE + #define qualitetrte QUALITETRTE #define areteideale ARETEIDEALE + +#else + #define tempscpu tempscpu_ + #define deltacpu deltacpu_ + #define insoar insoar_ + #define azeroi azeroi_ + #define fasoar fasoar_ + #define teajte teajte_ + #define tehote tehote_ + #define tetrte tetrte_ + #define aisoar aisoar_ + #define tedela tedela_ + #define terefr terefr_ + #define tesuex tesuex_ + #define teamqt teamqt_ + #define nusotr nusotr_ + #define qutr2d qutr2d_ + #define surtd2 surtd2_ + #define qualitetrte qualitetrte_ - #define MEFISTO2D_STDCALL __stdcall - -#elif defined(WIN32) && defined (__WATCOM__) - - #define MEFISTO2D_STDCALL - #define insoar insoar_ - #define azeroi azeroi_ - #define fasoar fasoar_ - #define teajte teajte_ - #define tehote tehote_ - #define tetrte tetrte_ - #define aisoar aisoar_ - #define tedela tedela_ - #define terefr terefr_ - #define tesuex tesuex_ - #define teamqt teamqt_ - #define nusotr nusotr_ - #define qutr2d qutr2d_ - #define surtd2 surtd2_ - #define qualitetrte qualitetrte_ - #define areteideale areteideale_ -#else //Lin and MacOSX use f77 - - #define MEFISTO2D_STDCALL - - #define insoar insoar_ - #define azeroi azeroi_ - #define fasoar fasoar_ - #define teajte teajte_ - #define tehote tehote_ - #define tetrte tetrte_ - #define aisoar aisoar_ - #define tedela tedela_ - #define terefr terefr_ - #define tesuex tesuex_ - #define teamqt teamqt_ - #define nusotr nusotr_ - #define qutr2d qutr2d_ - #define surtd2 surtd2_ - #define qualitetrte qualitetrte_ #define areteideale areteideale_ #endif -extern "C" { MEFISTO2D_EXPORT void MEFISTO2D_STDCALL qualitetrte( R3 *mnpxyd, - Z & mosoar, Z & mxsoar, Z *mnsoar, - Z & moartr, Z & mxartr, Z *mnartr, - Z & nbtria, R & quamoy, R & quamin ); } + +extern "C" { void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + qualitetrte( R3 *mnpxyd, + Z & mosoar, Z & mxsoar, Z *mnsoar, + Z & moartr, Z & mxartr, Z *mnartr, + Z & nbtria, R & quamoy, R & quamin ); } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // but : calculer la qualite moyenne et minimale de la triangulation // ----- actuelle definie par les tableaux nosoar et noartr @@ -207,27 +192,62 @@ extern "C" { MEFISTO2D_EXPORT void MEFISTO2D_STDCALL qualitetrte( R3 *mnpxyd, // quamin : qualite minimale des triangles actuels // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -extern "C" { void MEFISTO2D_STDCALL tempscpu( double & tempsec ); } +extern "C" { void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + tempscpu( double & tempsec ); +} //Retourne le temps CPU utilise en secondes -extern "C" { void MEFISTO2D_STDCALL deltacpu( R & dtcpu ); } +extern "C" { void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + deltacpu( R & dtcpu ); +} //Retourne le temps CPU utilise en secondes depuis le precedent appel //initialiser le tableau mnsoar pour le hachage des aretes -extern "C" { void MEFISTO2D_STDCALL insoar( Z & mxsomm, - Z & mosoar, - Z & mxsoar, - Z & n1soar, - Z * mnsoar );} +extern "C" {void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + insoar( Z & mxsomm, Z & mosoar, Z & mxsoar, Z & n1soar, Z * mnsoar ); +} //mettre a zero les nb entiers de tab -extern "C" { void MEFISTO2D_STDCALL azeroi( Z & nb, Z * tab ); } +extern "C" {void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + azeroi( Z & nb, Z * tab ); +} -extern "C" {void MEFISTO2D_STDCALL fasoar( Z & ns1, Z & ns2, Z & nt1, Z & nt2, Z & nolign, - Z & mosoar, Z & mxsoar, Z & n1soar, Z * mnsoar, Z * mnarst, - Z & noar, Z & ierr ); +extern "C" {void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + fasoar( Z & ns1, Z & ns2, Z & nt1, Z & nt2, Z & nolign, + Z & mosoar, Z & mxsoar, Z & n1soar, Z * mnsoar, Z * mnarst, + Z & noar, Z & ierr ); } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // but : former l'arete de sommet ns1-ns2 dans le hachage du tableau @@ -273,64 +293,121 @@ extern "C" {void MEFISTO2D_STDCALL fasoar( Z & ns1, Z & ns2, Z & nt1, Z & nt2, Z //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //initialisation du tableau letree et ajout dans letree des sommets 1 a nbsomm -extern "C" {void MEFISTO2D_STDCALL teajte( Z & mxsomm, Z & nbsomm, R3 * mnpxyd, R3 * comxmi, - R & aretmx, Z & mxtree, Z * letree, - Z & ierr ); +extern "C" {void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + teajte( Z & mxsomm, Z & nbsomm, R3 * mnpxyd, R3 * comxmi, + R & aretmx, Z & mxtree, Z * letree, + Z & ierr ); } -extern "C" {void MEFISTO2D_STDCALL tehote( Z & nutysu, Z & nbarpi, Z & mxsomm, Z & nbsomm, R3 * mnpxyd, - R3 * comxmi, R & aretmx, - Z * letree, Z & mxqueu, Z * mnqueu, - Z & ierr ); +extern "C" {void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + tehote( Z & nutysu, Z & nbarpi, Z & mxsomm, Z & nbsomm, R3 * mnpxyd, + R3 * comxmi, R & aretmx, + Z * letree, Z & mxqueu, Z * mnqueu, + Z & ierr ); } // homogeneisation de l'arbre des te a un saut de taille au plus // prise en compte des tailles d'aretes souhaitees autour des sommets initiaux -extern "C" {void MEFISTO2D_STDCALL tetrte( R3 * comxmi, R & aretmx, Z & nbarpi, Z & mxsomm, R3 * mnpxyd, - Z & mxqueu, Z * mnqueu, Z * mntree, - Z & mosoar, Z & mxsoar, Z & n1soar, Z * mnsoar, - Z & moartr, Z & mxartr, Z & n1artr, Z * mnartr, Z * mnarst, - Z & ierr ); +extern "C" {void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + tetrte( R3 * comxmi, R & aretmx, Z & nbarpi, Z & mxsomm, R3 * mnpxyd, + Z & mxqueu, Z * mnqueu, Z * mntree, + Z & mosoar, Z & mxsoar, Z & n1soar, Z * mnsoar, + Z & moartr, Z & mxartr, Z & n1artr, Z * mnartr, Z * mnarst, + Z & ierr ); } // trianguler les triangles equilateraux feuilles a partir de leurs 3 sommets // et des points de la frontiere, des points internes imposes interieurs -extern "C" { void MEFISTO2D_STDCALL aisoar( Z & mosoar, Z & mxsoar, Z * mnsoar, Z & na ); } +extern "C" {void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + aisoar( Z & mosoar, Z & mxsoar, Z * mnsoar, Z & na ); +} // formation du chainage 6 des aretes internes a echanger eventuellement -extern "C" { void MEFISTO2D_STDCALL tedela( R3 * mnpxyd, Z * mnarst, - Z & mosoar, Z & mxsoar, Z & n1soar, Z * mnsoar, Z & na, - Z & moartr, Z & mxartr, Z & n1artr, Z * mnartr, Z & n ); +extern "C" {void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + tedela( R3 * mnpxyd, Z * mnarst, + Z & mosoar, Z & mxsoar, Z & n1soar, Z * mnsoar, Z & na, + Z & moartr, Z & mxartr, Z & n1artr, Z * mnartr, Z & n ); } // boucle sur les aretes internes (non sur une ligne de la frontiere) // avec echange des 2 diagonales afin de rendre la triangulation delaunay -extern "C" { void MEFISTO2D_STDCALL terefr( Z & nbarpi, R3 * mnpxyd, - Z & mosoar, Z & mxsoar, Z & n1soar, Z * mnsoar, - Z & moartr, Z & mxartr, Z & n1artr, Z * mnartr, Z * mnarst, - Z & mxarcf, Z * mnarc1, Z * mnarc2, - Z * mnarc3, Z * mnarc4, - Z & n, Z & ierr ); +extern "C" {void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + terefr( Z & nbarpi, R3 * mnpxyd, + Z & mosoar, Z & mxsoar, Z & n1soar, Z * mnsoar, + Z & moartr, Z & mxartr, Z & n1artr, Z * mnartr, Z * mnarst, + Z & mxarcf, Z * mnarc1, Z * mnarc2, + Z * mnarc3, Z * mnarc4, + Z & n, Z & ierr ); } // detection des aretes frontalieres initiales perdues // triangulation frontale pour les restaurer -extern "C" { void MEFISTO2D_STDCALL tesuex( Z & nblf, Z * nulftr, - Z & ndtri0, Z & nbsomm, R3 * mnpxyd, Z * mnslig, - Z & mosoar, Z & mxsoar, Z * mnsoar, - Z & moartr, Z & mxartr, Z & n1artr, Z * mnartr, Z * mnarst, - Z & nbtria, Z * mntrsu, Z & ierr ); +extern "C" {void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + tesuex( Z & nblf, Z * nulftr, + Z & ndtri0, Z & nbsomm, R3 * mnpxyd, Z * mnslig, + Z & mosoar, Z & mxsoar, Z * mnsoar, + Z & moartr, Z & mxartr, Z & n1artr, Z * mnartr, Z * mnarst, + Z & nbtria, Z * mntrsu, Z & ierr ); } // suppression des triangles externes a la surface -extern "C" { void MEFISTO2D_STDCALL teamqt( Z & nutysu, R & aretmx, R & airemx, - Z * mnarst, Z & mosoar, Z & mxsoar, Z & n1soar, Z * mnsoar, - Z & moartr, Z & mxartr, Z & n1artr, Z * mnartr, - Z & mxarcf, Z * mntrcf, Z * mnstbo, - Z * n1arcf, Z * mnarcf, Z * mnarc1, - Z & nbarpi, Z & nbsomm, Z & mxsomm, - R3 * mnpxyd, Z * mnslig, - Z & ierr ); +extern "C" {void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + teamqt( Z & nutysu, R & aretmx, R & airemx, + Z * mnarst, Z & mosoar, Z & mxsoar, Z & n1soar, Z * mnsoar, + Z & moartr, Z & mxartr, Z & n1artr, Z * mnartr, + Z & mxarcf, Z * mntrcf, Z * mnstbo, + Z * n1arcf, Z * mnarcf, Z * mnarc1, + Z & nbarpi, Z & nbsomm, Z & mxsomm, + R3 * mnpxyd, Z * mnslig, + Z & ierr ); } // amelioration de la qualite de la triangulation par // barycentrage des sommets internes a la triangulation @@ -338,14 +415,37 @@ extern "C" { void MEFISTO2D_STDCALL teamqt( Z & nutysu, R & aretmx, R & airemx, // modification de la topologie des groupes de triangles // mise en delaunay de la triangulation -extern "C" { void MEFISTO2D_STDCALL nusotr( Z & nt, Z & mosoar, Z * mnsoar, Z & moartr, Z * mnartr,Z * nosotr ); +extern "C" {void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + nusotr( Z & nt, Z & mosoar, Z * mnsoar, Z & moartr, Z * mnartr,Z * nosotr ); } //retrouver les numero des 3 sommets du triangle nt -extern "C" { void MEFISTO2D_STDCALL qutr2d( R3 & p1, R3 & p2, R3 & p3, R & qualite ); } +extern "C" {void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + qutr2d( R3 & p1, R3 & p2, R3 & p3, R & qualite ); +} //calculer la qualite d'un triangle de R2 de sommets p1, p2, p3 -extern "C" { R MEFISTO2D_STDCALL surtd2( R3 & p1, R3 & p2, R3 & p3 ); } +extern "C" { R +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif + surtd2( R3 & p1, R3 & p2, R3 & p3 ); +} //calcul de la surface d'un triangle defini par 3 points de r**2 #endif diff --git a/src/3rdParty/salomesmesh/inc/chrono.hxx b/src/3rdParty/salomesmesh/inc/chrono.hxx new file mode 100644 index 000000000000..ba4c3c57212a --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/chrono.hxx @@ -0,0 +1,75 @@ +// Copyright (C) 2006-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +#ifndef _CHRONO_HXX_ +#define _CHRONO_HXX_ + +#include "SMESH_SMDS.hxx" + +#include +#include +#include +#include + +typedef struct acnt +{ + char* _ctrNames; + int _ctrLines; + int _ctrOccur; + double _ctrCumul; +} cntStruct; + +class SMDS_EXPORT counters +{ +public: + static cntStruct *_ctrs; + counters(int nb); + ~counters(); + static void stats(); +protected: + static int _nbChrono; +}; + +class SMDS_EXPORT chrono +{ +public: + chrono(int i); + ~chrono(); + void stop(); +protected: + bool _run; + int _ctr; + clock_t _start, _end; +}; + +#ifdef CHRONODEF +#define CHRONO(i) counters::_ctrs[i]._ctrNames = (char *)__FILE__; \ + counters::_ctrs[i]._ctrLines = __LINE__; \ + chrono aChrono##i(i); + +#define CHRONOSTOP(i) aChrono##i.stop(); + +#else // CHRONODEF + +#define CHRONO(i) +#define CHRONOSTOP(i) + +#endif // CHRONODEF + +#endif // _CHRONO_HXX_ diff --git a/src/3rdParty/salomesmesh/inc/libmesh5.h b/src/3rdParty/salomesmesh/inc/libmesh5.h new file mode 100644 index 000000000000..066853f52fb5 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/libmesh5.h @@ -0,0 +1,155 @@ + + +/*----------------------------------------------------------*/ +/* */ +/* LIBMESH V 5.46 */ +/* */ +/*----------------------------------------------------------*/ +/* */ +/* Description: handle .meshb file format I/O */ +/* Author: Loic MARECHAL */ +/* Creation date: feb 16 2007 */ +/* Last modification: dec 09 2011 */ +/* */ +/*----------------------------------------------------------*/ + + +/*----------------------------------------------------------*/ +/* Defines */ +/*----------------------------------------------------------*/ + +#include "SMESH_DriverGMF.hxx" + +#define GmfStrSiz 1024 +#define GmfMaxTyp 1000 +#define GmfMaxKwd 80 +#define GmfMshVer 1 +#define GmfRead 1 +#define GmfWrite 2 +#define GmfSca 1 +#define GmfVec 2 +#define GmfSymMat 3 +#define GmfMat 4 +#define GmfFloat 1 +#define GmfDouble 2 + +enum GmfKwdCod +{ + GmfReserved1, \ + GmfVersionFormatted, \ + GmfReserved2, \ + GmfDimension, \ + GmfVertices, \ + GmfEdges, \ + GmfTriangles, \ + GmfQuadrilaterals, \ + GmfTetrahedra, \ + GmfPrisms, \ + GmfHexahedra, \ + GmfIterationsAll, \ + GmfTimesAll, \ + GmfCorners, \ + GmfRidges, \ + GmfRequiredVertices, \ + GmfRequiredEdges, \ + GmfRequiredTriangles, \ + GmfRequiredQuadrilaterals, \ + GmfTangentAtEdgeVertices, \ + GmfNormalAtVertices, \ + GmfNormalAtTriangleVertices, \ + GmfNormalAtQuadrilateralVertices, \ + GmfAngleOfCornerBound, \ + GmfTrianglesP2, \ + GmfEdgesP2, \ + GmfSolAtPyramids, \ + GmfQuadrilateralsQ2, \ + GmfISolAtPyramids, \ + GmfSubDomainFromGeom, \ + GmfTetrahedraP2, \ + GmfFault_NearTri, \ + GmfFault_Inter, \ + GmfHexahedraQ2, \ + GmfExtraVerticesAtEdges, \ + GmfExtraVerticesAtTriangles, \ + GmfExtraVerticesAtQuadrilaterals, \ + GmfExtraVerticesAtTetrahedra, \ + GmfExtraVerticesAtPrisms, \ + GmfExtraVerticesAtHexahedra, \ + GmfVerticesOnGeometricVertices, \ + GmfVerticesOnGeometricEdges, \ + GmfVerticesOnGeometricTriangles, \ + GmfVerticesOnGeometricQuadrilaterals, \ + GmfEdgesOnGeometricEdges, \ + GmfFault_FreeEdge, \ + GmfPolyhedra, \ + GmfPolygons, \ + GmfFault_Overlap, \ + GmfPyramids, \ + GmfBoundingBox, \ + GmfBody, \ + GmfPrivateTable, \ + GmfFault_BadShape, \ + GmfEnd, \ + GmfTrianglesOnGeometricTriangles, \ + GmfTrianglesOnGeometricQuadrilaterals, \ + GmfQuadrilateralsOnGeometricTriangles, \ + GmfQuadrilateralsOnGeometricQuadrilaterals, \ + GmfTangents, \ + GmfNormals, \ + GmfTangentAtVertices, \ + GmfSolAtVertices, \ + GmfSolAtEdges, \ + GmfSolAtTriangles, \ + GmfSolAtQuadrilaterals, \ + GmfSolAtTetrahedra, \ + GmfSolAtPrisms, \ + GmfSolAtHexahedra, \ + GmfDSolAtVertices, \ + GmfISolAtVertices, \ + GmfISolAtEdges, \ + GmfISolAtTriangles, \ + GmfISolAtQuadrilaterals, \ + GmfISolAtTetrahedra, \ + GmfISolAtPrisms, \ + GmfISolAtHexahedra, \ + GmfIterations, \ + GmfTime, \ + GmfFault_SmallTri, \ + GmfCoarseHexahedra +}; + + +/*----------------------------------------------------------*/ +/* External procedures */ +/*----------------------------------------------------------*/ + +MESHDriverGMF_EXPORT extern int GmfOpenMesh(const char *, int, ...); +MESHDriverGMF_EXPORT extern int GmfCloseMesh(int); +MESHDriverGMF_EXPORT extern int GmfStatKwd(int, int, ...); +MESHDriverGMF_EXPORT extern int GmfGotoKwd(int, int); +MESHDriverGMF_EXPORT extern int GmfSetKwd(int, int, ...); +MESHDriverGMF_EXPORT extern void GmfGetLin(int, int, ...); +MESHDriverGMF_EXPORT extern void GmfSetLin(int, int, ...); + + +/*----------------------------------------------------------*/ +/* Fortran 77 API */ +/*----------------------------------------------------------*/ + +#if defined(F77_NO_UNDER_SCORE) +#define call(x) x +#else +#define call(x) x ## _ +#endif + + +/*----------------------------------------------------------*/ +/* Transmesh private API */ +/*----------------------------------------------------------*/ + +#ifdef TRANSMESH + +MESHDriverGMF_EXPORT extern char *GmfKwdFmt[ GmfMaxKwd + 1 ][4]; +MESHDriverGMF_EXPORT extern int GmfCpyLin(int, int, int); + +#endif diff --git a/src/3rdParty/salomesmesh/inc/memoire.h b/src/3rdParty/salomesmesh/inc/memoire.h new file mode 100644 index 000000000000..0c8b152d0a30 --- /dev/null +++ b/src/3rdParty/salomesmesh/inc/memoire.h @@ -0,0 +1,43 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +#ifndef _MEMOIRE_H_ +#define _MEMOIRE_H_ + +// #include +#include + +void memostat(const char* f, int l); + +void memostat(const char* f, int l) +{ +#ifdef WIN32 + //rnv: TODO: find alternative of the malloc_stats() on windows platform +#else + /* struct mallinfo mem = mallinfo(); */ + /* std::cerr << f << ":"<< l << " " << mem.arena << " " << mem.ordblks << " " << mem.hblks << " " << mem.hblkhd << " " << mem.uordblks << " " << mem.fordblks << " " << mem.keepcost << std::endl; */ + std::cerr << f << ":" << l << " --------------------------" << std::endl; + // malloc_stats(); + std::cerr << f << ":" << l << " --------------------------" << std::endl; +#endif +} + +#define MEMOSTAT //memostat( __FILE__, __LINE__ ) + +#endif diff --git a/src/3rdParty/salomesmesh/src/Controls/SMESHControls.cpp b/src/3rdParty/salomesmesh/src/Controls/SMESHControls.cpp deleted file mode 100644 index e12427015a0b..000000000000 --- a/src/3rdParty/salomesmesh/src/Controls/SMESHControls.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE -// -// Copyright (C) 2003-2007 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 -// -#include "SMESH_ControlsDef.hxx" - -int main(int argc, char** argv) -{ - using namespace SMESH::Controls; - new MinimumAngle(); - new AspectRatio(); - new Warping(); - new Taper(); - new Skew(); - new Area(); - new Length(); - // new Length2D(); - new MultiConnection(); - // new MultiConnection2D(); - new FreeBorders(); - new LessThan(); - new MoreThan(); - new EqualTo(); - new LogicalNOT(); - new LogicalAND(); - new LogicalOR(); - new ManifoldPart(); - - return 1; -} diff --git a/src/3rdParty/salomesmesh/src/Controls/SMESH_Controls.cpp b/src/3rdParty/salomesmesh/src/Controls/SMESH_Controls.cpp index 5bba65447426..769096df4344 100644 --- a/src/3rdParty/salomesmesh/src/Controls/SMESH_Controls.cpp +++ b/src/3rdParty/salomesmesh/src/Controls/SMESH_Controls.cpp @@ -1,55 +1,62 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -#ifdef _MSC_VER -#define _USE_MATH_DEFINES -#endif // _MSC_VER -#include #include "SMESH_ControlsDef.hxx" -#include +#include "SMDS_BallElement.hxx" +#include "SMDS_Iterator.hxx" +#include "SMDS_Mesh.hxx" +#include "SMDS_MeshElement.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMDS_QuadraticEdge.hxx" +#include "SMDS_QuadraticFaceOfNodes.hxx" +#include "SMDS_VolumeTool.hxx" +#include "SMESHDS_GroupBase.hxx" +#include "SMESHDS_GroupOnFilter.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_MeshAlgos.hxx" +#include "SMESH_OctreeNode.hxx" + +#include #include #include #include - -#include -#include -#include -#include -#include -#include -#include - #include #include #include - #include #include #include #include #include - +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -58,26 +65,25 @@ #include #include -#include "SMDS_Mesh.hxx" -#include "SMDS_Iterator.hxx" -#include "SMDS_MeshElement.hxx" -#include "SMDS_MeshNode.hxx" -#include "SMDS_VolumeTool.hxx" -#include "SMDS_QuadraticFaceOfNodes.hxx" -#include "SMDS_QuadraticEdge.hxx" - -#include "SMESHDS_Mesh.hxx" -#include "SMESHDS_GroupBase.hxx" +#include -#ifndef PI -#define PI M_PI -#endif +#include +#include /* AUXILIARY METHODS */ -namespace{ +namespace { + + const double theEps = 1e-100; + const double theInf = 1e+100; + + inline gp_XYZ gpXYZ(const SMDS_MeshNode* aNode ) + { + return gp_XYZ(aNode->X(), aNode->Y(), aNode->Z() ); + } + inline double getAngle( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 ) { gp_Vec v1( P1 - P2 ), v2( P3 - P2 ); @@ -130,8 +136,8 @@ namespace{ int aResult0 = 0, aResult1 = 0; // last node, it is a medium one in a quadratic edge const SMDS_MeshNode* aLastNode = anEdge->GetNode( anEdge->NbNodes() - 1 ); - const SMDS_MeshNode* aNode0 = anEdge->GetNode( 0 ); - const SMDS_MeshNode* aNode1 = anEdge->GetNode( 1 ); + const SMDS_MeshNode* aNode0 = anEdge->GetNode( 0 ); + const SMDS_MeshNode* aNode1 = anEdge->GetNode( 1 ); if ( aNode1 == aLastNode ) aNode1 = 0; SMDS_ElemIteratorPtr anElemIter = aLastNode->GetInverseElementIterator(); @@ -153,32 +159,29 @@ namespace{ } int aResult = std::max ( aResult0, aResult1 ); -// TColStd_MapOfInteger aMap; - -// SMDS_ElemIteratorPtr anIter = anEdge->nodesIterator(); -// if ( anIter != 0 ) { -// while( anIter->more() ) { -// const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next(); -// if ( aNode == 0 ) -// return 0; -// SMDS_ElemIteratorPtr anElemIter = aNode->GetInverseElementIterator(); -// while( anElemIter->more() ) { -// const SMDS_MeshElement* anElem = anElemIter->next(); -// if ( anElem != 0 && anElem->GetType() != SMDSAbs_Edge ) { -// int anId = anElem->GetID(); - -// if ( anIter->more() ) // i.e. first node -// aMap.Add( anId ); -// else if ( aMap.Contains( anId ) ) -// aResult++; -// } -// } -// } -// } - return aResult; } + gp_XYZ getNormale( const SMDS_MeshFace* theFace, bool* ok=0 ) + { + int aNbNode = theFace->NbNodes(); + + gp_XYZ q1 = gpXYZ( theFace->GetNode(1)) - gpXYZ( theFace->GetNode(0)); + gp_XYZ q2 = gpXYZ( theFace->GetNode(2)) - gpXYZ( theFace->GetNode(0)); + gp_XYZ n = q1 ^ q2; + if ( aNbNode > 3 ) { + gp_XYZ q3 = gpXYZ( theFace->GetNode(3)) - gpXYZ( theFace->GetNode(0)); + n += q2 ^ q3; + } + double len = n.Modulus(); + bool zeroLen = ( len <= numeric_limits::min()); + if ( !zeroLen ) + n /= len; + + if (ok) *ok = !zeroLen; + + return n; + } } @@ -186,13 +189,16 @@ namespace{ using namespace SMESH::Controls; /* - FUNCTORS -*/ + * FUNCTORS + */ +//================================================================================ /* Class : NumericalFunctor Description : Base class for numerical functors */ +//================================================================================ + NumericalFunctor::NumericalFunctor(): myMesh(NULL) { @@ -204,7 +210,7 @@ void NumericalFunctor::SetMesh( const SMDS_Mesh* theMesh ) myMesh = theMesh; } -bool NumericalFunctor::GetPoints(const int theId, +bool NumericalFunctor::GetPoints(const int theId, TSequenceOfXYZ& theRes ) const { theRes.clear(); @@ -212,7 +218,11 @@ bool NumericalFunctor::GetPoints(const int theId, if ( myMesh == 0 ) return false; - return GetPoints( myMesh->FindElement( theId ), theRes ); + const SMDS_MeshElement* anElem = myMesh->FindElement( theId ); + if ( !anElem || anElem->GetType() != this->GetType() ) + return false; + + return GetPoints( anElem, theRes ); } bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem, @@ -220,10 +230,11 @@ bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem, { theRes.clear(); - if ( anElem == 0) + if ( anElem == 0 ) return false; theRes.reserve( anElem->NbNodes() ); + theRes.setElement( anElem ); // Get nodes of the element SMDS_ElemIteratorPtr anIter; @@ -231,16 +242,15 @@ bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem, if ( anElem->IsQuadratic() ) { switch ( anElem->GetType() ) { case SMDSAbs_Edge: - anIter = static_cast + anIter = dynamic_cast (anElem)->interlacedNodesElemIterator(); break; case SMDSAbs_Face: - anIter = static_cast + anIter = dynamic_cast (anElem)->interlacedNodesElemIterator(); break; default: anIter = anElem->nodesIterator(); - //return false; } } else { @@ -248,9 +258,13 @@ bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem, } if ( anIter ) { + double xyz[3]; while( anIter->more() ) { if ( const SMDS_MeshNode* aNode = static_cast( anIter->next() )) - theRes.push_back( gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) ); + { + aNode->GetXYZ( xyz ); + theRes.push_back( gp_XYZ( xyz[0], xyz[1], xyz[2] )); + } } } @@ -265,30 +279,125 @@ long NumericalFunctor::GetPrecision() const void NumericalFunctor::SetPrecision( const long thePrecision ) { myPrecision = thePrecision; + myPrecisionValue = pow( 10., (double)( myPrecision ) ); } double NumericalFunctor::GetValue( long theId ) { + double aVal = 0; + myCurrElement = myMesh->FindElement( theId ); + TSequenceOfXYZ P; - if ( GetPoints( theId, P )) + if ( GetPoints( theId, P )) // elem type is checked here + aVal = Round( GetValue( P )); + + return aVal; +} + +double NumericalFunctor::Round( const double & aVal ) +{ + return ( myPrecision >= 0 ) ? floor( aVal * myPrecisionValue + 0.5 ) / myPrecisionValue : aVal; +} + +//================================================================================ +/*! + * \brief Return histogram of functor values + * \param nbIntervals - number of intervals + * \param nbEvents - number of mesh elements having values within i-th interval + * \param funValues - boundaries of intervals + * \param elements - elements to check vulue of; empty list means "of all" + * \param minmax - boundaries of diapason of values to divide into intervals + */ +//================================================================================ + +void NumericalFunctor::GetHistogram(int nbIntervals, + std::vector& nbEvents, + std::vector& funValues, + const vector& elements, + const double* minmax, + const bool isLogarithmic) +{ + if ( nbIntervals < 1 || + !myMesh || + !myMesh->GetMeshInfo().NbElements( GetType() )) + return; + nbEvents.resize( nbIntervals, 0 ); + funValues.resize( nbIntervals+1 ); + + // get all values sorted + std::multiset< double > values; + if ( elements.empty() ) { - double aVal = GetValue( P ); - if ( myPrecision >= 0 ) + SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator( GetType() ); + while ( elemIt->more() ) + values.insert( GetValue( elemIt->next()->GetID() )); + } + else + { + vector::const_iterator id = elements.begin(); + for ( ; id != elements.end(); ++id ) + values.insert( GetValue( *id )); + } + + if ( minmax ) + { + funValues[0] = minmax[0]; + funValues[nbIntervals] = minmax[1]; + } + else + { + funValues[0] = *values.begin(); + funValues[nbIntervals] = *values.rbegin(); + } + // case nbIntervals == 1 + if ( nbIntervals == 1 ) + { + nbEvents[0] = values.size(); + return; + } + // case of 1 value + if (funValues.front() == funValues.back()) + { + nbEvents.resize( 1 ); + nbEvents[0] = values.size(); + funValues[1] = funValues.back(); + funValues.resize( 2 ); + } + // generic case + std::multiset< double >::iterator min = values.begin(), max; + for ( int i = 0; i < nbIntervals; ++i ) + { + // find end value of i-th interval + double r = (i+1) / double(nbIntervals); + if (isLogarithmic && funValues.front() > 1e-07 && funValues.back() > 1e-07) { + double logmin = log10(funValues.front()); + double lval = logmin + r * (log10(funValues.back()) - logmin); + funValues[i+1] = pow(10.0, lval); + } + else { + funValues[i+1] = funValues.front() * (1-r) + funValues.back() * r; + } + + // count values in the i-th interval if there are any + if ( min != values.end() && *min <= funValues[i+1] ) { - double prec = pow( 10., (double)( myPrecision ) ); - aVal = floor( aVal * prec + 0.5 ) / prec; + // find the first value out of the interval + max = values.upper_bound( funValues[i+1] ); // max is greater than funValues[i+1], or end() + nbEvents[i] = std::distance( min, max ); + min = max; } - return aVal; } - - return 0.; + // add values larger than minmax[1] + nbEvents.back() += std::distance( min, values.end() ); } //======================================================================= -//function : GetValue -//purpose : -//======================================================================= +/* + Class : Volume + Description : Functor calculating volume of a 3D element +*/ +//================================================================================ double Volume::GetValue( long theElementId ) { @@ -300,31 +409,287 @@ double Volume::GetValue( long theElementId ) return 0; } -//======================================================================= -//function : GetBadRate -//purpose : meaningless as it is not quality control functor -//======================================================================= - double Volume::GetBadRate( double Value, int /*nbNodes*/ ) const { return Value; } +SMDSAbs_ElementType Volume::GetType() const +{ + return SMDSAbs_Volume; +} + //======================================================================= -//function : GetType -//purpose : +/* + Class : MaxElementLength2D + Description : Functor calculating maximum length of 2D element +*/ +//================================================================================ + +double MaxElementLength2D::GetValue( const TSequenceOfXYZ& P ) +{ + if(P.size() == 0) + return 0.; + double aVal = 0; + int len = P.size(); + if( len == 3 ) { // triangles + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 1 )); + aVal = Max(L1,Max(L2,L3)); + } + else if( len == 4 ) { // quadrangles + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 1 )); + double D1 = getDistance(P( 1 ),P( 3 )); + double D2 = getDistance(P( 2 ),P( 4 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2)); + } + else if( len == 6 ) { // quadratic triangles + double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 )); + double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 )); + double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 )); + aVal = Max(L1,Max(L2,L3)); + } + else if( len == 8 || len == 9 ) { // quadratic quadrangles + double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 )); + double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 )); + double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 )); + double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 )); + double D1 = getDistance(P( 1 ),P( 5 )); + double D2 = getDistance(P( 3 ),P( 7 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2)); + } + // Diagonals are undefined for concave polygons + // else if ( P.getElementEntity() == SMDSEntity_Quad_Polygon && P.size() > 2 ) // quad polygon + // { + // // sides + // aVal = getDistance( P( 1 ), P( P.size() )) + getDistance( P( P.size() ), P( P.size()-1 )); + // for ( size_t i = 1; i < P.size()-1; i += 2 ) + // { + // double L = getDistance( P( i ), P( i+1 )) + getDistance( P( i+1 ), P( i+2 )); + // aVal = Max( aVal, L ); + // } + // // diagonals + // for ( int i = P.size()-5; i > 0; i -= 2 ) + // for ( int j = i + 4; j < P.size() + i - 2; i += 2 ) + // { + // double D = getDistance( P( i ), P( j )); + // aVal = Max( aVal, D ); + // } + // } + // { // polygons + + // } + + if( myPrecision >= 0 ) + { + double prec = pow( 10., (double)myPrecision ); + aVal = floor( aVal * prec + 0.5 ) / prec; + } + return aVal; +} + +double MaxElementLength2D::GetValue( long theElementId ) +{ + TSequenceOfXYZ P; + return GetPoints( theElementId, P ) ? GetValue(P) : 0.0; +} + +double MaxElementLength2D::GetBadRate( double Value, int /*nbNodes*/ ) const +{ + return Value; +} + +SMDSAbs_ElementType MaxElementLength2D::GetType() const +{ + return SMDSAbs_Face; +} + //======================================================================= +/* + Class : MaxElementLength3D + Description : Functor calculating maximum length of 3D element +*/ +//================================================================================ -SMDSAbs_ElementType Volume::GetType() const +double MaxElementLength3D::GetValue( long theElementId ) { - return SMDSAbs_Volume; + TSequenceOfXYZ P; + if( GetPoints( theElementId, P ) ) { + double aVal = 0; + const SMDS_MeshElement* aElem = myMesh->FindElement( theElementId ); + SMDSAbs_ElementType aType = aElem->GetType(); + int len = P.size(); + switch( aType ) { + case SMDSAbs_Volume: + if( len == 4 ) { // tetras + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 1 )); + double L4 = getDistance(P( 1 ),P( 4 )); + double L5 = getDistance(P( 2 ),P( 4 )); + double L6 = getDistance(P( 3 ),P( 4 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + break; + } + else if( len == 5 ) { // pyramids + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 1 )); + double L5 = getDistance(P( 1 ),P( 5 )); + double L6 = getDistance(P( 2 ),P( 5 )); + double L7 = getDistance(P( 3 ),P( 5 )); + double L8 = getDistance(P( 4 ),P( 5 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(L7,L8)); + break; + } + else if( len == 6 ) { // pentas + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 1 )); + double L4 = getDistance(P( 4 ),P( 5 )); + double L5 = getDistance(P( 5 ),P( 6 )); + double L6 = getDistance(P( 6 ),P( 4 )); + double L7 = getDistance(P( 1 ),P( 4 )); + double L8 = getDistance(P( 2 ),P( 5 )); + double L9 = getDistance(P( 3 ),P( 6 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(Max(L7,L8),L9)); + break; + } + else if( len == 8 ) { // hexas + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 1 )); + double L5 = getDistance(P( 5 ),P( 6 )); + double L6 = getDistance(P( 6 ),P( 7 )); + double L7 = getDistance(P( 7 ),P( 8 )); + double L8 = getDistance(P( 8 ),P( 5 )); + double L9 = getDistance(P( 1 ),P( 5 )); + double L10= getDistance(P( 2 ),P( 6 )); + double L11= getDistance(P( 3 ),P( 7 )); + double L12= getDistance(P( 4 ),P( 8 )); + double D1 = getDistance(P( 1 ),P( 7 )); + double D2 = getDistance(P( 2 ),P( 8 )); + double D3 = getDistance(P( 3 ),P( 5 )); + double D4 = getDistance(P( 4 ),P( 6 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10))); + aVal = Max(aVal,Max(L11,L12)); + aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4))); + break; + } + else if( len == 12 ) { // hexagonal prism + for ( int i1 = 1; i1 < 12; ++i1 ) + for ( int i2 = i1+1; i1 <= 12; ++i1 ) + aVal = Max( aVal, getDistance(P( i1 ),P( i2 ))); + break; + } + else if( len == 10 ) { // quadratic tetras + double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 )); + double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 )); + double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 )); + double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + break; + } + else if( len == 13 ) { // quadratic pyramids + double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 )); + double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 )); + double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 )); + double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 )); + double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(L7,L8)); + break; + } + else if( len == 15 ) { // quadratic pentas + double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 )); + double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 )); + double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 )); + double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 )); + double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 )); + double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 )); + double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(Max(L7,L8),L9)); + break; + } + else if( len == 20 || len == 27 ) { // quadratic hexas + double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 )); + double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 )); + double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 )); + double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 )); + double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 )); + double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 )); + double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 )); + double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 )); + double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 )); + double D1 = getDistance(P( 1 ),P( 7 )); + double D2 = getDistance(P( 2 ),P( 8 )); + double D3 = getDistance(P( 3 ),P( 5 )); + double D4 = getDistance(P( 4 ),P( 6 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10))); + aVal = Max(aVal,Max(L11,L12)); + aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4))); + break; + } + else if( len > 1 && aElem->IsPoly() ) { // polys + // get the maximum distance between all pairs of nodes + for( int i = 1; i <= len; i++ ) { + for( int j = 1; j <= len; j++ ) { + if( j > i ) { // optimization of the loop + double D = getDistance( P(i), P(j) ); + aVal = Max( aVal, D ); + } + } + } + } + } + + if( myPrecision >= 0 ) + { + double prec = pow( 10., (double)myPrecision ); + aVal = floor( aVal * prec + 0.5 ) / prec; + } + return aVal; + } + return 0.; +} + +double MaxElementLength3D::GetBadRate( double Value, int /*nbNodes*/ ) const +{ + return Value; } +SMDSAbs_ElementType MaxElementLength3D::GetType() const +{ + return SMDSAbs_Volume; +} +//======================================================================= /* Class : MinimumAngle Description : Functor for calculation of minimum angle */ +//================================================================================ double MinimumAngle::GetValue( const TSequenceOfXYZ& P ) { @@ -336,12 +701,13 @@ double MinimumAngle::GetValue( const TSequenceOfXYZ& P ) aMin = getAngle(P( P.size() ), P( 1 ), P( 2 )); aMin = Min(aMin,getAngle(P( P.size()-1 ), P( P.size() ), P( 1 ))); - for (int i=2; iFindElement( theId ); + if ( myCurrElement && myCurrElement->GetVtkType() == VTK_QUAD ) + { + // issue 21723 + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myCurrElement->getMeshId()]->getGrid(); + if ( vtkCell* avtkCell = grid->GetCell( myCurrElement->getVtkId() )) + aVal = Round( vtkMeshQuality::QuadAspectRatio( avtkCell )); + } + else + { + TSequenceOfXYZ P; + if ( GetPoints( myCurrElement, P )) + aVal = Round( GetValue( P )); + } + return aVal; +} + double AspectRatio::GetValue( const TSequenceOfXYZ& P ) { // According to "Mesh quality control" by Nadir Bouhamau referring to @@ -391,8 +780,8 @@ double AspectRatio::GetValue( const TSequenceOfXYZ& P ) double maxLen = Max( aLen[ 0 ], Max( aLen[ 1 ], aLen[ 2 ] ) ); double half_perimeter = ( aLen[0] + aLen[1] + aLen[2] ) / 2.; double anArea = getArea( P( 1 ), P( 2 ), P( 3 ) ); - if ( anArea <= Precision::Confusion() ) - return 0.; + if ( anArea <= theEps ) + return theInf; return alfa * maxLen * half_perimeter / anArea; } else if ( nbNodes == 6 ) { // quadratic triangles @@ -411,60 +800,108 @@ double AspectRatio::GetValue( const TSequenceOfXYZ& P ) double maxLen = Max( aLen[ 0 ], Max( aLen[ 1 ], aLen[ 2 ] ) ); double half_perimeter = ( aLen[0] + aLen[1] + aLen[2] ) / 2.; double anArea = getArea( P(1), P(3), P(5) ); - if ( anArea <= Precision::Confusion() ) - return 0.; + if ( anArea <= theEps ) + return theInf; return alfa * maxLen * half_perimeter / anArea; } else if( nbNodes == 4 ) { // quadrangle - // return aspect ratio of the worst triange which can be built + // Compute lengths of the sides + std::vector< double > aLen (4); + aLen[0] = getDistance( P(1), P(2) ); + aLen[1] = getDistance( P(2), P(3) ); + aLen[2] = getDistance( P(3), P(4) ); + aLen[3] = getDistance( P(4), P(1) ); + // Compute lengths of the diagonals + std::vector< double > aDia (2); + aDia[0] = getDistance( P(1), P(3) ); + aDia[1] = getDistance( P(2), P(4) ); + // Compute areas of all triangles which can be built // taking three nodes of the quadrangle - TSequenceOfXYZ triaPnts(3); - // triangle on nodes 1 3 2 - triaPnts(1) = P(1); - triaPnts(2) = P(3); - triaPnts(3) = P(2); - double ar = GetValue( triaPnts ); - // triangle on nodes 1 3 4 - triaPnts(3) = P(4); - ar = Max ( ar, GetValue( triaPnts )); - // triangle on nodes 1 2 4 - triaPnts(2) = P(2); - ar = Max ( ar, GetValue( triaPnts )); - // triangle on nodes 3 2 4 - triaPnts(1) = P(3); - ar = Max ( ar, GetValue( triaPnts )); - - return ar; - } - else { // nbNodes==8 - quadratic quadrangle - // return aspect ratio of the worst triange which can be built + std::vector< double > anArea (4); + anArea[0] = getArea( P(1), P(2), P(3) ); + anArea[1] = getArea( P(1), P(2), P(4) ); + anArea[2] = getArea( P(1), P(3), P(4) ); + anArea[3] = getArea( P(2), P(3), P(4) ); + // Q = alpha * L * C1 / C2, where + // + // alpha = sqrt( 1/32 ) + // L = max( L1, L2, L3, L4, D1, D2 ) + // C1 = sqrt( ( L1^2 + L1^2 + L1^2 + L1^2 ) / 4 ) + // C2 = min( S1, S2, S3, S4 ) + // Li - lengths of the edges + // Di - lengths of the diagonals + // Si - areas of the triangles + const double alpha = sqrt( 1 / 32. ); + double L = Max( aLen[ 0 ], + Max( aLen[ 1 ], + Max( aLen[ 2 ], + Max( aLen[ 3 ], + Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) ); + double C1 = sqrt( ( aLen[0] * aLen[0] + + aLen[1] * aLen[1] + + aLen[2] * aLen[2] + + aLen[3] * aLen[3] ) / 4. ); + double C2 = Min( anArea[ 0 ], + Min( anArea[ 1 ], + Min( anArea[ 2 ], anArea[ 3 ] ) ) ); + if ( C2 <= theEps ) + return theInf; + return alpha * L * C1 / C2; + } + else if( nbNodes == 8 || nbNodes == 9 ) { // nbNodes==8 - quadratic quadrangle + // Compute lengths of the sides + std::vector< double > aLen (4); + aLen[0] = getDistance( P(1), P(3) ); + aLen[1] = getDistance( P(3), P(5) ); + aLen[2] = getDistance( P(5), P(7) ); + aLen[3] = getDistance( P(7), P(1) ); + // Compute lengths of the diagonals + std::vector< double > aDia (2); + aDia[0] = getDistance( P(1), P(5) ); + aDia[1] = getDistance( P(3), P(7) ); + // Compute areas of all triangles which can be built // taking three nodes of the quadrangle - TSequenceOfXYZ triaPnts(3); - // triangle on nodes 1 3 2 - triaPnts(1) = P(1); - triaPnts(2) = P(5); - triaPnts(3) = P(3); - double ar = GetValue( triaPnts ); - // triangle on nodes 1 3 4 - triaPnts(3) = P(7); - ar = Max ( ar, GetValue( triaPnts )); - // triangle on nodes 1 2 4 - triaPnts(2) = P(3); - ar = Max ( ar, GetValue( triaPnts )); - // triangle on nodes 3 2 4 - triaPnts(1) = P(5); - ar = Max ( ar, GetValue( triaPnts )); - - return ar; + std::vector< double > anArea (4); + anArea[0] = getArea( P(1), P(3), P(5) ); + anArea[1] = getArea( P(1), P(3), P(7) ); + anArea[2] = getArea( P(1), P(5), P(7) ); + anArea[3] = getArea( P(3), P(5), P(7) ); + // Q = alpha * L * C1 / C2, where + // + // alpha = sqrt( 1/32 ) + // L = max( L1, L2, L3, L4, D1, D2 ) + // C1 = sqrt( ( L1^2 + L1^2 + L1^2 + L1^2 ) / 4 ) + // C2 = min( S1, S2, S3, S4 ) + // Li - lengths of the edges + // Di - lengths of the diagonals + // Si - areas of the triangles + const double alpha = sqrt( 1 / 32. ); + double L = Max( aLen[ 0 ], + Max( aLen[ 1 ], + Max( aLen[ 2 ], + Max( aLen[ 3 ], + Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) ); + double C1 = sqrt( ( aLen[0] * aLen[0] + + aLen[1] * aLen[1] + + aLen[2] * aLen[2] + + aLen[3] * aLen[3] ) / 4. ); + double C2 = Min( anArea[ 0 ], + Min( anArea[ 1 ], + Min( anArea[ 2 ], anArea[ 3 ] ) ) ); + if ( C2 <= theEps ) + return theInf; + return alpha * L * C1 / C2; } + return 0; } double AspectRatio::GetBadRate( double Value, int /*nbNodes*/ ) const { // the aspect ratio is in the range [1.0,infinity] + // < 1.0 = very bad, zero area // 1.0 = good // infinity = bad - return Value / 1000.; + return ( Value < 0.9 ) ? 1000 : Value / 1000.; } SMDSAbs_ElementType AspectRatio::GetType() const @@ -473,10 +910,13 @@ SMDSAbs_ElementType AspectRatio::GetType() const } +//================================================================================ /* Class : AspectRatio3D Description : Functor for calculating aspect ratio */ +//================================================================================ + namespace{ inline double getHalfPerimeter(double theTria[3]){ @@ -485,9 +925,9 @@ namespace{ inline double getArea(double theHalfPerim, double theTria[3]){ return sqrt(theHalfPerim* - (theHalfPerim-theTria[0])* - (theHalfPerim-theTria[1])* - (theHalfPerim-theTria[2])); + (theHalfPerim-theTria[0])* + (theHalfPerim-theTria[1])* + (theHalfPerim-theTria[2])); } inline double getVolume(double theLen[6]){ @@ -539,6 +979,28 @@ namespace{ } +double AspectRatio3D::GetValue( long theId ) +{ + double aVal = 0; + myCurrElement = myMesh->FindElement( theId ); + if ( myCurrElement && myCurrElement->GetVtkType() == VTK_TETRA ) + { + // Action from CoTech | ACTION 31.3: + // EURIWARE BO: Homogenize the formulas used to calculate the Controls in SMESH to fit with + // those of ParaView. The library used by ParaView for those calculations can be reused in SMESH. + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myCurrElement->getMeshId()]->getGrid(); + if ( vtkCell* avtkCell = grid->GetCell( myCurrElement->getVtkId() )) + aVal = Round( vtkMeshQuality::TetAspectRatio( avtkCell )); + } + else + { + TSequenceOfXYZ P; + if ( GetPoints( myCurrElement, P )) + aVal = Round( GetValue( P )); + } + return aVal; +} + double AspectRatio3D::GetValue( const TSequenceOfXYZ& P ) { double aQuality = 0.0; @@ -551,10 +1013,11 @@ double AspectRatio3D::GetValue( const TSequenceOfXYZ& P ) else if(nbNodes==13) nbNodes=5; // quadratic pyramid else if(nbNodes==15) nbNodes=6; // quadratic pentahedron else if(nbNodes==20) nbNodes=8; // quadratic hexahedron + else if(nbNodes==27) nbNodes=8; // quadratic hexahedron else return aQuality; } - switch(nbNodes){ + switch(nbNodes) { case 4:{ double aLen[6] = { getDistance(P( 1 ),P( 2 )), // a @@ -772,7 +1235,22 @@ double AspectRatio3D::GetValue( const TSequenceOfXYZ& P ) } break; } - } + case 12: + { + gp_XYZ aXYZ[8] = {P( 1 ),P( 2 ),P( 4 ),P( 5 ),P( 7 ),P( 8 ),P( 10 ),P( 11 )}; + aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8])),aQuality); + } + { + gp_XYZ aXYZ[8] = {P( 2 ),P( 3 ),P( 5 ),P( 6 ),P( 8 ),P( 9 ),P( 11 ),P( 12 )}; + aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8])),aQuality); + } + { + gp_XYZ aXYZ[8] = {P( 3 ),P( 4 ),P( 6 ),P( 1 ),P( 9 ),P( 10 ),P( 12 ),P( 7 )}; + aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8])),aQuality); + } + break; + } // switch(nbNodes) + if ( nbNodes > 4 ) { // avaluate aspect ratio of quadranle faces AspectRatio aspect2D; @@ -805,10 +1283,13 @@ SMDSAbs_ElementType AspectRatio3D::GetType() const } +//================================================================================ /* Class : Warping Description : Functor for calculating warping */ +//================================================================================ + double Warping::GetValue( const TSequenceOfXYZ& P ) { if ( P.size() != 4 ) @@ -821,7 +1302,11 @@ double Warping::GetValue( const TSequenceOfXYZ& P ) double A3 = ComputeA( P( 3 ), P( 4 ), P( 1 ), G ); double A4 = ComputeA( P( 4 ), P( 1 ), P( 2 ), G ); - return Max( Max( A1, A2 ), Max( A3, A4 ) ); + double val = Max( Max( A1, A2 ), Max( A3, A4 ) ); + + const double eps = 0.1; // val is in degrees + + return val < eps ? 0. : val; } double Warping::ComputeA( const gp_XYZ& thePnt1, @@ -832,20 +1317,20 @@ double Warping::ComputeA( const gp_XYZ& thePnt1, double aLen1 = gp_Pnt( thePnt1 ).Distance( gp_Pnt( thePnt2 ) ); double aLen2 = gp_Pnt( thePnt2 ).Distance( gp_Pnt( thePnt3 ) ); double L = Min( aLen1, aLen2 ) * 0.5; - if ( L < Precision::Confusion()) - return 0.; + if ( L < theEps ) + return theInf; gp_XYZ GI = ( thePnt2 + thePnt1 ) / 2. - theG; gp_XYZ GJ = ( thePnt3 + thePnt2 ) / 2. - theG; gp_XYZ N = GI.Crossed( GJ ); if ( N.Modulus() < gp::Resolution() ) - return PI / 2; + return M_PI / 2; N.Normalize(); double H = ( thePnt2 - theG ).Dot( N ); - return asin( fabs( H / L ) ) * 180. / PI; + return asin( fabs( H / L ) ) * 180. / M_PI; } double Warping::GetBadRate( double Value, int /*nbNodes*/ ) const @@ -862,37 +1347,44 @@ SMDSAbs_ElementType Warping::GetType() const } +//================================================================================ /* Class : Taper Description : Functor for calculating taper */ +//================================================================================ + double Taper::GetValue( const TSequenceOfXYZ& P ) { if ( P.size() != 4 ) return 0.; // Compute taper - double J1 = getArea( P( 4 ), P( 1 ), P( 2 ) ) / 2.; - double J2 = getArea( P( 3 ), P( 1 ), P( 2 ) ) / 2.; - double J3 = getArea( P( 2 ), P( 3 ), P( 4 ) ) / 2.; - double J4 = getArea( P( 3 ), P( 4 ), P( 1 ) ) / 2.; + double J1 = getArea( P( 4 ), P( 1 ), P( 2 ) ); + double J2 = getArea( P( 3 ), P( 1 ), P( 2 ) ); + double J3 = getArea( P( 2 ), P( 3 ), P( 4 ) ); + double J4 = getArea( P( 3 ), P( 4 ), P( 1 ) ); double JA = 0.25 * ( J1 + J2 + J3 + J4 ); - if ( JA <= Precision::Confusion() ) - return 0.; + if ( JA <= theEps ) + return theInf; double T1 = fabs( ( J1 - JA ) / JA ); double T2 = fabs( ( J2 - JA ) / JA ); double T3 = fabs( ( J3 - JA ) / JA ); double T4 = fabs( ( J4 - JA ) / JA ); - return Max( Max( T1, T2 ), Max( T3, T4 ) ); + double val = Max( Max( T1, T2 ), Max( T3, T4 ) ); + + const double eps = 0.01; + + return val < eps ? 0. : val; } double Taper::GetBadRate( double Value, int /*nbNodes*/ ) const { // the taper is in the range [0.0,1.0] - // 0.0 = good (no taper) + // 0.0 = good (no taper) // 1.0 = bad (les cotes opposes sont allignes) return Value; } @@ -902,11 +1394,13 @@ SMDSAbs_ElementType Taper::GetType() const return SMDSAbs_Face; } - +//================================================================================ /* Class : Skew Description : Functor for calculating skew in degrees */ +//================================================================================ + static inline double skewAngle( const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3 ) { gp_XYZ p12 = ( p2 + p1 ) / 2.; @@ -924,14 +1418,14 @@ double Skew::GetValue( const TSequenceOfXYZ& P ) return 0.; // Compute skew - static double PI2 = PI / 2.; + const double PI2 = M_PI / 2.; if ( P.size() == 3 ) { double A0 = fabs( PI2 - skewAngle( P( 3 ), P( 1 ), P( 2 ) ) ); double A1 = fabs( PI2 - skewAngle( P( 1 ), P( 2 ), P( 3 ) ) ); double A2 = fabs( PI2 - skewAngle( P( 2 ), P( 3 ), P( 1 ) ) ); - return Max( A0, Max( A1, A2 ) ) * 180. / PI; + return Max( A0, Max( A1, A2 ) ) * 180. / M_PI; } else { @@ -944,11 +1438,11 @@ double Skew::GetValue( const TSequenceOfXYZ& P ) double A = v1.Magnitude() <= gp::Resolution() || v2.Magnitude() <= gp::Resolution() ? 0. : fabs( PI2 - v1.Angle( v2 ) ); - //BUG SWP12743 - if ( A < Precision::Angular() ) - return 0.; + double val = A * 180. / M_PI; + + const double eps = 0.1; // val is in degrees - return A * 180. / PI; + return val < eps ? 0. : val; } } @@ -966,22 +1460,32 @@ SMDSAbs_ElementType Skew::GetType() const } +//================================================================================ /* Class : Area Description : Functor for calculating area */ +//================================================================================ + double Area::GetValue( const TSequenceOfXYZ& P ) { - gp_Vec aVec1( P(2) - P(1) ); - gp_Vec aVec2( P(3) - P(1) ); - gp_Vec SumVec = aVec1 ^ aVec2; - for (int i=4; i<=P.size(); i++) { - gp_Vec aVec1( P(i-1) - P(1) ); - gp_Vec aVec2( P(i) - P(1) ); - gp_Vec tmp = aVec1 ^ aVec2; - SumVec.Add(tmp); + double val = 0.0; + if ( P.size() > 2 ) + { + gp_Vec aVec1( P(2) - P(1) ); + gp_Vec aVec2( P(3) - P(1) ); + gp_Vec SumVec = aVec1 ^ aVec2; + + for (int i=4; i<=P.size(); i++) + { + gp_Vec aVec1( P(i-1) - P(1) ); + gp_Vec aVec2( P(i) - P(1) ); + gp_Vec tmp = aVec1 ^ aVec2; + SumVec.Add(tmp); + } + val = SumVec.Magnitude() * 0.5; } - return SumVec.Magnitude() * 0.5; + return val; } double Area::GetBadRate( double Value, int /*nbNodes*/ ) const @@ -995,11 +1499,13 @@ SMDSAbs_ElementType Area::GetType() const return SMDSAbs_Face; } - +//================================================================================ /* Class : Length - Description : Functor for calculating length off edge + Description : Functor for calculating length of edge */ +//================================================================================ + double Length::GetValue( const TSequenceOfXYZ& P ) { switch ( P.size() ) { @@ -1020,192 +1526,240 @@ SMDSAbs_ElementType Length::GetType() const return SMDSAbs_Edge; } +//================================================================================ /* Class : Length2D - Description : Functor for calculating length of edge + Description : Functor for calculating minimal length of edge */ +//================================================================================ -double Length2D::GetValue( long theElementId) +double Length2D::GetValue( long theElementId ) { TSequenceOfXYZ P; - //cout<<"Length2D::GetValue"<FindElement( theElementId ); - SMDSAbs_ElementType aType = aElem->GetType(); - + if ( GetPoints( theElementId, P )) + { + double aVal = 0; int len = P.size(); + SMDSAbs_EntityType aType = P.getElementEntity(); - switch (aType){ - case SMDSAbs_All: - case SMDSAbs_Node: - case SMDSAbs_Edge: - if (len == 2){ - aVal = getDistance( P( 1 ), P( 2 ) ); - break; - } - else if (len == 3){ // quadratic edge - aVal = getDistance(P( 1 ),P( 3 )) + getDistance(P( 3 ),P( 2 )); - break; - } - case SMDSAbs_Face: + switch (aType) { + case SMDSEntity_Edge: + if (len == 2) + aVal = getDistance( P( 1 ), P( 2 ) ); + break; + case SMDSEntity_Quad_Edge: + if (len == 3) // quadratic edge + aVal = getDistance(P( 1 ),P( 3 )) + getDistance(P( 3 ),P( 2 )); + break; + case SMDSEntity_Triangle: if (len == 3){ // triangles - double L1 = getDistance(P( 1 ),P( 2 )); - double L2 = getDistance(P( 2 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 1 )); - aVal = Max(L1,Max(L2,L3)); - break; + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 1 )); + aVal = Min(L1,Min(L2,L3)); } - else if (len == 4){ // quadrangles - double L1 = getDistance(P( 1 ),P( 2 )); - double L2 = getDistance(P( 2 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 4 )); - double L4 = getDistance(P( 4 ),P( 1 )); - aVal = Max(Max(L1,L2),Max(L3,L4)); - break; + break; + case SMDSEntity_Quadrangle: + if (len == 4){ // quadrangles + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 1 )); + aVal = Min(Min(L1,L2),Min(L3,L4)); } - if (len == 6){ // quadratic triangles - double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 )); - double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 )); - double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 )); - aVal = Max(L1,Max(L2,L3)); - //cout<<"L1="<FindElement( theId ); + if ( !anElem ) + return false; const SMDSAbs_ElementType anElemType = anElem->GetType(); - if ( !anElem || (myType != SMDSAbs_All && anElemType != myType) ) + if ( myType != SMDSAbs_All && anElemType != myType ) return false; - const int aNbNode = anElem->NbNodes(); - bool isOk = false; - switch( anElemType ) - { - case SMDSAbs_Node: - isOk = (myGeomType == SMDSGeom_POINT); - break; - - case SMDSAbs_Edge: - isOk = (myGeomType == SMDSGeom_EDGE); - break; - - case SMDSAbs_Face: - if ( myGeomType == SMDSGeom_TRIANGLE ) - isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 6 : aNbNode == 3)); - else if ( myGeomType == SMDSGeom_QUADRANGLE ) - isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 8 : aNbNode == 4)); - else if ( myGeomType == SMDSGeom_POLYGON ) - isOk = anElem->IsPoly(); - break; - - case SMDSAbs_Volume: - if ( myGeomType == SMDSGeom_TETRA ) - isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 10 : aNbNode == 4)); - else if ( myGeomType == SMDSGeom_PYRAMID ) - isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 13 : aNbNode == 5)); - else if ( myGeomType == SMDSGeom_PENTA ) - isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 15 : aNbNode == 6)); - else if ( myGeomType == SMDSGeom_HEXA ) - isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 20 : aNbNode == 8)); - else if ( myGeomType == SMDSGeom_POLYHEDRA ) - isOk = anElem->IsPoly(); - break; - - default: break; - } + bool isOk = ( anElem->GetGeomType() == myGeomType ); return isOk; } @@ -2009,75 +2797,337 @@ SMDSAbs_GeometryType ElemGeomType::GetGeomType() const return myGeomType; } +//================================================================================ /* - Class : RangeOfIds - Description : Predicate for Range of Ids. - Range may be specified with two ways. - 1. Using AddToRange method - 2. With SetRangeStr method. Parameter of this method is a string - like as "1,2,3,50-60,63,67,70-" + Class : ElemEntityType + Description : Predicate to check element entity type */ +//================================================================================ -//======================================================================= -// name : RangeOfIds -// Purpose : Constructor -//======================================================================= -RangeOfIds::RangeOfIds() +ElemEntityType::ElemEntityType(): + myMesh( 0 ), + myType( SMDSAbs_All ), + myEntityType( SMDSEntity_0D ) { - myMesh = 0; - myType = SMDSAbs_All; } -//======================================================================= -// name : SetMesh -// Purpose : Set mesh -//======================================================================= -void RangeOfIds::SetMesh( const SMDS_Mesh* theMesh ) +void ElemEntityType::SetMesh( const SMDS_Mesh* theMesh ) { myMesh = theMesh; } -//======================================================================= -// name : AddToRange -// Purpose : Add ID to the range -//======================================================================= -bool RangeOfIds::AddToRange( long theEntityId ) +bool ElemEntityType::IsSatisfy( long theId ) { - myIds.Add( theEntityId ); - return true; + if ( !myMesh ) return false; + if ( myType == SMDSAbs_Node ) + return myMesh->FindNode( theId ); + const SMDS_MeshElement* anElem = myMesh->FindElement( theId ); + return ( anElem && + myEntityType == anElem->GetEntityType() ); } -//======================================================================= -// name : GetRangeStr -// Purpose : Get range as a string. -// Example: "1,2,3,50-60,63,67,70-" -//======================================================================= -void RangeOfIds::GetRangeStr( TCollection_AsciiString& theResStr ) +void ElemEntityType::SetType( SMDSAbs_ElementType theType ) { - theResStr.Clear(); + myType = theType; +} - TColStd_SequenceOfInteger anIntSeq; - TColStd_SequenceOfAsciiString aStrSeq; +SMDSAbs_ElementType ElemEntityType::GetType() const +{ + return myType; +} - TColStd_MapIteratorOfMapOfInteger anIter( myIds ); - for ( ; anIter.More(); anIter.Next() ) +void ElemEntityType::SetElemEntityType( SMDSAbs_EntityType theEntityType ) +{ + myEntityType = theEntityType; +} + +SMDSAbs_EntityType ElemEntityType::GetElemEntityType() const +{ + return myEntityType; +} + +//================================================================================ +/*! + * \brief Class ConnectedElements + */ +//================================================================================ + +ConnectedElements::ConnectedElements(): + myNodeID(0), myType( SMDSAbs_All ), myOkIDsReady( false ) {} + +SMDSAbs_ElementType ConnectedElements::GetType() const +{ return myType; } + +int ConnectedElements::GetNode() const +{ return myXYZ.empty() ? myNodeID : 0; } // myNodeID can be found by myXYZ + +std::vector ConnectedElements::GetPoint() const +{ return myXYZ; } + +void ConnectedElements::clearOkIDs() +{ myOkIDsReady = false; myOkIDs.clear(); } + +void ConnectedElements::SetType( SMDSAbs_ElementType theType ) +{ + if ( myType != theType || myMeshModifTracer.IsMeshModified() ) + clearOkIDs(); + myType = theType; +} + +void ConnectedElements::SetMesh( const SMDS_Mesh* theMesh ) +{ + myMeshModifTracer.SetMesh( theMesh ); + if ( myMeshModifTracer.IsMeshModified() ) { - int anId = anIter.Key(); - TCollection_AsciiString aStr( anId ); - anIntSeq.Append( anId ); - aStrSeq.Append( aStr ); + clearOkIDs(); + if ( !myXYZ.empty() ) + SetPoint( myXYZ[0], myXYZ[1], myXYZ[2] ); // find a node near myXYZ it in a new mesh } +} - for ( int i = 1, n = myMin.Length(); i <= n; i++ ) - { - int aMinId = myMin( i ); - int aMaxId = myMax( i ); +void ConnectedElements::SetNode( int nodeID ) +{ + myNodeID = nodeID; + myXYZ.clear(); - TCollection_AsciiString aStr; - if ( aMinId != IntegerFirst() ) - aStr += aMinId; + bool isSameDomain = false; + if ( myOkIDsReady && myMeshModifTracer.GetMesh() && !myMeshModifTracer.IsMeshModified() ) + if ( const SMDS_MeshNode* n = myMeshModifTracer.GetMesh()->FindNode( myNodeID )) + { + SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator( myType ); + while ( !isSameDomain && eIt->more() ) + isSameDomain = IsSatisfy( eIt->next()->GetID() ); + } + if ( !isSameDomain ) + clearOkIDs(); +} - aStr += "-"; +void ConnectedElements::SetPoint( double x, double y, double z ) +{ + myXYZ.resize(3); + myXYZ[0] = x; + myXYZ[1] = y; + myXYZ[2] = z; + myNodeID = 0; + + bool isSameDomain = false; + + // find myNodeID by myXYZ if possible + if ( myMeshModifTracer.GetMesh() ) + { + auto_ptr searcher + ( SMESH_MeshAlgos::GetElementSearcher( (SMDS_Mesh&) *myMeshModifTracer.GetMesh() )); + + vector< const SMDS_MeshElement* > foundElems; + searcher->FindElementsByPoint( gp_Pnt(x,y,z), SMDSAbs_All, foundElems ); + + if ( !foundElems.empty() ) + { + myNodeID = foundElems[0]->GetNode(0)->GetID(); + if ( myOkIDsReady && !myMeshModifTracer.IsMeshModified() ) + isSameDomain = IsSatisfy( foundElems[0]->GetID() ); + } + } + if ( !isSameDomain ) + clearOkIDs(); +} + +bool ConnectedElements::IsSatisfy( long theElementId ) +{ + // Here we do NOT check if the mesh has changed, we do it in Set...() only!!! + + if ( !myOkIDsReady ) + { + if ( !myMeshModifTracer.GetMesh() ) + return false; + const SMDS_MeshNode* node0 = myMeshModifTracer.GetMesh()->FindNode( myNodeID ); + if ( !node0 ) + return false; + + list< const SMDS_MeshNode* > nodeQueue( 1, node0 ); + std::set< int > checkedNodeIDs; + // algo: + // foreach node in nodeQueue: + // foreach element sharing a node: + // add ID of an element of myType to myOkIDs; + // push all element nodes absent from checkedNodeIDs to nodeQueue; + while ( !nodeQueue.empty() ) + { + const SMDS_MeshNode* node = nodeQueue.front(); + nodeQueue.pop_front(); + + // loop on elements sharing the node + SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(); + while ( eIt->more() ) + { + // keep elements of myType + const SMDS_MeshElement* element = eIt->next(); + if ( element->GetType() == myType ) + myOkIDs.insert( myOkIDs.end(), element->GetID() ); + + // enqueue nodes of the element + SMDS_ElemIteratorPtr nIt = element->nodesIterator(); + while ( nIt->more() ) + { + const SMDS_MeshNode* n = static_cast< const SMDS_MeshNode* >( nIt->next() ); + if ( checkedNodeIDs.insert( n->GetID() ).second ) + nodeQueue.push_back( n ); + } + } + } + if ( myType == SMDSAbs_Node ) + std::swap( myOkIDs, checkedNodeIDs ); + + size_t totalNbElems = myMeshModifTracer.GetMesh()->GetMeshInfo().NbElements( myType ); + if ( myOkIDs.size() == totalNbElems ) + myOkIDs.clear(); + + myOkIDsReady = true; + } + + return myOkIDs.empty() ? true : myOkIDs.count( theElementId ); +} + +//================================================================================ +/*! + * \brief Class CoplanarFaces + */ +//================================================================================ + +CoplanarFaces::CoplanarFaces() + : myFaceID(0), myToler(0) +{ +} +void CoplanarFaces::SetMesh( const SMDS_Mesh* theMesh ) +{ + myMeshModifTracer.SetMesh( theMesh ); + if ( myMeshModifTracer.IsMeshModified() ) + { + // Build a set of coplanar face ids + + myCoplanarIDs.clear(); + + if ( !myMeshModifTracer.GetMesh() || !myFaceID || !myToler ) + return; + + const SMDS_MeshElement* face = myMeshModifTracer.GetMesh()->FindElement( myFaceID ); + if ( !face || face->GetType() != SMDSAbs_Face ) + return; + + bool normOK; + gp_Vec myNorm = getNormale( static_cast(face), &normOK ); + if (!normOK) + return; + + const double radianTol = myToler * M_PI / 180.; + std::set< SMESH_TLink > checkedLinks; + + std::list< pair< const SMDS_MeshElement*, gp_Vec > > faceQueue; + faceQueue.push_back( make_pair( face, myNorm )); + while ( !faceQueue.empty() ) + { + face = faceQueue.front().first; + myNorm = faceQueue.front().second; + faceQueue.pop_front(); + + for ( int i = 0, nbN = face->NbCornerNodes(); i < nbN; ++i ) + { + const SMDS_MeshNode* n1 = face->GetNode( i ); + const SMDS_MeshNode* n2 = face->GetNode(( i+1 )%nbN); + if ( !checkedLinks.insert( SMESH_TLink( n1, n2 )).second ) + continue; + SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + if ( f->GetNodeIndex( n2 ) > -1 ) + { + gp_Vec norm = getNormale( static_cast(f), &normOK ); + if (!normOK || myNorm.Angle( norm ) <= radianTol) + { + myCoplanarIDs.insert( f->GetID() ); + faceQueue.push_back( make_pair( f, norm )); + } + } + } + } + } + } +} +bool CoplanarFaces::IsSatisfy( long theElementId ) +{ + return myCoplanarIDs.count( theElementId ); +} + +/* + *Class : RangeOfIds + *Description : Predicate for Range of Ids. + * Range may be specified with two ways. + * 1. Using AddToRange method + * 2. With SetRangeStr method. Parameter of this method is a string + * like as "1,2,3,50-60,63,67,70-" +*/ + +//======================================================================= +// name : RangeOfIds +// Purpose : Constructor +//======================================================================= +RangeOfIds::RangeOfIds() +{ + myMesh = 0; + myType = SMDSAbs_All; +} + +//======================================================================= +// name : SetMesh +// Purpose : Set mesh +//======================================================================= +void RangeOfIds::SetMesh( const SMDS_Mesh* theMesh ) +{ + myMesh = theMesh; +} + +//======================================================================= +// name : AddToRange +// Purpose : Add ID to the range +//======================================================================= +bool RangeOfIds::AddToRange( long theEntityId ) +{ + myIds.Add( theEntityId ); + return true; +} + +//======================================================================= +// name : GetRangeStr +// Purpose : Get range as a string. +// Example: "1,2,3,50-60,63,67,70-" +//======================================================================= +void RangeOfIds::GetRangeStr( TCollection_AsciiString& theResStr ) +{ + theResStr.Clear(); + + TColStd_SequenceOfInteger anIntSeq; + TColStd_SequenceOfAsciiString aStrSeq; + + TColStd_MapIteratorOfMapOfInteger anIter( myIds ); + for ( ; anIter.More(); anIter.Next() ) + { + int anId = anIter.Key(); + TCollection_AsciiString aStr( anId ); + anIntSeq.Append( anId ); + aStrSeq.Append( aStr ); + } + + for ( int i = 1, n = myMin.Length(); i <= n; i++ ) + { + int aMinId = myMin( i ); + int aMaxId = myMax( i ); + + TCollection_AsciiString aStr; + if ( aMinId != IntegerFirst() ) + aStr += aMinId; + + aStr += "-"; if ( aMaxId != IntegerLast() ) aStr += aMaxId; @@ -2134,11 +3184,14 @@ bool RangeOfIds::SetRangeStr( const TCollection_AsciiString& theStr ) myIds.Clear(); TCollection_AsciiString aStr = theStr; - aStr.RemoveAll( ' ' ); - aStr.RemoveAll( '\t' ); + //aStr.RemoveAll( ' ' ); + //aStr.RemoveAll( '\t' ); + for ( int i = 1; i <= aStr.Length(); ++i ) + if ( isspace( aStr.Value( i ))) + aStr.SetValue( i, ','); for ( int aPos = aStr.Search( ",," ); aPos != -1; aPos = aStr.Search( ",," ) ) - aStr.Remove( aPos, 2 ); + aStr.Remove( aPos, 1 ); TCollection_AsciiString tmpStr = aStr.Token( ",", 1 ); int i = 1; @@ -2209,7 +3262,7 @@ bool RangeOfIds::IsSatisfy( long theId ) else { const SMDS_MeshElement* anElem = myMesh->FindElement( theId ); - if ( anElem == 0 || (myType != anElem->GetType() && myType != SMDSAbs_All) ) + if ( anElem == 0 || (myType != anElem->GetType() && myType != SMDSAbs_All )) return false; } @@ -2267,7 +3320,7 @@ double Comparator::GetMargin() */ bool LessThan::IsSatisfy( long theId ) { - return (myFunctor!=NULL) && myFunctor->GetValue( theId ) < myMargin; + return myFunctor && myFunctor->GetValue( theId ) < myMargin; } @@ -2277,7 +3330,7 @@ bool LessThan::IsSatisfy( long theId ) */ bool MoreThan::IsSatisfy( long theId ) { - return (myFunctor!=NULL) && myFunctor->GetValue( theId ) > myMargin; + return myFunctor && myFunctor->GetValue( theId ) > myMargin; } @@ -2291,7 +3344,7 @@ EqualTo::EqualTo(): bool EqualTo::IsSatisfy( long theId ) { - return (myFunctor!=NULL) && fabs( myFunctor->GetValue( theId ) - myMargin ) < myToler; + return myFunctor && fabs( myFunctor->GetValue( theId ) - myMargin ) < myToler; } void EqualTo::SetTolerance( double theToler ) @@ -2316,7 +3369,7 @@ LogicalNOT::~LogicalNOT() bool LogicalNOT::IsSatisfy( long theId ) { - return (myPredicate!=NULL) && !myPredicate->IsSatisfy( theId ); + return myPredicate && !myPredicate->IsSatisfy( theId ); } void LogicalNOT::SetMesh( const SMDS_Mesh* theMesh ) @@ -2384,8 +3437,8 @@ SMDSAbs_ElementType LogicalBinary::GetType() const bool LogicalAND::IsSatisfy( long theId ) { return - (myPredicate1!=NULL) && - (myPredicate2!=NULL) && + myPredicate1 && + myPredicate2 && myPredicate1->IsSatisfy( theId ) && myPredicate2->IsSatisfy( theId ); } @@ -2398,11 +3451,10 @@ bool LogicalAND::IsSatisfy( long theId ) bool LogicalOR::IsSatisfy( long theId ) { return - (myPredicate1!=NULL) && - (myPredicate2!=NULL) && ( - myPredicate1->IsSatisfy( theId ) || - myPredicate2->IsSatisfy( theId ) - ); + myPredicate1 && + myPredicate2 && + (myPredicate1->IsSatisfy( theId ) || + myPredicate2->IsSatisfy( theId )); } @@ -2410,6 +3462,31 @@ bool LogicalOR::IsSatisfy( long theId ) FILTER */ +// #ifdef WITH_TBB +// #include +// #include + +// namespace Parallel +// { +// typedef tbb::enumerable_thread_specific< TIdSequence > TIdSeq; + +// struct Predicate +// { +// const SMDS_Mesh* myMesh; +// PredicatePtr myPredicate; +// TIdSeq & myOKIds; +// Predicate( const SMDS_Mesh* m, PredicatePtr p, TIdSeq & ids ): +// myMesh(m), myPredicate(p->Duplicate()), myOKIds(ids) {} +// void operator() ( const tbb::blocked_range& r ) const +// { +// for ( size_t i = r.begin(); i != r.end(); ++i ) +// if ( myPredicate->IsSatisfy( i )) +// myOKIds.local().push_back(); +// } +// } +// } +// #endif + Filter::Filter() {} @@ -2421,26 +3498,9 @@ void Filter::SetPredicate( PredicatePtr thePredicate ) myPredicate = thePredicate; } -template -inline void FillSequence(const TIterator& theIterator, - TPredicate& thePredicate, - Filter::TIdSequence& theSequence) -{ - if ( theIterator ) { - while( theIterator->more() ) { - TElement anElem = theIterator->next(); - long anId = anElem->GetID(); - if ( thePredicate->IsSatisfy( anId ) ) - theSequence.push_back( anId ); - } - } -} - -void -Filter:: -GetElementsId( const SMDS_Mesh* theMesh, - PredicatePtr thePredicate, - TIdSequence& theSequence ) +void Filter::GetElementsId( const SMDS_Mesh* theMesh, + PredicatePtr thePredicate, + TIdSequence& theSequence ) { theSequence.clear(); @@ -2449,31 +3509,19 @@ GetElementsId( const SMDS_Mesh* theMesh, thePredicate->SetMesh( theMesh ); - SMDSAbs_ElementType aType = thePredicate->GetType(); - switch(aType){ - case SMDSAbs_Node: - FillSequence(theMesh->nodesIterator(),thePredicate,theSequence); - break; - case SMDSAbs_Edge: - FillSequence(theMesh->edgesIterator(),thePredicate,theSequence); - break; - case SMDSAbs_Face: - FillSequence(theMesh->facesIterator(),thePredicate,theSequence); - break; - case SMDSAbs_Volume: - FillSequence(theMesh->volumesIterator(),thePredicate,theSequence); - break; - case SMDSAbs_All: - FillSequence(theMesh->edgesIterator(),thePredicate,theSequence); - FillSequence(theMesh->facesIterator(),thePredicate,theSequence); - FillSequence(theMesh->volumesIterator(),thePredicate,theSequence); - break; + SMDS_ElemIteratorPtr elemIt = theMesh->elementsIterator( thePredicate->GetType() ); + if ( elemIt ) { + while ( elemIt->more() ) { + const SMDS_MeshElement* anElem = elemIt->next(); + long anId = anElem->GetID(); + if ( thePredicate->IsSatisfy( anId ) ) + theSequence.push_back( anId ); + } } } -void -Filter::GetElementsId( const SMDS_Mesh* theMesh, - Filter::TIdSequence& theSequence ) +void Filter::GetElementsId( const SMDS_Mesh* theMesh, + Filter::TIdSequence& theSequence ) { GetElementsId(theMesh,myPredicate,theSequence); } @@ -2646,32 +3694,6 @@ static void getLinks( const SMDS_MeshFace* theFace, } } -static gp_XYZ getNormale( const SMDS_MeshFace* theFace ) -{ - gp_XYZ n; - int aNbNode = theFace->NbNodes(); - TColgp_Array1OfXYZ anArrOfXYZ(1,4); - SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator(); - int i = 1; - for ( ; aNodeItr->more() && i <= 4; i++ ) { - SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next(); - anArrOfXYZ.SetValue(i, gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) ); - } - - gp_XYZ q1 = anArrOfXYZ.Value(2) - anArrOfXYZ.Value(1); - gp_XYZ q2 = anArrOfXYZ.Value(3) - anArrOfXYZ.Value(1); - n = q1 ^ q2; - if ( aNbNode > 3 ) { - gp_XYZ q3 = anArrOfXYZ.Value(4) - anArrOfXYZ.Value(1); - n += q2 ^ q3; - } - double len = n.Modulus(); - if ( len > 0 ) - n /= len; - - return n; -} - bool ManifoldPart::findConnected ( const ManifoldPart::TDataMapFacePtrInt& theAllFacePtrInt, SMDS_MeshFace* theStartFace, @@ -2826,7 +3848,7 @@ void ManifoldPart::expandBoundary void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink, ManifoldPart::TVectorOfFacePtr& theFaces ) const { - SMDS_Mesh::SetOfFaces aSetOfFaces; + std::set aSetOfFaces; // take all faces that shared first node SMDS_ElemIteratorPtr anItr = theLink.myNode1->facesIterator(); for ( ; anItr->more(); ) @@ -2834,7 +3856,7 @@ void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink, SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next(); if ( !aFace ) continue; - aSetOfFaces.Add( aFace ); + aSetOfFaces.insert( aFace ); } // take all faces that shared second node anItr = theLink.myNode2->facesIterator(); @@ -2842,19 +3864,68 @@ void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink, for ( ; anItr->more(); ) { SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next(); - if ( aSetOfFaces.Contains( aFace ) ) + if ( aSetOfFaces.count( aFace ) ) theFaces.push_back( aFace ); } } +/* + Class : BelongToMeshGroup + Description : Verify whether a mesh element is included into a mesh group +*/ +BelongToMeshGroup::BelongToMeshGroup(): myGroup( 0 ) +{ +} + +void BelongToMeshGroup::SetGroup( SMESHDS_GroupBase* g ) +{ + myGroup = g; +} + +void BelongToMeshGroup::SetStoreName( const std::string& sn ) +{ + myStoreName = sn; +} + +void BelongToMeshGroup::SetMesh( const SMDS_Mesh* theMesh ) +{ + if ( myGroup && myGroup->GetMesh() != theMesh ) + { + myGroup = 0; + } + if ( !myGroup && !myStoreName.empty() ) + { + if ( const SMESHDS_Mesh* aMesh = dynamic_cast(theMesh)) + { + const std::set& grps = aMesh->GetGroups(); + std::set::const_iterator g = grps.begin(); + for ( ; g != grps.end() && !myGroup; ++g ) + if ( *g && myStoreName == (*g)->GetStoreName() ) + myGroup = *g; + } + } + if ( myGroup ) + { + myGroup->IsEmpty(); // make GroupOnFilter update its predicate + } +} + +bool BelongToMeshGroup::IsSatisfy( long theElementId ) +{ + return myGroup ? myGroup->Contains( theElementId ) : false; +} + +SMDSAbs_ElementType BelongToMeshGroup::GetType() const +{ + return myGroup ? myGroup->GetType() : SMDSAbs_All; +} /* - ElementsOnSurface + ElementsOnSurface */ ElementsOnSurface::ElementsOnSurface() { - myMesh = 0; myIds.Clear(); myType = SMDSAbs_All; mySurf.Nullify(); @@ -2864,15 +3935,13 @@ ElementsOnSurface::ElementsOnSurface() ElementsOnSurface::~ElementsOnSurface() { - myMesh = 0; } void ElementsOnSurface::SetMesh( const SMDS_Mesh* theMesh ) { - if ( myMesh == theMesh ) - return; - myMesh = theMesh; - process(); + myMeshModifTracer.SetMesh( theMesh ); + if ( myMeshModifTracer.IsMeshModified()) + process(); } bool ElementsOnSurface::IsSatisfy( long theElementId ) @@ -2927,32 +3996,14 @@ void ElementsOnSurface::process() if ( mySurf.IsNull() ) return; - if ( myMesh == 0 ) + if ( !myMeshModifTracer.GetMesh() ) return; - if ( myType == SMDSAbs_Face || myType == SMDSAbs_All ) - { - myIds.ReSize( myMesh->NbFaces() ); - SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); - for(; anIter->more(); ) - process( anIter->next() ); - } - - if ( myType == SMDSAbs_Edge || myType == SMDSAbs_All ) - { - myIds.ReSize( myIds.Extent() + myMesh->NbEdges() ); - SMDS_EdgeIteratorPtr anIter = myMesh->edgesIterator(); - for(; anIter->more(); ) - process( anIter->next() ); - } + myIds.ReSize( myMeshModifTracer.GetMesh()->GetMeshInfo().NbElements( myType )); - if ( myType == SMDSAbs_Node ) - { - myIds.ReSize( myMesh->NbNodes() ); - SMDS_NodeIteratorPtr anIter = myMesh->nodesIterator(); - for(; anIter->more(); ) - process( anIter->next() ); - } + SMDS_ElemIteratorPtr anIter = myMeshModifTracer.GetMesh()->elementsIterator( myType ); + for(; anIter->more(); ) + process( anIter->next() ); } void ElementsOnSurface::process( const SMDS_MeshElement* theElemPtr ) @@ -3010,29 +4061,16 @@ bool ElementsOnSurface::isOnSurface( const SMDS_MeshNode* theNode ) */ ElementsOnShape::ElementsOnShape() - : myMesh(0), + : //myMesh(0), myType(SMDSAbs_All), myToler(Precision::Confusion()), myAllNodesFlag(false) { - myCurShapeType = TopAbs_SHAPE; } ElementsOnShape::~ElementsOnShape() { -} - -void ElementsOnShape::SetMesh (const SMDS_Mesh* theMesh) -{ - if (myMesh != theMesh) { - myMesh = theMesh; - SetShape(myShape, myType); - } -} - -bool ElementsOnShape::IsSatisfy (long theElementId) -{ - return myIds.Contains(theElementId); + clearClassifiers(); } SMDSAbs_ElementType ElementsOnShape::GetType() const @@ -3055,241 +4093,673 @@ double ElementsOnShape::GetTolerance() const void ElementsOnShape::SetAllNodes (bool theAllNodes) { - if (myAllNodesFlag != theAllNodes) { - myAllNodesFlag = theAllNodes; - SetShape(myShape, myType); + myAllNodesFlag = theAllNodes; +} + +void ElementsOnShape::SetMesh (const SMDS_Mesh* theMesh) +{ + myMeshModifTracer.SetMesh( theMesh ); + if ( myMeshModifTracer.IsMeshModified()) + { + size_t nbNodes = theMesh ? theMesh->NbNodes() : 0; + if ( myNodeIsChecked.size() == nbNodes ) + { + std::fill( myNodeIsChecked.begin(), myNodeIsChecked.end(), false ); + } + else + { + SMESHUtils::FreeVector( myNodeIsChecked ); + SMESHUtils::FreeVector( myNodeIsOut ); + myNodeIsChecked.resize( nbNodes, false ); + myNodeIsOut.resize( nbNodes ); + } + } +} + +bool ElementsOnShape::getNodeIsOut( const SMDS_MeshNode* n, bool& isOut ) +{ + if ( n->GetID() >= (int) myNodeIsChecked.size() || + !myNodeIsChecked[ n->GetID() ]) + return false; + + isOut = myNodeIsOut[ n->GetID() ]; + return true; +} + +void ElementsOnShape::setNodeIsOut( const SMDS_MeshNode* n, bool isOut ) +{ + if ( n->GetID() < (int) myNodeIsChecked.size() ) + { + myNodeIsChecked[ n->GetID() ] = true; + myNodeIsOut [ n->GetID() ] = isOut; } } void ElementsOnShape::SetShape (const TopoDS_Shape& theShape, const SMDSAbs_ElementType theType) { - myType = theType; + myType = theType; myShape = theShape; - myIds.Clear(); + if ( myShape.IsNull() ) return; - if (myMesh == 0) return; + TopTools_IndexedMapOfShape shapesMap; + TopAbs_ShapeEnum shapeTypes[4] = { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX }; + TopExp_Explorer sub; + for ( int i = 0; i < 4; ++i ) + { + if ( shapesMap.IsEmpty() ) + for ( sub.Init( myShape, shapeTypes[i] ); sub.More(); sub.Next() ) + shapesMap.Add( sub.Current() ); + if ( i > 0 ) + for ( sub.Init( myShape, shapeTypes[i], shapeTypes[i-1] ); sub.More(); sub.Next() ) + shapesMap.Add( sub.Current() ); + } - switch (myType) + clearClassifiers(); + myClassifiers.resize( shapesMap.Extent() ); + for ( int i = 0; i < shapesMap.Extent(); ++i ) + myClassifiers[ i ] = new TClassifier( shapesMap( i+1 ), myToler ); + + if ( theType == SMDSAbs_Node ) { - case SMDSAbs_All: - myIds.ReSize(myMesh->NbEdges() + myMesh->NbFaces() + myMesh->NbVolumes()); - break; - case SMDSAbs_Node: - myIds.ReSize(myMesh->NbNodes()); - break; - case SMDSAbs_Edge: - myIds.ReSize(myMesh->NbEdges()); - break; - case SMDSAbs_Face: - myIds.ReSize(myMesh->NbFaces()); - break; - case SMDSAbs_Volume: - myIds.ReSize(myMesh->NbVolumes()); - break; - default: - break; + SMESHUtils::FreeVector( myNodeIsChecked ); + SMESHUtils::FreeVector( myNodeIsOut ); } + else + { + std::fill( myNodeIsChecked.begin(), myNodeIsChecked.end(), false ); + } +} - myShapesMap.Clear(); - addShape(myShape); +void ElementsOnShape::clearClassifiers() +{ + for ( size_t i = 0; i < myClassifiers.size(); ++i ) + delete myClassifiers[ i ]; + myClassifiers.clear(); } -void ElementsOnShape::addShape (const TopoDS_Shape& theShape) +bool ElementsOnShape::IsSatisfy (long elemId) { - if (theShape.IsNull() || myMesh == 0) - return; + const SMDS_Mesh* mesh = myMeshModifTracer.GetMesh(); + const SMDS_MeshElement* elem = + ( myType == SMDSAbs_Node ? mesh->FindNode( elemId ) : mesh->FindElement( elemId )); + if ( !elem || myClassifiers.empty() ) + return false; - if (!myShapesMap.Add(theShape)) return; + bool isSatisfy = myAllNodesFlag, isNodeOut; - myCurShapeType = theShape.ShapeType(); - switch (myCurShapeType) + gp_XYZ centerXYZ (0, 0, 0); + + SMDS_ElemIteratorPtr aNodeItr = elem->nodesIterator(); + while (aNodeItr->more() && (isSatisfy == myAllNodesFlag)) { - case TopAbs_COMPOUND: - case TopAbs_COMPSOLID: - case TopAbs_SHELL: - case TopAbs_WIRE: + SMESH_TNodeXYZ aPnt( aNodeItr->next() ); + centerXYZ += aPnt; + + isNodeOut = true; + if ( !getNodeIsOut( aPnt._node, isNodeOut )) { - TopoDS_Iterator anIt (theShape, Standard_True, Standard_True); - for (; anIt.More(); anIt.Next()) addShape(anIt.Value()); + for ( size_t i = 0; i < myClassifiers.size() && isNodeOut; ++i ) + isNodeOut = myClassifiers[i]->IsOut( aPnt ); + + setNodeIsOut( aPnt._node, isNodeOut ); } - break; - case TopAbs_SOLID: + isSatisfy = !isNodeOut; + } + + // Check the center point for volumes MantisBug 0020168 + if (isSatisfy && + myAllNodesFlag && + myClassifiers[0]->ShapeType() == TopAbs_SOLID) + { + centerXYZ /= elem->NbNodes(); + isSatisfy = false; + for ( size_t i = 0; i < myClassifiers.size() && !isSatisfy; ++i ) + isSatisfy = ! myClassifiers[i]->IsOut( centerXYZ ); + } + + return isSatisfy; +} + +TopAbs_ShapeEnum ElementsOnShape::TClassifier::ShapeType() const +{ + return myShape.ShapeType(); +} + +bool ElementsOnShape::TClassifier::IsOut(const gp_Pnt& p) +{ + return (this->*myIsOutFun)( p ); +} + +void ElementsOnShape::TClassifier::Init (const TopoDS_Shape& theShape, double theTol) +{ + myShape = theShape; + myTol = theTol; + switch ( myShape.ShapeType() ) + { + case TopAbs_SOLID: { + if ( isBox( theShape )) { - myCurSC.Load(theShape); - process(); - } - break; - case TopAbs_FACE: - { - TopoDS_Face aFace = TopoDS::Face(theShape); - BRepAdaptor_Surface SA (aFace, true); - Standard_Real - u1 = SA.FirstUParameter(), - u2 = SA.LastUParameter(), - v1 = SA.FirstVParameter(), - v2 = SA.LastVParameter(); - Handle(Geom_Surface) surf = BRep_Tool::Surface(aFace); - myCurProjFace.Init(surf, u1,u2, v1,v2); - myCurFace = aFace; - process(); + myIsOutFun = & ElementsOnShape::TClassifier::isOutOfBox; } - break; - case TopAbs_EDGE: + else { - TopoDS_Edge anEdge = TopoDS::Edge(theShape); - Standard_Real u1, u2; - Handle(Geom_Curve) curve = BRep_Tool::Curve(anEdge, u1, u2); - myCurProjEdge.Init(curve, u1, u2); - process(); + mySolidClfr.Load(theShape); + myIsOutFun = & ElementsOnShape::TClassifier::isOutOfSolid; } break; - case TopAbs_VERTEX: - { - TopoDS_Vertex aV = TopoDS::Vertex(theShape); - myCurPnt = BRep_Tool::Pnt(aV); - process(); - } + } + case TopAbs_FACE: { + Standard_Real u1,u2,v1,v2; + Handle(Geom_Surface) surf = BRep_Tool::Surface( TopoDS::Face( theShape )); + surf->Bounds( u1,u2,v1,v2 ); + myProjFace.Init(surf, u1,u2, v1,v2, myTol ); + myIsOutFun = & ElementsOnShape::TClassifier::isOutOfFace; break; - default: + } + case TopAbs_EDGE: { + Standard_Real u1, u2; + Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge(theShape), u1, u2); + myProjEdge.Init(curve, u1, u2); + myIsOutFun = & ElementsOnShape::TClassifier::isOutOfEdge; + break; + } + case TopAbs_VERTEX:{ + myVertexXYZ = BRep_Tool::Pnt( TopoDS::Vertex( theShape ) ); + myIsOutFun = & ElementsOnShape::TClassifier::isOutOfVertex; break; } + default: + throw SALOME_Exception("Programmer error in usage of ElementsOnShape::TClassifier"); + } } -void ElementsOnShape::process() +bool ElementsOnShape::TClassifier::isOutOfSolid (const gp_Pnt& p) { - if (myShape.IsNull() || myMesh == 0) - return; + mySolidClfr.Perform( p, myTol ); + return ( mySolidClfr.State() != TopAbs_IN && mySolidClfr.State() != TopAbs_ON ); +} - if (myType == SMDSAbs_Node) +bool ElementsOnShape::TClassifier::isOutOfBox (const gp_Pnt& p) +{ + return myBox.IsOut( p.XYZ() ); +} + +bool ElementsOnShape::TClassifier::isOutOfFace (const gp_Pnt& p) +{ + myProjFace.Perform( p ); + if ( myProjFace.IsDone() && myProjFace.LowerDistance() <= myTol ) { - SMDS_NodeIteratorPtr anIter = myMesh->nodesIterator(); - while (anIter->more()) - process(anIter->next()); + // check relatively to the face + Quantity_Parameter u, v; + myProjFace.LowerDistanceParameters(u, v); + gp_Pnt2d aProjPnt (u, v); + BRepClass_FaceClassifier aClsf ( TopoDS::Face( myShape ), aProjPnt, myTol ); + if ( aClsf.State() == TopAbs_IN || aClsf.State() == TopAbs_ON ) + return false; } - else + return true; +} + +bool ElementsOnShape::TClassifier::isOutOfEdge (const gp_Pnt& p) +{ + myProjEdge.Perform( p ); + return ! ( myProjEdge.NbPoints() > 0 && myProjEdge.LowerDistance() <= myTol ); +} + +bool ElementsOnShape::TClassifier::isOutOfVertex(const gp_Pnt& p) +{ + return ( myVertexXYZ.Distance( p ) > myTol ); +} + +bool ElementsOnShape::TClassifier::isBox (const TopoDS_Shape& theShape) +{ + TopTools_IndexedMapOfShape vMap; + TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap ); + if ( vMap.Extent() != 8 ) + return false; + + myBox.Clear(); + for ( int i = 1; i <= 8; ++i ) + myBox.Add( BRep_Tool::Pnt( TopoDS::Vertex( vMap( i ))).XYZ() ); + + gp_XYZ pMin = myBox.CornerMin(), pMax = myBox.CornerMax(); + for ( int i = 1; i <= 8; ++i ) { - if (myType == SMDSAbs_Edge || myType == SMDSAbs_All) + gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( vMap( i ))); + for ( int iC = 1; iC <= 3; ++ iC ) { - SMDS_EdgeIteratorPtr anIter = myMesh->edgesIterator(); - while (anIter->more()) - process(anIter->next()); + double d1 = Abs( pMin.Coord( iC ) - p.Coord( iC )); + double d2 = Abs( pMax.Coord( iC ) - p.Coord( iC )); + if ( Min( d1, d2 ) > myTol ) + return false; } + } + myBox.Enlarge( myTol ); + return true; +} + + +/* + Class : BelongToGeom + Description : Predicate for verifying whether entity belongs to + specified geometrical support +*/ + +BelongToGeom::BelongToGeom() + : myMeshDS(NULL), + myType(SMDSAbs_All), + myIsSubshape(false), + myTolerance(Precision::Confusion()) +{} + +void BelongToGeom::SetMesh( const SMDS_Mesh* theMesh ) +{ + myMeshDS = dynamic_cast(theMesh); + init(); +} - if (myType == SMDSAbs_Face || myType == SMDSAbs_All) +void BelongToGeom::SetGeom( const TopoDS_Shape& theShape ) +{ + myShape = theShape; + init(); +} + +static bool IsSubShape (const TopTools_IndexedMapOfShape& theMap, + const TopoDS_Shape& theShape) +{ + if (theMap.Contains(theShape)) return true; + + if (theShape.ShapeType() == TopAbs_COMPOUND || + theShape.ShapeType() == TopAbs_COMPSOLID) + { + TopoDS_Iterator anIt (theShape, Standard_True, Standard_True); + for (; anIt.More(); anIt.Next()) { - SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); - while (anIter->more()) { - process(anIter->next()); + if (!IsSubShape(theMap, anIt.Value())) { + return false; } } + return true; + } - if (myType == SMDSAbs_Volume || myType == SMDSAbs_All) - { - SMDS_VolumeIteratorPtr anIter = myMesh->volumesIterator(); - while (anIter->more()) - process(anIter->next()); - } + return false; +} + +void BelongToGeom::init() +{ + if (!myMeshDS || myShape.IsNull()) return; + + // is sub-shape of main shape? + TopoDS_Shape aMainShape = myMeshDS->ShapeToMesh(); + if (aMainShape.IsNull()) { + myIsSubshape = false; + } + else { + TopTools_IndexedMapOfShape aMap; + TopExp::MapShapes(aMainShape, aMap); + myIsSubshape = IsSubShape(aMap, myShape); + } + + //if (!myIsSubshape) // to be always ready to check an element not bound to geometry + { + myElementsOnShapePtr.reset(new ElementsOnShape()); + myElementsOnShapePtr->SetTolerance(myTolerance); + myElementsOnShapePtr->SetAllNodes(true); // "belong", while false means "lays on" + myElementsOnShapePtr->SetMesh(myMeshDS); + myElementsOnShapePtr->SetShape(myShape, myType); } } -void ElementsOnShape::process (const SMDS_MeshElement* theElemPtr) +static bool IsContains( const SMESHDS_Mesh* theMeshDS, + const TopoDS_Shape& theShape, + const SMDS_MeshElement* theElem, + TopAbs_ShapeEnum theFindShapeEnum, + TopAbs_ShapeEnum theAvoidShapeEnum = TopAbs_SHAPE ) { - if (myShape.IsNull()) - return; + TopExp_Explorer anExp( theShape,theFindShapeEnum,theAvoidShapeEnum ); - SMDS_ElemIteratorPtr aNodeItr = theElemPtr->nodesIterator(); - bool isSatisfy = myAllNodesFlag; + while( anExp.More() ) + { + const TopoDS_Shape& aShape = anExp.Current(); + if( SMESHDS_SubMesh* aSubMesh = theMeshDS->MeshElements( aShape ) ){ + if( aSubMesh->Contains( theElem ) ) + return true; + } + anExp.Next(); + } + return false; +} - gp_XYZ centerXYZ (0, 0, 0); +bool BelongToGeom::IsSatisfy (long theId) +{ + if (myMeshDS == 0 || myShape.IsNull()) + return false; - while (aNodeItr->more() && (isSatisfy == myAllNodesFlag)) + if (!myIsSubshape) { - SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next(); - gp_Pnt aPnt (aNode->X(), aNode->Y(), aNode->Z()); - centerXYZ += aPnt.XYZ(); + return myElementsOnShapePtr->IsSatisfy(theId); + } - switch (myCurShapeType) + // Case of submesh + if (myType == SMDSAbs_Node) + { + if( const SMDS_MeshNode* aNode = myMeshDS->FindNode( theId ) ) { - case TopAbs_SOLID: - { - myCurSC.Perform(aPnt, myToler); - isSatisfy = (myCurSC.State() == TopAbs_IN || myCurSC.State() == TopAbs_ON); - } - break; - case TopAbs_FACE: + if ( aNode->getshapeId() < 1 ) + return myElementsOnShapePtr->IsSatisfy(theId); + + const SMDS_PositionPtr& aPosition = aNode->GetPosition(); + SMDS_TypeOfPosition aTypeOfPosition = aPosition->GetTypeOfPosition(); + switch( aTypeOfPosition ) { - myCurProjFace.Perform(aPnt); - isSatisfy = (myCurProjFace.IsDone() && myCurProjFace.LowerDistance() <= myToler); - if (isSatisfy) - { - // check relatively the face - Quantity_Parameter u, v; - myCurProjFace.LowerDistanceParameters(u, v); - gp_Pnt2d aProjPnt (u, v); - BRepClass_FaceClassifier aClsf (myCurFace, aProjPnt, myToler); - isSatisfy = (aClsf.State() == TopAbs_IN || aClsf.State() == TopAbs_ON); - } + case SMDS_TOP_VERTEX : return ( IsContains( myMeshDS,myShape,aNode,TopAbs_VERTEX )); + case SMDS_TOP_EDGE : return ( IsContains( myMeshDS,myShape,aNode,TopAbs_EDGE )); + case SMDS_TOP_FACE : return ( IsContains( myMeshDS,myShape,aNode,TopAbs_FACE )); + case SMDS_TOP_3DSPACE: return ( IsContains( myMeshDS,myShape,aNode,TopAbs_SOLID ) || + IsContains( myMeshDS,myShape,aNode,TopAbs_SHELL )); } - break; - case TopAbs_EDGE: + } + } + else + { + if ( const SMDS_MeshElement* anElem = myMeshDS->FindElement( theId )) + { + if ( anElem->getshapeId() < 1 ) + return myElementsOnShapePtr->IsSatisfy(theId); + + if( myType == SMDSAbs_All ) { - myCurProjEdge.Perform(aPnt); - isSatisfy = (myCurProjEdge.NbPoints() > 0 && myCurProjEdge.LowerDistance() <= myToler); + return ( IsContains( myMeshDS,myShape,anElem,TopAbs_EDGE ) || + IsContains( myMeshDS,myShape,anElem,TopAbs_FACE ) || + IsContains( myMeshDS,myShape,anElem,TopAbs_SOLID )|| + IsContains( myMeshDS,myShape,anElem,TopAbs_SHELL )); } - break; - case TopAbs_VERTEX: + else if( myType == anElem->GetType() ) { - isSatisfy = (aPnt.Distance(myCurPnt) <= myToler); - } - break; - default: - { - isSatisfy = false; + switch( myType ) + { + case SMDSAbs_Edge : return ( IsContains( myMeshDS,myShape,anElem,TopAbs_EDGE )); + case SMDSAbs_Face : return ( IsContains( myMeshDS,myShape,anElem,TopAbs_FACE )); + case SMDSAbs_Volume: return ( IsContains( myMeshDS,myShape,anElem,TopAbs_SOLID )|| + IsContains( myMeshDS,myShape,anElem,TopAbs_SHELL )); + } } } } - if (isSatisfy && myCurShapeType == TopAbs_SOLID) { // Check the center point for volumes MantisBug 0020168 - centerXYZ /= theElemPtr->NbNodes(); - gp_Pnt aCenterPnt (centerXYZ); - myCurSC.Perform(aCenterPnt, myToler); - if ( !(myCurSC.State() == TopAbs_IN || myCurSC.State() == TopAbs_ON)) - isSatisfy = false; + return false; +} + +void BelongToGeom::SetType (SMDSAbs_ElementType theType) +{ + myType = theType; + init(); +} + +SMDSAbs_ElementType BelongToGeom::GetType() const +{ + return myType; +} + +TopoDS_Shape BelongToGeom::GetShape() +{ + return myShape; +} + +const SMESHDS_Mesh* BelongToGeom::GetMeshDS() const +{ + return myMeshDS; +} + +void BelongToGeom::SetTolerance (double theTolerance) +{ + myTolerance = theTolerance; + if (!myIsSubshape) + init(); +} + +double BelongToGeom::GetTolerance() +{ + return myTolerance; +} + +/* + Class : LyingOnGeom + Description : Predicate for verifying whether entiy lying or partially lying on + specified geometrical support +*/ + +LyingOnGeom::LyingOnGeom() + : myMeshDS(NULL), + myType(SMDSAbs_All), + myIsSubshape(false), + myTolerance(Precision::Confusion()) +{} + +void LyingOnGeom::SetMesh( const SMDS_Mesh* theMesh ) +{ + myMeshDS = dynamic_cast(theMesh); + init(); +} + +void LyingOnGeom::SetGeom( const TopoDS_Shape& theShape ) +{ + myShape = theShape; + init(); +} + +void LyingOnGeom::init() +{ + if (!myMeshDS || myShape.IsNull()) return; + + // is sub-shape of main shape? + TopoDS_Shape aMainShape = myMeshDS->ShapeToMesh(); + if (aMainShape.IsNull()) { + myIsSubshape = false; + } + else { + myIsSubshape = myMeshDS->IsGroupOfSubShapes( myShape ); } - if (isSatisfy) - myIds.Add(theElemPtr->GetID()); + if (myIsSubshape) + { + TopTools_IndexedMapOfShape shapes; + TopExp::MapShapes( myShape, shapes ); + mySubShapesIDs.Clear(); + for ( int i = 1; i <= shapes.Extent(); ++i ) + { + int subID = myMeshDS->ShapeToIndex( shapes( i )); + if ( subID > 0 ) + mySubShapesIDs.Add( subID ); + } + } + else + { + myElementsOnShapePtr.reset(new ElementsOnShape()); + myElementsOnShapePtr->SetTolerance(myTolerance); + myElementsOnShapePtr->SetAllNodes(false); // lays on, while true means "belong" + myElementsOnShapePtr->SetMesh(myMeshDS); + myElementsOnShapePtr->SetShape(myShape, myType); + } } -TSequenceOfXYZ::TSequenceOfXYZ() +bool LyingOnGeom::IsSatisfy( long theId ) +{ + if ( myMeshDS == 0 || myShape.IsNull() ) + return false; + + if (!myIsSubshape) + { + return myElementsOnShapePtr->IsSatisfy(theId); + } + + // Case of sub-mesh + + const SMDS_MeshElement* elem = + ( myType == SMDSAbs_Node ) ? myMeshDS->FindNode( theId ) : myMeshDS->FindElement( theId ); + + if ( mySubShapesIDs.Contains( elem->getshapeId() )) + return true; + + if ( elem->GetType() != SMDSAbs_Node ) + { + SMDS_ElemIteratorPtr nodeItr = elem->nodesIterator(); + while ( nodeItr->more() ) + { + const SMDS_MeshElement* aNode = nodeItr->next(); + if ( mySubShapesIDs.Contains( aNode->getshapeId() )) + return true; + } + } + + return false; +} + +void LyingOnGeom::SetType( SMDSAbs_ElementType theType ) +{ + myType = theType; + init(); +} + +SMDSAbs_ElementType LyingOnGeom::GetType() const +{ + return myType; +} + +TopoDS_Shape LyingOnGeom::GetShape() +{ + return myShape; +} + +const SMESHDS_Mesh* LyingOnGeom::GetMeshDS() const +{ + return myMeshDS; +} + +void LyingOnGeom::SetTolerance (double theTolerance) +{ + myTolerance = theTolerance; + if (!myIsSubshape) + init(); +} + +double LyingOnGeom::GetTolerance() +{ + return myTolerance; +} + +bool LyingOnGeom::Contains( const SMESHDS_Mesh* theMeshDS, + const TopoDS_Shape& theShape, + const SMDS_MeshElement* theElem, + TopAbs_ShapeEnum theFindShapeEnum, + TopAbs_ShapeEnum theAvoidShapeEnum ) +{ + // if (IsContains(theMeshDS, theShape, theElem, theFindShapeEnum, theAvoidShapeEnum)) + // return true; + + // TopTools_MapOfShape aSubShapes; + // TopExp_Explorer exp( theShape, theFindShapeEnum, theAvoidShapeEnum ); + // for ( ; exp.More(); exp.Next() ) + // { + // const TopoDS_Shape& aShape = exp.Current(); + // if ( !aSubShapes.Add( aShape )) continue; + + // if ( SMESHDS_SubMesh* aSubMesh = theMeshDS->MeshElements( aShape )) + // { + // if ( aSubMesh->Contains( theElem )) + // return true; + + // SMDS_ElemIteratorPtr nodeItr = theElem->nodesIterator(); + // while ( nodeItr->more() ) + // { + // const SMDS_MeshElement* aNode = nodeItr->next(); + // if ( aSubMesh->Contains( aNode )) + // return true; + // } + // } + // } + return false; +} + +TSequenceOfXYZ::TSequenceOfXYZ(): myElem(0) {} -TSequenceOfXYZ::TSequenceOfXYZ(size_type n) : std::vector(n) +TSequenceOfXYZ::TSequenceOfXYZ(size_type n) : myArray(n), myElem(0) {} -TSequenceOfXYZ::TSequenceOfXYZ(size_type n, const value_type& t) : std::vector(n,t) +TSequenceOfXYZ::TSequenceOfXYZ(size_type n, const gp_XYZ& t) : myArray(n,t), myElem(0) {} -TSequenceOfXYZ::TSequenceOfXYZ(const TSequenceOfXYZ& theSequenceOfXYZ) : std::vector(theSequenceOfXYZ) +TSequenceOfXYZ::TSequenceOfXYZ(const TSequenceOfXYZ& theSequenceOfXYZ) : myArray(theSequenceOfXYZ.myArray), myElem(theSequenceOfXYZ.myElem) {} template -TSequenceOfXYZ::TSequenceOfXYZ(InputIterator theBegin, InputIterator theEnd): std::vector(theBegin,theEnd) +TSequenceOfXYZ::TSequenceOfXYZ(InputIterator theBegin, InputIterator theEnd): myArray(theBegin,theEnd), myElem(0) +{} + +TSequenceOfXYZ::~TSequenceOfXYZ() {} TSequenceOfXYZ& TSequenceOfXYZ::operator=(const TSequenceOfXYZ& theSequenceOfXYZ) { - std::vector::operator=(theSequenceOfXYZ); + myArray = theSequenceOfXYZ.myArray; + myElem = theSequenceOfXYZ.myElem; return *this; } -std::vector::reference TSequenceOfXYZ::operator()(size_type n) +gp_XYZ& TSequenceOfXYZ::operator()(size_type n) +{ + return myArray[n-1]; +} + +const gp_XYZ& TSequenceOfXYZ::operator()(size_type n) const +{ + return myArray[n-1]; +} + +void TSequenceOfXYZ::clear() +{ + myArray.clear(); +} + +void TSequenceOfXYZ::reserve(size_type n) +{ + myArray.reserve(n); +} + +void TSequenceOfXYZ::push_back(const gp_XYZ& v) +{ + myArray.push_back(v); +} + +TSequenceOfXYZ::size_type TSequenceOfXYZ::size() const +{ + return myArray.size(); +} + +SMDSAbs_EntityType TSequenceOfXYZ::getElementEntity() const { - return std::vector::operator[](n-1); + return myElem ? myElem->GetEntityType() : SMDSEntity_Last; } -std::vector::const_reference TSequenceOfXYZ::operator()(size_type n) const +TMeshModifTracer::TMeshModifTracer(): + myMeshModifTime(0), myMesh(0) { - return std::vector::operator[](n-1); +} +void TMeshModifTracer::SetMesh( const SMDS_Mesh* theMesh ) +{ + if ( theMesh != myMesh ) + myMeshModifTime = 0; + myMesh = theMesh; +} +bool TMeshModifTracer::IsMeshModified() +{ + bool modified = false; + if ( myMesh ) + { + modified = ( myMeshModifTime != myMesh->GetMTime() ); + myMeshModifTime = myMesh->GetMTime(); + } + return modified; } diff --git a/src/3rdParty/salomesmesh/src/Driver/Driver_Document.cpp b/src/3rdParty/salomesmesh/src/Driver/Driver_Document.cpp index 77b99b8bbc2e..d97bcd0c32ee 100644 --- a/src/3rdParty/salomesmesh/src/Driver/Driver_Document.cpp +++ b/src/3rdParty/salomesmesh/src/Driver/Driver_Document.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #include "Driver_Document.h" Driver_Document::Driver_Document(): diff --git a/src/3rdParty/salomesmesh/src/Driver/Driver_Mesh.cpp b/src/3rdParty/salomesmesh/src/Driver/Driver_Mesh.cpp index 0f4b51a85072..03971550da7c 100644 --- a/src/3rdParty/salomesmesh/src/Driver/Driver_Mesh.cpp +++ b/src/3rdParty/salomesmesh/src/Driver/Driver_Mesh.cpp @@ -1,35 +1,41 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH Driver : implementaion of driver for reading and writing + +// SMESH Driver : implementaion of driver for reading and writing // File : Mesh_Reader.cxx // Module : SMESH // #include "Driver_Mesh.h" +#include "SMESH_Comment.hxx" + +#include + using namespace std; Driver_Mesh::Driver_Mesh(): myFile(""), - myMeshId(-1) + myMeshId(-1), + myStatus( DRS_OK ) {} @@ -38,8 +44,60 @@ void Driver_Mesh::SetMeshId(int theMeshId) myMeshId = theMeshId; } +void Driver_Mesh::SetMeshName(const std::string& theMeshName) +{ + myMeshName = theMeshName; +} + +std::string Driver_Mesh::GetMeshName() const +{ + return myMeshName; +} + void Driver_Mesh::SetFile(const std::string& theFileName) { myFile = theFileName; } + + +//================================================================================ +/*! + * \brief Stores an error message + * + * We consider an error fatal if none mesh can be read + */ +//================================================================================ + +Driver_Mesh::Status Driver_Mesh::addMessage(const std::string& msg, + const bool isFatal/*=false*/) +{ + if ( isFatal ) + myErrorMessages.clear(); // warnings are useless if a fatal error encounters + + myErrorMessages.push_back( msg ); + + MESSAGE(msg); +#ifdef _DEBUG_ + cout << msg << endl; +#endif + return ( myStatus = isFatal ? DRS_FAIL : DRS_WARN_SKIP_ELEM ); +} + +//================================================================================ +/*! + * \brief Return a structure containing description of errors + */ +//================================================================================ + +SMESH_ComputeErrorPtr Driver_Mesh::GetError() +{ + SMESH_Comment msg; + for ( size_t i = 0; i < myErrorMessages.size(); ++i ) + { + msg << myErrorMessages[i]; + if ( i+1 < myErrorMessages.size() ) + msg << "\n"; + } + return SMESH_ComputeError::New( myStatus == DRS_OK ? int(COMPERR_OK) : int(myStatus), msg ); +} diff --git a/src/3rdParty/salomesmesh/src/Driver/Driver_SMDS_Mesh.cpp b/src/3rdParty/salomesmesh/src/Driver/Driver_SMDS_Mesh.cpp index b723c5c7b8cb..e321b598017a 100644 --- a/src/3rdParty/salomesmesh/src/Driver/Driver_SMDS_Mesh.cpp +++ b/src/3rdParty/salomesmesh/src/Driver/Driver_SMDS_Mesh.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #include "Driver_SMDS_Mesh.h" using namespace std; diff --git a/src/3rdParty/salomesmesh/src/Driver/Driver_SMESHDS_Mesh.cpp b/src/3rdParty/salomesmesh/src/Driver/Driver_SMESHDS_Mesh.cpp index bb0b75de4900..841e8cb593cd 100644 --- a/src/3rdParty/salomesmesh/src/Driver/Driver_SMESHDS_Mesh.cpp +++ b/src/3rdParty/salomesmesh/src/Driver/Driver_SMESHDS_Mesh.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #include "Driver_SMESHDS_Mesh.h" using namespace std; diff --git a/src/3rdParty/salomesmesh/src/DriverDAT/DriverDAT_R_SMDS_Mesh.cpp b/src/3rdParty/salomesmesh/src/DriverDAT/DriverDAT_R_SMDS_Mesh.cpp index 6c0abb7303d5..824702e1875f 100644 --- a/src/3rdParty/salomesmesh/src/DriverDAT/DriverDAT_R_SMDS_Mesh.cpp +++ b/src/3rdParty/salomesmesh/src/DriverDAT/DriverDAT_R_SMDS_Mesh.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #include #include "DriverDAT_R_SMDS_Mesh.h" @@ -26,10 +27,13 @@ #include "utilities.h" +#include + using namespace std; Driver_Mesh::Status DriverDAT_R_SMDS_Mesh::Perform() { +// Kernel_Utils::Localizer loc; Status aResult = DRS_OK; int i, j; @@ -40,19 +44,16 @@ Driver_Mesh::Status DriverDAT_R_SMDS_Mesh::Perform() int intNumMaille, Degre; int ValElement; - int ValDegre; int NoeudsMaille[20]; int NoeudMaille; - bool ok; - MESSAGE("in DriverDAT_R_SMDS_Mesh::Read()"); /**************************************************************************** * OUVERTURE DU FICHIER EN LECTURE * ****************************************************************************/ char *file2Read = (char *)myFile.c_str(); FILE* aFileId = fopen(file2Read, "r"); - if (aFileId < 0) { + if ( !aFileId ) { fprintf(stderr, ">> ERREUR : ouverture du fichier %s \n", file2Read); return DRS_FAIL; } @@ -68,7 +69,7 @@ Driver_Mesh::Status DriverDAT_R_SMDS_Mesh::Perform() for (i = 0; i < nbNodes; i++){ fscanf(aFileId, "%d %e %e %e\n", &intNumPoint, &coordX, &coordY, &coordZ); - ok = myMesh->AddNodeWithID(coordX, coordY, coordZ, intNumPoint); + myMesh->AddNodeWithID(coordX, coordY, coordZ, intNumPoint); } fprintf(stdout, "%d noeuds\n", myMesh->NbNodes()); @@ -96,72 +97,66 @@ Driver_Mesh::Status DriverDAT_R_SMDS_Mesh::Perform() switch (ValElement) { case 102: case 103: - ValDegre = 3; nbNoeuds = 2; - ok = myMesh->AddEdgeWithID(NoeudsMaille[0], NoeudsMaille[1], - intNumMaille); + myMesh->AddEdgeWithID(NoeudsMaille[0], NoeudsMaille[1], + intNumMaille); break; case 204: case 208: - ValDegre = 9; nbNoeuds = 4; - ok = myMesh->AddFaceWithID(NoeudsMaille[0], NoeudsMaille[1], - NoeudsMaille[2], NoeudsMaille[3], - intNumMaille); + myMesh->AddFaceWithID(NoeudsMaille[0], NoeudsMaille[1], + NoeudsMaille[2], NoeudsMaille[3], + intNumMaille); break; case 203: case 206: - ValDegre = 5; nbNoeuds = 3; - ok = myMesh->AddFaceWithID(NoeudsMaille[0], NoeudsMaille[1], - NoeudsMaille[2], intNumMaille); + myMesh->AddFaceWithID(NoeudsMaille[0], NoeudsMaille[1], + NoeudsMaille[2], intNumMaille); break; case 308: case 320: - ValDegre = 12; nbNoeuds = 8; if (ValElement == 320){ - //A voir, correspondance VTK - NoeudsMaille[4] = NoeudsMaille[8]; - NoeudsMaille[5] = NoeudsMaille[9]; - NoeudsMaille[6] = NoeudsMaille[10]; - NoeudsMaille[7] = NoeudsMaille[11]; + //A voir, correspondance VTK + NoeudsMaille[4] = NoeudsMaille[8]; + NoeudsMaille[5] = NoeudsMaille[9]; + NoeudsMaille[6] = NoeudsMaille[10]; + NoeudsMaille[7] = NoeudsMaille[11]; } - ok = myMesh->AddVolumeWithID(NoeudsMaille[0], NoeudsMaille[1], - NoeudsMaille[2], NoeudsMaille[3], - NoeudsMaille[4], NoeudsMaille[5], - NoeudsMaille[6], NoeudsMaille[7], - intNumMaille); + myMesh->AddVolumeWithID(NoeudsMaille[0], NoeudsMaille[1], + NoeudsMaille[2], NoeudsMaille[3], + NoeudsMaille[4], NoeudsMaille[5], + NoeudsMaille[6], NoeudsMaille[7], + intNumMaille); break; case 304: case 310: - ValDegre = 10; nbNoeuds = 4; if (ValElement == 310) - NoeudsMaille[3] = NoeudsMaille[6]; - ok = myMesh->AddVolumeWithID(NoeudsMaille[0], NoeudsMaille[1], - NoeudsMaille[2], NoeudsMaille[3], - intNumMaille); + NoeudsMaille[3] = NoeudsMaille[6]; + myMesh->AddVolumeWithID(NoeudsMaille[0], NoeudsMaille[1], + NoeudsMaille[2], NoeudsMaille[3], + intNumMaille); break; case 306: case 315: - ValDegre = 12; nbNoeuds = 8; if (ValElement == 315) { - NoeudsMaille[3] = NoeudsMaille[6]; - NoeudsMaille[4] = NoeudsMaille[7]; - NoeudsMaille[5] = NoeudsMaille[8]; + NoeudsMaille[3] = NoeudsMaille[6]; + NoeudsMaille[4] = NoeudsMaille[7]; + NoeudsMaille[5] = NoeudsMaille[8]; } NoeudsMaille[7] = NoeudsMaille[5]; NoeudsMaille[6] = NoeudsMaille[5]; NoeudsMaille[5] = NoeudsMaille[4]; NoeudsMaille[4] = NoeudsMaille[3]; NoeudsMaille[3] = NoeudsMaille[2]; - ok = myMesh->AddVolumeWithID(NoeudsMaille[0], NoeudsMaille[1], - NoeudsMaille[2], NoeudsMaille[3], - NoeudsMaille[4], NoeudsMaille[5], - intNumMaille); - break; + myMesh->AddVolumeWithID(NoeudsMaille[0], NoeudsMaille[1], + NoeudsMaille[2], NoeudsMaille[3], + NoeudsMaille[4], NoeudsMaille[5], + intNumMaille); + break; } } /**************************************************************************** diff --git a/src/3rdParty/salomesmesh/src/DriverDAT/DriverDAT_W_SMDS_Mesh.cpp b/src/3rdParty/salomesmesh/src/DriverDAT/DriverDAT_W_SMDS_Mesh.cpp index 91b06d6b1d89..e6747d700724 100644 --- a/src/3rdParty/salomesmesh/src/DriverDAT/DriverDAT_W_SMDS_Mesh.cpp +++ b/src/3rdParty/salomesmesh/src/DriverDAT/DriverDAT_W_SMDS_Mesh.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #include #include "DriverDAT_W_SMDS_Mesh.h" @@ -27,18 +28,20 @@ #include "utilities.h" +#include + using namespace std; Driver_Mesh::Status DriverDAT_W_SMDS_Mesh::Perform() { +// Kernel_Utils::Localizer loc; Status aResult = DRS_OK; int nbNodes, nbCells; - //int i; - + char *file2Read = (char *)myFile.c_str(); FILE* aFileId = fopen(file2Read, "w+"); - if (aFileId < 0) { + if ( !aFileId ) { fprintf(stderr, ">> ERREUR : ouverture du fichier %s \n", file2Read); return DRS_FAIL; } @@ -46,15 +49,12 @@ Driver_Mesh::Status DriverDAT_W_SMDS_Mesh::Perform() /**************************************************************************** * NOMBRES D'OBJETS * ****************************************************************************/ - fprintf(stdout, "\n(****************************)\n"); - fprintf(stdout, "(* INFORMATIONS GENERALES : *)\n"); - fprintf(stdout, "(****************************)\n"); - + /* Combien de noeuds ? */ nbNodes = myMesh->NbNodes(); - + /* Combien de mailles, faces ou aretes ? */ - int /*nb_of_nodes,*/ nb_of_edges, nb_of_faces, nb_of_volumes; + int nb_of_edges, nb_of_faces, nb_of_volumes; nb_of_edges = myMesh->NbEdges(); nb_of_faces = myMesh->NbFaces(); nb_of_volumes = myMesh->NbVolumes(); @@ -62,29 +62,23 @@ Driver_Mesh::Status DriverDAT_W_SMDS_Mesh::Perform() SCRUTE(nb_of_edges); SCRUTE(nb_of_faces); SCRUTE(nb_of_volumes); - - fprintf(stdout, "%d %d\n", nbNodes, nbCells); + + //fprintf(stdout, "%d %d\n", nbNodes, nbCells); fprintf(aFileId, "%d %d\n", nbNodes, nbCells); - + /**************************************************************************** * ECRITURE DES NOEUDS * ****************************************************************************/ - fprintf(stdout, "\n(************************)\n"); - fprintf(stdout, "(* NOEUDS DU MAILLAGE : *)\n"); - fprintf(stdout, "(************************)\n"); - + SMDS_NodeIteratorPtr itNodes=myMesh->nodesIterator(); - while(itNodes->more()){ + while(itNodes->more()){ const SMDS_MeshNode * node = itNodes->next(); - fprintf(aFileId, "%d %e %e %e\n", node->GetID(), node->X(), node->Y(), node->Z()); + fprintf(aFileId, "%d %.14e %.14e %.14e\n", node->GetID(), node->X(), node->Y(), node->Z()); } - + /**************************************************************************** * ECRITURE DES ELEMENTS * ****************************************************************************/ - fprintf(stdout, "\n(**************************)\n"); - fprintf(stdout, "(* ELEMENTS DU MAILLAGE : *)\n"); - fprintf(stdout, "(**************************)"); /* Ecriture des connectivites, noms, numeros des mailles */ SMDS_EdgeIteratorPtr itEdges=myMesh->edgesIterator(); @@ -107,17 +101,10 @@ Driver_Mesh::Status DriverDAT_W_SMDS_Mesh::Perform() SMDS_FaceIteratorPtr itFaces=myMesh->facesIterator(); while(itFaces->more()){ const SMDS_MeshElement * elem = itFaces->next(); - switch (elem->NbNodes()) { - case 3: - fprintf(aFileId, "%d %d ", elem->GetID(), 203); - break; - case 4: - fprintf(aFileId, "%d %d ", elem->GetID(), 204); - break; - case 6: - fprintf(aFileId, "%d %d ", elem->GetID(), 206); - break; - } + if ( elem->IsPoly() ) + fprintf(aFileId, "%d %d ", elem->GetID(), 400+elem->NbNodes()); + else + fprintf(aFileId, "%d %d ", elem->GetID(), 200+elem->NbNodes()); SMDS_ElemIteratorPtr it=elem->nodesIterator(); while(it->more()) fprintf(aFileId, "%d ", it->next()->GetID()); @@ -127,12 +114,10 @@ Driver_Mesh::Status DriverDAT_W_SMDS_Mesh::Perform() SMDS_VolumeIteratorPtr itVolumes=myMesh->volumesIterator(); while(itVolumes->more()){ const SMDS_MeshElement * elem = itVolumes->next(); - switch (elem->NbNodes()) { - case 8: - fprintf(aFileId, "%d %d ", elem->GetID(), 308); - break; - } - + if ( elem->IsPoly() ) + fprintf(aFileId, "%d %d ", elem->GetID(), 500+elem->NbNodes()); + else + fprintf(aFileId, "%d %d ", elem->GetID(), 300+elem->NbNodes()); SMDS_ElemIteratorPtr it=elem->nodesIterator(); while(it->more()) fprintf(aFileId, "%d ", it->next()->GetID()); diff --git a/src/3rdParty/salomesmesh/src/DriverSTL/Basics_Utils.cpp b/src/3rdParty/salomesmesh/src/DriverSTL/Basics_Utils.cpp new file mode 100644 index 000000000000..cbbbc769c031 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/DriverSTL/Basics_Utils.cpp @@ -0,0 +1,141 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 : Basics_Utils.cxx +// Autor : Alexander A. BORODIN +// Module : SALOME +// + +#include "Basics_Utils.hxx" +#include +#include + +#ifndef WIN32 +#include +#include +#include +#endif + + +namespace Kernel_Utils +{ + // threadsafe + std::string GetHostname() + { + int ls = 100, r = 1; + char *s; + + while (ls < 10000 && r) + { + ls *= 2; + s = new char[ls]; + r = gethostname(s, ls-1);//threadsafe see man 7 pthread + switch (r) + { + case 0: + break; + default: +#ifdef EINVAL + case EINVAL: +#endif +#ifdef ENAMETOOLONG + case ENAMETOOLONG: +#endif +#ifdef WIN32 + case WSAEFAULT: +#endif + delete [] s; + continue; + } + + } + + if (r != 0) + { + s = new char[50]; + strcpy(s, "localhost"); + } + + // remove all after '.' + char *aDot = (strchr(s,'.')); + if (aDot) aDot[0] = '\0'; + + std::string p = s; + delete [] s; + return p; + } + + Localizer::Localizer() + { + myCurLocale = setlocale(LC_NUMERIC, 0); + setlocale(LC_NUMERIC, "C"); + } + + Localizer::~Localizer() + { + setlocale(LC_NUMERIC, myCurLocale.c_str()); + } + + std::string GetGUID( GUIDtype type ) + { + std::string guid; + + switch ( type ) { + case DefUserID: + guid = "FFFFFFFF-D9CD-11d6-945D-1050DA506788"; break; + case ObjectdID: + guid = "C08F3C95-F112-4023-8776-78F1427D0B6D"; break; + } + + return guid; + } + +#ifndef WIN32 + void print_traceback() + { + void *array[50]; + size_t size; + char **strings; + size_t i; + + size = backtrace (array, 40); + strings = backtrace_symbols (array, size); + + for (i = 0; i < size; i++) + { + std::cerr << strings[i] << std::endl; + } + + free (strings); + } +#else + #if (_MSC_VER >= 1400) // Visual Studio 2005 + #include + int setenv(const char *name, const char *value, int rewrite) + { + std::stringstream sstr; + sstr< -#include -//======================================================================= -//function : HashCode -//purpose : -//======================================================================= -inline Standard_Integer HashCode - (const gp_Pnt& point, Standard_Integer Upper) -{ - union - { - Standard_Real R[3]; - Standard_Integer I[6]; - } U; - - point.Coord(U.R[0],U.R[1],U.R[2]); - return ::HashCode(U.I[0]/23+U.I[1]/19+U.I[2]/17+U.I[3]/13+U.I[4]/11+U.I[5]/7,Upper); -} -static Standard_Real tab1[3]; -static Standard_Real tab2[3]; -//======================================================================= -//function : IsEqual -//purpose : -//======================================================================= -inline Standard_Boolean IsEqual - (const gp_Pnt& point1, const gp_Pnt& point2) -{ - point1.Coord(tab1[0],tab1[1],tab1[2]); - point2.Coord(tab2[0],tab2[1],tab2[2]); - return (memcmp(tab1,tab2,sizeof(tab1)) == 0); -} #include "DriverSTL_R_SMDS_Mesh.h" -#include "SMDS_Mesh.hxx" -#include "SMDS_MeshElement.hxx" -#include "SMDS_MeshNode.hxx" +#include -#include -#include -#include -#include -#include +#include +#include #include -#include "utilities.h" - -static const int HEADER_SIZE = 84; -static const int SIZEOF_STL_FACET = 50; -//static const int STL_MIN_FILE_SIZE = 284; -static const int ASCII_LINES_PER_FACET = 7; +#include "SMDS_Mesh.hxx" +#include "SMDS_MeshElement.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMESH_File.hxx" +namespace +{ + struct Hasher + { + //======================================================================= + //function : HashCode + //purpose : + //======================================================================= + inline static Standard_Integer HashCode + (const gp_Pnt& point, Standard_Integer Upper) + { + union + { + Standard_Real R[3]; + Standard_Integer I[6]; + } U; -//typedef NCollection_BaseCollection DriverSTL_ColOfNodePtr; + point.Coord( U.R[0], U.R[1], U.R[2] ); + return ::HashCode(U.I[0]/23+U.I[1]/19+U.I[2]/17+U.I[3]/13+U.I[4]/11+U.I[5]/7,Upper); + } + //======================================================================= + //function : IsEqual + //purpose : + //======================================================================= + inline static Standard_Boolean IsEqual + (const gp_Pnt& point1, const gp_Pnt& point2) + { + static Standard_Real tab1[3], tab2[3]; + point1.Coord(tab1[0],tab1[1],tab1[2]); + point2.Coord(tab2[0],tab2[1],tab2[2]); + return (memcmp(tab1,tab2,sizeof(tab1)) == 0); + } + }; + typedef NCollection_DataMap TDataMapOfPntNodePtr; + + const int HEADER_SIZE = 84; + const int SIZEOF_STL_FACET = 50; + const int ASCII_LINES_PER_FACET = 7; + const int SIZE_OF_FLOAT = 4; + // const int STL_MIN_FILE_SIZE = 284; +} -#include -typedef NCollection_DataMap DriverSTL_DataMapOfPntNodePtr; //======================================================================= //function : DriverSTL_R_SMDS_Mesh -//purpose : +//purpose : //======================================================================= DriverSTL_R_SMDS_Mesh::DriverSTL_R_SMDS_Mesh() @@ -103,44 +102,35 @@ void DriverSTL_R_SMDS_Mesh::SetIsCreateFaces( const bool theIsCreate ) Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::Perform() { + // Kernel_Utils::Localizer loc; + Status aResult = DRS_OK; - TCollection_AsciiString aFileName( (char *)myFile.c_str() ); - if ( aFileName.IsEmpty() ) { + if ( myFile.empty() ) { fprintf(stderr, ">> ERREOR : invalid file name \n"); return DRS_FAIL; } - filebuf fic; - Standard_IStream is(&fic); - if (!fic.open(aFileName.ToCString(),ios::in)) { - fprintf(stderr, ">> ERROR : cannot open file %s \n", aFileName.ToCString()); + SMESH_File file( myFile, /*open=*/false ); + if ( !file.open() ) { + fprintf(stderr, ">> ERROR : cannot open file %s \n", myFile.c_str()); + if ( file.error().empty() ) + fprintf(stderr, ">> ERROR : %s \n", file.error().c_str()); return DRS_FAIL; } - - OSD_Path aPath( aFileName ); - OSD_File file = OSD_File( aPath ); - file.Open(OSD_ReadOnly,OSD_Protection(OSD_RWD,OSD_RWD,OSD_RWD,OSD_RWD)); - unsigned char str[128]; - Standard_Integer lread,i; - Standard_Address ach; - ach = (Standard_Address)str; // we skip the header which is in Ascii for both modes - file.Read(ach,HEADER_SIZE,lread); + const char* data = file; + data += HEADER_SIZE; - // we read 128 characters to detect if we have a non-ascii char - file.Read(ach,sizeof(str),lread); - + // we check 128 characters to detect if we have a non-ascii char myIsAscii = Standard_True; - for (i = 0; i < lread; ++i) { - if (str[i] > '~') { + for (int i = 0; i < 128; ++i, ++data) { + if ( !isascii( *data ) && data < file.end() ) { myIsAscii = Standard_False; break; } } - - file.Close(); if ( !myMesh ) { fprintf(stderr, ">> ERREOR : cannot create mesh \n"); @@ -148,37 +138,34 @@ Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::Perform() } if ( myIsAscii ) - aResult = readAscii(); + aResult = readAscii( file ); else - aResult = readBinary(); + aResult = readBinary( file ); return aResult; } // static methods -static Standard_Real readFloat(OSD_File& theFile) +static Standard_Real readFloat(SMESH_File& theFile) { union { - Standard_Integer i; + Standard_Boolean i; Standard_ShortReal f; - }u; + } u; - char c[4]; - Standard_Address adr; - adr = (Standard_Address)c; - Standard_Integer lread; - theFile.Read(adr,4,lread); + const char* c = theFile; u.i = c[0] & 0xFF; u.i |= (c[1] & 0xFF) << 0x08; u.i |= (c[2] & 0xFF) << 0x10; u.i |= (c[3] & 0xFF) << 0x18; + theFile += SIZE_OF_FLOAT; return u.f; } static SMDS_MeshNode* addNode(const gp_Pnt& P, - DriverSTL_DataMapOfPntNodePtr& uniqnodes, + TDataMapOfPntNodePtr& uniqnodes, SMDS_Mesh* theMesh) { SMDS_MeshNode* node = 0; @@ -193,7 +180,7 @@ static SMDS_MeshNode* addNode(const gp_Pnt& P, } static SMDS_MeshNode* readNode(FILE* file, - DriverSTL_DataMapOfPntNodePtr& uniqnodes, + TDataMapOfPntNodePtr& uniqnodes, SMDS_Mesh* theMesh) { Standard_ShortReal coord[3]; @@ -204,17 +191,16 @@ static SMDS_MeshNode* readNode(FILE* file, return addNode( P, uniqnodes, theMesh ); } -static SMDS_MeshNode* readNode(OSD_File& theFile, - DriverSTL_DataMapOfPntNodePtr& uniqnodes, +static SMDS_MeshNode* readNode(SMESH_File& theFile, + TDataMapOfPntNodePtr& uniqnodes, SMDS_Mesh* theMesh) { - Standard_ShortReal coord[3]; - coord[0] = readFloat(theFile); - coord[1] = readFloat(theFile); - coord[2] = readFloat(theFile); + gp_Pnt coord; + coord.SetX( readFloat(theFile)); + coord.SetY( readFloat(theFile)); + coord.SetZ( readFloat(theFile)); - gp_Pnt P(coord[0],coord[1],coord[2]); - return addNode( P, uniqnodes, theMesh ); + return addNode( coord, uniqnodes, theMesh ); } //======================================================================= @@ -222,35 +208,30 @@ static SMDS_MeshNode* readNode(OSD_File& theFile, //purpose : //======================================================================= -Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readAscii() const +Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readAscii(SMESH_File& theFile) const { Status aResult = DRS_OK; - long ipos; - Standard_Integer nbLines = 0; - // Open the file - TCollection_AsciiString aFileName( (char *)myFile.c_str() ); - FILE* file = fopen(aFileName.ToCString(),"r"); - fseek(file,0L,SEEK_END); // get the file size - long filesize = ftell(file); - fclose(file); - file = fopen(aFileName.ToCString(),"r"); - + long filesize = theFile.size(); + theFile.close(); + + // Open the file + FILE* file = fopen( myFile.c_str(),"r"); + // count the number of lines - for (ipos = 0; ipos < filesize; ++ipos) { + Standard_Integer nbLines = 0; + for (long ipos = 0; ipos < filesize; ++ipos) { if (getc(file) == '\n') nbLines++; } // go back to the beginning of the file -// fclose(file); -// file = fopen(aFileName.ToCString(),"r"); rewind(file); Standard_Integer nbTri = (nbLines / ASCII_LINES_PER_FACET); - DriverSTL_DataMapOfPntNodePtr uniqnodes; + TDataMapOfPntNodePtr uniqnodes; // skip header while (getc(file) != '\n'); @@ -288,23 +269,14 @@ Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readAscii() const //purpose : //======================================================================= -Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readBinary() const +Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readBinary(SMESH_File& file) const { Status aResult = DRS_OK; - char buftest[5]; - Standard_Address adr; - adr = (Standard_Address)buftest; - - TCollection_AsciiString aFileName( (char *)myFile.c_str() ); - OSD_File aFile = OSD_File(OSD_Path( aFileName )); - aFile.Open(OSD_ReadOnly,OSD_Protection(OSD_RWD,OSD_RWD,OSD_RWD,OSD_RWD)); - // the size of the file (minus the header size) // must be a multiple of SIZEOF_STL_FACET - // compute file size - Standard_Integer filesize = aFile.Size(); + long filesize = file.size(); if ( (filesize - HEADER_SIZE) % SIZEOF_STL_FACET !=0 // Commented to allow reading small files (ex: 1 face) @@ -317,29 +289,25 @@ Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readBinary() const Standard_Integer nbTri = ((filesize - HEADER_SIZE) / SIZEOF_STL_FACET); // skip the header - aFile.Seek(HEADER_SIZE,OSD_FromBeginning); + file += HEADER_SIZE; - DriverSTL_DataMapOfPntNodePtr uniqnodes; - Standard_Integer lread; + TDataMapOfPntNodePtr uniqnodes; for (Standard_Integer iTri = 0; iTri < nbTri; ++iTri) { // ignore normals - readFloat(aFile); - readFloat(aFile); - readFloat(aFile); + file += 3 * SIZE_OF_FLOAT; // read vertices - SMDS_MeshNode* node1 = readNode( aFile, uniqnodes, myMesh ); - SMDS_MeshNode* node2 = readNode( aFile, uniqnodes, myMesh ); - SMDS_MeshNode* node3 = readNode( aFile, uniqnodes, myMesh ); + SMDS_MeshNode* node1 = readNode( file, uniqnodes, myMesh ); + SMDS_MeshNode* node2 = readNode( file, uniqnodes, myMesh ); + SMDS_MeshNode* node3 = readNode( file, uniqnodes, myMesh ); if (myIsCreateFaces) myMesh->AddFace(node1,node2,node3); // skip extra bytes - aFile.Read(adr,2,lread); + file += 2; } - aFile.Close(); return aResult; } diff --git a/src/3rdParty/salomesmesh/src/DriverSTL/DriverSTL_W_SMDS_Mesh.cpp b/src/3rdParty/salomesmesh/src/DriverSTL/DriverSTL_W_SMDS_Mesh.cpp index 0f68b7583a11..1a653effd022 100644 --- a/src/3rdParty/salomesmesh/src/DriverSTL/DriverSTL_W_SMDS_Mesh.cpp +++ b/src/3rdParty/salomesmesh/src/DriverSTL/DriverSTL_W_SMDS_Mesh.cpp @@ -1,43 +1,50 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -#include #include "DriverSTL_W_SMDS_Mesh.h" +#ifdef WIN32 +#define NOMINMAX +#endif + +#include + +#include "SMDS_FaceOfNodes.hxx" +#include "SMDS_IteratorOnIterators.hxx" #include "SMDS_Mesh.hxx" #include "SMDS_MeshElement.hxx" #include "SMDS_MeshNode.hxx" -#include -#include -#include -#include -#include -#include -#include -#include +#include "SMDS_PolygonalFaceOfNodes.hxx" +#include "SMDS_SetIterator.hxx" +#include "SMDS_VolumeTool.hxx" +#include "SMESH_File.hxx" +#include "SMESH_TypeDefs.hxx" -#include "utilities.h" +#include +#include +#include + +#include -//using namespace std; // definition des constantes static const int LABEL_SIZE = 80; @@ -54,12 +61,15 @@ void DriverSTL_W_SMDS_Mesh::SetIsAscii( const bool theIsAscii ) Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::Perform() { + // Kernel_Utils::Localizer loc; + Status aResult = DRS_OK; if ( !myMesh ) { fprintf(stderr, ">> ERROR : Mesh is null \n"); return DRS_FAIL; } + findVolumeTriangles(); if ( myIsAscii ) aResult = writeAscii(); else @@ -68,15 +78,88 @@ Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::Perform() return aResult; } +//================================================================================ +/*! + * \brief Destructor deletes temporary faces + */ +//================================================================================ + +DriverSTL_W_SMDS_Mesh::~DriverSTL_W_SMDS_Mesh() +{ + for ( unsigned i = 0; i < myVolumeFacets.size(); ++i ) + delete myVolumeFacets[i]; +} + +//================================================================================ +/*! + * \brief Finds free facets of volumes for which faces are missing in the mesh + */ +//================================================================================ + +void DriverSTL_W_SMDS_Mesh::findVolumeTriangles() +{ + myNbVolumeTrias = 0; + + SMDS_VolumeTool theVolume; + SMDS_VolumeIteratorPtr vIt = myMesh->volumesIterator(); + std::vector< const SMDS_MeshNode*> nodes; + while ( vIt->more() ) + { + theVolume.Set( vIt->next(), /*ignoreCentralNodes=*/false ); + for ( int iF = 0; iF < theVolume.NbFaces(); ++iF ) + if ( theVolume.IsFreeFace( iF )) + { + const SMDS_MeshNode** n = theVolume.GetFaceNodes(iF); + int nbN = theVolume.NbFaceNodes(iF); + nodes.assign( n, n+nbN ); + if ( !myMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false)) + { + if (( nbN == 9 || nbN == 7 ) && + ( !theVolume.IsPoly() )) // facet is bi-quaratic + { + int nbTria = nbN - 1; + for ( int iT = 0; iT < nbTria; ++iT ) + myVolumeFacets.push_back( new SMDS_FaceOfNodes( n[8], n[0+iT], n[1+iT] )); + myNbVolumeTrias += nbTria; + } + else + { + myVolumeFacets.push_back( new SMDS_PolygonalFaceOfNodes( nodes )); + myNbVolumeTrias += nbN - 2; + } + } + } + } +} + +//================================================================================ +/*! + * \brief Return iterator on both faces in the mesh and on temporary faces + */ +//================================================================================ + +SMDS_ElemIteratorPtr DriverSTL_W_SMDS_Mesh::getFaces() const +{ + SMDS_ElemIteratorPtr facesIter = myMesh->elementsIterator(SMDSAbs_Face); + SMDS_ElemIteratorPtr tmpTriaIter( new SMDS_ElementVectorIterator( myVolumeFacets.begin(), + myVolumeFacets.end())); + typedef std::vector< SMDS_ElemIteratorPtr > TElemIterVector; + TElemIterVector iters(2); + iters[0] = facesIter; + iters[1] = tmpTriaIter; + + typedef SMDS_IteratorOnIterators TItersIter; + return SMDS_ElemIteratorPtr( new TItersIter( iters )); +} + // static methods -static void writeInteger( const Standard_Integer& theVal, - OSD_File& ofile ) +static void writeInteger( const Standard_Integer& theVal, SMESH_File& ofile ) { union { Standard_Integer i; char c[4]; - }u; + } u; u.i = theVal; @@ -86,16 +169,15 @@ static void writeInteger( const Standard_Integer& theVal, entier |= (u.c[2] & 0xFF) << 0x10; entier |= (u.c[3] & 0xFF) << 0x18; - ofile.Write((char *)&entier,sizeof(u.c)); + ofile.write( entier ); } -static void writeFloat ( const Standard_ShortReal& theVal, - OSD_File& ofile) +static void writeFloat( const Standard_ShortReal& theVal, SMESH_File& ofile) { union { Standard_ShortReal f; char c[4]; - }u; + } u; u.f = theVal; @@ -106,158 +188,408 @@ static void writeFloat ( const Standard_ShortReal& theVal, entier |= (u.c[2] & 0xFF) << 0x10; entier |= (u.c[3] & 0xFF) << 0x18; - ofile.Write((char *)&entier,sizeof(u.c)); + ofile.write( entier ); } -static gp_XYZ getNormale( const SMDS_MeshFace* theFace ) +static gp_XYZ getNormale( const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n3) { - gp_XYZ n; - int aNbNode = theFace->NbNodes(); - TColgp_Array1OfXYZ anArrOfXYZ(1,4); - gp_XYZ p1, p2, p3, p4; - SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator(); - int i = 1; - for ( ; aNodeItr->more() && i <= 4; i++ ) - { - SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next(); - anArrOfXYZ.SetValue(i, gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) ); - } - - gp_XYZ q1 = anArrOfXYZ.Value(2) - anArrOfXYZ.Value(1); - gp_XYZ q2 = anArrOfXYZ.Value(3) - anArrOfXYZ.Value(1); - n = q1 ^ q2; - if ( aNbNode > 3 ) - { - gp_XYZ q3 = anArrOfXYZ.Value(4) - anArrOfXYZ.Value(1); - n += q2 ^ q3; - } + SMESH_TNodeXYZ xyz1( n1 ); + SMESH_TNodeXYZ xyz2( n2 ); + SMESH_TNodeXYZ xyz3( n3 ); + gp_XYZ q1 = xyz2 - xyz1; + gp_XYZ q2 = xyz3 - xyz1; + gp_XYZ n = q1 ^ q2; double len = n.Modulus(); - if ( len > 0 ) + if ( len > std::numeric_limits::min() ) n /= len; return n; } +namespace +{ + /*! + * \brief Vertex of a polygon. Together with 2 neighbor Vertices represents a triangle + */ + struct PolyVertex + { + SMESH_TNodeXYZ _nxyz; + gp_XY _xy; + PolyVertex* _prev; + PolyVertex* _next; + + void SetNodeAndNext( const SMDS_MeshNode* n, PolyVertex& v ) + { + _nxyz.Set( n ); + _next = &v; + v._prev = this; + } + PolyVertex* Delete() + { + _prev->_next = _next; + _next->_prev = _prev; + return _next; + } + void GetTriaNodes( const SMDS_MeshNode** nodes) const + { + nodes[0] = _prev->_nxyz._node; + nodes[1] = this->_nxyz._node; + nodes[2] = _next->_nxyz._node; + } + + inline static double Area( const PolyVertex* v0, const PolyVertex* v1, const PolyVertex* v2 ) + { + gp_XY vPrev = v0->_xy - v1->_xy; + gp_XY vNext = v2->_xy - v1->_xy; + return vNext ^ vPrev; + } + double TriaArea() const { return Area( _prev, this, _next ); } + + bool IsInsideTria( const PolyVertex* v ) + { + gp_XY p = _prev->_xy - v->_xy; + gp_XY t = this->_xy - v->_xy; + gp_XY n = _next->_xy - v->_xy; + const double tol = -1e-12; + return (( p ^ t ) >= tol && + ( t ^ n ) >= tol && + ( n ^ p ) >= tol ); + // return ( Area( _prev, this, v ) > 0 && + // Area( this, _next, v ) > 0 && + // Area( _next, _prev, v ) > 0 ); + } + }; + + //================================================================================ + /*! + * \brief Triangulate a polygon. Assure correct orientation for concave polygons + */ + //================================================================================ + + bool triangulate( std::vector< const SMDS_MeshNode*>& nodes, const size_t nbNodes ) + { + // connect nodes into a ring + std::vector< PolyVertex > pv( nbNodes ); + for ( size_t i = 1; i < nbNodes; ++i ) + pv[i-1].SetNodeAndNext( nodes[i-1], pv[i] ); + pv[ nbNodes-1 ].SetNodeAndNext( nodes[ nbNodes-1 ], pv[0] ); + + // get a polygon normal + gp_XYZ normal(0,0,0), p0,v01,v02; + p0 = pv[0]._nxyz; + v01 = pv[1]._nxyz - p0; + for ( size_t i = 2; i < nbNodes; ++i ) + { + v02 = pv[i]._nxyz - p0; + normal += v01 ^ v02; + v01 = v02; + } + // project nodes to the found plane + gp_Ax2 axes; + try { + axes = gp_Ax2( p0, normal, v01 ); + } + catch ( Standard_Failure ) { + return false; + } + for ( size_t i = 0; i < nbNodes; ++i ) + { + gp_XYZ p = pv[i]._nxyz - p0; + pv[i]._xy.SetX( axes.XDirection().XYZ() * p ); + pv[i]._xy.SetY( axes.YDirection().XYZ() * p ); + } + + // in a loop, find triangles with positive area and having no vertices inside + int iN = 0, nbTria = nbNodes - 2; + nodes.reserve( nbTria * 3 ); + const double minArea = 1e-6; + PolyVertex* v = &pv[0], *vi; + int nbVertices = nbNodes, nbBadTria = 0, isGoodTria; + while ( nbBadTria < nbVertices ) + { + if (( isGoodTria = v->TriaArea() > minArea )) + { + for ( vi = v->_next->_next; + vi != v->_prev; + vi = vi->_next ) + { + if ( v->IsInsideTria( vi )) + break; + } + isGoodTria = ( vi == v->_prev ); + } + if ( isGoodTria ) + { + v->GetTriaNodes( &nodes[ iN ] ); + iN += 3; + v = v->Delete(); + if ( --nbVertices == 3 ) + { + // last triangle remains + v->GetTriaNodes( &nodes[ iN ] ); + return true; + } + nbBadTria = 0; + } + else + { + v = v->_next; + ++nbBadTria; + } + } + + // the polygon is invalid; add triangles with positive area + nbBadTria = 0; + while ( nbBadTria < nbVertices ) + { + isGoodTria = v->TriaArea() > minArea; + if ( isGoodTria ) + { + v->GetTriaNodes( &nodes[ iN ] ); + iN += 3; + v = v->Delete(); + if ( --nbVertices == 3 ) + { + // last triangle remains + v->GetTriaNodes( &nodes[ iN ] ); + return true; + } + nbBadTria = 0; + } + else + { + v = v->_next; + ++nbBadTria; + } + } + + // add all the rest triangles + while ( nbVertices >= 3 ) + { + v->GetTriaNodes( &nodes[ iN ] ); + iN += 3; + v = v->Delete(); + --nbVertices; + } + + return true; + + } // triangulate() +} // namespace + +//================================================================================ +/*! + * \brief Return nb triangles in a decomposed mesh face + * \retval int - number of triangles + */ +//================================================================================ + +static int getNbTriangles( const SMDS_MeshElement* face) +{ + // WARNING: counting triangles must be coherent with getTriangles() + switch ( face->GetEntityType() ) + { + case SMDSEntity_BiQuad_Triangle: + case SMDSEntity_BiQuad_Quadrangle: + return face->NbNodes() - 1; + // case SMDSEntity_Triangle: + // case SMDSEntity_Quad_Triangle: + // case SMDSEntity_Quadrangle: + // case SMDSEntity_Quad_Quadrangle: + // case SMDSEntity_Polygon: + // case SMDSEntity_Quad_Polygon: + default: + return face->NbNodes() - 2; + } + return 0; +} + +//================================================================================ +/*! + * \brief Decompose a mesh face into triangles + * \retval int - number of triangles + */ +//================================================================================ + +static int getTriangles( const SMDS_MeshElement* face, + std::vector< const SMDS_MeshNode*>& nodes) +{ + // WARNING: decomposing into triangles must be coherent with getNbTriangles() + int nbTria, i = 0, nbNodes = face->NbNodes(); + SMDS_NodeIteratorPtr nIt = face->interlacedNodesIterator(); + nodes.resize( nbNodes * 3 ); + nodes[ i++ ] = nIt->next(); + nodes[ i++ ] = nIt->next(); + + const SMDSAbs_EntityType type = face->GetEntityType(); + switch ( type ) + { + case SMDSEntity_BiQuad_Triangle: + case SMDSEntity_BiQuad_Quadrangle: + nbTria = ( type == SMDSEntity_BiQuad_Triangle ) ? 6 : 8; + nodes[ i++ ] = face->GetNode( nbTria ); + for ( i = 3; i < 3*(nbTria-1); i += 3 ) + { + nodes[ i+0 ] = nodes[ i-2 ]; + nodes[ i+1 ] = nIt->next(); + nodes[ i+2 ] = nodes[ 2 ]; + } + nodes[ i+0 ] = nodes[ i-2 ]; + nodes[ i+1 ] = nodes[ 0 ]; + nodes[ i+2 ] = nodes[ 2 ]; + break; + case SMDSEntity_Triangle: + nbTria = 1; + nodes[ i++ ] = nIt->next(); + break; + default: + // case SMDSEntity_Quad_Triangle: + // case SMDSEntity_Quadrangle: + // case SMDSEntity_Quad_Quadrangle: + // case SMDSEntity_Polygon: + // case SMDSEntity_Quad_Polygon: + nbTria = nbNodes - 2; + while ( nIt->more() ) + nodes[ i++ ] = nIt->next(); + + if ( !triangulate( nodes, nbNodes )) + { + nIt = face->interlacedNodesIterator(); + nodes[ 0 ] = nIt->next(); + nodes[ 1 ] = nIt->next(); + nodes[ 2 ] = nIt->next(); + for ( i = 3; i < 3*nbTria; i += 3 ) + { + nodes[ i+0 ] = nodes[ 0 ]; + nodes[ i+1 ] = nodes[ i-1 ]; + nodes[ i+2 ] = nIt->next(); + } + } + break; + } + return nbTria; +} + // private methods Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeAscii() const { Status aResult = DRS_OK; - TCollection_AsciiString aFileName( (char *)myFile.c_str() ); - if ( aFileName.IsEmpty() ) { + if ( myFile.empty() ) { fprintf(stderr, ">> ERREOR : invalid file name \n"); return DRS_FAIL; } - OSD_File aFile = OSD_File(OSD_Path(aFileName)); - aFile.Build(OSD_WriteOnly,OSD_Protection()); - TCollection_AsciiString buf = TCollection_AsciiString ("solid\n"); - aFile.Write (buf,buf.Length());buf.Clear(); - char sval[16]; + SMESH_File aFile( myFile, /*openForReading=*/false ); + aFile.openForWriting(); - SMDS_FaceIteratorPtr itFaces = myMesh->facesIterator(); - - for (; itFaces->more() ;) { - SMDS_MeshFace* aFace = (SMDS_MeshFace*)itFaces->next(); - - if (aFace->NbNodes() == 3) { - gp_XYZ normale = getNormale( aFace ); - - buf += " facet normal "; - sprintf (sval,"% 12e",normale.X()); - buf += sval; - buf += " "; - sprintf (sval,"% 12e",normale.Y()); - buf += sval; - buf += " "; - sprintf (sval,"% 12e",normale.Z()); - buf += sval; - buf += '\n'; - aFile.Write (buf,buf.Length());buf.Clear(); - buf += " outer loop\n"; - aFile.Write (buf,buf.Length());buf.Clear(); - - SMDS_ElemIteratorPtr aNodeIter = aFace->nodesIterator(); - for (; aNodeIter->more(); ) { - SMDS_MeshNode* node = (SMDS_MeshNode*)aNodeIter->next(); - buf += " vertex "; - sprintf (sval,"% 12e",node->X()); - buf += sval; - buf += " "; - sprintf (sval,"% 12e",node->Y()); - buf += sval; - buf += " "; - sprintf (sval,"% 12e",node->Z()); - buf += sval; - buf += '\n'; - aFile.Write (buf,buf.Length());buf.Clear(); + std::string buf("solid\n"); + aFile.writeRaw( buf.c_str(), buf.size() ); + + char sval[128]; + std::vector< const SMDS_MeshNode* > triaNodes; + + SMDS_ElemIteratorPtr itFaces = getFaces(); + while ( itFaces->more() ) + { + const SMDS_MeshElement* aFace = itFaces->next(); + int nbTria = getTriangles( aFace, triaNodes ); + + for ( int iT = 0, iN = 0; iT < nbTria; ++iT ) + { + gp_XYZ normale = getNormale( triaNodes[iN], + triaNodes[iN+1], + triaNodes[iN+2] ); + sprintf (sval, + " facet normal % 12e % 12e % 12e\n" + " outer loop\n" , + normale.X(), normale.Y(), normale.Z()); + aFile.writeRaw ( sval, 70 + strlen( sval + 70 )); // at least 70 but can be more (WIN) + + for ( int jN = 0; jN < 3; ++jN, ++iN ) + { + SMESH_TNodeXYZ node = triaNodes[iN]; + sprintf (sval, + " vertex % 12e % 12e % 12e\n", + node.X(), node.Y(), node.Z() ); + aFile.writeRaw ( sval, 54 + strlen( sval + 54 )); } - buf += " endloop\n"; - aFile.Write (buf,buf.Length());buf.Clear(); - buf += " endfacet\n"; - aFile.Write (buf,buf.Length());buf.Clear(); - } + aFile.writeRaw (" endloop\n" + " endfacet\n", 21 ); + } } - buf += "endsolid\n"; - aFile.Write (buf,buf.Length());buf.Clear(); - - aFile.Close (); + aFile.writeRaw ("endsolid\n" , 9 ); return aResult; } +//================================================================================ +/*! + * \brief Writes all triangles in binary format + * \return Driver_Mesh::Status - DRS_FAIL if no file name is provided + */ +//================================================================================ + Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeBinary() const { Status aResult = DRS_OK; - TCollection_AsciiString aFileName( (char *)myFile.c_str() ); - if ( aFileName.IsEmpty() ) { + + if ( myFile.empty() ) { fprintf(stderr, ">> ERREOR : invalid filename \n"); return DRS_FAIL; } - OSD_File aFile = OSD_File(OSD_Path(aFileName)); - aFile.Build(OSD_WriteOnly,OSD_Protection()); - - char sval[80]; - Standard_Integer nbTri = 0; - SMDS_FaceIteratorPtr itFaces = myMesh->facesIterator(); + SMESH_File aFile( myFile ); + aFile.openForWriting(); // we first count the number of triangles - for (;itFaces->more();) { - SMDS_MeshFace* aFace = (SMDS_MeshFace*)itFaces->next(); - if (aFace->NbNodes() == 3) - nbTri++; + int nbTri = myNbVolumeTrias; + { + SMDS_FaceIteratorPtr itFaces = myMesh->facesIterator(); + while ( itFaces->more() ) { + const SMDS_MeshElement* aFace = itFaces->next(); + nbTri += getNbTriangles( aFace ); + } } + std::string sval( LABEL_SIZE, ' ' ); + aFile.write( sval.c_str(), LABEL_SIZE ); // write number of triangles - //unsigned int NBT = nbTri; - aFile.Write((Standard_Address)sval,LABEL_SIZE); - writeInteger(nbTri,aFile); + writeInteger( nbTri, aFile ); + + // Loop writing nodes - // loop writing nodes. take face iterator again int dum=0; - itFaces = myMesh->facesIterator(); - - for (;itFaces->more();) { - SMDS_MeshFace* aFace = (SMDS_MeshFace*)itFaces->next(); + + std::vector< const SMDS_MeshNode* > triaNodes; + + SMDS_ElemIteratorPtr itFaces = getFaces(); + while ( itFaces->more() ) + { + const SMDS_MeshElement* aFace = itFaces->next(); + int nbTria = getTriangles( aFace, triaNodes ); - if (aFace->NbNodes() == 3) { - gp_XYZ aNorm = getNormale( aFace ); - writeFloat(aNorm.X(),aFile); - writeFloat(aNorm.Y(),aFile); - writeFloat(aNorm.Z(),aFile); - - SMDS_ElemIteratorPtr aNodeIter = aFace->nodesIterator(); - for (; aNodeIter->more(); ) { - SMDS_MeshNode* node = (SMDS_MeshNode*)aNodeIter->next(); - writeFloat(node->X(),aFile); - writeFloat(node->Y(),aFile); - writeFloat(node->Z(),aFile); + for ( int iT = 0, iN = 0; iT < nbTria; ++iT ) + { + gp_XYZ normale = getNormale( triaNodes[iN], + triaNodes[iN+1], + triaNodes[iN+2] ); + writeFloat(normale.X(),aFile); + writeFloat(normale.Y(),aFile); + writeFloat(normale.Z(),aFile); + + for ( int jN = 0; jN < 3; ++jN, ++iN ) + { + const SMDS_MeshNode* node = triaNodes[iN]; + writeFloat(node->X(),aFile); + writeFloat(node->Y(),aFile); + writeFloat(node->Z(),aFile); } - aFile.Write (&dum,2); - } + aFile.writeRaw ( &dum, 2 ); + } } - aFile.Close (); return aResult; } diff --git a/src/3rdParty/salomesmesh/src/DriverSTL/SMESH_File.cpp b/src/3rdParty/salomesmesh/src/DriverSTL/SMESH_File.cpp new file mode 100644 index 000000000000..fd3daf555c0f --- /dev/null +++ b/src/3rdParty/salomesmesh/src/DriverSTL/SMESH_File.cpp @@ -0,0 +1,336 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 : SMESH_File.cxx +// Created : Wed Mar 10 11:23:25 2010 +// Author : Edward AGAPOV (eap) +// + +#include "SMESH_File.hxx" + +#include +#include + +#ifdef WIN32 +#include +#else +#include +#include +#endif + +#include + +namespace boofs = boost::filesystem; + +//================================================================================ +/*! + * \brief Creator opening the file for reading by default + */ +//================================================================================ + +SMESH_File::SMESH_File(const std::string& name, bool open) + :_name(name), _size(-1), +#ifdef WIN32 + _file(INVALID_HANDLE_VALUE), +#else + _file(-1), +#endif + _map(0), _pos(0), _end(0) +{ + if ( open ) this->open(); +} + +//================================================================================ +/*! + * \brief Destructor closing the file + */ +//================================================================================ + +SMESH_File::~SMESH_File() +{ + close(); +} + +//================================================================================ +/*! + * \brief Open file for reading. Return true if there is something to read + */ +//================================================================================ + +bool SMESH_File::open() +{ + int length = size(); + if ( !_map && length > 0 ) + { +#ifdef WIN32 + _file = CreateFile(_name.data(), GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + bool ok = ( _file != INVALID_HANDLE_VALUE ); +#else + _file = ::open(_name.data(), O_RDONLY ); + bool ok = ( _file >= 0 ); +#endif + if ( ok ) + { +#ifdef WIN32 + _mapObj = CreateFileMapping(_file, NULL, PAGE_READONLY, 0, (DWORD)length, NULL); + _map = (void*) MapViewOfFile( _mapObj, FILE_MAP_READ, 0, 0, 0 ); +#else + _map = ::mmap(0,length,PROT_READ,MAP_PRIVATE,_file,0); + if ( _map == MAP_FAILED ) _map = NULL; +#endif + if ( _map != NULL ) + { + _size = length; + _pos = (char*) _map; + _end = _pos + _size; + } + else + { +#ifdef WIN32 + CloseHandle(_mapObj); + CloseHandle(_file); +#else + ::close(_file); +#endif + } + } + else if ( _error.empty() ) + { + _error = "Can't open for reading an existing file " + _name; + } + } + return _pos; +} + +//================================================================================ +/*! + * \brief Close the file + */ +//================================================================================ + +void SMESH_File::close() +{ + if ( _map != NULL ) + { +#ifdef WIN32 + UnmapViewOfFile(_map); + CloseHandle(_mapObj); + CloseHandle(_file); +#else + ::munmap(_map, _size); + ::close(_file); +#endif + _map = NULL; + _pos = _end = 0; + _size = -1; + } + else if ( _file >= 0 ) + { +#ifdef WIN32 + if(_file != INVALID_HANDLE_VALUE) { + CloseHandle(_file); + _file = INVALID_HANDLE_VALUE; + } +#else + if(_file != -1) { + ::close(_file); + _file = -1; + } +#endif + } +} + +//================================================================================ +/*! + * \brief Remove the file + */ +//================================================================================ + +bool SMESH_File::remove() +{ + close(); + + boost::system::error_code err; + boofs::remove( _name, err ); + _error = err.message(); + + return !err; +} + +//================================================================================ +/*! + * \brief Return file size + */ +//================================================================================ + +long SMESH_File::size() +{ + if ( _size >= 0 ) return _size; // size of an open file + + boost::system::error_code err; + boost::uintmax_t size = boofs::file_size( _name, err ); + _error = err.message(); + + return err ? -1 : (long) size; +} + +//================================================================================ +/*! + * \brief Check existence + */ +//================================================================================ + +bool SMESH_File::exists() +{ + boost::system::error_code err; + bool res = boofs::exists( _name, err ); + _error = err.message(); + + return err ? false : res; +} + +//================================================================================ +/*! + * \brief Check existence + */ +//================================================================================ + +bool SMESH_File::isDirectory() +{ + boost::system::error_code err; + bool res = boofs::is_directory( _name, err ); + _error = err.message(); + + return err ? false : res; +} + +//================================================================================ +/*! + * \brief Set cursor to the given position + */ +//================================================================================ + +void SMESH_File::setPos(const char* pos) +{ + if ( pos > (const char*)_map && pos < _end ) + _pos = (char*) pos; +} + +//================================================================================ +/*! + * \brief Skip till current line end and return the skipped string + */ +//================================================================================ + +std::string SMESH_File::getLine() +{ + std::string line; + const char* p = _pos; + while ( !eof() ) + if ( *(++_pos) == '\n' ) + break; + line.append( p, _pos ); + if ( !eof() ) _pos++; + return line; +} + +//================================================================================ +/*! + * \brief Move cursor to the file beginning + */ +//================================================================================ + +void SMESH_File::rewind() +{ + _pos = (char*) _map; +} + +//================================================================================ +/*! + * \brief Fill vector by reading out integers from file. Vector size gives number + * of integers to read + */ +//================================================================================ + +bool SMESH_File::getInts(std::vector& ints) +{ + size_t i = 0; + while ( i < ints.size() ) + { + while ( !isdigit( *_pos ) && !eof()) ++_pos; + if ( eof() ) break; + if ( _pos[-1] == '-' ) --_pos; + ints[ i++ ] = strtol( _pos, (char**)&_pos, 10 ); + } + return ( i == ints.size() ); +} + +//================================================================================ +/*! + * \brief Open for binary writing only. + */ +//================================================================================ + +bool SMESH_File::openForWriting() +{ +#ifdef WIN32 + + _file = CreateFile( _name.c_str(), // name of the write + GENERIC_WRITE, // open for writing + 0, // do not share + NULL, // default security + OPEN_ALWAYS, // CREATE NEW or OPEN EXISTING + FILE_ATTRIBUTE_NORMAL, // normal file + NULL); // no attr. template + return ( _file != INVALID_HANDLE_VALUE ); + +#else + + _file = ::open( _name.c_str(), + O_WRONLY | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); // rw-r--r-- + return _file >= 0; + +#endif +} + +//================================================================================ +/*! + * \brief Write binary data + */ +//================================================================================ + +bool SMESH_File::writeRaw(const void* data, size_t size) +{ +#ifdef WIN32 + + DWORD nbWritten = 0; + BOOL err = WriteFile( _file, data, size, & nbWritten, NULL); + + return (( err == FALSE ) && + ( nbWritten == (DWORD) size )); + +#else + + ssize_t nbWritten = ::write( _file, data, size ); + return ( nbWritten == (ssize_t) size ); + +#endif +} diff --git a/src/3rdParty/salomesmesh/src/DriverUNV/DriverUNV_R_SMDS_Mesh.cpp b/src/3rdParty/salomesmesh/src/DriverUNV/DriverUNV_R_SMDS_Mesh.cpp index c438fa334639..868fc3e6fca0 100644 --- a/src/3rdParty/salomesmesh/src/DriverUNV/DriverUNV_R_SMDS_Mesh.cpp +++ b/src/3rdParty/salomesmesh/src/DriverUNV/DriverUNV_R_SMDS_Mesh.cpp @@ -1,44 +1,95 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #include "DriverUNV_R_SMDS_Mesh.h" #include "SMDS_Mesh.hxx" #include "SMDS_MeshGroup.hxx" #include "utilities.h" +#include "UNV164_Structure.hxx" #include "UNV2411_Structure.hxx" #include "UNV2412_Structure.hxx" #include "UNV2417_Structure.hxx" +#include "UNV2420_Structure.hxx" #include "UNV_Utilities.hxx" +#include + using namespace std; #ifdef _DEBUG_ -static int MYDEBUG = 0; +static int MYDEBUG = 1; #else static int MYDEBUG = 0; #endif +namespace +{ + /*! + * \brief Move node coordinates to the global Cartesian CS + */ + void transformNodes( UNV2411::TDataSet::const_iterator fromNode, + UNV2411::TDataSet::const_iterator endNode, + const UNV2420::TRecord & csRecord ) + { + const int csLabel = fromNode->exp_coord_sys_num; + + UNV2411::TDataSet::const_iterator nodeIt; + + // apply Transformation Matrix + if ( !csRecord.isIdentityMatrix() ) + { + for ( nodeIt = fromNode; nodeIt != endNode; ++nodeIt ) + { + const UNV2411::TRecord& nodeRec = *nodeIt; + if ( nodeRec.exp_coord_sys_num == csLabel ) + csRecord.ApplyMatrix( (double*) nodeRec.coord ); + } + } + + // transform from Cylindrical CS + if ( csRecord.coord_sys_type == UNV2420::Cylindrical ) + { + for ( nodeIt = fromNode; nodeIt != endNode; ++nodeIt ) + { + const UNV2411::TRecord& nodeRec = *nodeIt; + if ( nodeRec.exp_coord_sys_num == csLabel ) + csRecord.FromCylindricalCS( (double*) nodeRec.coord ); + } + } + // transform from Spherical CS + else if ( csRecord.coord_sys_type == UNV2420::Spherical ) + { + for ( nodeIt = fromNode; nodeIt != endNode; ++nodeIt ) + { + const UNV2411::TRecord& nodeRec = *nodeIt; + if ( nodeRec.exp_coord_sys_num == csLabel ) + csRecord.FromSphericalCS( (double*) nodeRec.coord ); + } + } + } +} DriverUNV_R_SMDS_Mesh::~DriverUNV_R_SMDS_Mesh() { @@ -49,309 +100,388 @@ DriverUNV_R_SMDS_Mesh::~DriverUNV_R_SMDS_Mesh() Driver_Mesh::Status DriverUNV_R_SMDS_Mesh::Perform() { + // Kernel_Utils::Localizer loc; Status aResult = DRS_OK; std::ifstream in_stream(myFile.c_str()); - try{ + try + { { + // Read Units + UNV164::TRecord aUnitsRecord; + UNV164::Read( in_stream, aUnitsRecord ); + + // Read Coordinate systems + UNV2420::TDataSet aCoordSysDataSet; + UNV2420::Read(in_stream, myMeshName, aCoordSysDataSet); + + // Read nodes using namespace UNV2411; TDataSet aDataSet2411; UNV2411::Read(in_stream,aDataSet2411); if(MYDEBUG) MESSAGE("Perform - aDataSet2411.size() = "<exp_coord_sys_num == csIter->coord_sys_label ) + { + transformNodes( nodeIter, aDataSet2411.end(), *csIter ); + break; + } + } + } + // Move nodes to SI unit system + const double lenFactor = aUnitsRecord.factors[ UNV164::LENGTH_FACTOR ]; + if ( lenFactor != 1. ) + { + TDataSet::iterator nodeIter = aDataSet2411.begin(), nodeEnd; + for ( nodeEnd = aDataSet2411.end(); nodeIter != nodeEnd; nodeIter++) + { + UNV2411::TRecord& nodeRec = *nodeIter; + nodeRec.coord[0] *= lenFactor; + nodeRec.coord[1] *= lenFactor; + nodeRec.coord[2] *= lenFactor; + } + } + + // Create nodes in the mesh TDataSet::const_iterator anIter = aDataSet2411.begin(); - for(; anIter != aDataSet2411.end(); anIter++){ - const TNodeLab& aLabel = anIter->first; - const TRecord& aRec = anIter->second; - myMesh->AddNodeWithID(aRec.coord[0],aRec.coord[1],aRec.coord[2],aLabel); + for(; anIter != aDataSet2411.end(); anIter++) + { + const TRecord& aRec = *anIter; + myMesh->AddNodeWithID(aRec.coord[0],aRec.coord[1],aRec.coord[2],aRec.label); } } { using namespace UNV2412; - in_stream.seekg(0); TDataSet aDataSet2412; UNV2412::Read(in_stream,aDataSet2412); TDataSet::const_iterator anIter = aDataSet2412.begin(); if(MYDEBUG) MESSAGE("Perform - aDataSet2412.size() = "<first; - const TRecord& aRec = anIter->second; - if(IsBeam(aRec.fe_descriptor_id)) { + for(; anIter != aDataSet2412.end(); anIter++) + { + SMDS_MeshElement* anElement = NULL; + const TRecord& aRec = *anIter; + if(IsBeam(aRec.fe_descriptor_id)) { switch ( aRec.node_labels.size() ) { case 2: // edge with two nodes + //MESSAGE("add edge " << aLabel << " " << aRec.node_labels[0] << " " << aRec.node_labels[1]); anElement = myMesh->AddEdgeWithID(aRec.node_labels[0], aRec.node_labels[1], - aLabel); + aRec.label); break; case 3: // quadratic edge (with 3 nodes) + //MESSAGE("add edge " << aRec.label << " " << aRec.node_labels[0] << " " << aRec.node_labels[1] << " " << aRec.node_labels[2]); anElement = myMesh->AddEdgeWithID(aRec.node_labels[0], aRec.node_labels[2], aRec.node_labels[1], - aLabel); + aRec.label); } - } + } else if(IsFace(aRec.fe_descriptor_id)) { - switch(aRec.fe_descriptor_id){ - case 71: // TRI3 - case 72: - case 74: - - case 41: // Plane Stress Linear Triangle - TRI3 - case 91: // Thin Shell Linear Triangle - TRI3 - anElement = myMesh->AddFaceWithID(aRec.node_labels[0], - aRec.node_labels[1], - aRec.node_labels[2], - aLabel); - break; - - case 42: // Plane Stress Quadratic Triangle - TRI6 - case 92: // Thin Shell Quadratic Triangle - TRI6 - anElement = myMesh->AddFaceWithID(aRec.node_labels[0], - aRec.node_labels[2], - aRec.node_labels[4], - aRec.node_labels[1], - aRec.node_labels[3], - aRec.node_labels[5], - aLabel); - break; - - case 44: // Plane Stress Linear Quadrilateral - QUAD4 - case 94: // Thin Shell Linear Quadrilateral - QUAD4 - anElement = myMesh->AddFaceWithID(aRec.node_labels[0], - aRec.node_labels[1], - aRec.node_labels[2], - aRec.node_labels[3], - aLabel); - break; - - case 45: // Plane Stress Quadratic Quadrilateral - QUAD8 - case 95: // Thin Shell Quadratic Quadrilateral - QUAD8 - anElement = myMesh->AddFaceWithID(aRec.node_labels[0], - aRec.node_labels[2], - aRec.node_labels[4], - aRec.node_labels[6], - aRec.node_labels[1], - aRec.node_labels[3], - aRec.node_labels[5], - aRec.node_labels[7], - aLabel); - break; - } - } + //MESSAGE("add face " << aRec.label); + switch(aRec.fe_descriptor_id){ + case 41: // Plane Stress Linear Triangle + case 51: // Plane Strain Linear Triangle + case 61: // Plate Linear Triangle + case 74: // Membrane Linear Triangle + case 81: // Axisymetric Solid Linear Triangle + case 91: // Thin Shell Linear Triangle + anElement = myMesh->AddFaceWithID(aRec.node_labels[0], + aRec.node_labels[1], + aRec.node_labels[2], + aRec.label); + break; + + case 42: // Plane Stress Parabolic Triangle + case 52: // Plane Strain Parabolic Triangle + case 62: // Plate Parabolic Triangle + case 72: // Membrane Parabolic Triangle + case 82: // Axisymetric Solid Parabolic Triangle + case 92: // Thin Shell Parabolic Triangle + if ( aRec.node_labels.size() == 7 ) + anElement = myMesh->AddFaceWithID(aRec.node_labels[0], + aRec.node_labels[2], + aRec.node_labels[4], + aRec.node_labels[1], + aRec.node_labels[3], + aRec.node_labels[5], + aRec.node_labels[6], + aRec.label); + else + anElement = myMesh->AddFaceWithID(aRec.node_labels[0], + aRec.node_labels[2], + aRec.node_labels[4], + aRec.node_labels[1], + aRec.node_labels[3], + aRec.node_labels[5], + aRec.label); + break; + + case 44: // Plane Stress Linear Quadrilateral + case 54: // Plane Strain Linear Quadrilateral + case 64: // Plate Linear Quadrilateral + case 71: // Membrane Linear Quadrilateral + case 84: // Axisymetric Solid Linear Quadrilateral + case 94: // Thin Shell Linear Quadrilateral + anElement = myMesh->AddFaceWithID(aRec.node_labels[0], + aRec.node_labels[1], + aRec.node_labels[2], + aRec.node_labels[3], + aRec.label); + break; + + case 45: // Plane Stress Parabolic Quadrilateral + case 55: // Plane Strain Parabolic Quadrilateral + case 65: // Plate Parabolic Quadrilateral + case 75: // Membrane Parabolic Quadrilateral + case 85: // Axisymetric Solid Parabolic Quadrilateral + case 95: // Thin Shell Parabolic Quadrilateral + if ( aRec.node_labels.size() == 9 ) + anElement = myMesh->AddFaceWithID(aRec.node_labels[0], + aRec.node_labels[2], + aRec.node_labels[4], + aRec.node_labels[6], + aRec.node_labels[1], + aRec.node_labels[3], + aRec.node_labels[5], + aRec.node_labels[7], + aRec.node_labels[8], + aRec.label); + else + anElement = myMesh->AddFaceWithID(aRec.node_labels[0], + aRec.node_labels[2], + aRec.node_labels[4], + aRec.node_labels[6], + aRec.node_labels[1], + aRec.node_labels[3], + aRec.node_labels[5], + aRec.node_labels[7], + aRec.label); + break; + } + } else if(IsVolume(aRec.fe_descriptor_id)){ - switch(aRec.fe_descriptor_id){ - - case 111: // Solid Linear Tetrahedron - TET4 - anElement = myMesh->AddVolumeWithID(aRec.node_labels[0], - aRec.node_labels[2], - aRec.node_labels[1], - aRec.node_labels[3], - aLabel); - break; - - case 118: // Solid Quadratic Tetrahedron - TET10 - anElement = myMesh->AddVolumeWithID(aRec.node_labels[0], - aRec.node_labels[4], - aRec.node_labels[2], - - aRec.node_labels[9], - - aRec.node_labels[5], - aRec.node_labels[3], + //MESSAGE("add volume " << aRec.label); + switch(aRec.fe_descriptor_id){ + + case 111: // Solid Linear Tetrahedron - TET4 + anElement = myMesh->AddVolumeWithID(aRec.node_labels[0], + aRec.node_labels[2], + aRec.node_labels[1], + aRec.node_labels[3], + aRec.label); + break; + + case 118: // Solid Quadratic Tetrahedron - TET10 + anElement = myMesh->AddVolumeWithID(aRec.node_labels[0], + aRec.node_labels[4], + aRec.node_labels[2], + + aRec.node_labels[9], + + aRec.node_labels[5], + aRec.node_labels[3], aRec.node_labels[1], aRec.node_labels[6], - aRec.node_labels[8], - aRec.node_labels[7], - aLabel); - break; - - case 112: // Solid Linear Prism - PRISM6 - anElement = myMesh->AddVolumeWithID(aRec.node_labels[0], - aRec.node_labels[2], - aRec.node_labels[1], - aRec.node_labels[3], - aRec.node_labels[5], - aRec.node_labels[4], - aLabel); - break; - - case 113: // Solid Quadratic Prism - PRISM15 - anElement = myMesh->AddVolumeWithID(aRec.node_labels[0], - aRec.node_labels[4], - aRec.node_labels[2], - - aRec.node_labels[9], - aRec.node_labels[13], - aRec.node_labels[11], - - aRec.node_labels[5], - aRec.node_labels[3], + aRec.node_labels[8], + aRec.node_labels[7], + aRec.label); + break; + + case 112: // Solid Linear Prism - PRISM6 + anElement = myMesh->AddVolumeWithID(aRec.node_labels[0], + aRec.node_labels[2], aRec.node_labels[1], + aRec.node_labels[3], + aRec.node_labels[5], + aRec.node_labels[4], + aRec.label); + break; + + case 113: // Solid Quadratic Prism - PRISM15 + anElement = myMesh->AddVolumeWithID(aRec.node_labels[0], + aRec.node_labels[4], + aRec.node_labels[2], - aRec.node_labels[14], - aRec.node_labels[12], + aRec.node_labels[9], + aRec.node_labels[13], + aRec.node_labels[11], + + aRec.node_labels[5], + aRec.node_labels[3], + aRec.node_labels[1], + + aRec.node_labels[14], + aRec.node_labels[12], aRec.node_labels[10], aRec.node_labels[6], - aRec.node_labels[8], - aRec.node_labels[7], - aLabel); - break; - - case 115: // Solid Linear Brick - HEX8 - anElement = myMesh->AddVolumeWithID(aRec.node_labels[0], - aRec.node_labels[3], - aRec.node_labels[2], - aRec.node_labels[1], - aRec.node_labels[4], - aRec.node_labels[7], - aRec.node_labels[6], - aRec.node_labels[5], - aLabel); - break; - - case 116: // Solid Quadratic Brick - HEX20 - anElement = myMesh->AddVolumeWithID(aRec.node_labels[0], - aRec.node_labels[6], - aRec.node_labels[4], - aRec.node_labels[2], - - aRec.node_labels[12], - aRec.node_labels[18], - aRec.node_labels[16], - aRec.node_labels[14], - - aRec.node_labels[7], - aRec.node_labels[5], - aRec.node_labels[3], - aRec.node_labels[1], - - aRec.node_labels[19], - aRec.node_labels[17], - aRec.node_labels[15], + aRec.node_labels[8], + aRec.node_labels[7], + aRec.label); + break; + + case 115: // Solid Linear Brick - HEX8 + anElement = myMesh->AddVolumeWithID(aRec.node_labels[0], + aRec.node_labels[3], + aRec.node_labels[2], + aRec.node_labels[1], + aRec.node_labels[4], + aRec.node_labels[7], + aRec.node_labels[6], + aRec.node_labels[5], + aRec.label); + break; + + case 116: // Solid Quadratic Brick - HEX20 + anElement = myMesh->AddVolumeWithID(aRec.node_labels[0], + aRec.node_labels[6], + aRec.node_labels[4], + aRec.node_labels[2], + + aRec.node_labels[12], + aRec.node_labels[18], + aRec.node_labels[16], + aRec.node_labels[14], + + aRec.node_labels[7], + aRec.node_labels[5], + aRec.node_labels[3], + aRec.node_labels[1], + + aRec.node_labels[19], + aRec.node_labels[17], + aRec.node_labels[15], aRec.node_labels[13], aRec.node_labels[8], - aRec.node_labels[11], - aRec.node_labels[10], - aRec.node_labels[9], - aLabel); - break; - - case 114: // pyramid of 13 nodes (quadratic) - PIRA13 - anElement = myMesh->AddVolumeWithID(aRec.node_labels[0], - aRec.node_labels[6], - aRec.node_labels[4], - aRec.node_labels[2], - aRec.node_labels[7], - aRec.node_labels[5], - aRec.node_labels[3], - aRec.node_labels[1], - - aRec.node_labels[8], - aRec.node_labels[11], - aRec.node_labels[10], - aRec.node_labels[9], - aRec.node_labels[12], - aLabel); - break; - - } - } - // if(!anElement) - // MESSAGE("DriverUNV_R_SMDS_Mesh::Perform - can not add element with ID = "< 0) - aGrName.erase (i, 2); - myGroupNames.insert(TGroupNamesMap::value_type(aNodesGroup, aGrName)); - myGroupId.insert(TGroupIdMap::value_type(aNodesGroup, aLabel)); - - for (i = 0; i < aNodesNb; i++) { - const SMDS_MeshNode* aNode = myMesh->FindNode(aRec.NodeList[i]); - if (aNode) - aNodesGroup->Add(aNode); - } - } - if (aElementsNb > 0){ - SMDS_MeshGroup* aEdgesGroup = 0; - SMDS_MeshGroup* aFacesGroup = 0; - SMDS_MeshGroup* aVolumeGroup = 0; - bool createdGroup = false; - - for (i = 0; i < aElementsNb; i++) { - const SMDS_MeshElement* aElement = myMesh->FindElement(aRec.ElementList[i]); - if (aElement) { - switch (aElement->GetType()) { - case SMDSAbs_Edge: - if (!aEdgesGroup) { - aEdgesGroup = (SMDS_MeshGroup*) myGroup->AddSubGroup(SMDSAbs_Edge); - if (!useSuffix && createdGroup) useSuffix = true; - std::string aEdgesGrName = (useSuffix) ? aRec.GroupName + "_Edges" : aRec.GroupName; - int i = aEdgesGrName.find( "\r" ); - if (i > 0) - aEdgesGrName.erase (i, 2); - myGroupNames.insert(TGroupNamesMap::value_type(aEdgesGroup, aEdgesGrName)); - myGroupId.insert(TGroupIdMap::value_type(aEdgesGroup, aLabel)); - createdGroup = true; - } - aEdgesGroup->Add(aElement); - break; - case SMDSAbs_Face: - if (!aFacesGroup) { - aFacesGroup = (SMDS_MeshGroup*) myGroup->AddSubGroup(SMDSAbs_Face); - if (!useSuffix && createdGroup) useSuffix = true; - std::string aFacesGrName = (useSuffix) ? aRec.GroupName + "_Faces" : aRec.GroupName; - int i = aFacesGrName.find( "\r" ); - if (i > 0) - aFacesGrName.erase (i, 2); - myGroupNames.insert(TGroupNamesMap::value_type(aFacesGroup, aFacesGrName)); - myGroupId.insert(TGroupIdMap::value_type(aFacesGroup, aLabel)); - createdGroup = true; - } - aFacesGroup->Add(aElement); - break; - case SMDSAbs_Volume: - if (!aVolumeGroup) { - aVolumeGroup = (SMDS_MeshGroup*) myGroup->AddSubGroup(SMDSAbs_Volume); - if (!useSuffix && createdGroup) useSuffix = true; - std::string aVolumeGrName = (useSuffix) ? aRec.GroupName + "_Volumes" : aRec.GroupName; - int i = aVolumeGrName.find( "\r" ); - if (i > 0) - aVolumeGrName.erase (i, 2); - myGroupNames.insert(TGroupNamesMap::value_type(aVolumeGroup, aVolumeGrName)); - myGroupId.insert(TGroupIdMap::value_type(aVolumeGroup, aLabel)); - createdGroup = true; - } - aVolumeGroup->Add(aElement); - break; - } - } - } - } - } + myGroup = new SMDS_MeshGroup(myMesh); + TDataSet::const_iterator anIter = aDataSet2417.begin(); + for(; anIter != aDataSet2417.end(); anIter++){ + const TGroupId& aLabel = anIter->first; + const TRecord& aRec = anIter->second; + + int aNodesNb = aRec.NodeList.size(); + int aElementsNb = aRec.ElementList.size(); + + bool useSuffix = ((aNodesNb > 0) && (aElementsNb > 0)); + int i; + if (aNodesNb > 0) { + SMDS_MeshGroup* aNodesGroup = (SMDS_MeshGroup*) myGroup->AddSubGroup(SMDSAbs_Node); + std::string aGrName = (useSuffix) ? aRec.GroupName + "_Nodes" : aRec.GroupName; + int i = aGrName.find( "\r" ); + if (i > 0) + aGrName.erase (i, 2); + myGroupNames.insert(TGroupNamesMap::value_type(aNodesGroup, aGrName)); + myGroupId.insert(TGroupIdMap::value_type(aNodesGroup, aLabel)); + + for (i = 0; i < aNodesNb; i++) { + const SMDS_MeshNode* aNode = myMesh->FindNode(aRec.NodeList[i]); + if (aNode) + aNodesGroup->Add(aNode); + } + } + if (aElementsNb > 0){ + SMDS_MeshGroup* aEdgesGroup = 0; + SMDS_MeshGroup* aFacesGroup = 0; + SMDS_MeshGroup* aVolumeGroup = 0; + bool createdGroup = false; + + for (i = 0; i < aElementsNb; i++) { + const SMDS_MeshElement* aElement = myMesh->FindElement(aRec.ElementList[i]); + if (aElement) { + switch (aElement->GetType()) { + case SMDSAbs_Edge: + if (!aEdgesGroup) { + aEdgesGroup = (SMDS_MeshGroup*) myGroup->AddSubGroup(SMDSAbs_Edge); + if (!useSuffix && createdGroup) useSuffix = true; + std::string aEdgesGrName = (useSuffix) ? aRec.GroupName + "_Edges" : aRec.GroupName; + int i = aEdgesGrName.find( "\r" ); + if (i > 0) + aEdgesGrName.erase (i, 2); + myGroupNames.insert(TGroupNamesMap::value_type(aEdgesGroup, aEdgesGrName)); + myGroupId.insert(TGroupIdMap::value_type(aEdgesGroup, aLabel)); + createdGroup = true; + } + aEdgesGroup->Add(aElement); + break; + case SMDSAbs_Face: + if (!aFacesGroup) { + aFacesGroup = (SMDS_MeshGroup*) myGroup->AddSubGroup(SMDSAbs_Face); + if (!useSuffix && createdGroup) useSuffix = true; + std::string aFacesGrName = (useSuffix) ? aRec.GroupName + "_Faces" : aRec.GroupName; + int i = aFacesGrName.find( "\r" ); + if (i > 0) + aFacesGrName.erase (i, 2); + myGroupNames.insert(TGroupNamesMap::value_type(aFacesGroup, aFacesGrName)); + myGroupId.insert(TGroupIdMap::value_type(aFacesGroup, aLabel)); + createdGroup = true; + } + aFacesGroup->Add(aElement); + break; + case SMDSAbs_Volume: + if (!aVolumeGroup) { + aVolumeGroup = (SMDS_MeshGroup*) myGroup->AddSubGroup(SMDSAbs_Volume); + if (!useSuffix && createdGroup) useSuffix = true; + std::string aVolumeGrName = (useSuffix) ? aRec.GroupName + "_Volumes" : aRec.GroupName; + int i = aVolumeGrName.find( "\r" ); + if (i > 0) + aVolumeGrName.erase (i, 2); + myGroupNames.insert(TGroupNamesMap::value_type(aVolumeGroup, aVolumeGrName)); + myGroupId.insert(TGroupIdMap::value_type(aVolumeGroup, aLabel)); + createdGroup = true; + } + aVolumeGroup->Add(aElement); + break; + } + } + } + } + } } } } @@ -361,5 +491,7 @@ Driver_Mesh::Status DriverUNV_R_SMDS_Mesh::Perform() catch(...){ INFOS("Unknown exception was cought !!!"); } + if (myMesh) + myMesh->compactMesh(); return aResult; } diff --git a/src/3rdParty/salomesmesh/src/DriverUNV/DriverUNV_W_SMDS_Mesh.cpp b/src/3rdParty/salomesmesh/src/DriverUNV/DriverUNV_W_SMDS_Mesh.cpp index 7a4da5e92370..217fb2e9a507 100644 --- a/src/3rdParty/salomesmesh/src/DriverUNV/DriverUNV_W_SMDS_Mesh.cpp +++ b/src/3rdParty/salomesmesh/src/DriverUNV/DriverUNV_W_SMDS_Mesh.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #include #include "DriverUNV_W_SMDS_Mesh.h" @@ -31,11 +32,15 @@ #include "utilities.h" +#include "UNV164_Structure.hxx" #include "UNV2411_Structure.hxx" #include "UNV2412_Structure.hxx" #include "UNV2417_Structure.hxx" +#include "UNV2420_Structure.hxx" #include "UNV_Utilities.hxx" +#include + using namespace std; using namespace UNV; @@ -43,7 +48,7 @@ namespace{ typedef std::vector TConnect; int GetConnect(const SMDS_ElemIteratorPtr& theNodesIter, - TConnect& theConnect) + TConnect& theConnect) { theConnect.clear(); for(; theNodesIter->more();){ @@ -57,9 +62,14 @@ namespace{ Driver_Mesh::Status DriverUNV_W_SMDS_Mesh::Perform() { + // Kernel_Utils::Localizer loc; Status aResult = DRS_OK; std::ofstream out_stream(myFile.c_str()); try{ + + UNV164::Write( out_stream ); // unit system + UNV2420::Write( out_stream, myMeshName ); // Coordinate system + { using namespace UNV2411; TDataSet aDataSet2411; @@ -67,14 +77,15 @@ Driver_Mesh::Status DriverUNV_W_SMDS_Mesh::Perform() //----------------------------------- MESSAGE("Perform - myMesh->NbNodes() = "<NbNodes()); SMDS_NodeIteratorPtr aNodesIter = myMesh->nodesIterator(); - for(; aNodesIter->more();){ - const SMDS_MeshNode* aNode = aNodesIter->next(); - TRecord aRec; - aRec.coord[0] = aNode->X(); - aRec.coord[1] = aNode->Y(); - aRec.coord[2] = aNode->Z(); - const TNodeLab& aLabel = aNode->GetID(); - aDataSet2411.insert(TDataSet::value_type(aLabel,aRec)); + TRecord aRec; + while ( aNodesIter->more() ) + { + const SMDS_MeshNode* aNode = aNodesIter->next(); + aRec.label = aNode->GetID(); + aRec.coord[0] = aNode->X(); + aRec.coord[1] = aNode->Y(); + aRec.coord[2] = aNode->Z(); + aDataSet2411.push_back( aRec ); } MESSAGE("Perform - aDataSet2411.size() = "<NbEdges() = "<NbEdges()); if(myMesh->NbEdges()){ - SMDS_EdgeIteratorPtr anIter = myMesh->edgesIterator(); - for(; anIter->more();){ - const SMDS_MeshEdge* anElem = anIter->next(); - TElementLab aLabel = anElem->GetID(); - int aNbNodes = anElem->NbNodes(); - TRecord aRec; - aRec.node_labels.reserve(aNbNodes); - SMDS_ElemIteratorPtr aNodesIter; + SMDS_EdgeIteratorPtr anIter = myMesh->edgesIterator(); + while( anIter->more() ) + { + const SMDS_MeshEdge* anElem = anIter->next(); + int aNbNodes = anElem->NbNodes(); + TRecord aRec; + aRec.label = anElem->GetID(); + aRec.node_labels.reserve(aNbNodes); if( anElem->IsQuadratic() ) { - aNodesIter = static_cast - ( anElem )->interlacedNodesElemIterator(); aRec.fe_descriptor_id = 22; } else { - aNodesIter = anElem->nodesIterator(); aRec.fe_descriptor_id = 11; } - for(; aNodesIter->more();){ - const SMDS_MeshElement* aNode = aNodesIter->next(); - aRec.node_labels.push_back(aNode->GetID()); - } - aDataSet2412.insert(TDataSet::value_type(aLabel,aRec)); - } - MESSAGE("Perform - aDataSet2412.size() = "<nodesIteratorToUNV(); + while( aNodesIter->more()) + { + const SMDS_MeshNode* aNode = aNodesIter->next(); + aRec.node_labels.push_back( aNode->GetID() ); + } + aDataSet2412.push_back(aRec); + } + MESSAGE("Perform - aDataSet2412.size() = "<NbFaces() = "<NbFaces()); - if(myMesh->NbFaces()){ - SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); - for(; anIter->more();){ - const SMDS_MeshFace* anElem = anIter->next(); - TElementLab aLabel = anElem->GetID(); - int aNbNodes = anElem->NbNodes(); - TRecord aRec; - aRec.node_labels.reserve(aNbNodes); - SMDS_ElemIteratorPtr aNodesIter; - if( anElem->IsQuadratic() ) - aNodesIter = static_cast - ( anElem )->interlacedNodesElemIterator(); - else - aNodesIter = anElem->nodesIterator(); - for(; aNodesIter->more();){ - const SMDS_MeshElement* aNode = aNodesIter->next(); - aRec.node_labels.push_back(aNode->GetID()); - } - switch(aNbNodes){ - case 3: - aRec.fe_descriptor_id = 41; - break; - case 4: - aRec.fe_descriptor_id = 44; - break; - case 6: - aRec.fe_descriptor_id = 42; - break; - case 8: - aRec.fe_descriptor_id = 45; - break; - default: - continue; - } - aDataSet2412.insert(TDataSet::value_type(aLabel,aRec)); - } - MESSAGE("Perform - aDataSet2412.size() = "<NbFaces() ) + { + SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); + while ( anIter->more()) + { + const SMDS_MeshFace* anElem = anIter->next(); + if ( anElem->IsPoly() ) continue; + int aNbNodes = anElem->NbNodes(); + TRecord aRec; + aRec.label = anElem->GetID(); + aRec.node_labels.reserve(aNbNodes); + SMDS_NodeIteratorPtr aNodesIter = anElem->nodesIteratorToUNV(); + while( aNodesIter->more() ) { + const SMDS_MeshNode* aNode = aNodesIter->next(); + aRec.node_labels.push_back( aNode->GetID() ); + } + switch ( aNbNodes ) { + case 3: aRec.fe_descriptor_id = 41; break; + case 4: aRec.fe_descriptor_id = 44; break; + case 6: aRec.fe_descriptor_id = 42; break; + case 7: aRec.fe_descriptor_id = 42; break; + case 8: aRec.fe_descriptor_id = 45; break; + case 9: aRec.fe_descriptor_id = 45; aRec.node_labels.resize( 8 ); break; + default: + continue; + } + aDataSet2412.push_back(aRec); + } + MESSAGE("Perform - aDataSet2412.size() = "<NbVolumes() = "<NbVolumes()); - if(myMesh->NbVolumes()){ - SMDS_VolumeIteratorPtr anIter = myMesh->volumesIterator(); - for(; anIter->more();){ - const SMDS_MeshVolume* anElem = anIter->next(); - TElementLab aLabel = anElem->GetID(); - - int aNbNodes = anElem->NbNodes(); - SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator(); - if ( anElem->IsPoly() ) { - if ( const SMDS_PolyhedralVolumeOfNodes* ph = - dynamic_cast (anElem)) + if ( myMesh->NbVolumes() ) + { + SMDS_VolumeIteratorPtr anIter = myMesh->volumesIterator(); + while ( anIter->more()) + { + const SMDS_MeshVolume* anElem = anIter->next(); + if ( anElem->IsPoly() ) + continue; + int aNbNodes = anElem->NbNodes(); + int anId = -1; + switch(aNbNodes) { + case 4: anId = 111; break; + case 6: anId = 112; break; + case 8: anId = 115; break; + case 10: anId = 118; break; + case 13: anId = 114; break; + case 15: anId = 113; break; + case 20: + case 27: anId = 116; aNbNodes = 20; break; + default: + continue; + } + if(anId>0){ + TRecord aRec; + aRec.label = anElem->GetID(); + aRec.fe_descriptor_id = anId; + aRec.node_labels.reserve(aNbNodes); + SMDS_NodeIteratorPtr aNodesIter = anElem->nodesIteratorToUNV(); + while ( aNodesIter->more() && aRec.node_labels.size() < aNbNodes ) { - aNbNodes = ph->NbUniqueNodes(); - aNodesIter = ph->uniqueNodesIterator(); + const SMDS_MeshElement* aNode = aNodesIter->next(); + aRec.node_labels.push_back(aNode->GetID()); } + aDataSet2412.push_back(aRec); } - aConnect.resize(aNbNodes); - GetConnect(aNodesIter,aConnect); - - int anId = -1; - int* aConn = NULL; - switch(aNbNodes){ - case 4: { - static int anIds[] = {0,2,1,3}; - aConn = anIds; - anId = 111; - break; - } - case 6: { - static int anIds[] = {0,2,1,3,5,4}; - aConn = anIds; - anId = 112; - break; - } - case 8: { - static int anIds[] = {0,3,2,1,4,7,6,5}; - aConn = anIds; - anId = 115; - break; - } - case 10: { - static int anIds[] = {0,4,2,9,5,3, 1,6,8, 7}; - aConn = anIds; - anId = 118; - break; - } - case 13: { - static int anIds[] = {0,6,4,2,7,5,3,1,8,11,10,9,12}; - aConn = anIds; - anId = 114; - break; - } - case 15: { - static int anIds[] = {0,4,2,9,13,11,5,3,1,14,12,10,6,8,7}; - aConn = anIds; - anId = 113; - break; - } - case 20: { - static int anIds[] = {0,6, 4,2, 12,18,16,14,7, 5, 3, 1, 19,17,15,13,8, 11,10,9}; - aConn = anIds; - anId = 116; - break; - } - default: - continue; - } - if(aConn){ - TRecord aRec; - aRec.fe_descriptor_id = anId; - aRec.node_labels.resize(aNbNodes); - for(int aNodeId = 0; aNodeId < aNbNodes; aNodeId++){ - aRec.node_labels[aConn[aNodeId]] = aConnect[aNodeId]; - } - aDataSet2412.insert(TDataSet::value_type(aLabel,aRec)); - } - } - MESSAGE("Perform - aDataSet2412.size() = "< +#include +#include + +using namespace std; +using namespace UNV; +using namespace UNV164; + +static string _label_dataset = "164"; + +void UNV164::Read(std::ifstream& in_stream, TRecord& theUnitsRecord ) +{ + if(!in_stream.good()) + EXCEPTION(runtime_error,"ERROR: Input file not good."); + + if(!beginning_of_dataset(in_stream,_label_dataset)) + return; + + string num_buf; + char line[theMaxLineLen] = ""; + + in_stream >> theUnitsRecord.units_code; + in_stream.readsome( line, 20 ); + theUnitsRecord.units_description = line; + in_stream >> theUnitsRecord.temp_mode; + + for ( int i = 0; i < 4; i++ ) + { + in_stream >> num_buf; + theUnitsRecord.factors[i] = D_to_e(num_buf); + } +} + +void UNV164::Write(std::ofstream& out_stream) +{ + if(!out_stream.good()) + EXCEPTION(runtime_error,"ERROR: Output file not good."); + + out_stream<<" -1" << endl; + out_stream<<" "<<_label_dataset << endl; + + out_stream<<" 1 SI: Meter (newton) 2" << endl; + out_stream<<" 1.0000000000000000E+0 1.0000000000000000E+0 1.0000000000000000E+0" << endl; + out_stream<<" 2.7314999999999998E+2" << endl; + + out_stream<<" -1" << endl; +} + +UNV164::TRecord::TRecord() +{ + units_code = 1; + units_description = "SI: Meter (newton)"; + temp_mode = 2; + factors[0] = 1.0; + factors[1] = 1.0; + factors[2] = 1.0; + factors[3] = 273.15; +} diff --git a/src/3rdParty/salomesmesh/src/DriverUNV/UNV2411_Structure.cpp b/src/3rdParty/salomesmesh/src/DriverUNV/UNV2411_Structure.cpp index 55ad1cec2461..89a80abd6430 100644 --- a/src/3rdParty/salomesmesh/src/DriverUNV/UNV2411_Structure.cpp +++ b/src/3rdParty/salomesmesh/src/DriverUNV/UNV2411_Structure.cpp @@ -1,26 +1,27 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -#include -#include + +#include +#include #include "UNV2411_Structure.hxx" #include "UNV_Utilities.hxx" @@ -32,10 +33,12 @@ using namespace UNV2411; static string _label_dataset = "2411"; UNV2411::TRecord::TRecord(): - exp_coord_sys_num(0), - disp_coord_sys_num(0), + exp_coord_sys_num(1), + disp_coord_sys_num(1), color(11)//(0) - 0019936: EDF 794 SMESH : Export UNV : Node color and group id -{} +{ + coord[1] = coord[2] = 0.0; // prepare to e.g. 2D mesh +} void UNV2411::Read(std::ifstream& in_stream, TDataSet& theDataSet) { @@ -53,16 +56,49 @@ void UNV2411::Read(std::ifstream& in_stream, TDataSet& theDataSet) * always 3 coordinates in the UNV file, no matter * which dimensionality libMesh is in */ - TNodeLab aLabel; + int dim = 3; std::string num_buf; - for(; !in_stream.eof();){ - in_stream >> aLabel ; - if(aLabel == -1){ + + // Issue 22638. Find out space dimension to read a 2D mesh from a file + // generated by SIMAIL from Simulog + if ( !in_stream.eof() ) + { + int where = in_stream.tellg(); + + TRecord aRec; + in_stream >> aRec.label ; + if ( aRec.label == -1 ) return; // dataset end + + dim = 0; + num_buf = read_line( in_stream ); + for ( size_t i = 0; i < num_buf.size(); ) + { + // skip spaces + while ( i < num_buf.size() && num_buf[i] == ' ' ) + ++i; + + dim += ( i < num_buf.size() ); + + // skip non-spaces + while ( i < num_buf.size() && num_buf[i] != ' ' ) + ++i; + } + if ( dim == 0 ) + return; + + in_stream.seekg( where, in_stream.beg ); + } + + // read the rest records + while ( !in_stream.eof() ) + { + TRecord aRec; + in_stream >> aRec.label ; + if ( aRec.label == -1 ) { // end of dataset is reached break; } - TRecord aRec; in_stream>>aRec.exp_coord_sys_num; in_stream>>aRec.disp_coord_sys_num; in_stream>>aRec.color; @@ -71,12 +107,12 @@ void UNV2411::Read(std::ifstream& in_stream, TDataSet& theDataSet) * take care of the * floating-point data */ - for(int d = 0; d < 3; d++){ + for(int d = 0; d < dim; d++){ in_stream>>num_buf; aRec.coord[d] = D_to_e(num_buf); } - theDataSet.insert(TDataSet::value_type(aLabel,aRec)); + theDataSet.push_back(aRec); } } @@ -93,22 +129,22 @@ void UNV2411::Write(std::ofstream& out_stream, const TDataSet& theDataSet) out_stream<<" "<<_label_dataset<<"\n"; TDataSet::const_iterator anIter = theDataSet.begin(); - for(; anIter != theDataSet.end(); anIter++){ - const TNodeLab& aLabel = anIter->first; - const TRecord& aRec = anIter->second; + for(; anIter != theDataSet.end(); anIter++) + { + const TRecord& aRec = *anIter; char buf[78]; sprintf(buf, "%10d%10d%10d%10d\n", - aLabel, - aRec.exp_coord_sys_num, - aRec.disp_coord_sys_num, - aRec.color); + aRec.label, + aRec.exp_coord_sys_num, + aRec.disp_coord_sys_num, + aRec.color); out_stream< + +#include #include #include "UNV2412_Structure.hxx" @@ -29,21 +30,167 @@ using namespace std; using namespace UNV; using namespace UNV2412; -#ifdef _DEBUG_ -static int MYDEBUG = 1; -#else -static int MYDEBUG = 0; -#endif +// Universal Dataset Number 2412 + +// Name: Elements +// Status: Current +// Owner: Simulation +// Revision Date: 14-AUG-1992 +// ----------------------------------------------------------------------- + +// Record 1: FORMAT(6I10) +// Field 1 -- element label +// Field 2 -- fe descriptor id +// Field 3 -- physical property table number +// Field 4 -- material property table number +// Field 5 -- color +// Field 6 -- number of nodes on element + +// Record 2: *** FOR NON-BEAM ELEMENTS *** +// FORMAT(8I10) +// Fields 1-n -- node labels defining element + +// Record 2: *** FOR BEAM ELEMENTS ONLY *** +// FORMAT(3I10) +// Field 1 -- beam orientation node number +// Field 2 -- beam fore-end cross section number +// Field 3 -- beam aft-end cross section number + +// Record 3: *** FOR BEAM ELEMENTS ONLY *** +// FORMAT(8I10) +// Fields 1-n -- node labels defining element + +// Records 1 and 2 are repeated for each non-beam element in the model. +// Records 1 - 3 are repeated for each beam element in the model. + +// Example: + +// -1 +// 2412 +// 1 11 1 5380 7 2 +// 0 1 1 +// 1 2 +// 2 21 2 5380 7 2 +// 0 1 1 +// 3 4 +// 3 22 3 5380 7 2 +// 0 1 2 +// 5 6 +// 6 91 6 5380 7 3 +// 11 18 12 +// 9 95 6 5380 7 8 +// 22 25 29 30 31 26 24 23 +// 14 136 8 0 7 2 +// 53 54 +// 36 116 16 5380 7 20 +// 152 159 168 167 166 158 150 151 +// 154 170 169 153 157 161 173 172 +// 171 160 155 156 +// -1 + +// FE Descriptor Id definitions +// ____________________________ + +// 11 Rod +// 21 Linear beam +// 22 Tapered beam +// 23 Curved beam +// 24 Parabolic beam +// 31 Straight pipe +// 32 Curved pipe +// 41 Plane Stress Linear Triangle +// 42 Plane Stress Parabolic Triangle +// 43 Plane Stress Cubic Triangle +// 44 Plane Stress Linear Quadrilateral +// 45 Plane Stress Parabolic Quadrilateral +// 46 Plane Strain Cubic Quadrilateral +// 51 Plane Strain Linear Triangle +// 52 Plane Strain Parabolic Triangle +// 53 Plane Strain Cubic Triangle +// 54 Plane Strain Linear Quadrilateral +// 55 Plane Strain Parabolic Quadrilateral +// 56 Plane Strain Cubic Quadrilateral +// 61 Plate Linear Triangle +// 62 Plate Parabolic Triangle +// 63 Plate Cubic Triangle +// 64 Plate Linear Quadrilateral +// 65 Plate Parabolic Quadrilateral +// 66 Plate Cubic Quadrilateral +// 71 Membrane Linear Quadrilateral +// 72 Membrane Parabolic Triangle +// 73 Membrane Cubic Triangle +// 74 Membrane Linear Triangle +// 75 Membrane Parabolic Quadrilateral +// 76 Membrane Cubic Quadrilateral +// 81 Axisymetric Solid Linear Triangle +// 82 Axisymetric Solid Parabolic Triangle +// 84 Axisymetric Solid Linear Quadrilateral +// 85 Axisymetric Solid Parabolic Quadrilateral +// 91 Thin Shell Linear Triangle +// 92 Thin Shell Parabolic Triangle +// 93 Thin Shell Cubic Triangle +// 94 Thin Shell Linear Quadrilateral +// 95 Thin Shell Parabolic Quadrilateral +// 96 Thin Shell Cubic Quadrilateral +// 101 Thick Shell Linear Wedge +// 102 Thick Shell Parabolic Wedge +// 103 Thick Shell Cubic Wedge +// 104 Thick Shell Linear Brick +// 105 Thick Shell Parabolic Brick +// 106 Thick Shell Cubic Brick +// 111 Solid Linear Tetrahedron +// 112 Solid Linear Wedge +// 113 Solid Parabolic Wedge +// 114 Solid Cubic Wedge +// 115 Solid Linear Brick +// 116 Solid Parabolic Brick +// 117 Solid Cubic Brick +// 118 Solid Parabolic Tetrahedron +// 121 Rigid Bar +// 122 Rigid Element +// 136 Node To Node Translational Spring +// 137 Node To Node Rotational Spring +// 138 Node To Ground Translational Spring +// 139 Node To Ground Rotational Spring +// 141 Node To Node Damper +// 142 Node To Gound Damper +// 151 Node To Node Gap +// 152 Node To Ground Gap +// 161 Lumped Mass +// 171 Axisymetric Linear Shell +// 172 Axisymetric Parabolic Shell +// 181 Constraint +// 191 Plastic Cold Runner +// 192 Plastic Hot Runner +// 193 Plastic Water Line +// 194 Plastic Fountain +// 195 Plastic Baffle +// 196 Plastic Rod Heater +// 201 Linear node-to-node interface +// 202 Linear edge-to-edge interface +// 203 Parabolic edge-to-edge interface +// 204 Linear face-to-face interface +// 208 Parabolic face-to-face interface +// 212 Linear axisymmetric interface +// 213 Parabolic axisymmetric interface +// 221 Linear rigid surface +// 222 Parabolic rigin surface +// 231 Axisymetric linear rigid surface +// 232 Axisymentric parabolic rigid surface + + static string _label_dataset = "2412"; UNV2412::TRecord::TRecord(): + label(-1), + fe_descriptor_id(-1), phys_prop_tab_num(2), mat_prop_tab_num(1), color(7), beam_orientation(0), - beam_fore_end(0), - beam_aft_end(0) + beam_fore_end(1), // default values + beam_aft_end(1) // default values {} void UNV2412::Read(std::ifstream& in_stream, TDataSet& theDataSet) @@ -58,16 +205,15 @@ void UNV2412::Read(std::ifstream& in_stream, TDataSet& theDataSet) if(!beginning_of_dataset(in_stream,_label_dataset)) EXCEPTION(runtime_error,"ERROR: Could not find "<<_label_dataset<<" dataset!"); - TElementLab aLabel; - for(; !in_stream.eof();){ - in_stream >> aLabel ; - if(aLabel == -1){ + TRecord aRec; + while( !in_stream.eof()) + { + in_stream >> aRec.label ; + if (aRec.label == -1) // end of dataset is reached break; - } int n_nodes; - TRecord aRec; in_stream>>aRec.fe_descriptor_id; in_stream>>aRec.phys_prop_tab_num; in_stream>>aRec.mat_prop_tab_num; @@ -81,12 +227,11 @@ void UNV2412::Read(std::ifstream& in_stream, TDataSet& theDataSet) } aRec.node_labels.resize(n_nodes); - for(int j=0; j < n_nodes; j++){ + for(int j=0; j < n_nodes; j++) // read node labels in_stream>>aRec.node_labels[j]; - } - theDataSet.insert(TDataSet::value_type(aLabel,aRec)); + theDataSet.push_back(aRec); } } @@ -104,17 +249,18 @@ void UNV2412::Write(std::ofstream& out_stream, const TDataSet& theDataSet) out_stream<<" "<<_label_dataset<<"\n"; TDataSet::const_iterator anIter = theDataSet.begin(); - for(; anIter != theDataSet.end(); anIter++){ - const TElementLab& aLabel = anIter->first; - const TRecord& aRec = anIter->second; - out_stream< +#include #include using namespace std; using namespace UNV; using namespace UNV2417; -#ifdef _DEBUG_ -static int MYDEBUG = 0; -#else -static int MYDEBUG = 0; -#endif - - static string _group_labels[] = {"2417", "2429", "2430", "2432", - "2435", "2452", "2467", "2477"}; + "2435", "2452", "2467", "2477"}; #define NBGROUP 8 static string _label_dataset = "2467"; @@ -55,7 +49,7 @@ void UNV2417::Read(std::ifstream& in_stream, TDataSet& theDataSet) * a "-1" followed by a number means the beginning of a dataset * stop combing at the end of the file */ - while( ((olds != "-1") || (news == "-1") ) && !in_stream.eof() ){ + while( ((olds != "-1") || (news == "-1") ) && !in_stream.eof() ){ olds = news; in_stream >> news; } @@ -63,7 +57,7 @@ void UNV2417::Read(std::ifstream& in_stream, TDataSet& theDataSet) return; for (int i = 0; i < NBGROUP; i++) { if (news == _group_labels[i]) { - ReadGroup(news, in_stream, theDataSet); + ReadGroup(news, in_stream, theDataSet); } } } @@ -102,23 +96,23 @@ void UNV2417::ReadGroup(const std::string& myGroupLabel, std::ifstream& in_strea in_stream>>aElType; in_stream>>aElId; if ((myGroupLabel.compare("2435") == 0) || - (myGroupLabel.compare("2452") == 0) || - (myGroupLabel.compare("2467") == 0) || - (myGroupLabel.compare("2477") == 0)) { - in_stream>>aTmp; - in_stream>>aTmp; + (myGroupLabel.compare("2452") == 0) || + (myGroupLabel.compare("2467") == 0) || + (myGroupLabel.compare("2477") == 0)) { + in_stream>>aTmp; + in_stream>>aTmp; } switch (aElType) { case 7: // Nodes - aNum = aRec.NodeList.size(); - aRec.NodeList.resize(aNum + 1); - aRec.NodeList[aNum] = aElId; - break; + aNum = aRec.NodeList.size(); + aRec.NodeList.resize(aNum + 1); + aRec.NodeList[aNum] = aElId; + break; case 8: // Elements - aNum = aRec.ElementList.size(); - aRec.ElementList.resize(aNum + 1); - aRec.ElementList[aNum] = aElId; - break; + aNum = aRec.ElementList.size(); + aRec.ElementList.resize(aNum + 1); + aRec.ElementList[aNum] = aElId; + break; } } theDataSet.insert(TDataSet::value_type(aId,aRec)); @@ -160,8 +154,8 @@ void UNV2417::Write(std::ofstream& out_stream, const TDataSet& theDataSet) int i; for (i = 0; i < aNbNodes; i++) { if (aRow == 2) { - out_stream< +#include +#include + +using namespace std; +using namespace UNV; +using namespace UNV2420; + +static string _label_dataset = "2420"; + +void UNV2420::Read(std::ifstream& in_stream, + std::string& part_name, // can re-store a mesh name + TDataSet& theDataSet) +{ + if(!in_stream.good()) + EXCEPTION(runtime_error,"ERROR: Input file not good."); + + /* + * adjust the \p istream to our + * position + */ + if(!beginning_of_dataset(in_stream,_label_dataset)) + return; + + string num_buf; + int part_uid; + + in_stream >> part_uid; // Record 1 + part_name = read_line( in_stream ); // Record 2 + + while ( !in_stream.eof() ) + { + TRecord aRec; + + // Record 3 + in_stream >> aRec.coord_sys_label; + if ( aRec.coord_sys_label == -1 ) // end of dataset is reached + break; + in_stream >> aRec.coord_sys_type; + in_stream >> aRec.coord_sys_color; + + aRec.coord_sys_name = read_line( in_stream ); // Record 4 + + // Records 5-8: rows of Transformation Matrix + for ( int row = 0; row < 4; ++row ) + for ( int i = 0; i < 3; i++ ) + { + in_stream >> num_buf; + aRec.matrix[row][i] = D_to_e(num_buf); + } + // Store a CS data only if it requires conversion into the global Cartesian CS + if ( aRec.coord_sys_type != 0 || !aRec.isIdentityMatrix() ) // 0 - Cartesian CS + theDataSet.push_back( aRec ); + } +} + + +void UNV2420::Write(std::ofstream& out_stream, + const std::string& part_name) +// const TDataSet& theDataSet) +{ + if(!out_stream.good()) + EXCEPTION(runtime_error,"ERROR: Output file not good."); + + out_stream<<" -1" << endl; + out_stream<<" "<<_label_dataset << endl; + + out_stream<<" 1" << endl; // R1: Part UID + if ( part_name.empty() ) + out_stream<<"SMESH_Mesh" << endl; // R2: Part Name + else + out_stream<< part_name << endl; + out_stream<<" 1 0 0" << endl; // R3: Label, Type, Color + + out_stream<<"Global Cartesian Coordinate System" << endl; // R4: Name + out_stream<<" 1.0000000000000000E+0 0.0000000000000000E+0 0.0000000000000000E+0" << endl; + out_stream<<" 0.0000000000000000E+0 1.0000000000000000E+0 0.0000000000000000E+0" << endl; + out_stream<<" 0.0000000000000000E+0 0.0000000000000000E+0 1.0000000000000000E+0" << endl; + out_stream<<" 0.0000000000000000E+0 0.0000000000000000E+0 0.0000000000000000E+0" << endl; + + out_stream<<" -1" << endl; +} + + +bool UNV2420::TRecord::isIdentityMatrix() const +{ + bool isIdentity = true; + for ( int row = 0; row < 4 && isIdentity; ++row ) + for ( int i = 0; i < 3; i++ ) + { + if ( matrix[row][i] != ( row==i ? 1. : 0. )) + { + isIdentity = false; + break; + } + } + return isIdentity; +} + +void UNV2420::TRecord::ApplyMatrix( double* c ) const +{ + const double x = matrix[0][0] * c[0] + matrix[0][1] * c[1] + matrix[0][2] * c[2]; + const double y = matrix[1][0] * c[0] + matrix[1][1] * c[1] + matrix[1][2] * c[2]; + const double z = matrix[2][0] * c[0] + matrix[2][1] * c[1] + matrix[2][2] * c[2]; + c[0] = x + matrix[3][0]; + c[1] = y + matrix[3][1]; + c[2] = z + matrix[3][2]; +} + +void UNV2420::TRecord::FromCylindricalCS( double* coords ) +{ + const double x = coords[0] * cos( coords[1] ); + const double y = coords[0] * sin( coords[1] ); + coords[0] = x; + coords[1] = y; +} + +void UNV2420::TRecord::FromSphericalCS ( double* coords ) +{ + const double sin2 = sin( coords[2] ); + const double x = coords[0] * cos( coords[1] ) * sin2; + const double y = coords[0] * sin( coords[1] ) * sin2; + const double z = coords[0] * cos( coords[2] ); + coords[0] = x; + coords[1] = y; + coords[2] = z; +} diff --git a/src/3rdParty/salomesmesh/src/DriverUNV/UNV_Utilities.cpp b/src/3rdParty/salomesmesh/src/DriverUNV/UNV_Utilities.cpp index 2928bd1003f8..546e98d3ffae 100644 --- a/src/3rdParty/salomesmesh/src/DriverUNV/UNV_Utilities.cpp +++ b/src/3rdParty/salomesmesh/src/DriverUNV/UNV_Utilities.cpp @@ -1,34 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + #include "UNV_Utilities.hxx" using namespace std; -#ifdef _DEBUG_ -static int MYDEBUG = 1; -#else -static int MYDEBUG = 0; -#endif - int UNV::PrefixPrinter::myCounter = 0; diff --git a/src/3rdParty/salomesmesh/src/MEFISTO2/aptrte.cpp b/src/3rdParty/salomesmesh/src/MEFISTO2/aptrte.cpp index ce1e7bf77c0a..ca2474262911 100644 --- a/src/3rdParty/salomesmesh/src/MEFISTO2/aptrte.cpp +++ b/src/3rdParty/salomesmesh/src/MEFISTO2/aptrte.cpp @@ -1,46 +1,49 @@ // MEFISTO2: a library to compute 2D triangulation from segmented boundaries // // -// Copyright (C) 2006 Laboratoire J.-L. Lions UPMC Paris +// Copyright (C) 2006-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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.ann.jussieu.fr/~perronne or email Perronnet@ann.jussieu.fr +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // // File : aptrte.cxx le C++ de l'appel du trianguleur plan // Module : SMESH // Author : Alain PERRONNET // Date : 13 novembre 2006 - #include "Rn.h" #include "aptrte.h" #include "utilities.h" - using namespace std; extern "C" { R aretemaxface_; MEFISTO2D_EXPORT - void - MEFISTO2D_STDCALL - areteideale(R &_areteideale) + R + #ifdef WIN32 + #ifdef F2C_BUILD + #else + __stdcall + #endif + #endif + areteideale()//( R3 xyz, R3 direction ) { - _areteideale = aretemaxface_; + return aretemaxface_; } } //calcul de la longueur ideale de l'arete au sommet xyz (z ici inactif) @@ -50,7 +53,14 @@ extern "C" static double cpunew, cpuold=0; -void MEFISTO2D_STDCALL tempscpu_( double & tempsec ) +void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif +tempscpu_( double & tempsec ) //Retourne le temps CPU utilise en secondes { tempsec = ( (double) clock() ) / CLOCKS_PER_SEC; @@ -58,7 +68,14 @@ void MEFISTO2D_STDCALL tempscpu_( double & tempsec ) } -void MEFISTO2D_STDCALL deltacpu_( R & dtcpu ) +void +#ifdef WIN32 +#ifdef F2C_BUILD +#else + __stdcall +#endif +#endif +deltacpu_( R & dtcpu ) //Retourne le temps CPU utilise en secondes depuis le precedent appel { tempscpu_( cpunew ); @@ -70,11 +87,11 @@ void MEFISTO2D_STDCALL deltacpu_( R & dtcpu ) void aptrte( Z nutysu, R aretmx, - Z nblf, Z * nudslf, R2 * uvslf, - Z nbpti, R2 * uvpti, - Z & nbst, R2 * & uvst, - Z & nbt, Z * & nust, - Z & ierr ) + Z nblf, Z * nudslf, R2 * uvslf, + Z nbpti, R2 * uvpti, + Z & nbst, R2 * & uvst, + Z & nbt, Z * & nust, + Z & ierr ) //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // but : appel de la triangulation par un arbre-4 recouvrant // ----- de triangles equilateraux @@ -124,7 +141,7 @@ void aptrte( Z nutysu, R aretmx, //no st1, st2, st3, 0 (non quadrangle) R d, tcpu=0; - R3 direction=R3(0,0,0); //direction pour areteideale() inactive ici! +// R3 direction=R3(0,0,0); //direction pour areteideale() inactive ici! Z nbarfr=nudslf[nblf]; //nombre total d'aretes des lignes fermees Z mxtrou = Max( 1024, nblf ); //nombre maximal de trous dans la surface @@ -167,7 +184,7 @@ void aptrte( Z nutysu, R aretmx, mxsomm = Max( 20000, 64*nbpti+i*i ); MESSAGE( "APTRTE: Debut de la triangulation plane avec " ); MESSAGE( "nutysu=" << nutysu << " aretmx=" << aretmx - << " mxsomm=" << mxsomm ); + << " mxsomm=" << mxsomm ); MESSAGE( nbarfr << " sommets sur la frontiere et " << nbpti << " points internes"); NEWDEPART: @@ -228,9 +245,9 @@ void aptrte( Z nutysu, R aretmx, ns0 = nudslf[n-1]; mnpxyd[ns0].x = uvslf[ns0].x; mnpxyd[ns0].y = uvslf[ns0].y; - areteideale(mnpxyd[ns0].z);//( mnpxyd[ns0], direction ); + mnpxyd[ns0].z = areteideale();//( mnpxyd[ns0], direction ); // MESSAGE("Sommet " << ns0 << ": " << mnpxyd[ns0].x -// << " " << mnpxyd[ns0].y << " longueur arete=" << mnpxyd[ns0].z); +// << " " << mnpxyd[ns0].y << " longueur arete=" << mnpxyd[ns0].z); //carre de la longueur de l'arete 1 de la ligne fermee n d = pow( uvslf[ns0+1].x - uvslf[ns0].x, 2 ) @@ -251,8 +268,8 @@ void aptrte( Z nutysu, R aretmx, //le numero n de la ligne du sommet et son numero ns1 dans la ligne mnslig[ns0-1] = 1000000 * n + ns1-nudslf[n-1]; fasoar( ns1, ns2, moins1, moins1, n, - mosoar, mxsoar, n1soar, mnsoar, mnarst, - noar0, ierr ); + mosoar, mxsoar, n1soar, mnsoar, mnarst, + noar0, ierr ); //pas de test sur ierr car pas de saturation possible a ce niveau //le pointeur dans le hachage sur la premiere arete de la ligne fermee n @@ -269,11 +286,11 @@ void aptrte( Z nutysu, R aretmx, { ns1 = ns2; //le numero de l'arete et le numero du premier sommet de l'arete if( i < nbarli ) - //nbs+1 est le 2-eme sommet de l'arete i de la ligne fermee n - ns2 = ns1+1; + //nbs+1 est le 2-eme sommet de l'arete i de la ligne fermee n + ns2 = ns1+1; else - //le 2-eme sommet de la derniere arete est le premier sommet de la ligne - ns2 = ns0; + //le 2-eme sommet de la derniere arete est le premier sommet de la ligne + ns2 = ns0; //l'arete precedente est dotee de sa suivante:celle cree ensuite //les 2 coordonnees du sommet ns2 de la ligne @@ -281,11 +298,11 @@ void aptrte( Z nutysu, R aretmx, //debut ajout 5/10/2006 ................................................ nuds = Max( nuds, ns ); //le numero du dernier sommet traite //fin ajout 5/10/2006 ................................................ - mnpxyd[ns].x = uvslf[ns].x; - mnpxyd[ns].y = uvslf[ns].y; - areteideale(mnpxyd[ns].z );//( mnpxyd[ns], direction ); - MESSAGE("Sommet " << ns << ": " << mnpxyd[ns].x - << " " << mnpxyd[ns].y << " longueur arete=" << mnpxyd[ns].z); + mnpxyd[ns].x = uvslf[ns].x; + mnpxyd[ns].y = uvslf[ns].y; + mnpxyd[ns].z = areteideale();//( mnpxyd[ns], direction ); +// MESSAGE("Sommet " << ns << ": " << mnpxyd[ns].x +// << " " << mnpxyd[ns].y << " longueur arete=" << mnpxyd[ns].z); //carre de la longueur de l'arete d = pow( uvslf[ns2-1].x - uvslf[ns1-1].x, 2) @@ -306,8 +323,8 @@ void aptrte( Z nutysu, R aretmx, //ajout de l'arete dans la liste fasoar( ns1, ns2, moins1, moins1, n, - mosoar, mxsoar, n1soar, mnsoar, - mnarst, noar, ierr ); + mosoar, mxsoar, n1soar, mnsoar, + mnarst, noar, ierr ); //pas de test sur ierr car pas de saturation possible a ce niveau //chainage des aretes frontalieres en position 6 du tableau mnsoar @@ -351,7 +368,7 @@ void aptrte( Z nutysu, R aretmx, MESSAGE("Sur le bord: arete min=" << aremin << " arete max=" << aremax ); MESSAGE("Triangulation: arete mx=" << aretmx - << " triangle aire mx=" << airemx ); + << " triangle aire mx=" << airemx ); //chainage des aretes frontalieres : la derniere arete frontaliere mnsoar[ mosoar * noar - mosoar + 5 ] = 0; @@ -375,7 +392,7 @@ void aptrte( Z nutysu, R aretmx, //les 2 coordonnees du point i de sommet nbs mnpxyd[ns1].x = uvpti[i].x; mnpxyd[ns1].y = uvpti[i].y; - areteideale(mnpxyd[ns1].z);//( mnpxyd[ns1], direction ); + mnpxyd[ns1].z = areteideale();//( mnpxyd[ns1], direction ); //le numero i du point interne mnslig[ns1] = i+1; ns1++; @@ -398,6 +415,8 @@ void aptrte( Z nutysu, R aretmx, if( mntree==NULL ) goto ERREUR; //initialisation du tableau letree et ajout dans letree des sommets 1 a nbsomm + comxmi[0].x = comxmi[1].x = uvslf[0].x; + comxmi[0].y = comxmi[1].y = uvslf[0].y; teajte( mxsomm, nbsomm, mnpxyd, comxmi, aretmx, mxtree, mntree, ierr ); comxmi[0].z=0; comxmi[1].z=0; @@ -427,9 +446,9 @@ void aptrte( Z nutysu, R aretmx, if( mnqueu==NULL) goto ERREUR; tehote( nutysu, nbarpi, mxsomm, nbsomm, mnpxyd, - comxmi, aretmx, - mntree, mxqueu, mnqueu, - ierr ); + comxmi, aretmx, + mntree, mxqueu, mnqueu, + ierr ); deltacpu_( d ); tcpu += d; @@ -454,9 +473,9 @@ void aptrte( Z nutysu, R aretmx, // et des points de la frontiere, des points internes imposes interieurs // ========================================================================== tetrte( comxmi, aretmx, nbarpi, mxsomm, mnpxyd, - mxqueu, mnqueu, mntree, mosoar, mxsoar, n1soar, mnsoar, - moartr, mxartr, n1artr, mnartr, mnarst, - ierr ); + mxqueu, mnqueu, mntree, mosoar, mxsoar, n1soar, mnsoar, + moartr, mxartr, n1artr, mnartr, mnarst, + ierr ); // destruction de la queue et de l'arbre devenus inutiles delete [] mnqueu; mnqueu=NULL; @@ -476,7 +495,7 @@ void aptrte( Z nutysu, R aretmx, //qualites de la triangulation actuelle qualitetrte( mnpxyd, mosoar, mxsoar, mnsoar, moartr, mxartr, mnartr, - nbt, quamoy, quamin ); + nbt, quamoy, quamin ); // boucle sur les aretes internes (non sur une ligne de la frontiere) // avec echange des 2 diagonales afin de rendre la triangulation delaunay @@ -484,8 +503,8 @@ void aptrte( Z nutysu, R aretmx, // formation du chainage 6 des aretes internes a echanger eventuellement aisoar( mosoar, mxsoar, mnsoar, na ); tedela( mnpxyd, mnarst, - mosoar, mxsoar, n1soar, mnsoar, na, - moartr, mxartr, n1artr, mnartr, n ); + mosoar, mxsoar, n1soar, mnsoar, na, + moartr, mxartr, n1artr, mnartr, n ); MESSAGE( "Nombre d'echanges des diagonales de 2 triangles=" << n ); deltacpu_( d ); @@ -495,7 +514,7 @@ void aptrte( Z nutysu, R aretmx, //qualites de la triangulation actuelle qualitetrte( mnpxyd, mosoar, mxsoar, mnsoar, moartr, mxartr, mnartr, - nbt, quamoy, quamin ); + nbt, quamoy, quamin ); // detection des aretes frontalieres initiales perdues // triangulation frontale pour les restaurer @@ -515,10 +534,10 @@ void aptrte( Z nutysu, R aretmx, if( mnarcf2 == NULL ) goto ERREUR; terefr( nbarpi, mnpxyd, - mosoar, mxsoar, n1soar, mnsoar, - moartr, mxartr, n1artr, mnartr, mnarst, - mxarcf, mn1arcf, mnarcf, mnarcf1, mnarcf2, - n, ierr ); + mosoar, mxsoar, n1soar, mnsoar, + moartr, mxartr, n1artr, mnartr, mnarst, + mxarcf, mn1arcf, mnarcf, mnarcf1, mnarcf2, + n, ierr ); MESSAGE( "Restauration de " << n << " aretes perdues de la frontiere ierr=" << ierr ); deltacpu_( d ); @@ -530,7 +549,7 @@ void aptrte( Z nutysu, R aretmx, //qualites de la triangulation actuelle qualitetrte( mnpxyd, mosoar, mxsoar, mnsoar, moartr, mxartr, mnartr, - nbt, quamoy, quamin ); + nbt, quamoy, quamin ); // fin de la triangulation avec respect des aretes initiales frontalieres @@ -556,10 +575,10 @@ void aptrte( Z nutysu, R aretmx, mnlftr[n] = n+1; tesuex( nblf, mnlftr, - ndtri0, nbsomm, mnpxyd, mnslig, - mosoar, mxsoar, mnsoar, - moartr, mxartr, n1artr, mnartr, mnarst, - nbt, mntrsu, ierr ); + ndtri0, nbsomm, mnpxyd, mnslig, + mosoar, mxsoar, mnsoar, + moartr, mxartr, n1artr, mnartr, mnarst, + nbt, mntrsu, ierr ); delete [] mnlftr; mnlftr=NULL; delete [] mntrsu; mntrsu=NULL; @@ -571,7 +590,7 @@ void aptrte( Z nutysu, R aretmx, //qualites de la triangulation actuelle qualitetrte( mnpxyd, mosoar, mxsoar, mnsoar, moartr, mxartr, mnartr, - nbt, quamoy, quamin ); + nbt, quamoy, quamin ); // amelioration de la qualite de la triangulation par // barycentrage des sommets internes a la triangulation @@ -586,12 +605,12 @@ void aptrte( Z nutysu, R aretmx, goto ERREUR; } teamqt( nutysu, aretmx, airemx, - mnarst, mosoar, mxsoar, n1soar, mnsoar, - moartr, mxartr, n1artr, mnartr, - mxarcf, mnarcf2, mnarcf3, - mn1arcf, mnarcf, mnarcf1, - nbarpi, nbsomm, mxsomm, mnpxyd, mnslig, - ierr ); + mnarst, mosoar, mxsoar, n1soar, mnsoar, + moartr, mxartr, n1artr, mnartr, + mxarcf, mnarcf2, mnarcf3, + mn1arcf, mnarcf, mnarcf1, + nbarpi, nbsomm, mxsomm, mnpxyd, mnslig, + ierr ); if( mnarcf3 != NULL ) {delete [] mnarcf3; mnarcf3=NULL;} if( mn1arcf != NULL ) {delete [] mn1arcf; mn1arcf=NULL;} if( mnarcf != NULL ) {delete [] mnarcf; mnarcf =NULL;} @@ -606,7 +625,7 @@ void aptrte( Z nutysu, R aretmx, //qualites de la triangulation finale qualitetrte( mnpxyd, mosoar, mxsoar, mnsoar, moartr, mxartr, mnartr, - nbt, quamoy, quamin ); + nbt, quamoy, quamin ); // renumerotation des sommets internes: mnarst(i)=numero final du sommet // =================================== @@ -652,22 +671,22 @@ void aptrte( Z nutysu, R aretmx, n = mnslig[i]; if( n > 0 ) { - if( n >= 1000000 ) - { - //sommet d'une ligne - //retour aux coordonnees initiales dans uvslf - l = n / 1000000; - n = n - 1000000 * l + nudslf[l-1] - 1; - uvst[nbst].x = uvslf[n].x; - uvst[nbst].y = uvslf[n].y; - } - else - { - //point utilisateur n interne impose - //retour aux coordonnees initiales dans uvpti - uvst[nbst].x = uvpti[n-1].x; - uvst[nbst].y = uvpti[n-1].y; - } + if( n >= 1000000 ) + { + //sommet d'une ligne + //retour aux coordonnees initiales dans uvslf + l = n / 1000000; + n = n - 1000000 * l + nudslf[l-1] - 1; + uvst[nbst].x = uvslf[n].x; + uvst[nbst].y = uvslf[n].y; + } + else + { + //point utilisateur n interne impose + //retour aux coordonnees initiales dans uvpti + uvst[nbst].x = uvpti[n-1].x; + uvst[nbst].y = uvpti[n-1].y; + } } } } @@ -695,7 +714,7 @@ void aptrte( Z nutysu, R aretmx, } nbt /= nbsttria; //le nombre final de triangles de la surface MESSAGE( "APTRTE: Fin de la triangulation plane avec "< using namespace std; @@ -38,16 +43,22 @@ using namespace std; NETGENPlugin_Hypothesis::NETGENPlugin_Hypothesis (int hypId, int studyId, SMESH_Gen * gen) : SMESH_Hypothesis(hypId, studyId, gen), - _maxSize (GetDefaultMaxSize()), - _growthRate (GetDefaultGrowthRate()), - _nbSegPerEdge (GetDefaultNbSegPerEdge()), - _nbSegPerRadius(GetDefaultNbSegPerRadius()), - _fineness (GetDefaultFineness()), - _secondOrder (GetDefaultSecondOrder()), - _optimize (GetDefaultOptimize()) + _maxSize (GetDefaultMaxSize()), + _minSize (0), + _growthRate (GetDefaultGrowthRate()), + _nbSegPerEdge (GetDefaultNbSegPerEdge()), + _nbSegPerRadius (GetDefaultNbSegPerRadius()), + _fineness (GetDefaultFineness()), + _secondOrder (GetDefaultSecondOrder()), + _optimize (GetDefaultOptimize()), + _localSize (GetDefaultLocalSize()), + _quadAllowed (GetDefaultQuadAllowed()), + _surfaceCurvature(GetDefaultSurfaceCurvature()), + _fuseEdges (GetDefaultFuseEdges()) { _name = "NETGEN_Parameters"; _param_algo_dim = 3; + _localSize.clear(); } //============================================================================= @@ -64,6 +75,20 @@ void NETGENPlugin_Hypothesis::SetMaxSize(double theSize) } } +//============================================================================= +/*! + * + */ +//============================================================================= +void NETGENPlugin_Hypothesis::SetMinSize(double theSize) +{ + if (theSize != _minSize) + { + _minSize = theSize; + NotifySubMeshesHypothesisModification(); + } +} + //============================================================================= /*! * @@ -188,6 +213,117 @@ void NETGENPlugin_Hypothesis::SetNbSegPerRadius(double theVal) * */ //============================================================================= +void NETGENPlugin_Hypothesis::SetLocalSizeOnEntry(const std::string& entry, double localSize) +{ + if(_localSize[entry] != localSize) + { + _localSize[entry] = localSize; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= +double NETGENPlugin_Hypothesis::GetLocalSizeOnEntry(const std::string& entry) +{ + TLocalSize::iterator it = _localSize.find( entry ); + if ( it != _localSize.end() ) + return it->second; + else + return -1.0; +} + +//============================================================================= +/*! + * + */ +//============================================================================= +void NETGENPlugin_Hypothesis::UnsetLocalSizeOnEntry(const std::string& entry) +{ + _localSize.erase(entry); + NotifySubMeshesHypothesisModification(); +} + +//============================================================================= +/*! + * + */ +//============================================================================= +void NETGENPlugin_Hypothesis::SetQuadAllowed(bool theVal) +{ + if (theVal != _quadAllowed) + { + _quadAllowed = theVal; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= +bool NETGENPlugin_Hypothesis::GetDefaultQuadAllowed() +{ + return false; +} + +//============================================================================= +/*! + * + */ +//============================================================================= +void NETGENPlugin_Hypothesis::SetSurfaceCurvature(bool theVal) +{ + if (theVal != _surfaceCurvature) + { + _surfaceCurvature = theVal; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= +bool NETGENPlugin_Hypothesis::GetDefaultSurfaceCurvature() +{ + return true; +} + +//============================================================================= +/*! + * + */ +//============================================================================= +void NETGENPlugin_Hypothesis::SetFuseEdges(bool theVal) +{ + if (theVal != _fuseEdges) + { + _fuseEdges = theVal; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= +bool NETGENPlugin_Hypothesis::GetDefaultFuseEdges() +{ + return true; // false; -- for SALOME_TESTS/Grids/smesh/3D_mesh_NETGEN_05/F6 +} + +//============================================================================= +/*! + * + */ +//============================================================================= ostream & NETGENPlugin_Hypothesis::SaveTo(ostream & save) { save << _maxSize << " " << _fineness; @@ -197,6 +333,20 @@ ostream & NETGENPlugin_Hypothesis::SaveTo(ostream & save) save << " " << (int)_secondOrder << " " << (int)_optimize; + TLocalSize::iterator it_sm = _localSize.begin(); + if (it_sm != _localSize.end()) { + save << " " << "__LOCALSIZE_BEGIN__"; + for ( ; it_sm != _localSize.end(); ++it_sm ) { + save << " " << it_sm->first + << " " << it_sm->second << "%#"; // "%#" is a mark of value end + } + save << " " << "__LOCALSIZE_END__"; + } + save << " " << _minSize; + save << " " << _quadAllowed; + save << " " << _surfaceCurvature; + save << " " << _fuseEdges; + return save; } @@ -211,13 +361,13 @@ istream & NETGENPlugin_Hypothesis::LoadFrom(istream & load) int is; double val; - isOK = !(load >> val).bad(); + isOK = (bool)(load >> val); if (isOK) _maxSize = val; else load.clear(ios::badbit | load.rdstate()); - isOK = !(load >> is).bad(); + isOK = (bool)(load >> is); if (isOK) SetFineness((Fineness) is); else @@ -225,36 +375,76 @@ istream & NETGENPlugin_Hypothesis::LoadFrom(istream & load) if (_fineness == UserDefined) { - isOK = !(load >> val).bad(); + isOK = (bool)(load >> val); if (isOK) _growthRate = val; else load.clear(ios::badbit | load.rdstate()); - isOK = !(load >> val).bad(); + isOK = (bool)(load >> val); if (isOK) _nbSegPerEdge = val; else load.clear(ios::badbit | load.rdstate()); - isOK = !(load >> val).bad(); + isOK =(bool) (load >> val); if (isOK) _nbSegPerRadius = val; else load.clear(ios::badbit | load.rdstate()); } - isOK = !(load >> is).bad(); + isOK = (bool)(load >> is); if (isOK) _secondOrder = (bool) is; else load.clear(ios::badbit | load.rdstate()); - isOK = !(load >> is).bad(); + isOK = (bool)(load >> is); if (isOK) _optimize = (bool) is; else load.clear(ios::badbit | load.rdstate()); + + std::string option_or_sm; + bool hasLocalSize = false; + + isOK = (bool)(load >> option_or_sm); + if (isOK) + if (option_or_sm == "__LOCALSIZE_BEGIN__") + hasLocalSize = true; + + std::string smEntry, smValue; + while (isOK && hasLocalSize) { + isOK = (bool)(load >> smEntry); + if (isOK) { + if (smEntry == "__LOCALSIZE_END__") + break; + isOK = (bool)(load >> smValue); + } + if (isOK) { + std::istringstream tmp(smValue); + double val; + tmp >> val; + _localSize[ smEntry ] = val; + } + } + + if ( !hasLocalSize && !option_or_sm.empty() ) + _minSize = atof( option_or_sm.c_str() ); + + isOK = (bool)( load >> _quadAllowed ); + if ( !isOK ) + _quadAllowed = GetDefaultQuadAllowed(); + + isOK = (bool)( load >> _surfaceCurvature ); + if ( !isOK ) + _surfaceCurvature = GetDefaultSurfaceCurvature(); + + isOK = (bool)( load >> _fuseEdges ); + if ( !isOK ) + _fuseEdges = GetDefaultFuseEdges(); + return load; } @@ -301,10 +491,16 @@ bool NETGENPlugin_Hypothesis::SetParametersByMesh(const SMESH_Mesh* theMesh, //================================================================================ bool NETGENPlugin_Hypothesis::SetParametersByDefaults(const TDefaults& dflts, - const SMESH_Mesh* /*theMesh*/) + const SMESH_Mesh* theMesh) { _nbSegPerEdge = dflts._nbSegments; _maxSize = dflts._elemLength; + + if ( dflts._shape && !dflts._shape->IsNull() ) + _minSize = NETGENPlugin_Mesher::GetDefaultMinSize( *dflts._shape, _maxSize ); + else if ( theMesh && theMesh->HasShapeToMesh() ) + _minSize = NETGENPlugin_Mesher::GetDefaultMinSize( theMesh->GetShapeToMesh(), _maxSize ); + return _nbSegPerEdge && _maxSize > 0; } diff --git a/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.cpp b/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.cpp index 41b19f839918..2d3a48aaee95 100644 --- a/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.cpp +++ b/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.cpp @@ -1,33 +1,33 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // NETGENPlugin : C++ implementation // File : NETGENPlugin_Hypothesis_2D.cxx // Author : Michael Sazonov (OCN) // Date : 28/03/2006 // Project : SALOME -// $Header: /home/server/cvs/NETGENPLUGIN/NETGENPLUGIN_SRC/src/NETGENPlugin/NETGENPlugin_Hypothesis_2D.cxx,v 1.4.2.1 2008/11/27 14:29:44 abd Exp $ //============================================================================= // -#include +#include "NETGENPlugin_Hypothesis_2D.hxx" #include using namespace std; @@ -39,8 +39,8 @@ using namespace std; //============================================================================= NETGENPlugin_Hypothesis_2D::NETGENPlugin_Hypothesis_2D (int hypId, int studyId, SMESH_Gen * gen) - : NETGENPlugin_Hypothesis(hypId, studyId, gen), - _quadAllowed (GetDefaultQuadAllowed()) + : NETGENPlugin_Hypothesis(hypId, studyId, gen)/*, + _quadAllowed (GetDefaultQuadAllowed())*/ { _name = "NETGEN_Parameters_2D"; _param_algo_dim = 2; @@ -51,56 +51,56 @@ NETGENPlugin_Hypothesis_2D::NETGENPlugin_Hypothesis_2D (int hypId, int studyId, * */ //============================================================================= -void NETGENPlugin_Hypothesis_2D::SetQuadAllowed(bool theVal) -{ - if (theVal != _quadAllowed) - { - _quadAllowed = theVal; - NotifySubMeshesHypothesisModification(); - } -} +// void NETGENPlugin_Hypothesis_2D::SetQuadAllowed(bool theVal) +// { +// if (theVal != _quadAllowed) +// { +// _quadAllowed = theVal; +// NotifySubMeshesHypothesisModification(); +// } +// } -//============================================================================= -/*! - * - */ -//============================================================================= -bool NETGENPlugin_Hypothesis_2D::GetDefaultQuadAllowed() -{ - return false; -} +// //============================================================================= +// /*! +// * +// */ +// //============================================================================= +// bool NETGENPlugin_Hypothesis_2D::GetDefaultQuadAllowed() +// { +// return false; +// } -//============================================================================= -/*! - * - */ -//============================================================================= -ostream & NETGENPlugin_Hypothesis_2D::SaveTo(ostream & save) -{ - NETGENPlugin_Hypothesis::SaveTo(save); +// //============================================================================= +// /*! +// * +// */ +// //============================================================================= +// ostream & NETGENPlugin_Hypothesis_2D::SaveTo(ostream & save) +// { +// NETGENPlugin_Hypothesis::SaveTo(save); - save << " " << (int)_quadAllowed; +// save << " " << (int)_quadAllowed; - return save; -} +// return save; +// } -//============================================================================= -/*! - * - */ -//============================================================================= -istream & NETGENPlugin_Hypothesis_2D::LoadFrom(istream & load) -{ - NETGENPlugin_Hypothesis::LoadFrom(load); +// //============================================================================= +// /*! +// * +// */ +// //============================================================================= +// istream & NETGENPlugin_Hypothesis_2D::LoadFrom(istream & load) +// { +// NETGENPlugin_Hypothesis::LoadFrom(load); - bool isOK = true; - int is; +// bool isOK = true; +// int is; - isOK = !(load >> is).bad(); - if (isOK) - _quadAllowed = (bool) is; - else - load.clear(ios::badbit | load.rdstate()); +// isOK = (load >> is); +// if (isOK) +// _quadAllowed = (bool) is; +// else +// load.clear(ios::badbit | load.rdstate()); - return load; -} +// return load; +// } diff --git a/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_Mesher.cpp b/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_Mesher.cpp index 713d09bc0218..01327fc966b0 100644 --- a/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_Mesher.cpp +++ b/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_Mesher.cpp @@ -1,59 +1,71 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // NETGENPlugin : C++ implementation // File : NETGENPlugin_Mesher.cxx // Author : Michael Sazonov (OCN) // Date : 31/03/2006 // Project : SALOME //============================================================================= -// + #include "NETGENPlugin_Mesher.hxx" #include "NETGENPlugin_Hypothesis_2D.hxx" #include "NETGENPlugin_SimpleHypothesis_3D.hxx" -#include +#include +#include +#include +#include +#include #include #include -#include +#include +#include +#include #include -#include -#include -#include -#include +#include +#include +#include -#include +// #include + +#include +#include #include +#include +#include +#include +#include +#include #include #include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include -// Netgen include files #ifdef _MSC_VER #pragma warning(disable : 4067) #endif @@ -62,7 +74,7 @@ namespace nglib { #include } #ifndef OCCGEOMETRY -# define OCCGEOMETRY +#define OCCGEOMETRY #endif #include @@ -70,31 +82,105 @@ namespace nglib { //#include namespace netgen { #ifdef NETGEN_V5 - DLL_HEADER extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, MeshingParameters&, int, int); - DLL_HEADER extern MeshingParameters mparam; + extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, MeshingParameters&, int, int); #else - DLL_HEADER extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, int, int, char*); + extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, int, int, char*); #endif + //extern void OCCSetLocalMeshSize(OCCGeometry & geom, Mesh & mesh); + extern MeshingParameters mparam; + extern volatile multithreadt multithread; + extern bool merge_solids; } +#include +#include + +#ifdef WIN32 +#include +#endif +using namespace nglib; using namespace std; +#ifdef _DEBUG_ +#define nodeVec_ACCESS(index) ((SMDS_MeshNode*) nodeVec.at((index))) +#else +#define nodeVec_ACCESS(index) ((SMDS_MeshNode*) nodeVec[index]) +#endif + +#define NGPOINT_COORDS(p) p(0),p(1),p(2) + +#ifdef _DEBUG_ +// dump elements added to ng mesh +//#define DUMP_SEGMENTS +//#define DUMP_TRIANGLES +//#define DUMP_TRIANGLES_SCRIPT "/tmp/trias.py" //!< debug AddIntVerticesInSolids() +#endif + +TopTools_IndexedMapOfShape ShapesWithLocalSize; +std::map VertexId2LocalSize; +std::map EdgeId2LocalSize; +std::map FaceId2LocalSize; + //============================================================================= /*! * */ //============================================================================= -NETGENPlugin_Mesher::NETGENPlugin_Mesher (SMESH_Mesh* mesh, +NETGENPlugin_Mesher::NETGENPlugin_Mesher (SMESH_Mesh* mesh, const TopoDS_Shape& aShape, - const bool isVolume) + const bool isVolume) : _mesh (mesh), _shape (aShape), _isVolume(isVolume), _optimize(true), - _simpleHyp(NULL) + _fineness(NETGENPlugin_Hypothesis::GetDefaultFineness()), + _isViscousLayers2D(false), + _ngMesh(NULL), + _occgeom(NULL), + _curShapeIndex(-1), + _progressTic(1), + _totalTime(1.0), + _simpleHyp(NULL), + _ptrToMe(NULL) +{ + SetDefaultParameters(); + ShapesWithLocalSize.Clear(); + VertexId2LocalSize.clear(); + EdgeId2LocalSize.clear(); + FaceId2LocalSize.clear(); +} + +//================================================================================ +/*! + * Destuctor + */ +//================================================================================ + +NETGENPlugin_Mesher::~NETGENPlugin_Mesher() +{ + if ( _ptrToMe ) + *_ptrToMe = NULL; + _ptrToMe = 0; + _ngMesh = NULL; +} + +//================================================================================ +/*! + * Set pointer to NETGENPlugin_Mesher* field of the holder, that will be + * nullified at destruction of this + */ +//================================================================================ + +void NETGENPlugin_Mesher::SetSelfPointer( NETGENPlugin_Mesher ** ptr ) { - defaultParameters(); + if ( _ptrToMe ) + *_ptrToMe = NULL; + + _ptrToMe = ptr; + + if ( _ptrToMe ) + *_ptrToMe = this; } //================================================================================ @@ -103,28 +189,58 @@ NETGENPlugin_Mesher::NETGENPlugin_Mesher (SMESH_Mesh* mesh, */ //================================================================================ -void NETGENPlugin_Mesher::defaultParameters() +void NETGENPlugin_Mesher::SetDefaultParameters() { -//#ifdef WNT -// netgen::MeshingParameters& mparams = netgen::GlobalMeshingParameters(); -//#else netgen::MeshingParameters& mparams = netgen::mparam; -//#endif // maximal mesh edge size - mparams.maxh = NETGENPlugin_Hypothesis::GetDefaultMaxSize(); + mparams.maxh = 0;//NETGENPlugin_Hypothesis::GetDefaultMaxSize(); + mparams.minh = 0; // minimal number of segments per edge mparams.segmentsperedge = NETGENPlugin_Hypothesis::GetDefaultNbSegPerEdge(); // rate of growth of size between elements - mparams.grading = NETGENPlugin_Hypothesis::GetDefaultGrowthRate(); + mparams.grading = NETGENPlugin_Hypothesis::GetDefaultGrowthRate(); // safety factor for curvatures (elements per radius) mparams.curvaturesafety = NETGENPlugin_Hypothesis::GetDefaultNbSegPerRadius(); // create elements of second order - mparams.secondorder = NETGENPlugin_Hypothesis::GetDefaultSecondOrder() ? 1 : 0; + mparams.secondorder = NETGENPlugin_Hypothesis::GetDefaultSecondOrder(); // quad-dominated surface meshing if (_isVolume) - mparams.quad = 0; + mparams.quad = 0; + else + mparams.quad = NETGENPlugin_Hypothesis_2D::GetDefaultQuadAllowed(); + _fineness = NETGENPlugin_Hypothesis::GetDefaultFineness(); + mparams.uselocalh = NETGENPlugin_Hypothesis::GetDefaultSurfaceCurvature(); + netgen::merge_solids = NETGENPlugin_Hypothesis::GetDefaultFuseEdges(); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +void SetLocalSize(TopoDS_Shape GeomShape, double LocalSize) +{ + if ( GeomShape.IsNull() ) return; + TopAbs_ShapeEnum GeomType = GeomShape.ShapeType(); + if (GeomType == TopAbs_COMPOUND) { + for (TopoDS_Iterator it (GeomShape); it.More(); it.Next()) { + SetLocalSize(it.Value(), LocalSize); + } + return; + } + int key; + if (! ShapesWithLocalSize.Contains(GeomShape)) + key = ShapesWithLocalSize.Add(GeomShape); else - mparams.quad = NETGENPlugin_Hypothesis_2D::GetDefaultQuadAllowed() ? 1 : 0; + key = ShapesWithLocalSize.FindIndex(GeomShape); + if (GeomType == TopAbs_VERTEX) { + VertexId2LocalSize[key] = LocalSize; + } else if (GeomType == TopAbs_EDGE) { + EdgeId2LocalSize[key] = LocalSize; + } else if (GeomType == TopAbs_FACE) { + FaceId2LocalSize[key] = LocalSize; + } } //============================================================================= @@ -136,29 +252,58 @@ void NETGENPlugin_Mesher::SetParameters(const NETGENPlugin_Hypothesis* hyp) { if (hyp) { -//#ifdef WNT -// netgen::MeshingParameters& mparams = netgen::GlobalMeshingParameters(); -//#else netgen::MeshingParameters& mparams = netgen::mparam; -//#endif // Initialize global NETGEN parameters: // maximal mesh segment size - mparams.maxh = hyp->GetMaxSize(); + mparams.maxh = hyp->GetMaxSize(); + // maximal mesh element linear size + mparams.minh = hyp->GetMinSize(); // minimal number of segments per edge mparams.segmentsperedge = hyp->GetNbSegPerEdge(); // rate of growth of size between elements - mparams.grading = hyp->GetGrowthRate(); + mparams.grading = hyp->GetGrowthRate(); // safety factor for curvatures (elements per radius) mparams.curvaturesafety = hyp->GetNbSegPerRadius(); // create elements of second order - mparams.secondorder = hyp->GetSecondOrder() ? 1 : 0; + mparams.secondorder = hyp->GetSecondOrder() ? 1 : 0; // quad-dominated surface meshing - // only triangles are allowed for volumic mesh - if (!_isVolume) - mparams.quad = static_cast - (hyp)->GetQuadAllowed() ? 1 : 0; - _optimize = hyp->GetOptimize(); + // only triangles are allowed for volumic mesh (before realizing IMP 0021676) + //if (!_isVolume) + mparams.quad = hyp->GetQuadAllowed() ? 1 : 0; + _optimize = hyp->GetOptimize(); + _fineness = hyp->GetFineness(); + mparams.uselocalh = hyp->GetSurfaceCurvature(); + netgen::merge_solids = hyp->GetFuseEdges(); _simpleHyp = NULL; + + +/* vejmarie + + SMESH_Gen_i* smeshGen_i = SMESH_Gen_i::GetSMESHGen(); + CORBA::Object_var anObject = smeshGen_i->GetNS()->Resolve("/myStudyManager"); + SALOMEDS::StudyManager_var aStudyMgr = SALOMEDS::StudyManager::_narrow(anObject); + SALOMEDS::Study_var myStudy = aStudyMgr->GetStudyByID(hyp->GetStudyId()); + const NETGENPlugin_Hypothesis::TLocalSize localSizes = hyp->GetLocalSizesAndEntries(); + NETGENPlugin_Hypothesis::TLocalSize::const_iterator it = localSizes.begin(); + for (it ; it != localSizes.end() ; it++) + { + std::string entry = (*it).first; + double val = (*it).second; + // -- + GEOM::GEOM_Object_var aGeomObj; + TopoDS_Shape S = TopoDS_Shape(); + SALOMEDS::SObject_var aSObj = myStudy->FindObjectID( entry.c_str() ); + if (!aSObj->_is_nil()) { + CORBA::Object_var obj = aSObj->GetObject(); + aGeomObj = GEOM::GEOM_Object::_narrow(obj); + aSObj->UnRegister(); + } + if ( !aGeomObj->_is_nil() ) + S = smeshGen_i->GeomObjectToShape( aGeomObj.in() ); + // -- + SetLocalSize(S, val); + } +*/ } } @@ -172,7 +317,7 @@ void NETGENPlugin_Mesher::SetParameters(const NETGENPlugin_SimpleHypothesis_2D* { _simpleHyp = hyp; if ( _simpleHyp ) - defaultParameters(); + SetDefaultParameters(); } //============================================================================= @@ -185,6 +330,11 @@ struct Link int n1, n2; Link(int _n1, int _n2) : n1(_n1), n2(_n2) {} Link() : n1(0), n2(0) {} + bool Contains( int n ) const { return n == n1 || n == n2; } + bool IsConnected( const Link& other ) const + { + return (( Contains( other.n1 ) || Contains( other.n2 )) && ( this != &other )); + } }; int HashCode(const Link& aLink, int aLimit) @@ -194,8 +344,223 @@ int HashCode(const Link& aLink, int aLimit) Standard_Boolean IsEqual(const Link& aLink1, const Link& aLink2) { - return (aLink1.n1 == aLink2.n1 && aLink1.n2 == aLink2.n2) || - (aLink1.n1 == aLink2.n2 && aLink1.n2 == aLink2.n1); + return (aLink1.n1 == aLink2.n1 && aLink1.n2 == aLink2.n2 || + aLink1.n1 == aLink2.n2 && aLink1.n2 == aLink2.n1); +} + +namespace +{ + //================================================================================ + /*! + * \brief return id of netgen point corresponding to SMDS node + */ + //================================================================================ + typedef map< const SMDS_MeshNode*, int > TNode2IdMap; + + int ngNodeId( const SMDS_MeshNode* node, + netgen::Mesh& ngMesh, + TNode2IdMap& nodeNgIdMap) + { + int newNgId = ngMesh.GetNP() + 1; + + TNode2IdMap::iterator node_id = nodeNgIdMap.insert( make_pair( node, newNgId )).first; + + if ( node_id->second == newNgId) + { +#if defined(DUMP_SEGMENTS) || defined(DUMP_TRIANGLES) + cout << "Ng " << newNgId << " - " << node; +#endif + netgen::MeshPoint p( netgen::Point<3> (node->X(), node->Y(), node->Z()) ); + ngMesh.AddPoint( p ); + } + return node_id->second; + } + + //================================================================================ + /*! + * \brief Return computed EDGEs connected to the given one + */ + //================================================================================ + + list< TopoDS_Edge > getConnectedEdges( const TopoDS_Edge& edge, + const TopoDS_Face& face, + const set< SMESH_subMesh* > & computedSM, + const SMESH_MesherHelper& helper, + map< SMESH_subMesh*, set< int > >& addedEdgeSM2Faces) + { + // get ordered EDGEs + list< TopoDS_Edge > edges; + list< int > nbEdgesInWire; + int nbWires = SMESH_Block::GetOrderedEdges( face, edges, nbEdgesInWire); + + // find within + list< TopoDS_Edge >::iterator eItFwd = edges.begin(); + for ( ; eItFwd != edges.end(); ++eItFwd ) + if ( edge.IsSame( *eItFwd )) + break; + if ( eItFwd == edges.end()) return list< TopoDS_Edge>(); + + if ( eItFwd->Orientation() >= TopAbs_INTERNAL ) + { + // connected INTERNAL edges returned from GetOrderedEdges() are wrongly oriented + // so treat each INTERNAL edge separately + TopoDS_Edge e = *eItFwd; + edges.clear(); + edges.push_back( e ); + return edges; + } + + // get all computed EDGEs connected to + + list< TopoDS_Edge >::iterator eItBack = eItFwd, ePrev; + TopoDS_Vertex vCommon; + TopTools_MapOfShape eAdded; // map used not to add a seam edge twice to + eAdded.Add( edge ); + + // put edges before to back + while ( edges.begin() != eItFwd ) + edges.splice( edges.end(), edges, edges.begin() ); + + // search forward + ePrev = eItFwd; + while ( ++eItFwd != edges.end() ) + { + SMESH_subMesh* sm = helper.GetMesh()->GetSubMesh( *eItFwd ); + + bool connected = TopExp::CommonVertex( *ePrev, *eItFwd, vCommon ); + bool computed = sm->IsMeshComputed(); + bool added = addedEdgeSM2Faces[ sm ].count( helper.GetSubShapeID() ); + bool doubled = !eAdded.Add( *eItFwd ); + bool orientOK = (( ePrev ->Orientation() < TopAbs_INTERNAL ) == + ( eItFwd->Orientation() < TopAbs_INTERNAL ) ); + if ( !connected || !computed || !orientOK || added || doubled ) + { + // stop advancement; move edges from tail to head + while ( edges.back() != *ePrev ) + edges.splice( edges.begin(), edges, --edges.end() ); + break; + } + ePrev = eItFwd; + } + // search backward + while ( eItBack != edges.begin() ) + { + ePrev = eItBack; + --eItBack; + SMESH_subMesh* sm = helper.GetMesh()->GetSubMesh( *eItBack ); + + bool connected = TopExp::CommonVertex( *ePrev, *eItBack, vCommon ); + bool computed = sm->IsMeshComputed(); + bool added = addedEdgeSM2Faces[ sm ].count( helper.GetSubShapeID() ); + bool doubled = !eAdded.Add( *eItBack ); + bool orientOK = (( ePrev ->Orientation() < TopAbs_INTERNAL ) == + ( eItBack->Orientation() < TopAbs_INTERNAL ) ); + if ( !connected || !computed || !orientOK || added || doubled) + { + // stop advancement + edges.erase( edges.begin(), ePrev ); + break; + } + } + if ( edges.front() != edges.back() ) + { + // assure that the 1st vertex is meshed + TopoDS_Edge eLast = edges.back(); + while ( !SMESH_Algo::VertexNode( SMESH_MesherHelper::IthVertex( 0, edges.front()), helper.GetMeshDS()) + && + edges.front() != eLast ) + edges.splice( edges.end(), edges, edges.begin() ); + } + return edges; + } + + //================================================================================ + /*! + * \brief Make triangulation of a shape precise enough + */ + //================================================================================ + + void updateTriangulation( const TopoDS_Shape& shape ) + { + // static set< Poly_Triangulation* > updated; + + // TopLoc_Location loc; + // TopExp_Explorer fExp( shape, TopAbs_FACE ); + // for ( ; fExp.More(); fExp.Next() ) + // { + // Handle(Poly_Triangulation) triangulation = + // BRep_Tool::Triangulation ( TopoDS::Face( fExp.Current() ), loc); + // if ( triangulation.IsNull() || + // updated.insert( triangulation.operator->() ).second ) + // { + // BRepTools::Clean (shape); + try { + OCC_CATCH_SIGNALS; + BRepMesh_IncrementalMesh e(shape, 0.01, true); + } + catch (Standard_Failure) + { + } + // updated.erase( triangulation.operator->() ); + // triangulation = BRep_Tool::Triangulation ( TopoDS::Face( fExp.Current() ), loc); + // updated.insert( triangulation.operator->() ); + // } + // } + } + //================================================================================ + /*! + * \brief Returns a medium node either existing in SMESH of created by NETGEN + * \param [in] corner1 - corner node 1 + * \param [in] corner2 - corner node 2 + * \param [in] defaultMedium - the node created by NETGEN + * \param [in] helper - holder of medium nodes existing in SMESH + * \return const SMDS_MeshNode* - the result node + */ + //================================================================================ + + const SMDS_MeshNode* mediumNode( const SMDS_MeshNode* corner1, + const SMDS_MeshNode* corner2, + const SMDS_MeshNode* defaultMedium, + const SMESH_MesherHelper* helper) + { + if ( helper ) + { + TLinkNodeMap::const_iterator l2n = + helper->GetTLinkNodeMap().find( SMESH_TLink( corner1, corner2 )); + if ( l2n != helper->GetTLinkNodeMap().end() ) + defaultMedium = l2n->second; + } + return defaultMedium; + } + + //================================================================================ + /*! + * \brief Assure that mesh on given shapes is quadratic + */ + //================================================================================ + + void makeQuadratic( const TopTools_IndexedMapOfShape& shapes, + SMESH_Mesh* mesh ) + { + for ( int i = 1; i <= shapes.Extent(); ++i ) + { + SMESHDS_SubMesh* smDS = mesh->GetMeshDS()->MeshElements( shapes(i) ); + if ( !smDS ) continue; + SMDS_ElemIteratorPtr elemIt = smDS->GetElements(); + if ( !elemIt->more() ) continue; + const SMDS_MeshElement* e = elemIt->next(); + if ( !e || e->IsQuadratic() ) + continue; + + TIDSortedElemSet elems; + elems.insert( e ); + while ( elemIt->more() ) + elems.insert( elems.end(), elemIt->next() ); + + SMESH_MeshEditor( mesh ).ConvertToQuadratic( /*3d=*/false, elems, /*biQuad=*/false ); + } + } + } //================================================================================ @@ -207,16 +572,11 @@ Standard_Boolean IsEqual(const Link& aLink1, const Link& aLink2) void NETGENPlugin_Mesher::PrepareOCCgeometry(netgen::OCCGeometry& occgeo, const TopoDS_Shape& shape, SMESH_Mesh& mesh, - list< SMESH_subMesh* > * meshedSM) + list< SMESH_subMesh* > * meshedSM, + NETGENPlugin_Internals* intern) { - BRepTools::Clean (shape); - try { -#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 - OCC_CATCH_SIGNALS; -#endif - BRepMesh_IncrementalMesh e(shape, 0.01, true); - } catch (Standard_Failure) { - } + updateTriangulation( shape ); + Bnd_Box bb; BRepBndLib::Add (shape, bb); double x1,y1,z1,x2,y2,z2; @@ -230,14 +590,14 @@ void NETGENPlugin_Mesher::PrepareOCCgeometry(netgen::OCCGeometry& occgeo, occgeo.shape = shape; occgeo.changed = 1; - //occgeo.BuildFMap(); // fill maps of shapes of occgeo with not yet meshed subshapes // get root submeshes list< SMESH_subMesh* > rootSM; - if ( SMESH_subMesh* sm = mesh.GetSubMeshContaining( shape )) { - rootSM.push_back( sm ); + const int shapeID = mesh.GetMeshDS()->ShapeToIndex( shape ); + if ( shapeID > 0 ) { // SMESH_subMesh with ID 0 may exist, don't use it! + rootSM.push_back( mesh.GetSubMesh( shape )); } else { for ( TopoDS_Iterator it( shape ); it.More(); it.Next() ) @@ -253,12 +613,18 @@ void NETGENPlugin_Mesher::PrepareOCCgeometry(netgen::OCCGeometry& occgeo, // to find a right orientation of subshapes (PAL20462) TopTools_IndexedMapOfShape subShapes; TopExp::MapShapes(root->GetSubShape(), subShapes); - while ( smIt->more() ) { + while ( smIt->more() ) + { SMESH_subMesh* sm = smIt->next(); - if ( sm->IsEmpty() ) { - TopoDS_Shape shape = sm->GetSubShape(); + TopoDS_Shape shape = sm->GetSubShape(); + if ( intern && intern->isShapeToPrecompute( shape )) + continue; + if ( !meshedSM || sm->IsEmpty() ) + { if ( shape.ShapeType() != TopAbs_VERTEX ) - shape = subShapes( subShapes.FindIndex( shape ));// - shape->index->oriented shape + shape = subShapes( subShapes.FindIndex( shape ));// shape -> index -> oriented shape + if ( shape.Orientation() >= TopAbs_INTERNAL ) + shape.Orientation( TopAbs_FORWARD ); // isuue 0020676 switch ( shape.ShapeType() ) { case TopAbs_FACE : occgeo.fmap.Add( shape ); break; case TopAbs_EDGE : occgeo.emap.Add( shape ); break; @@ -268,41 +634,101 @@ void NETGENPlugin_Mesher::PrepareOCCgeometry(netgen::OCCGeometry& occgeo, } } // collect submeshes of meshed shapes - else if (meshedSM) { - meshedSM->push_back( sm ); + else if (meshedSM) + { + const int dim = SMESH_Gen::GetShapeDim( shape ); + meshedSM[ dim ].push_back( sm ); } } } occgeo.facemeshstatus.SetSize (occgeo.fmap.Extent()); occgeo.facemeshstatus = 0; - - occgeo.face_maxh.DeleteAll(); - occgeo.face_maxh.SetSize (occgeo.fmap.Extent()); + occgeo.face_maxh_modified.SetSize(occgeo.fmap.Extent()); + occgeo.face_maxh_modified = 0; + occgeo.face_maxh.SetSize(occgeo.fmap.Extent()); occgeo.face_maxh = netgen::mparam.maxh; - - } //================================================================================ /*! - * \brief return id of netgen point corresponding to SMDS node + * \brief Return a default min size value suitable for the given geometry. */ //================================================================================ -typedef map< const SMDS_MeshNode*, int > TNode2IdMap; -static int ngNodeId( const SMDS_MeshNode* node, - netgen::Mesh& ngMesh, - TNode2IdMap& nodeNgIdMap) +double NETGENPlugin_Mesher::GetDefaultMinSize(const TopoDS_Shape& geom, + const double maxSize) { - int newNgId = ngMesh.GetNP() + 1; + updateTriangulation( geom ); + + TopLoc_Location loc; + int i1, i2, i3; + const int* pi[4] = { &i1, &i2, &i3, &i1 }; + double minh = 1e100; + Bnd_B3d bb; + TopExp_Explorer fExp( geom, TopAbs_FACE ); + for ( ; fExp.More(); fExp.Next() ) + { + Handle(Poly_Triangulation) triangulation = + BRep_Tool::Triangulation ( TopoDS::Face( fExp.Current() ), loc); + if ( triangulation.IsNull() ) continue; + const double fTol = BRep_Tool::Tolerance( TopoDS::Face( fExp.Current() )); + const TColgp_Array1OfPnt& points = triangulation->Nodes(); + const Poly_Array1OfTriangle& trias = triangulation->Triangles(); + for ( int iT = trias.Lower(); iT <= trias.Upper(); ++iT ) + { + trias(iT).Get( i1, i2, i3 ); + for ( int j = 0; j < 3; ++j ) + { + double dist2 = points(*pi[j]).SquareDistance( points( *pi[j+1] )); + if ( dist2 < minh && fTol*fTol < dist2 ) + minh = dist2; + bb.Add( points(*pi[j])); + } + } + } + if ( minh > 0.25 * bb.SquareExtent() ) // simple geometry, rough triangulation + { + minh = 1e-3 * sqrt( bb.SquareExtent()); + //cout << "BND BOX minh = " <ShapeToIndex( face ) << endl + << "\tface index: " << seg.si << endl + << "\tp1: " << seg[0] << endl + << "\tp2: " << seg[1] << endl + << "\tp0 param: " << seg.epgeominfo[ 0 ].dist << endl + << "\tp0 uv: " << seg.epgeominfo[ 0 ].u <<", "<< seg.epgeominfo[ 0 ].v << endl + //<< "\tp0 edge: " << seg.epgeominfo[ 0 ].edgenr << endl + << "\tp1 param: " << seg.epgeominfo[ 1 ].dist << endl + << "\tp1 uv: " << seg.epgeominfo[ 1 ].u <<", "<< seg.epgeominfo[ 1 ].v << endl; + //<< "\tp1 edge: " << seg.epgeominfo[ 1 ].edgenr << endl; +#endif if ( isSeam ) { - if ( helper.GetPeriodicIndex() == 1 ) { + if ( helper.GetPeriodicIndex() && 1 ) { seg.epgeominfo[ 0 ].u = otherSeamParam; seg.epgeominfo[ 1 ].u = otherSeamParam; swap (seg.epgeominfo[0].v, seg.epgeominfo[1].v); @@ -415,14 +893,41 @@ bool NETGENPlugin_Mesher::fillNgMesh(netgen::OCCGeometry& occgeom, seg.epgeominfo[ 1 ].v = otherSeamParam; swap (seg.epgeominfo[0].u, seg.epgeominfo[1].u); } - swap (seg.pnums[0], seg.pnums[1]); + swap (seg[0], seg[1]); swap (seg.epgeominfo[0].dist, seg.epgeominfo[1].dist); seg.edgenr = ngMesh.GetNSeg() + 1; // segment id ngMesh.AddSegment (seg); +#ifdef DUMP_SEGMENTS + cout << "Segment: " << seg.edgenr << endl + << "\t is SEAM (reverse) of the previous. " + << " Other " << (helper.GetPeriodicIndex() && 1 ? "U" : "V") + << " = " << otherSeamParam << endl; +#endif + } + else if ( fOri == TopAbs_INTERNAL ) + { + swap (seg[0], seg[1]); + swap( seg.epgeominfo[0], seg.epgeominfo[1] ); + seg.edgenr = ngMesh.GetNSeg() + 1; // segment id + ngMesh.AddSegment (seg); +#ifdef DUMP_SEGMENTS + cout << "Segment: " << seg.edgenr << endl << "\t is REVERSE of the previous" << endl; +#endif } } } // loop on geomEdge ancestors + if ( quadHelper ) // remember medium nodes of sub-meshes + { + SMDS_ElemIteratorPtr edges = smDS->GetElements(); + while ( edges->more() ) + { + const SMDS_MeshElement* e = edges->next(); + if ( !quadHelper->AddTLinks( static_cast< const SMDS_MeshEdge*>( e ))) + break; + } + } + break; } // case TopAbs_EDGE @@ -430,89 +935,158 @@ bool NETGENPlugin_Mesher::fillNgMesh(netgen::OCCGeometry& occgeom, // ---------------------- const TopoDS_Face& geomFace = TopoDS::Face( sm->GetSubShape() ); helper.SetSubShape( geomFace ); + bool isInternalFace = ( geomFace.Orientation() == TopAbs_INTERNAL ); // Find solids the geomFace bounds int solidID1 = 0, solidID2 = 0; - const TopTools_ListOfShape& ancestors = _mesh->GetAncestors( geomFace ); - TopTools_ListIteratorOfListOfShape ancestorIt ( ancestors ); - for ( ; ancestorIt.More(); ancestorIt.Next() ) + StdMeshers_QuadToTriaAdaptor* quadAdaptor = + dynamic_cast( proxyMesh.get() ); + if ( quadAdaptor ) { - const TopoDS_Shape & solid = ancestorIt.Value(); - if ( solid.ShapeType() == TopAbs_SOLID ) { - int id = occgeom.somap.FindIndex ( solid ); + solidID1 = occgeom.somap.FindIndex( quadAdaptor->GetShape() ); + } + else + { + PShapeIteratorPtr solidIt = helper.GetAncestors( geomFace, *sm->GetFather(), TopAbs_SOLID); + while ( const TopoDS_Shape * solid = solidIt->next() ) + { + int id = occgeom.somap.FindIndex ( *solid ); if ( solidID1 && id != solidID1 ) solidID2 = id; else solidID1 = id; } } - faceID++; - _faceDescriptors[ faceID ].first = solidID1; - _faceDescriptors[ faceID ].second = solidID2; + // Add ng face descriptors of meshed faces + faceNgID++; + ngMesh.AddFaceDescriptor (netgen::FaceDescriptor(faceNgID, solidID1, solidID2, 0)); + + // if second oreder is required, even already meshed faces must be passed to NETGEN + int fID = occgeom.fmap.Add( geomFace ); + while ( fID < faceNgID ) // geomFace is already in occgeom.fmap, add a copy + fID = occgeom.fmap.Add( BRepBuilderAPI_Copy( geomFace, /*copyGeom=*/false )); + // Problem with the second order in a quadrangular mesh remains. + // 1) All quadrangles generated by NETGEN are moved to an inexistent face + // by FillSMesh() (find "AddFaceDescriptor") + // 2) Temporary triangles generated by StdMeshers_QuadToTriaAdaptor + // are on faces where quadrangles were. + // Due to these 2 points, wrong geom faces are used while conversion to qudratic + // of the mentioned above quadrangles and triangles // Orient the face correctly in solidID1 (issue 0020206) bool reverse = false; if ( solidID1 ) { TopoDS_Shape solid = occgeom.somap( solidID1 ); - for ( TopExp_Explorer f( solid, TopAbs_FACE ); f.More(); f.Next() ) { - if ( geomFace.IsSame( f.Current() )) { - reverse = SMESH_Algo::IsReversedSubMesh( TopoDS::Face( f.Current()), helper.GetMeshDS() ); - break; - } - } + TopAbs_Orientation faceOriInSolid = helper.GetSubShapeOri( solid, geomFace ); + if ( faceOriInSolid >= 0 ) + reverse = + helper.IsReversedSubMesh( TopoDS::Face( geomFace.Oriented( faceOriInSolid ))); } // Add surface elements - SMDS_ElemIteratorPtr faces = smDS->GetElements(); - while ( faces->more() ) { + netgen::Element2d tri(3); + tri.SetIndex ( faceNgID ); + SMESH_TNodeXYZ xyz[3]; + +#ifdef DUMP_TRIANGLES + cout << "SMESH face " << helper.GetMeshDS()->ShapeToIndex( geomFace ) + << " internal="<GetSubMesh( geomFace ); + + SMDS_ElemIteratorPtr faces = smDS->GetElements(); + while ( faces->more() ) + { const SMDS_MeshElement* f = faces->next(); - if ( f->NbNodes() % 3 != 0 ) { // not triangle - for ( ancestorIt.Initialize(ancestors); ancestorIt.More(); ancestorIt.Next() ) - if ( ancestorIt.Value().ShapeType() == TopAbs_SOLID ) { - sm = _mesh->GetSubMesh( ancestorIt.Value() ); - break; - } + if ( f->NbNodes() % 3 != 0 ) // not triangle + { + PShapeIteratorPtr solidIt=helper.GetAncestors(geomFace,*sm->GetFather(),TopAbs_SOLID); + if ( const TopoDS_Shape * solid = solidIt->next() ) + sm = _mesh->GetSubMesh( *solid ); SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); - smError.reset( new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH,"Not triangle submesh")); + smError.reset( new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH,"Not triangle sub-mesh")); smError->myBadElements.push_back( f ); return false; } - netgen::Element2d tri(3); - tri.SetIndex ( faceID ); - - for ( int i = 0; i < 3; ++i ) { + for ( int i = 0; i < 3; ++i ) + { const SMDS_MeshNode* node = f->GetNode( i ), * inFaceNode=0; - if ( helper.IsSeamShape( node->GetPosition()->GetShapeId() )) { - if ( helper.IsSeamShape( f->GetNodeWrap( i+1 )->GetPosition()->GetShapeId() )) { + xyz[i].Set( node ); + + // get node UV on face + int shapeID = node->getshapeId(); + if ( helper.IsSeamShape( shapeID )) + { + if ( helper.IsSeamShape( f->GetNodeWrap( i+1 )->getshapeId() )) inFaceNode = f->GetNodeWrap( i-1 ); - } else { + else inFaceNode = f->GetNodeWrap( i+1 ); - } } - gp_XY uv = helper.GetNodeUV( geomFace, node, inFaceNode ); - if ( reverse ) { - tri.GeomInfoPi(3-i).u = uv.X(); - tri.GeomInfoPi(3-i).v = uv.Y(); - tri.PNum (3-i) = ngNodeId( node, ngMesh, nodeNgIdMap ); - } else { - tri.GeomInfoPi(i+1).u = uv.X(); - tri.GeomInfoPi(i+1).v = uv.Y(); - tri.PNum (i+1) = ngNodeId( node, ngMesh, nodeNgIdMap ); - } + + int ind = reverse ? 3-i : i+1; + tri.GeomInfoPi(ind).u = uv.X(); + tri.GeomInfoPi(ind).v = uv.Y(); + tri.PNum (ind) = ngNodeId( node, ngMesh, nodeNgIdMap ); } + // pass a triangle size to NG size-map + double size = ( ( xyz[0] - xyz[1] ).Modulus() + + ( xyz[1] - xyz[2] ).Modulus() + + ( xyz[2] - xyz[0] ).Modulus() ) / 3; + gp_XYZ gc = ( xyz[0] + xyz[1] + xyz[2] ) / 3; + RestrictLocalSize( ngMesh, gc, size, /*overrideMinH=*/false ); + ngMesh.AddSurfaceElement (tri); +#ifdef DUMP_TRIANGLES + cout << tri << endl; +#endif + + if ( isInternalFace ) + { + swap( tri[1], tri[2] ); + ngMesh.AddSurfaceElement (tri); +#ifdef DUMP_TRIANGLES + cout << tri << endl; +#endif + } + } + if ( quadHelper ) // remember medium nodes of sub-meshes + { + SMDS_ElemIteratorPtr faces = smDS->GetElements(); + while ( faces->more() ) + { + const SMDS_MeshElement* f = faces->next(); + if ( !quadHelper->AddTLinks( static_cast< const SMDS_MeshFace*>( f ))) + break; + } } + break; - } // + } // case TopAbs_FACE case TopAbs_VERTEX: { // VERTEX // -------------------------- - SMDS_NodeIteratorPtr nodeIt = smDS->GetNodes(); - if ( nodeIt->more() ) - ngNodeId( nodeIt->next(), ngMesh, nodeNgIdMap ); + // issue 0021405. Add node only if a VERTEX is shared by a not meshed EDGE, + // else netgen removes a free node and nodeVector becomes invalid + PShapeIteratorPtr ansIt = helper.GetAncestors( sm->GetSubShape(), + *sm->GetFather(), + TopAbs_EDGE ); + bool toAdd = false; + while ( const TopoDS_Shape* e = ansIt->next() ) + { + SMESH_subMesh* eSub = helper.GetMesh()->GetSubMesh( *e ); + if (( toAdd = ( eSub->IsEmpty() && !SMESH_Algo::isDegenerated( TopoDS::Edge( *e ))))) + break; + } + if ( toAdd ) + { + SMDS_NodeIteratorPtr nodeIt = smDS->GetNodes(); + if ( nodeIt->more() ) + ngNodeId( nodeIt->next(), ngMesh, nodeNgIdMap ); + } break; } default:; @@ -523,474 +1097,2959 @@ bool NETGENPlugin_Mesher::fillNgMesh(netgen::OCCGeometry& occgeom, nodeVec.resize( ngMesh.GetNP() + 1 ); TNode2IdMap::iterator node_NgId, nodeNgIdEnd = nodeNgIdMap.end(); for ( node_NgId = nodeNgIdMap.begin(); node_NgId != nodeNgIdEnd; ++node_NgId) - nodeVec[ node_NgId->second ] = (SMDS_MeshNode*) node_NgId->first; + nodeVec[ node_NgId->second ] = node_NgId->first; return true; } -//============================================================================= +//================================================================================ /*! - * Here we are going to use the NETGEN mesher + * \brief Duplicate mesh faces on internal geom faces */ -//============================================================================= -bool NETGENPlugin_Mesher::Compute() +//================================================================================ + +void NETGENPlugin_Mesher::FixIntFaces(const netgen::OCCGeometry& occgeom, + netgen::Mesh& ngMesh, + NETGENPlugin_Internals& internalShapes) { -//#ifdef WNT -// netgen::MeshingParameters& mparams = netgen::GlobalMeshingParameters(); -//#else - netgen::MeshingParameters& mparams = netgen::mparam; -//#endif - MESSAGE("Compute with:\n" - " max size = " << mparams.maxh << "\n" - " segments per edge = " << mparams.segmentsperedge); - MESSAGE("\n" - " growth rate = " << mparams.grading << "\n" - " elements per radius = " << mparams.curvaturesafety << "\n" - " second order = " << mparams.secondorder << "\n" - " quad allowed = " << mparams.quad); + SMESHDS_Mesh* meshDS = internalShapes.getMesh().GetMeshDS(); + + // find ng indices of internal faces + set ngFaceIds; + for ( int ngFaceID = 1; ngFaceID <= occgeom.fmap.Extent(); ++ngFaceID ) + { + int smeshID = meshDS->ShapeToIndex( occgeom.fmap( ngFaceID )); + if ( internalShapes.isInternalShape( smeshID )) + ngFaceIds.insert( ngFaceID ); + } + if ( !ngFaceIds.empty() ) + { + // duplicate faces + int i, nbFaces = ngMesh.GetNSE(); + for (int i = 1; i <= nbFaces; ++i) + { + netgen::Element2d elem = ngMesh.SurfaceElement(i); + if ( ngFaceIds.count( elem.GetIndex() )) + { + swap( elem[1], elem[2] ); + ngMesh.AddSurfaceElement (elem); + } + } + } +} - SMESH_ComputeErrorPtr error = SMESH_ComputeError::New(); - nglib::Ng_Init(); +//================================================================================ +/*! + * \brief Tries to heal the mesh on a FACE. The FACE is supposed to be partially + * meshed due to NETGEN failure + * \param [in] occgeom - geometry + * \param [in,out] ngMesh - the mesh to fix + * \param [inout] faceID - ID of the FACE to fix the mesh on + * \return bool - is mesh is or becomes OK + */ +//================================================================================ - // ------------------------- - // Prepare OCC geometry - // ------------------------- +bool NETGENPlugin_Mesher::FixFaceMesh(const netgen::OCCGeometry& occgeom, + netgen::Mesh& ngMesh, + const int faceID) +{ + // we address a case where the FACE is almost fully meshed except small holes + // of usually triangular shape at FACE boundary (IPAL52861) - netgen::OCCGeometry occgeo; - list< SMESH_subMesh* > meshedSM; - PrepareOCCgeometry( occgeo, _shape, *_mesh, &meshedSM ); + // The case appeared to be not simple: holes only look triangular but + // indeed are a self intersecting polygon. A reason of the bug was in coincident + // NG points on a seam edge. But the code below is very nice, leave it for + // another case. + return false; - // ------------------------- - // Generate the mesh - // ------------------------- - netgen::Mesh *ngMesh = NULL; + if ( occgeom.fmap.Extent() < faceID ) + return false; + const TopoDS_Face& face = TopoDS::Face( occgeom.fmap( faceID )); - SMESH_Comment comment; - int err = 0; - int nbInitNod = 0; - int nbInitSeg = 0; - int nbInitFac = 0; - // vector of nodes in which node index == netgen ID - vector< SMDS_MeshNode* > nodeVec; - try + // find free links on the FACE + NCollection_Map linkMap; + for ( int iF = 1; iF <= ngMesh.GetNSE(); ++iF ) { - // ---------------- - // compute 1D mesh - // ---------------- - // pass 1D simple parameters to NETGEN - if ( _simpleHyp ) { - if ( int nbSeg = _simpleHyp->GetNumberOfSegments() ) { - // nb of segments - mparams.segmentsperedge = nbSeg + 0.1; - mparams.maxh = occgeo.boundingbox.Diam(); - mparams.grading = 0.01; - } - else { - // segment length - mparams.segmentsperedge = 1; - mparams.maxh = _simpleHyp->GetLocalLength(); - } + const netgen::Element2d& elem = ngMesh.SurfaceElement(iF); + if ( faceID != elem.GetIndex() ) + continue; + int n0 = elem[ elem.GetNP() - 1 ]; + for ( int i = 0; i < elem.GetNP(); ++i ) + { + int n1 = elem[i]; + Link link( n0, n1 ); + if ( !linkMap.Add( link )) + linkMap.Remove( link ); + n0 = n1; } - // let netgen create ngMesh and calculate element size on not meshed shapes -#ifndef NETGEN_V5 - char *optstr = 0; -#endif - int startWith = netgen::MESHCONST_ANALYSE; - int endWith = netgen::MESHCONST_ANALYSE; -#ifdef NETGEN_V5 - err = netgen::OCCGenerateMesh(occgeo, ngMesh,mparams, startWith, endWith); -#else - err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); -#endif - if (err) comment << "Error in netgen::OCCGenerateMesh() at MESHCONST_ANALYSE step"; + } + // add/remove boundary links + for ( int iSeg = 1; iSeg <= ngMesh.GetNSeg(); ++iSeg ) + { + const netgen::Segment& seg = ngMesh.LineSegment( iSeg ); + if ( seg.si != faceID ) // !edgeIDs.Contains( seg.edgenr )) + continue; + Link link( seg[1], seg[0] ); // reverse!!! + if ( !linkMap.Add( link )) + linkMap.Remove( link ); + } + if ( linkMap.IsEmpty() ) + return true; + if ( linkMap.Extent() < 3 ) + return false; - // fill ngMesh with nodes and elements of computed submeshes - err = ! fillNgMesh(occgeo, *ngMesh, nodeVec, meshedSM); - nbInitNod = ngMesh->GetNP(); - nbInitSeg = ngMesh->GetNSeg(); - nbInitFac = ngMesh->GetNSE(); + // make triangles of the links - // compute mesh - if (!err) - { - startWith = endWith = netgen::MESHCONST_MESHEDGES; -#ifdef NETGEN_V5 - err = netgen::OCCGenerateMesh(occgeo, ngMesh,mparams, startWith, endWith); -#else - err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); -#endif - if (err) comment << "Error in netgen::OCCGenerateMesh() at 1D mesh generation"; - } - // --------------------- - // compute surface mesh - // --------------------- - if (!err) - { - // pass 2D simple parameters to NETGEN - if ( _simpleHyp ) { - if ( double area = _simpleHyp->GetMaxElementArea() ) { - // face area - mparams.maxh = sqrt(2. * area/sqrt(3.0)); - mparams.grading = 0.4; // moderate size growth - } - else { - // length from edges - double length = 0; - for ( TopExp_Explorer exp( _shape, TopAbs_EDGE ); exp.More(); exp.Next() ) - length += SMESH_Algo::EdgeLength( TopoDS::Edge( exp.Current() )); - if ( ngMesh->GetNSeg() ) - mparams.maxh = length / ngMesh->GetNSeg(); - else - mparams.maxh = 1000; - mparams.grading = 0.2; // slow size growth - } - mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 ); - ngMesh->SetGlobalH (mparams.maxh); - netgen::Box<3> bb = occgeo.GetBoundingBox(); - bb.Increase (bb.Diam()/20); - ngMesh->SetLocalH (bb.PMin(), bb.PMax(), mparams.grading); - } - // let netgen compute 2D mesh - startWith = netgen::MESHCONST_MESHSURFACE; - endWith = _optimize ? netgen::MESHCONST_OPTSURFACE : netgen::MESHCONST_MESHSURFACE; -#ifdef NETGEN_V5 - err = netgen::OCCGenerateMesh(occgeo, ngMesh,mparams, startWith, endWith); -#else - err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); -#endif - if (err) comment << "Error in netgen::OCCGenerateMesh() at surface mesh generation"; - } - // --------------------- - // generate volume mesh - // --------------------- - if (!err && _isVolume) + netgen::Element2d tri(3); + tri.SetIndex ( faceID ); + + NCollection_Map::Iterator linkIt( linkMap ); + Link link1 = linkIt.Value(); + // look for a link connected to link1 + NCollection_Map::Iterator linkIt2 = linkIt; + for ( linkIt2.Next(); linkIt2.More(); linkIt2.Next() ) + { + const Link& link2 = linkIt2.Value(); + if ( link2.IsConnected( link1 )) { - // add ng face descriptors of meshed faces - std::map< int, std::pair >::iterator fId_soIds = _faceDescriptors.begin(); - for ( ; fId_soIds != _faceDescriptors.end(); ++fId_soIds ) { - int faceID = fId_soIds->first; - int solidID1 = fId_soIds->second.first; - int solidID2 = fId_soIds->second.second; - ngMesh->AddFaceDescriptor (netgen::FaceDescriptor(faceID, solidID1, solidID2, 0)); - } - // pass 3D simple parameters to NETGEN - const NETGENPlugin_SimpleHypothesis_3D* simple3d = - dynamic_cast< const NETGENPlugin_SimpleHypothesis_3D* > ( _simpleHyp ); - if ( simple3d ) { - if ( double vol = simple3d->GetMaxElementVolume() ) { - // max volume - mparams.maxh = pow( 72, 1/6. ) * pow( vol, 1/3. ); - mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 ); - } - else { - // length from faces - mparams.maxh = ngMesh->AverageH(); + // look for a link connected to both link1 and link2 + NCollection_Map::Iterator linkIt3 = linkIt2; + for ( linkIt3.Next(); linkIt3.More(); linkIt3.Next() ) + { + const Link& link3 = linkIt3.Value(); + if ( link3.IsConnected( link1 ) && + link3.IsConnected( link2 ) ) + { + // add a triangle + tri[0] = link1.n2; + tri[1] = link1.n1; + tri[2] = ( link2.Contains( link1.n1 ) ? link2.n1 : link3.n1 ); + if ( tri[0] == tri[2] || tri[1] == tri[2] ) + return false; + ngMesh.AddSurfaceElement( tri ); + + // prepare for the next tria search + if ( linkMap.Extent() == 3 ) + return true; + linkMap.Remove( link3 ); + linkMap.Remove( link2 ); + linkIt.Next(); + linkMap.Remove( link1 ); + link1 = linkIt.Value(); + linkIt2 = linkIt; + break; } -// netgen::ARRAY maxhdom; -// maxhdom.SetSize (occgeo.NrSolids()); -// maxhdom = mparams.maxh; -// ngMesh->SetMaxHDomain (maxhdom); - ngMesh->SetGlobalH (mparams.maxh); - mparams.grading = 0.4; -#ifdef NETGEN_V5 - ngMesh->CalcLocalH(mparams.grading); -#else - ngMesh->CalcLocalH(); -#endif } - // let netgen compute 3D mesh - startWith = netgen::MESHCONST_MESHVOLUME; - endWith = _optimize ? netgen::MESHCONST_OPTVOLUME : netgen::MESHCONST_MESHVOLUME; -#ifdef NETGEN_V5 - err = netgen::OCCGenerateMesh(occgeo, ngMesh,mparams, startWith, endWith); -#else - err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); -#endif - if (err) comment << "Error in netgen::OCCGenerateMesh()"; } - if (!err && mparams.secondorder > 0) + } + return false; + +} // FixFaceMesh() + +namespace +{ + //================================================================================ + // define gp_XY_Subtracted pointer to function calling gp_XY::Subtracted(gp_XY) + gp_XY_FunPtr(Subtracted); + //gp_XY_FunPtr(Added); + + //================================================================================ + /*! + * \brief Evaluate distance between two 2d points along the surface + */ + //================================================================================ + + double evalDist( const gp_XY& uv1, + const gp_XY& uv2, + const Handle(Geom_Surface)& surf, + const int stopHandler=-1) + { + if ( stopHandler > 0 ) // continue recursion { - netgen::OCCRefinementSurfaces ref (occgeo); - ref.MakeSecondOrder (*ngMesh); + gp_XY mid = SMESH_MesherHelper::GetMiddleUV( surf, uv1, uv2 ); + return evalDist( uv1,mid, surf, stopHandler-1 ) + evalDist( mid,uv2, surf, stopHandler-1 ); } + double dist3D = surf->Value( uv1.X(), uv1.Y() ).Distance( surf->Value( uv2.X(), uv2.Y() )); + if ( stopHandler == 0 ) // stop recursion + return dist3D; + + // start recursion if necessary + double dist2D = SMESH_MesherHelper::ApplyIn2D(surf, uv1, uv2, gp_XY_Subtracted, 0).Modulus(); + if ( fabs( dist3D - dist2D ) < dist2D * 1e-10 ) + return dist3D; // equal parametrization of a planar surface + + return evalDist( uv1, uv2, surf, 3 ); // start recursion } - catch (netgen::NgException exc) + + //================================================================================ + /*! + * \brief Data of vertex internal in geom face + */ + //================================================================================ + + struct TIntVData + { + gp_XY uv; //!< UV in face parametric space + int ngId; //!< ng id of corrsponding node + gp_XY uvClose; //!< UV of closest boundary node + int ngIdClose; //!< ng id of closest boundary node + }; + + //================================================================================ + /*! + * \brief Data of vertex internal in solid + */ + //================================================================================ + + struct TIntVSoData + { + int ngId; //!< ng id of corresponding node + int ngIdClose; //!< ng id of closest 2d mesh element + int ngIdCloseN; //!< ng id of closest node of the closest 2d mesh element + }; + + inline double dist2(const netgen::MeshPoint& p1, const netgen::MeshPoint& p2) { - error->myName = err = COMPERR_ALGO_FAILED; - comment << exc.What(); + return gp_Pnt( NGPOINT_COORDS(p1)).SquareDistance( gp_Pnt( NGPOINT_COORDS(p2))); } +} - int nbNod = ngMesh->GetNP(); - int nbSeg = ngMesh->GetNSeg(); - int nbFac = ngMesh->GetNSE(); - int nbVol = ngMesh->GetNE(); +//================================================================================ +/*! + * \brief Make netgen take internal vertices in faces into account by adding + * segments including internal vertices + * + * This function works in supposition that 1D mesh is already computed in ngMesh + */ +//================================================================================ - MESSAGE((err ? "Mesh Generation failure" : "End of Mesh Generation") << - ", nb nodes: " << nbNod << - ", nb segments: " << nbSeg << - ", nb faces: " << nbFac << - ", nb volumes: " << nbVol); +void NETGENPlugin_Mesher::AddIntVerticesInFaces(const netgen::OCCGeometry& occgeom, + netgen::Mesh& ngMesh, + vector& nodeVec, + NETGENPlugin_Internals& internalShapes) +{ + if ( nodeVec.size() < ngMesh.GetNP() ) + nodeVec.resize( ngMesh.GetNP(), 0 ); - // ----------------------------------------------------------- - // Feed back the SMESHDS with the generated Nodes and Elements - // ----------------------------------------------------------- + SMESHDS_Mesh* meshDS = internalShapes.getMesh().GetMeshDS(); + SMESH_MesherHelper helper( internalShapes.getMesh() ); - SMESHDS_Mesh* meshDS = _mesh->GetMeshDS(); - bool isOK = ( !err && (_isVolume ? (nbVol > 0) : (nbFac > 0)) ); - if ( true /*isOK*/ ) // get whatever built + const map >& face2Vert = internalShapes.getFacesWithVertices(); + map >::const_iterator f2v = face2Vert.begin(); + for ( ; f2v != face2Vert.end(); ++f2v ) { - // map of nodes assigned to submeshes - NCollection_Map pindMap; - // create and insert nodes into nodeVec - nodeVec.resize( nbNod + 1 ); - int i; - for (i = nbInitNod+1; i <= nbNod /*&& isOK*/; ++i ) - { - const netgen::MeshPoint& ngPoint = ngMesh->Point(i); - SMDS_MeshNode* node = NULL; - bool newNodeOnVertex = false; - TopoDS_Vertex aVert; - if (i-nbInitNod <= occgeo.vmap.Extent()) - { - // point on vertex - aVert = TopoDS::Vertex(occgeo.vmap(i-nbInitNod)); - SMESHDS_SubMesh * submesh = meshDS->MeshElements(aVert); - if (submesh) - { - SMDS_NodeIteratorPtr it = submesh->GetNodes(); - if (it->more()) - { - node = const_cast (it->next()); - pindMap.Add(i); - } - } - if (!node) - newNodeOnVertex = true; - } - if (!node) - node = meshDS->AddNode(ngPoint(0), ngPoint(1), ngPoint(2)); - if (!node) + const TopoDS_Face& face = TopoDS::Face( meshDS->IndexToShape( f2v->first )); + if ( face.IsNull() ) continue; + int faceNgID = occgeom.fmap.FindIndex (face); + if ( faceNgID < 0 ) continue; + + TopLoc_Location loc; + Handle(Geom_Surface) surf = BRep_Tool::Surface(face,loc); + + helper.SetSubShape( face ); + helper.SetElementsOnShape( true ); + + // Get data of internal vertices and add them to ngMesh + + multimap< double, TIntVData > dist2VData; // sort vertices by distance from boundary nodes + + int i, nbSegInit = ngMesh.GetNSeg(); + + // boundary characteristics + double totSegLen2D = 0; + int totNbSeg = 0; + + const list& iVertices = f2v->second; + list::const_iterator iv = iVertices.begin(); + for ( int nbV = 0; iv != iVertices.end(); ++iv, nbV++ ) + { + TIntVData vData; + // get node on vertex + const TopoDS_Vertex V = TopoDS::Vertex( meshDS->IndexToShape( *iv )); + const SMDS_MeshNode * nV = SMESH_Algo::VertexNode( V, meshDS ); + if ( !nV ) { - MESSAGE("Cannot create a mesh node"); - if ( !comment.size() ) comment << "Cannot create a mesh node"; - nbSeg = nbFac = nbVol = isOK = 0; - break; + SMESH_subMesh* sm = helper.GetMesh()->GetSubMesh( V ); + sm->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + nV = SMESH_Algo::VertexNode( V, meshDS ); + if ( !nV ) continue; } - nodeVec.at(i) = node; - if (newNodeOnVertex) + // add ng node + netgen::MeshPoint mp( netgen::Point<3> (nV->X(), nV->Y(), nV->Z()) ); + ngMesh.AddPoint ( mp, 1, netgen::EDGEPOINT ); + vData.ngId = ngMesh.GetNP(); + nodeVec.push_back( nV ); + + // get node UV + bool uvOK = true; + vData.uv = helper.GetNodeUV( face, nV, 0, &uvOK ); + if ( !uvOK ) helper.CheckNodeUV( face, nV, vData.uv, BRep_Tool::Tolerance(V),/*force=*/1); + + // loop on all segments of the face to find the node closest to vertex and to count + // average segment 2d length + double closeDist2 = numeric_limits::max(), dist2; + int ngIdLast = 0; + for (i = 1; i <= ngMesh.GetNSeg(); ++i) { - // point on vertex - meshDS->SetNodeOnVertex(node, aVert); - pindMap.Add(i); + netgen::Segment & seg = ngMesh.LineSegment(i); + if ( seg.si != faceNgID ) continue; + gp_XY uv[2]; + for ( int iEnd = 0; iEnd < 2; ++iEnd) + { + uv[iEnd].SetCoord( seg.epgeominfo[iEnd].u, seg.epgeominfo[iEnd].v ); + if ( ngIdLast == seg[ iEnd ] ) continue; + dist2 = helper.ApplyIn2D(surf, uv[iEnd], vData.uv, gp_XY_Subtracted,0).SquareModulus(); + if ( dist2 < closeDist2 ) + vData.ngIdClose = seg[ iEnd ], vData.uvClose = uv[iEnd], closeDist2 = dist2; + ngIdLast = seg[ iEnd ]; + } + if ( !nbV ) + { + totSegLen2D += helper.ApplyIn2D(surf, uv[0], uv[1], gp_XY_Subtracted, false).Modulus(); + totNbSeg++; + } } + dist2VData.insert( make_pair( closeDist2, vData )); } - // create mesh segments along geometric edges - NCollection_Map linkMap; - for (i = nbInitSeg+1; i <= nbSeg/* && isOK*/; ++i ) + if ( totNbSeg == 0 ) break; + double avgSegLen2d = totSegLen2D / totNbSeg; + + // Loop on vertices to add segments + + multimap< double, TIntVData >::iterator dist_vData = dist2VData.begin(); + for ( ; dist_vData != dist2VData.end(); ++dist_vData ) { - const netgen::Segment& seg = ngMesh->LineSegment(i); - Link link(seg.pnums[0], seg.pnums[1]); - if (linkMap.Contains(link)) - continue; - linkMap.Add(link); - TopoDS_Edge aEdge; - int pinds[3] = { seg.pnums[0], seg.pnums[1], seg.pnums[2] }; - int nbp = 0; - double param2 = 0; - for (int j=0; j < 3; ++j) - { - int pind = pinds[j]; - if (pind <= 0) continue; - ++nbp; - double param; - if (j < 2) - { - if (aEdge.IsNull()) - { - int aGeomEdgeInd = seg.epgeominfo[j].edgenr; - if (aGeomEdgeInd > 0 && aGeomEdgeInd <= occgeo.emap.Extent()) - aEdge = TopoDS::Edge(occgeo.emap(aGeomEdgeInd)); - } - param = seg.epgeominfo[j].dist; - param2 += param; - } - else - param = param2 * 0.5; - if (pind <= nbInitNod || pindMap.Contains(pind)) - continue; - if (!aEdge.IsNull()) + double closeDist2 = dist_vData->first, dist2; + TIntVData & vData = dist_vData->second; + + // try to find more close node among segments added for internal vertices + for (i = nbSegInit+1; i <= ngMesh.GetNSeg(); ++i) + { + netgen::Segment & seg = ngMesh.LineSegment(i); + if ( seg.si != faceNgID ) continue; + gp_XY uv[2]; + for ( int iEnd = 0; iEnd < 2; ++iEnd) { - meshDS->SetNodeOnEdge(nodeVec.at(pind), aEdge, param); - pindMap.Add(pind); + uv[iEnd].SetCoord( seg.epgeominfo[iEnd].u, seg.epgeominfo[iEnd].v ); + dist2 = helper.ApplyIn2D(surf, uv[iEnd], vData.uv, gp_XY_Subtracted,0).SquareModulus(); + if ( dist2 < closeDist2 ) + vData.ngIdClose = seg[ iEnd ], vData.uvClose = uv[iEnd], closeDist2 = dist2; } } - SMDS_MeshEdge* edge; - if (nbp < 3) // second order ? - edge = meshDS->AddEdge(nodeVec.at(pinds[0]), nodeVec.at(pinds[1])); - else - edge = meshDS->AddEdge(nodeVec.at(pinds[0]), nodeVec.at(pinds[1]), - nodeVec.at(pinds[2])); - if (!edge) + // decide whether to use the closest node as the second end of segment or to + // create a new point + int segEnd1 = vData.ngId; + int segEnd2 = vData.ngIdClose; // to use closest node + gp_XY uvV = vData.uv, uvP = vData.uvClose; + double segLenHint = ngMesh.GetH( ngMesh.Point( vData.ngId )); + double nodeDist2D = sqrt( closeDist2 ); + double nodeDist3D = evalDist( vData.uv, vData.uvClose, surf ); + bool avgLenOK = ( avgSegLen2d < 0.75 * nodeDist2D ); + bool hintLenOK = ( segLenHint < 0.75 * nodeDist3D ); + //cout << "uvV " << uvV.X() <<","<Value( uvP.X(), uvP.Y() ).Transformed( loc ); + + netgen::MeshPoint mp( netgen::Point<3> (P.X(), P.Y(), P.Z())); + ngMesh.AddPoint ( mp, 1, netgen::EDGEPOINT ); + segEnd2 = ngMesh.GetNP(); + //cout << "Middle " << r << " uv " << uvP.X() << "," << uvP.Y() << "( " << ngMesh.Point(segEnd2).X()<<","<SetMeshElementOnShape(edge, aEdge); + //else cout << "at Node " << " uv " << uvP.X() << "," << uvP.Y() << endl; + + // Add the segment + netgen::Segment seg; + + if ( segEnd1 > segEnd2 ) swap( segEnd1, segEnd2 ), swap( uvV, uvP ); + seg[0] = segEnd1; // ng node id + seg[1] = segEnd2; // ng node id + seg.edgenr = ngMesh.GetNSeg() + 1;// segment id + seg.si = faceNgID; + + seg.epgeominfo[ 0 ].dist = 0; // param on curve + seg.epgeominfo[ 0 ].u = uvV.X(); + seg.epgeominfo[ 0 ].v = uvV.Y(); + seg.epgeominfo[ 1 ].dist = 1; // param on curve + seg.epgeominfo[ 1 ].u = uvP.X(); + seg.epgeominfo[ 1 ].v = uvP.Y(); + +// seg.epgeominfo[ 0 ].edgenr = 10; // = geom.emap.FindIndex(edge); +// seg.epgeominfo[ 1 ].edgenr = 10; // = geom.emap.FindIndex(edge); + + ngMesh.AddSegment (seg); + + // add reverse segment + swap (seg[0], seg[1]); + swap( seg.epgeominfo[0], seg.epgeominfo[1] ); + seg.edgenr = ngMesh.GetNSeg() + 1; // segment id + ngMesh.AddSegment (seg); } - // create mesh faces along geometric faces - for (i = nbInitFac+1; i <= nbFac/* && isOK*/; ++i ) + } +} + +//================================================================================ +/*! + * \brief Make netgen take internal vertices in solids into account by adding + * faces including internal vertices + * + * This function works in supposition that 2D mesh is already computed in ngMesh + */ +//================================================================================ + +void NETGENPlugin_Mesher::AddIntVerticesInSolids(const netgen::OCCGeometry& occgeom, + netgen::Mesh& ngMesh, + vector& nodeVec, + NETGENPlugin_Internals& internalShapes) +{ +#ifdef DUMP_TRIANGLES_SCRIPT + // create a python script making a mesh containing triangles added for internal vertices + ofstream py(DUMP_TRIANGLES_SCRIPT); + py << "import SMESH"<< endl + << "from salome.smesh import smeshBuilder"< >& so2Vert = internalShapes.getSolidsWithVertices(); + map >::const_iterator s2v = so2Vert.begin(); + for ( ; s2v != so2Vert.end(); ++s2v ) + { + const TopoDS_Shape& solid = meshDS->IndexToShape( s2v->first ); + if ( solid.IsNull() ) continue; + int solidNgID = occgeom.somap.FindIndex (solid); + if ( solidNgID < 0 && !occgeom.somap.IsEmpty() ) continue; + + helper.SetSubShape( solid ); + helper.SetElementsOnShape( true ); + + // find ng indices of faces within the solid + set ngFaceIds; + for (TopExp_Explorer fExp(solid, TopAbs_FACE); fExp.More(); fExp.Next() ) + ngFaceIds.insert( occgeom.fmap.FindIndex( fExp.Current() )); + if ( ngFaceIds.size() == 1 && *ngFaceIds.begin() == 0 ) + ngFaceIds.insert( 1 ); + + // Get data of internal vertices and add them to ngMesh + + multimap< double, TIntVSoData > dist2VData; // sort vertices by distance from ng faces + + int i, nbFaceInit = ngMesh.GetNSE(); + + // boundary characteristics + double totSegLen = 0; + int totNbSeg = 0; + + const list& iVertices = s2v->second; + list::const_iterator iv = iVertices.begin(); + for ( int nbV = 0; iv != iVertices.end(); ++iv, nbV++ ) { - const netgen::Element2d& elem = ngMesh->SurfaceElement(i); - int aGeomFaceInd = elem.GetIndex(); - TopoDS_Face aFace; - if (aGeomFaceInd > 0 && aGeomFaceInd <= occgeo.fmap.Extent()) - aFace = TopoDS::Face(occgeo.fmap(aGeomFaceInd)); - vector nodes; - for (int j=1; j <= elem.GetNP(); ++j) - { - int pind = elem.PNum(j); - SMDS_MeshNode* node = nodeVec.at(pind); - nodes.push_back(node); - if (pind <= nbInitNod || pindMap.Contains(pind)) - continue; - if (!aFace.IsNull()) - { - const netgen::PointGeomInfo& pgi = elem.GeomInfoPi(j); - meshDS->SetNodeOnFace(node, aFace, pgi.u, pgi.v); - pindMap.Add(pind); - } - } - SMDS_MeshFace* face = NULL; - switch (elem.GetType()) + TIntVSoData vData; + const TopoDS_Vertex V = TopoDS::Vertex( meshDS->IndexToShape( *iv )); + + // get node on vertex + const SMDS_MeshNode * nV = SMESH_Algo::VertexNode( V, meshDS ); + if ( !nV ) { - case netgen::TRIG: - face = meshDS->AddFace(nodes[0],nodes[1],nodes[2]); - break; - case netgen::QUAD: - face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[3]); - break; - case netgen::TRIG6: - face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[5],nodes[3],nodes[4]); - break; - case netgen::QUAD8: - face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[3], - nodes[4],nodes[7],nodes[5],nodes[6]); - break; - default: - MESSAGE("NETGEN created a face of unexpected type, ignoring"); - continue; + SMESH_subMesh* sm = helper.GetMesh()->GetSubMesh( V ); + sm->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + nV = SMESH_Algo::VertexNode( V, meshDS ); + if ( !nV ) continue; } - if (!face) + // add ng node + netgen::MeshPoint mpV( netgen::Point<3> (nV->X(), nV->Y(), nV->Z()) ); + ngMesh.AddPoint ( mpV, 1, netgen::FIXEDPOINT ); + vData.ngId = ngMesh.GetNP(); + nodeVec.push_back( nV ); + + // loop on all 2d elements to find the one closest to vertex and to count + // average segment length + double closeDist2 = numeric_limits::max(), avgDist2; + for (i = 1; i <= ngMesh.GetNSE(); ++i) { - if ( !comment.size() ) comment << "Cannot create a mesh face"; - MESSAGE("Cannot create a mesh face"); - nbSeg = nbFac = nbVol = isOK = 0; - break; + const netgen::Element2d& elem = ngMesh.SurfaceElement(i); + if ( !ngFaceIds.count( elem.GetIndex() )) continue; + avgDist2 = 0; + multimap< double, int> dist2nID; // sort nodes of element by distance from V + for ( int j = 0; j < elem.GetNP(); ++j) + { + netgen::MeshPoint mp = ngMesh.Point( elem[j] ); + double d2 = dist2( mpV, mp ); + dist2nID.insert( make_pair( d2, elem[j] )); + avgDist2 += d2 / elem.GetNP(); + if ( !nbV ) + totNbSeg++, totSegLen+= sqrt( dist2( mp, ngMesh.Point( elem[(j+1)%elem.GetNP()]))); + } + double dist = dist2nID.begin()->first; //avgDist2; + if ( dist < closeDist2 ) + vData.ngIdClose= i, vData.ngIdCloseN= dist2nID.begin()->second, closeDist2= dist; } - if (!aFace.IsNull()) - meshDS->SetMeshElementOnShape(face, aFace); + dist2VData.insert( make_pair( closeDist2, vData )); } - // create tetrahedra - for (i = 1; i <= nbVol/* && isOK*/; ++i) + if ( totNbSeg == 0 ) break; + double avgSegLen = totSegLen / totNbSeg; + + // Loop on vertices to add triangles + + multimap< double, TIntVSoData >::iterator dist_vData = dist2VData.begin(); + for ( ; dist_vData != dist2VData.end(); ++dist_vData ) { - const netgen::Element& elem = ngMesh->VolumeElement(i); - int aSolidInd = elem.GetIndex(); - TopoDS_Solid aSolid; - if (aSolidInd > 0 && aSolidInd <= occgeo.somap.Extent()) - aSolid = TopoDS::Solid(occgeo.somap(aSolidInd)); - vector nodes; - for (int j=1; j <= elem.GetNP(); ++j) + double closeDist2 = dist_vData->first; + TIntVSoData & vData = dist_vData->second; + + const netgen::MeshPoint& mpV = ngMesh.Point( vData.ngId ); + + // try to find more close face among ones added for internal vertices + for (i = nbFaceInit+1; i <= ngMesh.GetNSE(); ++i) { - int pind = elem.PNum(j); - SMDS_MeshNode* node = nodeVec.at(pind); - nodes.push_back(node); - if (pind <= nbInitNod || pindMap.Contains(pind)) - continue; - if (!aSolid.IsNull()) + double avgDist2 = 0; + multimap< double, int> dist2nID; + const netgen::Element2d& elem = ngMesh.SurfaceElement(i); + for ( int j = 0; j < elem.GetNP(); ++j) { - // point in solid - meshDS->SetNodeInVolume(node, aSolid); - pindMap.Add(pind); + double d = dist2( mpV, ngMesh.Point( elem[j] )); + dist2nID.insert( make_pair( d, elem[j] )); + avgDist2 += d / elem.GetNP(); + if ( avgDist2 < closeDist2 ) + vData.ngIdClose= i, vData.ngIdCloseN= dist2nID.begin()->second, closeDist2= avgDist2; } } - SMDS_MeshVolume* vol = NULL; - switch (elem.GetType()) + // sort nodes of the closest face by angle with vector from V to the closest node + const double tol = numeric_limits::min(); + map< double, int > angle2ID; + const netgen::Element2d& closeFace = ngMesh.SurfaceElement( vData.ngIdClose ); + netgen::MeshPoint mp[2]; + mp[0] = ngMesh.Point( vData.ngIdCloseN ); + gp_XYZ p1( NGPOINT_COORDS( mp[0] )); + gp_XYZ pV( NGPOINT_COORDS( mpV )); + gp_Vec v2p1( pV, p1 ); + double distN1 = v2p1.Magnitude(); + if ( distN1 <= tol ) continue; + v2p1 /= distN1; + for ( int j = 0; j < closeFace.GetNP(); ++j) { - case netgen::TET: - vol = meshDS->AddVolume(nodes[0],nodes[1],nodes[2],nodes[3]); - break; - case netgen::TET10: - vol = meshDS->AddVolume(nodes[0],nodes[1],nodes[2],nodes[3], - nodes[4],nodes[7],nodes[5],nodes[6],nodes[8],nodes[9]); - break; - default: - MESSAGE("NETGEN created a volume of unexpected type, ignoring"); - continue; + mp[1] = ngMesh.Point( closeFace[j] ); + gp_Vec v2p( pV, gp_Pnt( NGPOINT_COORDS( mp[1] )) ); + angle2ID.insert( make_pair( v2p1.Angle( v2p ), closeFace[j])); } - if (!vol) + // get node with angle of 60 degrees or greater + map< double, int >::iterator angle_id = angle2ID.lower_bound( 60. * M_PI / 180. ); + if ( angle_id == angle2ID.end() ) angle_id = --angle2ID.end(); + const double minAngle = 30. * M_PI / 180.; + const double angle = angle_id->first; + bool angleOK = ( angle > minAngle ); + + // find points to create a triangle + netgen::Element2d tri(3); + tri.SetIndex ( 1 ); + tri[0] = vData.ngId; + tri[1] = vData.ngIdCloseN; // to use the closest nodes + tri[2] = angle_id->second; // to use the node with best angle + + // decide whether to use the closest node and the node with best angle or to create new ones + for ( int isBestAngleN = 0; isBestAngleN < 2; ++isBestAngleN ) { - if ( !comment.size() ) comment << "Cannot create a mesh volume"; - MESSAGE("Cannot create a mesh volume"); - nbSeg = nbFac = nbVol = isOK = 0; - break; + bool createNew = !angleOK, distOK = true; + double distFromV; + int triInd = isBestAngleN ? 2 : 1; + mp[isBestAngleN] = ngMesh.Point( tri[triInd] ); + if ( isBestAngleN ) + { + if ( angleOK ) + { + double distN2 = sqrt( dist2( mpV, mp[isBestAngleN])); + createNew = ( fabs( distN2 - distN1 ) > 0.25 * distN1 ); + } + else if ( angle < tol ) + { + v2p1.SetX( v2p1.X() + 1e-3 ); + } + distFromV = distN1; + } + else + { + double segLenHint = ngMesh.GetH( ngMesh.Point( vData.ngId )); + bool avgLenOK = ( avgSegLen < 0.75 * distN1 ); + bool hintLenOK = ( segLenHint < 0.75 * distN1 ); + createNew = (createNew || avgLenOK || hintLenOK ); + // we create a new node not closer than 0.5 to the closest face + // in order not to clash with other close face + double r = min( 0.5, ( hintLenOK ? segLenHint : avgSegLen ) / distN1 ); + distFromV = r * distN1; + } + if ( createNew ) + { + // create a new point, between the node and the vertex if angleOK + gp_XYZ p( NGPOINT_COORDS( mp[isBestAngleN] )); + gp_Vec v2p( pV, p ); v2p.Normalize(); + if ( isBestAngleN && !angleOK ) + p = p1 + gp_Dir( v2p.XYZ() - v2p1.XYZ()).XYZ() * distN1 * 0.95; + else + p = pV + v2p.XYZ() * distFromV; + + if ( !isBestAngleN ) p1 = p, distN1 = distFromV; + + mp[isBestAngleN].SetPoint( netgen::Point<3> (p.X(), p.Y(), p.Z())); + ngMesh.AddPoint ( mp[isBestAngleN], 1, netgen::SURFACEPOINT ); + tri[triInd] = ngMesh.GetNP(); + nodeVec.push_back( helper.AddNode( p.X(), p.Y(), p.Z()) ); + } } - if (!aSolid.IsNull()) - meshDS->SetMeshElementOnShape(vol, aSolid); + ngMesh.AddSurfaceElement (tri); + swap( tri[1], tri[2] ); + ngMesh.AddSurfaceElement (tri); + +#ifdef DUMP_TRIANGLES_SCRIPT + py << "n1 = m.AddNode( "<< mpV(0)<<", "<< mpV(1)<<", "<< mpV(2)<<") "<< endl + << "n2 = m.AddNode( "<< mp[0](0)<<", "<< mp[0](1)<<", "<< mp[0](2)<<") "<< endl + << "n3 = m.AddNode( "<< mp[1](0)<<", "<< mp[1](1)<<", "<< mp[1](2)<<" )" << endl + << "m.AddFace([n1,n2,n3])" << endl; +#endif + } // loop on internal vertices of a solid + + } // loop on solids with internal vertices +} + +//================================================================================ +/*! + * \brief Fill netgen mesh with segments of a FACE + * \param ngMesh - netgen mesh + * \param geom - container of OCCT geometry to mesh + * \param wires - data of nodes on FACE boundary + * \param helper - mesher helper holding the FACE + * \param nodeVec - vector of nodes in which node index == netgen ID + * \retval SMESH_ComputeErrorPtr - error description + */ +//================================================================================ + +SMESH_ComputeErrorPtr +NETGENPlugin_Mesher::AddSegmentsToMesh(netgen::Mesh& ngMesh, + netgen::OCCGeometry& geom, + const TSideVector& wires, + SMESH_MesherHelper& helper, + vector< const SMDS_MeshNode* > & nodeVec, + const bool overrideMinH) +{ + // ---------------------------- + // Check wires and count nodes + // ---------------------------- + int nbNodes = 0; + for ( int iW = 0; iW < wires.size(); ++iW ) + { + StdMeshers_FaceSidePtr wire = wires[ iW ]; + if ( wire->MissVertexNode() ) + { + // Commented for issue 0020960. It worked for the case, let's wait for case where it doesn't. + // It seems that there is no reason for this limitation +// return TError +// (new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH, "Missing nodes on vertices")); } + const vector& uvPtVec = wire->GetUVPtStruct(); + if ( uvPtVec.size() != wire->NbPoints() ) + return SMESH_ComputeError::New(COMPERR_BAD_INPUT_MESH, + SMESH_Comment("Unexpected nb of points on wire ") << iW + << ": " << uvPtVec.size()<<" != "<NbPoints()); + nbNodes += wire->NbPoints(); } + nodeVec.reserve( nodeVec.size() + nbNodes + 1 ); + if ( nodeVec.empty() ) + nodeVec.push_back( 0 ); - if ( error->IsOK() && ( !isOK || comment.size() > 0 )) - error->myName = COMPERR_ALGO_FAILED; - if ( !comment.empty() ) - error->myComment = comment; + // ----------------- + // Fill netgen mesh + // ----------------- + + const bool wasNgMeshEmpty = ( ngMesh.GetNP() < 1 ); /* true => this method is called by + NETGENPlugin_NETGEN_2D_ONLY */ - // set bad compute error to subshapes of all failed subshapes shapes - if ( !error->IsOK() && err ) + // map for nodes on vertices since they can be shared between wires + // ( issue 0020676, face_int_box.brep) and nodes built by NETGEN + map node2ngID; + if ( !wasNgMeshEmpty ) // fill node2ngID with nodes built by NETGEN { - for (int i = 1; i <= occgeo.fmap.Extent(); i++) { - int status = occgeo.facemeshstatus[i-1]; - if (status == 1 ) continue; - if ( SMESH_subMesh* sm = _mesh->GetSubMeshContaining( occgeo.fmap( i ))) { - SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); - if ( !smError || smError->IsOK() ) { - if ( status == -1 ) - smError.reset( new SMESH_ComputeError( error->myName, error->myComment )); - else - smError.reset( new SMESH_ComputeError( COMPERR_ALGO_FAILED, "Ignored" )); - } + set< int > subIDs; // ids of sub-shapes of the FACE + for ( int iW = 0; iW < wires.size(); ++iW ) + { + StdMeshers_FaceSidePtr wire = wires[ iW ]; + for ( int iE = 0, nbE = wire->NbEdges(); iE < nbE; ++iE ) + { + subIDs.insert( wire->EdgeID( iE )); + subIDs.insert( helper.GetMeshDS()->ShapeToIndex( wire->FirstVertex( iE ))); } } + for ( size_t ngID = 1; ngID < nodeVec.size(); ++ngID ) + if ( subIDs.count( nodeVec[ngID]->getshapeId() )) + node2ngID.insert( make_pair( nodeVec[ngID], ngID )); } - nglib::Ng_DeleteMesh((nglib::Ng_Mesh*)ngMesh); - nglib::Ng_Exit(); + const int solidID = 0, faceID = geom.fmap.FindIndex( helper.GetSubShape() ); + if ( ngMesh.GetNFD() < 1 ) + ngMesh.AddFaceDescriptor (netgen::FaceDescriptor(faceID, solidID, solidID, 0)); - //RemoveTmpFiles(); + for ( int iW = 0; iW < wires.size(); ++iW ) + { + StdMeshers_FaceSidePtr wire = wires[ iW ]; + const vector& uvPtVec = wire->GetUVPtStruct(); + const int nbSegments = wire->NbPoints() - 1; + + // assure the 1st node to be in node2ngID, which is needed to correctly + // "close chain of segments" (see below) in case if the 1st node is not + // onVertex because it is on a Viscous layer + node2ngID.insert( make_pair( uvPtVec[ 0 ].node, ngMesh.GetNP() + 1 )); + + // compute length of every segment + vector segLen( nbSegments ); + for ( int i = 0; i < nbSegments; ++i ) + segLen[i] = SMESH_TNodeXYZ( uvPtVec[ i ].node ).Distance( uvPtVec[ i+1 ].node ); + + int edgeID = 1, posID = -2; + bool isInternalWire = false; + double vertexNormPar = 0; + const int prevNbNGSeg = ngMesh.GetNSeg(); + for ( int i = 0; i < nbSegments; ++i ) // loop on segments + { + // Add the first point of a segment - return error->IsOK(); -} + const SMDS_MeshNode * n = uvPtVec[ i ].node; + const int posShapeID = n->getshapeId(); + bool onVertex = ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX ); + bool onEdge = ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_EDGE ); -//================================================================================ -/*! - * \brief Remove "test.out" and "problemfaces" files in current directory - */ -//================================================================================ + // skip nodes on degenerated edges + if ( helper.IsDegenShape( posShapeID ) && + helper.IsDegenShape( uvPtVec[ i+1 ].node->getshapeId() )) + continue; -void NETGENPlugin_Mesher::RemoveTmpFiles() -{ - TCollection_AsciiString str("test.out"); - OSD_Path path1( str ); - OSD_File file1( path1 ); - file1.Remove(); - str = "problemfaces"; - OSD_Path path2( str ); - OSD_File file2( path2 ); - file2.Remove(); + int ngID1 = ngMesh.GetNP() + 1, ngID2 = ngID1+1; + if ( onVertex || ( !wasNgMeshEmpty && onEdge ) || helper.IsRealSeam( posShapeID )) + ngID1 = node2ngID.insert( make_pair( n, ngID1 )).first->second; + if ( ngID1 > ngMesh.GetNP() ) + { + netgen::MeshPoint mp( netgen::Point<3> (n->X(), n->Y(), n->Z()) ); + ngMesh.AddPoint ( mp, 1, netgen::EDGEPOINT ); + nodeVec.push_back( n ); + } + else // n is in ngMesh already, and ngID2 in prev segment is wrong + { + ngID2 = ngMesh.GetNP() + 1; + if ( i > 0 ) // prev segment belongs to same wire + { + netgen::Segment& prevSeg = ngMesh.LineSegment( ngMesh.GetNSeg() ); + prevSeg[1] = ngID1; + } + } + + // Add the segment + + netgen::Segment seg; + + seg[0] = ngID1; // ng node id + seg[1] = ngID2; // ng node id + seg.edgenr = ngMesh.GetNSeg() + 1; // ng segment id + seg.si = faceID; // = geom.fmap.FindIndex (face); + + for ( int iEnd = 0; iEnd < 2; ++iEnd) + { + const UVPtStruct& pnt = uvPtVec[ i + iEnd ]; + + seg.epgeominfo[ iEnd ].dist = pnt.param; // param on curve + seg.epgeominfo[ iEnd ].u = pnt.u; + seg.epgeominfo[ iEnd ].v = pnt.v; + + // find out edge id and node parameter on edge + onVertex = ( pnt.normParam + 1e-10 > vertexNormPar ); + if ( onVertex || posShapeID != posID ) + { + // get edge id + double normParam = pnt.normParam; + if ( onVertex ) + normParam = 0.5 * ( uvPtVec[ i ].normParam + uvPtVec[ i+1 ].normParam ); + int edgeIndexInWire = wire->EdgeIndex( normParam ); + vertexNormPar = wire->LastParameter( edgeIndexInWire ); + const TopoDS_Edge& edge = wire->Edge( edgeIndexInWire ); + edgeID = geom.emap.FindIndex( edge ); + posID = posShapeID; + isInternalWire = ( edge.Orientation() == TopAbs_INTERNAL ); + // if ( onVertex ) // param on curve is different on each of two edges + // seg.epgeominfo[ iEnd ].dist = helper.GetNodeU( edge, pnt.node ); + } + seg.epgeominfo[ iEnd ].edgenr = edgeID; // = geom.emap.FindIndex(edge); + } + + ngMesh.AddSegment (seg); + { + // restrict size of elements near the segment + SMESH_TNodeXYZ np1( n ), np2( uvPtVec[ i+1 ].node ); + // get an average size of adjacent segments to avoid sharp change of + // element size (regression on issue 0020452, note 0010898) + int iPrev = SMESH_MesherHelper::WrapIndex( i-1, nbSegments ); + int iNext = SMESH_MesherHelper::WrapIndex( i+1, nbSegments ); + double sumH = segLen[ iPrev ] + segLen[ i ] + segLen[ iNext ]; + int nbSeg = ( int( segLen[ iPrev ] > sumH / 100.) + + int( segLen[ i ] > sumH / 100.) + + int( segLen[ iNext ] > sumH / 100.)); + if ( nbSeg > 0 ) + RestrictLocalSize( ngMesh, 0.5*(np1+np2), sumH / nbSeg, overrideMinH ); + } + if ( isInternalWire ) + { + swap (seg[0], seg[1]); + swap( seg.epgeominfo[0], seg.epgeominfo[1] ); + seg.edgenr = ngMesh.GetNSeg() + 1; // segment id + ngMesh.AddSegment (seg); + } + } // loop on segments on a wire + + // close chain of segments + if ( nbSegments > 0 ) + { + netgen::Segment& lastSeg = ngMesh.LineSegment( ngMesh.GetNSeg() - int( isInternalWire)); + const SMDS_MeshNode * lastNode = uvPtVec.back().node; + lastSeg[1] = node2ngID.insert( make_pair( lastNode, lastSeg[1] )).first->second; + if ( lastSeg[1] > ngMesh.GetNP() ) + { + netgen::MeshPoint mp( netgen::Point<3> (lastNode->X(), lastNode->Y(), lastNode->Z()) ); + ngMesh.AddPoint ( mp, 1, netgen::EDGEPOINT ); + nodeVec.push_back( lastNode ); + } + if ( isInternalWire ) + { + netgen::Segment& realLastSeg = ngMesh.LineSegment( ngMesh.GetNSeg() ); + realLastSeg[0] = lastSeg[1]; + } + } + +#ifdef DUMP_SEGMENTS + cout << "BEGIN WIRE " << iW << endl; + for ( int i = prevNbNGSeg+1; i <= ngMesh.GetNSeg(); ++i ) + { + netgen::Segment& seg = ngMesh.LineSegment( i ); + if ( i > 1 ) { + netgen::Segment& prevSeg = ngMesh.LineSegment( i-1 ); + if ( seg[0] == prevSeg[1] && seg[1] == prevSeg[0] ) + { + cout << "Segment: " << seg.edgenr << endl << "\tis REVRESE of the previous one" << endl; + continue; + } + } + cout << "Segment: " << seg.edgenr << endl + << "\tp1: " << seg[0] << " n" << nodeVec[ seg[0]]->GetID() << endl + << "\tp2: " << seg[1] << " n" << nodeVec[ seg[1]]->GetID() << endl + << "\tp0 param: " << seg.epgeominfo[ 0 ].dist << endl + << "\tp0 uv: " << seg.epgeominfo[ 0 ].u <<", "<< seg.epgeominfo[ 0 ].v << endl + << "\tp0 edge: " << seg.epgeominfo[ 0 ].edgenr << endl + << "\tp1 param: " << seg.epgeominfo[ 1 ].dist << endl + << "\tp1 uv: " << seg.epgeominfo[ 1 ].u <<", "<< seg.epgeominfo[ 1 ].v << endl + << "\tp1 edge: " << seg.epgeominfo[ 1 ].edgenr << endl; + } + cout << "--END WIRE " << iW << endl; +#endif + + } // loop on WIREs of a FACE + + // add a segment instead of an internal vertex + if ( wasNgMeshEmpty ) + { + NETGENPlugin_Internals intShapes( *helper.GetMesh(), helper.GetSubShape(), /*is3D=*/false ); + AddIntVerticesInFaces( geom, ngMesh, nodeVec, intShapes ); + } + ngMesh.CalcSurfacesOfNode(); + + return TError(); +} + +//================================================================================ +/*! + * \brief Fill SMESH mesh according to contents of netgen mesh + * \param occgeo - container of OCCT geometry to mesh + * \param ngMesh - netgen mesh + * \param initState - bn of entities in netgen mesh before computing + * \param sMesh - SMESH mesh to fill in + * \param nodeVec - vector of nodes in which node index == netgen ID + * \param comment - returns problem description + * \param quadHelper - holder of medium nodes of sub-meshes + * \retval int - error + */ +//================================================================================ + +int NETGENPlugin_Mesher::FillSMesh(const netgen::OCCGeometry& occgeo, + netgen::Mesh& ngMesh, + const NETGENPlugin_ngMeshInfo& initState, + SMESH_Mesh& sMesh, + std::vector& nodeVec, + SMESH_Comment& comment, + SMESH_MesherHelper* quadHelper) +{ + int nbNod = ngMesh.GetNP(); + int nbSeg = ngMesh.GetNSeg(); + int nbFac = ngMesh.GetNSE(); + int nbVol = ngMesh.GetNE(); + + SMESHDS_Mesh* meshDS = sMesh.GetMeshDS(); + + // quadHelper is used for either + // 1) making quadratic elements when a lower dimention mesh is loaded + // to SMESH before convertion to quadratic by NETGEN + // 2) sewing of quadratic elements with quadratic elements of sub-meshes + if ( quadHelper && !quadHelper->GetIsQuadratic() && quadHelper->GetTLinkNodeMap().empty() ) + quadHelper = 0; + + // ------------------------------------- + // Create and insert nodes into nodeVec + // ------------------------------------- + + nodeVec.resize( nbNod + 1 ); + int i, nbInitNod = initState._nbNodes; + for (i = nbInitNod+1; i <= nbNod; ++i ) + { + const netgen::MeshPoint& ngPoint = ngMesh.Point(i); + SMDS_MeshNode* node = NULL; + TopoDS_Vertex aVert; + // First, netgen creates nodes on vertices in occgeo.vmap, + // so node index corresponds to vertex index + // but (issue 0020776) netgen does not create nodes with equal coordinates + if ( i-nbInitNod <= occgeo.vmap.Extent() ) + { + gp_Pnt p ( NGPOINT_COORDS(ngPoint) ); + for (int iV = i-nbInitNod; aVert.IsNull() && iV <= occgeo.vmap.Extent(); ++iV) + { + aVert = TopoDS::Vertex( occgeo.vmap( iV )); + gp_Pnt pV = BRep_Tool::Pnt( aVert ); + if ( p.SquareDistance( pV ) > 1e-20 ) + aVert.Nullify(); + else + node = const_cast( SMESH_Algo::VertexNode( aVert, meshDS )); + } + } + if (!node) // node not found on vertex + { + node = meshDS->AddNode( NGPOINT_COORDS( ngPoint )); + if (!aVert.IsNull()) + meshDS->SetNodeOnVertex(node, aVert); + } + nodeVec[i] = node; + } + + // ------------------------------------------- + // Create mesh segments along geometric edges + // ------------------------------------------- + + int nbInitSeg = initState._nbSegments; + for (i = nbInitSeg+1; i <= nbSeg; ++i ) + { + const netgen::Segment& seg = ngMesh.LineSegment(i); + TopoDS_Edge aEdge; + int pinds[3] = { seg.pnums[0], seg.pnums[1], seg.pnums[2] }; + int nbp = 0; + double param2 = 0; + for (int j=0; j < 3; ++j) + { + int pind = pinds[j]; + if (pind <= 0 || !nodeVec_ACCESS(pind)) + break; + ++nbp; + double param; + if (j < 2) + { + if (aEdge.IsNull()) + { + int aGeomEdgeInd = seg.epgeominfo[j].edgenr; + if (aGeomEdgeInd > 0 && aGeomEdgeInd <= occgeo.emap.Extent()) + aEdge = TopoDS::Edge(occgeo.emap(aGeomEdgeInd)); + } + param = seg.epgeominfo[j].dist; + param2 += param; + } + else // middle point + { + param = param2 * 0.5; + } + if (!aEdge.IsNull() && nodeVec_ACCESS(pind)->getshapeId() < 1) + { + meshDS->SetNodeOnEdge(nodeVec_ACCESS(pind), aEdge, param); + } + } + if ( nbp > 1 ) + { + SMDS_MeshEdge* edge = 0; + if (nbp == 2) // second order ? + { + if ( meshDS->FindEdge( nodeVec_ACCESS(pinds[0]), nodeVec_ACCESS(pinds[1]))) + continue; + if ( quadHelper ) // final mesh must be quadratic + edge = quadHelper->AddEdge(nodeVec_ACCESS(pinds[0]), nodeVec_ACCESS(pinds[1])); + else + edge = meshDS->AddEdge(nodeVec_ACCESS(pinds[0]), nodeVec_ACCESS(pinds[1])); + } + else + { + if ( meshDS->FindEdge( nodeVec_ACCESS(pinds[0]), nodeVec_ACCESS(pinds[1]), + nodeVec_ACCESS(pinds[2]))) + continue; + edge = meshDS->AddEdge(nodeVec_ACCESS(pinds[0]), nodeVec_ACCESS(pinds[1]), + nodeVec_ACCESS(pinds[2])); + } + if (!edge) + { + if ( comment.empty() ) comment << "Cannot create a mesh edge"; + MESSAGE("Cannot create a mesh edge"); + nbSeg = nbFac = nbVol = 0; + break; + } + if ( !aEdge.IsNull() && edge->getshapeId() < 1 ) + meshDS->SetMeshElementOnShape(edge, aEdge); + } + else if ( comment.empty() ) + { + comment << "Invalid netgen segment #" << i; + } + } + + // ---------------------------------------- + // Create mesh faces along geometric faces + // ---------------------------------------- + + int nbInitFac = initState._nbFaces; + int quadFaceID = ngMesh.GetNFD() + 1; + if ( nbInitFac < nbFac ) + // add a faces descriptor to exclude qudrangle elements generated by NETGEN + // from computation of 3D mesh + ngMesh.AddFaceDescriptor (netgen::FaceDescriptor(quadFaceID, /*solid1=*/0, /*solid2=*/0, 0)); + + vector nodes; + for (i = nbInitFac+1; i <= nbFac; ++i ) + { + const netgen::Element2d& elem = ngMesh.SurfaceElement(i); + int aGeomFaceInd = elem.GetIndex(); + TopoDS_Face aFace; + if (aGeomFaceInd > 0 && aGeomFaceInd <= occgeo.fmap.Extent()) + aFace = TopoDS::Face(occgeo.fmap(aGeomFaceInd)); + nodes.clear(); + for (int j=1; j <= elem.GetNP(); ++j) + { + int pind = elem.PNum(j); + if ( pind < 1 || pind >= nodeVec.size() ) + break; + if ( SMDS_MeshNode* node = nodeVec_ACCESS(pind)) + { + nodes.push_back( node ); + if (!aFace.IsNull() && node->getshapeId() < 1) + { + const netgen::PointGeomInfo& pgi = elem.GeomInfoPi(j); + meshDS->SetNodeOnFace(node, aFace, pgi.u, pgi.v); + } + } + } + if ( nodes.size() != elem.GetNP() ) + { + if ( comment.empty() ) + comment << "Invalid netgen 2d element #" << i; + continue; // bad node ids + } + SMDS_MeshFace* face = NULL; + switch (elem.GetType()) + { + case netgen::TRIG: + if ( quadHelper ) // final mesh must be quadratic + face = quadHelper->AddFace(nodes[0],nodes[1],nodes[2]); + else + face = meshDS->AddFace(nodes[0],nodes[1],nodes[2]); + break; + case netgen::QUAD: + if ( quadHelper ) // final mesh must be quadratic + face = quadHelper->AddFace(nodes[0],nodes[1],nodes[2],nodes[3]); + else + face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[3]); + // exclude qudrangle elements from computation of 3D mesh + const_cast< netgen::Element2d& >( elem ).SetIndex( quadFaceID ); + break; + case netgen::TRIG6: + nodes[5] = mediumNode( nodes[0],nodes[1],nodes[5], quadHelper ); + nodes[3] = mediumNode( nodes[1],nodes[2],nodes[3], quadHelper ); + nodes[4] = mediumNode( nodes[2],nodes[0],nodes[4], quadHelper ); + face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[5],nodes[3],nodes[4]); + break; + case netgen::QUAD8: + nodes[4] = mediumNode( nodes[0],nodes[1],nodes[4], quadHelper ); + nodes[7] = mediumNode( nodes[1],nodes[2],nodes[7], quadHelper ); + nodes[5] = mediumNode( nodes[2],nodes[3],nodes[5], quadHelper ); + nodes[6] = mediumNode( nodes[3],nodes[0],nodes[6], quadHelper ); + face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[3], + nodes[4],nodes[7],nodes[5],nodes[6]); + // exclude qudrangle elements from computation of 3D mesh + const_cast< netgen::Element2d& >( elem ).SetIndex( quadFaceID ); + break; + default: + MESSAGE("NETGEN created a face of unexpected type, ignoring"); + continue; + } + if (!face) + { + if ( comment.empty() ) comment << "Cannot create a mesh face"; + MESSAGE("Cannot create a mesh face"); + nbSeg = nbFac = nbVol = 0; + break; + } + if (!aFace.IsNull()) + meshDS->SetMeshElementOnShape(face, aFace); + } + + // ------------------ + // Create tetrahedra + // ------------------ + + for (i = 1; i <= nbVol; ++i) + { + const netgen::Element& elem = ngMesh.VolumeElement(i); + int aSolidInd = elem.GetIndex(); + TopoDS_Solid aSolid; + if (aSolidInd > 0 && aSolidInd <= occgeo.somap.Extent()) + aSolid = TopoDS::Solid(occgeo.somap(aSolidInd)); + nodes.clear(); + for (int j=1; j <= elem.GetNP(); ++j) + { + int pind = elem.PNum(j); + if ( pind < 1 || pind >= nodeVec.size() ) + break; + if ( SMDS_MeshNode* node = nodeVec_ACCESS(pind) ) + { + nodes.push_back(node); + if ( !aSolid.IsNull() && node->getshapeId() < 1 ) + meshDS->SetNodeInVolume(node, aSolid); + } + } + if ( nodes.size() != elem.GetNP() ) + { + if ( comment.empty() ) + comment << "Invalid netgen 3d element #" << i; + continue; + } + SMDS_MeshVolume* vol = NULL; + switch (elem.GetType()) + { + case netgen::TET: + vol = meshDS->AddVolume(nodes[0],nodes[1],nodes[2],nodes[3]); + break; + case netgen::TET10: + nodes[4] = mediumNode( nodes[0],nodes[1],nodes[4], quadHelper ); + nodes[7] = mediumNode( nodes[1],nodes[2],nodes[7], quadHelper ); + nodes[5] = mediumNode( nodes[2],nodes[0],nodes[5], quadHelper ); + nodes[6] = mediumNode( nodes[0],nodes[3],nodes[6], quadHelper ); + nodes[8] = mediumNode( nodes[1],nodes[3],nodes[8], quadHelper ); + nodes[9] = mediumNode( nodes[2],nodes[3],nodes[9], quadHelper ); + vol = meshDS->AddVolume(nodes[0],nodes[1],nodes[2],nodes[3], + nodes[4],nodes[7],nodes[5],nodes[6],nodes[8],nodes[9]); + break; + default: + MESSAGE("NETGEN created a volume of unexpected type, ignoring"); + continue; + } + if (!vol) + { + if ( comment.empty() ) comment << "Cannot create a mesh volume"; + MESSAGE("Cannot create a mesh volume"); + nbSeg = nbFac = nbVol = 0; + break; + } + if (!aSolid.IsNull()) + meshDS->SetMeshElementOnShape(vol, aSolid); + } + return comment.empty() ? 0 : 1; +} + +namespace +{ + //================================================================================ + /*! + * \brief Restrict size of elements on the given edge + */ + //================================================================================ + + void setLocalSize(const TopoDS_Edge& edge, + double size, + netgen::Mesh& mesh) + { + if ( size <= std::numeric_limits::min() ) + return; + Standard_Real u1, u2; + Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, u1, u2); + if ( curve.IsNull() ) + { + TopoDS_Iterator vIt( edge ); + if ( !vIt.More() ) return; + gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( vIt.Value() )); + NETGENPlugin_Mesher::RestrictLocalSize( mesh, p.XYZ(), size ); + } + else + { + const int nb = (int)( 1.5 * SMESH_Algo::EdgeLength( edge ) / size ); + Standard_Real delta = (u2-u1)/nb; + for(int i=0; iValue(u); + NETGENPlugin_Mesher::RestrictLocalSize( mesh, p.XYZ(), size ); + netgen::Point3d pi(p.X(), p.Y(), p.Z()); + double resultSize = mesh.GetH(pi); + if ( resultSize - size > 0.1*size ) + // netgen does restriction iff oldH/newH > 1.2 (localh.cpp:136) + NETGENPlugin_Mesher::RestrictLocalSize( mesh, p.XYZ(), resultSize/1.201 ); + } + } + } + + //================================================================================ + /*! + * \brief Convert error into text + */ + //================================================================================ + + std::string text(int err) + { + if ( !err ) + return string(""); + return + SMESH_Comment("Error in netgen::OCCGenerateMesh() at ") << netgen::multithread.task; + } + + //================================================================================ + /*! + * \brief Convert exception into text + */ + //================================================================================ + + std::string text(Standard_Failure& ex) + { + SMESH_Comment str("Exception in netgen::OCCGenerateMesh()"); + str << " at " << netgen::multithread.task + << ": " << ex.DynamicType()->Name(); + if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) + str << ": " << ex.GetMessageString(); + return str; + } + //================================================================================ + /*! + * \brief Convert exception into text + */ + //================================================================================ + + std::string text(netgen::NgException& ex) + { + SMESH_Comment str("NgException"); + if ( strlen( netgen::multithread.task ) > 0 ) + str << " at " << netgen::multithread.task; + str << ": " << ex.What(); + return str; + } + + //================================================================================ + /*! + * \brief Looks for triangles lying on a SOLID + */ + //================================================================================ + + bool hasBadElemOnSolid( const list& elems, + SMESH_subMesh* solidSM ) + { + TopTools_IndexedMapOfShape solidSubs; + TopExp::MapShapes( solidSM->GetSubShape(), solidSubs ); + SMESHDS_Mesh* mesh = solidSM->GetFather()->GetMeshDS(); + + list::const_iterator e = elems.begin(); + for ( ; e != elems.end(); ++e ) + { + const SMDS_MeshElement* elem = *e; + // if ( elem->GetType() != SMDSAbs_Face ) -- 23047 + // continue; + int nbNodesOnSolid = 0, nbNodes = elem->NbNodes(); + SMDS_NodeIteratorPtr nIt = elem->nodeIterator(); + while ( nIt->more() ) + { + const SMDS_MeshNode* n = nIt->next(); + const TopoDS_Shape& s = mesh->IndexToShape( n->getshapeId() ); + nbNodesOnSolid += ( !s.IsNull() && solidSubs.Contains( s )); + if ( nbNodesOnSolid > 2 || + nbNodesOnSolid == nbNodes) + return true; + } + } + return false; + } + + const double edgeMeshingTime = 0.001; + const double faceMeshingTime = 0.019; + const double edgeFaceMeshingTime = edgeMeshingTime + faceMeshingTime; + const double faceOptimizTime = 0.06; + const double voluMeshingTime = 0.15; + const double volOptimizeTime = 0.77; +} + +//============================================================================= +/*! + * Here we are going to use the NETGEN mesher + */ +//============================================================================= + +bool NETGENPlugin_Mesher::Compute() +{ + NETGENPlugin_NetgenLibWrapper ngLib; + + netgen::MeshingParameters& mparams = netgen::mparam; + MESSAGE("Compute with:\n" + " max size = " << mparams.maxh << "\n" + " segments per edge = " << mparams.segmentsperedge); + MESSAGE("\n" + " growth rate = " << mparams.grading << "\n" + " elements per radius = " << mparams.curvaturesafety << "\n" + " second order = " << mparams.secondorder << "\n" + " quad allowed = " << mparams.quad << "\n" + " surface curvature = " << mparams.uselocalh << "\n" + " fuse edges = " << netgen::merge_solids); + + SMESH_ComputeErrorPtr error = SMESH_ComputeError::New(); + SMESH_MesherHelper quadHelper( *_mesh ); + quadHelper.SetIsQuadratic( mparams.secondorder ); + + static string debugFile = "/tmp/ngMesh.py"; /* to call toPython( _ngMesh, debugFile ) + while debugging netgen */ + // ------------------------- + // Prepare OCC geometry + // ------------------------- + + netgen::OCCGeometry occgeo; + list< SMESH_subMesh* > meshedSM[3]; // for 0-2 dimensions + NETGENPlugin_Internals internals( *_mesh, _shape, _isVolume ); + PrepareOCCgeometry( occgeo, _shape, *_mesh, meshedSM, &internals ); + _occgeom = &occgeo; + + _totalTime = edgeFaceMeshingTime; + if ( _optimize ) + _totalTime += faceOptimizTime; + if ( _isVolume ) + _totalTime += voluMeshingTime + ( _optimize ? volOptimizeTime : 0 ); + double doneTime = 0; + _ticTime = -1; + _progressTic = 1; + _curShapeIndex = -1; + + // ------------------------- + // Generate the mesh + // ------------------------- + + _ngMesh = NULL; + NETGENPlugin_ngMeshInfo initState; // it remembers size of ng mesh equal to size of Smesh + + SMESH_Comment comment; + int err = 0; + + // vector of nodes in which node index == netgen ID + vector< const SMDS_MeshNode* > nodeVec; + + { + // ---------------- + // compute 1D mesh + // ---------------- + if ( _simpleHyp ) + { + // not to RestrictLocalH() according to curvature during MESHCONST_ANALYSE + mparams.uselocalh = false; + mparams.grading = 0.8; // not limitited size growth + + if ( _simpleHyp->GetNumberOfSegments() ) + // nb of segments + mparams.maxh = occgeo.boundingbox.Diam(); + else + // segment length + mparams.maxh = _simpleHyp->GetLocalLength(); + } + + if ( mparams.maxh == 0.0 ) + mparams.maxh = occgeo.boundingbox.Diam(); + if ( _simpleHyp || ( mparams.minh == 0.0 && _fineness != NETGENPlugin_Hypothesis::UserDefined)) + mparams.minh = GetDefaultMinSize( _shape, mparams.maxh ); + + // Local size on faces + occgeo.face_maxh = mparams.maxh; + + // Let netgen create _ngMesh and calculate element size on not meshed shapes +#ifndef NETGEN_V5 + char *optstr = 0; +#endif + int startWith = netgen::MESHCONST_ANALYSE; + int endWith = netgen::MESHCONST_ANALYSE; + try + { + OCC_CATCH_SIGNALS; +#ifdef NETGEN_V5 + err = netgen::OCCGenerateMesh(occgeo, _ngMesh, mparams, startWith, endWith); +#else + err = netgen::OCCGenerateMesh(occgeo, _ngMesh, startWith, endWith, optstr); +#endif + if(netgen::multithread.terminate) + return false; + + comment << text(err); + } + catch (Standard_Failure& ex) + { + comment << text(ex); + } + err = 0; //- MESHCONST_ANALYSE isn't so important step + if ( !_ngMesh ) + return false; + ngLib.setMesh(( Ng_Mesh*) _ngMesh ); + + _ngMesh->ClearFaceDescriptors(); // we make descriptors our-self + + if ( _simpleHyp ) + { + // Pass 1D simple parameters to NETGEN + // -------------------------------- + int nbSeg = _simpleHyp->GetNumberOfSegments(); + double segSize = _simpleHyp->GetLocalLength(); + for ( int iE = 1; iE <= occgeo.emap.Extent(); ++iE ) + { + const TopoDS_Edge& e = TopoDS::Edge( occgeo.emap(iE)); + if ( nbSeg ) + segSize = SMESH_Algo::EdgeLength( e ) / ( nbSeg - 0.4 ); + setLocalSize( e, segSize, *_ngMesh ); + } + } + else // if ( ! _simpleHyp ) + { + // Local size on vertices and edges + // -------------------------------- + for(std::map::const_iterator it=EdgeId2LocalSize.begin(); it!=EdgeId2LocalSize.end(); it++) + { + int key = (*it).first; + double hi = (*it).second; + const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key); + const TopoDS_Edge& e = TopoDS::Edge(shape); + setLocalSize( e, hi, *_ngMesh ); + } + for(std::map::const_iterator it=VertexId2LocalSize.begin(); it!=VertexId2LocalSize.end(); it++) + { + int key = (*it).first; + double hi = (*it).second; + const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key); + const TopoDS_Vertex& v = TopoDS::Vertex(shape); + gp_Pnt p = BRep_Tool::Pnt(v); + NETGENPlugin_Mesher::RestrictLocalSize( *_ngMesh, p.XYZ(), hi ); + } + for(map::const_iterator it=FaceId2LocalSize.begin(); + it!=FaceId2LocalSize.end(); it++) + { + int key = (*it).first; + double val = (*it).second; + const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key); + int faceNgID = occgeo.fmap.FindIndex(shape); + occgeo.SetFaceMaxH(faceNgID, val); + for ( TopExp_Explorer edgeExp( shape, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() ) + setLocalSize( TopoDS::Edge( edgeExp.Current() ), val, *_ngMesh ); + } + } + + // Precompute internal edges (issue 0020676) in order to + // add mesh on them correctly (twice) to netgen mesh + if ( !err && internals.hasInternalEdges() ) + { + // load internal shapes into OCCGeometry + netgen::OCCGeometry intOccgeo; + internals.getInternalEdges( intOccgeo.fmap, intOccgeo.emap, intOccgeo.vmap, meshedSM ); + intOccgeo.boundingbox = occgeo.boundingbox; + intOccgeo.shape = occgeo.shape; + intOccgeo.face_maxh.SetSize(intOccgeo.fmap.Extent()); + intOccgeo.face_maxh = netgen::mparam.maxh; + netgen::Mesh *tmpNgMesh = NULL; + try + { + OCC_CATCH_SIGNALS; + // compute local H on internal shapes in the main mesh + //OCCSetLocalMeshSize(intOccgeo, *_ngMesh); it deletes _ngMesh->localH + + // let netgen create a temporary mesh +#ifdef NETGEN_V5 + netgen::OCCGenerateMesh(intOccgeo, tmpNgMesh, mparams, startWith, endWith); +#else + netgen::OCCGenerateMesh(intOccgeo, tmpNgMesh, startWith, endWith, optstr); +#endif + if(netgen::multithread.terminate) + return false; + + // copy LocalH from the main to temporary mesh + initState.transferLocalH( _ngMesh, tmpNgMesh ); + + // compute mesh on internal edges + startWith = endWith = netgen::MESHCONST_MESHEDGES; +#ifdef NETGEN_V5 + err = netgen::OCCGenerateMesh(intOccgeo, tmpNgMesh, mparams, startWith, endWith); +#else + err = netgen::OCCGenerateMesh(intOccgeo, tmpNgMesh, startWith, endWith, optstr); +#endif + comment << text(err); + } + catch (Standard_Failure& ex) + { + comment << text(ex); + err = 1; + } + initState.restoreLocalH( tmpNgMesh ); + + // fill SMESH by netgen mesh + vector< const SMDS_MeshNode* > tmpNodeVec; + FillSMesh( intOccgeo, *tmpNgMesh, initState, *_mesh, tmpNodeVec, comment ); + err = ( err || !comment.empty() ); + + nglib::Ng_DeleteMesh((nglib::Ng_Mesh*)tmpNgMesh); + } + + // Fill _ngMesh with nodes and segments of computed submeshes + if ( !err ) + { + err = ! ( FillNgMesh(occgeo, *_ngMesh, nodeVec, meshedSM[ MeshDim_0D ]) && + FillNgMesh(occgeo, *_ngMesh, nodeVec, meshedSM[ MeshDim_1D ], &quadHelper)); + } + initState = NETGENPlugin_ngMeshInfo(_ngMesh); + + // Compute 1d mesh + if (!err) + { + startWith = endWith = netgen::MESHCONST_MESHEDGES; + try + { + OCC_CATCH_SIGNALS; +#ifdef NETGEN_V5 + err = netgen::OCCGenerateMesh(occgeo, _ngMesh, mparams, startWith, endWith); +#else + err = netgen::OCCGenerateMesh(occgeo, _ngMesh, startWith, endWith, optstr); +#endif + if(netgen::multithread.terminate) + return false; + + comment << text(err); + } + catch (Standard_Failure& ex) + { + comment << text(ex); + err = 1; + } + } + if ( _isVolume ) + _ticTime = ( doneTime += edgeMeshingTime ) / _totalTime / _progressTic; + + mparams.uselocalh = true; // restore as it is used at surface optimization + + // --------------------- + // compute surface mesh + // --------------------- + if (!err) + { + // Pass 2D simple parameters to NETGEN + if ( _simpleHyp ) { + if ( double area = _simpleHyp->GetMaxElementArea() ) { + // face area + mparams.maxh = sqrt(2. * area/sqrt(3.0)); + mparams.grading = 0.4; // moderate size growth + } + else { + // length from edges + if ( _ngMesh->GetNSeg() ) { + double edgeLength = 0; + TopTools_MapOfShape visitedEdges; + for ( TopExp_Explorer exp( _shape, TopAbs_EDGE ); exp.More(); exp.Next() ) + if( visitedEdges.Add(exp.Current()) ) + edgeLength += SMESH_Algo::EdgeLength( TopoDS::Edge( exp.Current() )); + // we have to multiply length by 2 since for each TopoDS_Edge there + // are double set of NETGEN edges, in other words, we have to + // divide _ngMesh->GetNSeg() by 2. + mparams.maxh = 2*edgeLength / _ngMesh->GetNSeg(); + } + else { + mparams.maxh = 1000; + } + mparams.grading = 0.2; // slow size growth + } + mparams.quad = _simpleHyp->GetAllowQuadrangles(); + mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 ); + _ngMesh->SetGlobalH (mparams.maxh); + netgen::Box<3> bb = occgeo.GetBoundingBox(); + bb.Increase (bb.Diam()/20); + _ngMesh->SetLocalH (bb.PMin(), bb.PMax(), mparams.grading); + } + + // Care of vertices internal in faces (issue 0020676) + if ( internals.hasInternalVertexInFace() ) + { + // store computed segments in SMESH in order not to create SMESH + // edges for ng segments added by AddIntVerticesInFaces() + FillSMesh( occgeo, *_ngMesh, initState, *_mesh, nodeVec, comment ); + // add segments to faces with internal vertices + AddIntVerticesInFaces( occgeo, *_ngMesh, nodeVec, internals ); + initState = NETGENPlugin_ngMeshInfo(_ngMesh); + } + + // Build viscous layers + if ( _isViscousLayers2D ) + { + if ( !internals.hasInternalVertexInFace() ) { + FillSMesh( occgeo, *_ngMesh, initState, *_mesh, nodeVec, comment ); + initState = NETGENPlugin_ngMeshInfo(_ngMesh); + } + SMESH_ProxyMesh::Ptr viscousMesh; + SMESH_MesherHelper helper( *_mesh ); + for ( int faceID = 1; faceID <= occgeo.fmap.Extent(); ++faceID ) + { + const TopoDS_Face& F = TopoDS::Face( occgeo.fmap( faceID )); + viscousMesh = StdMeshers_ViscousLayers2D::Compute( *_mesh, F ); + if ( !viscousMesh ) + return false; + // exclude from computation ng segments built on EDGEs of F + for (int i = 1; i <= _ngMesh->GetNSeg(); i++) + { + netgen::Segment & seg = _ngMesh->LineSegment(i); + if (seg.si == faceID) + seg.si = 0; + } + // add new segments to _ngMesh instead of excluded ones + helper.SetSubShape( F ); + TSideVector wires = + StdMeshers_FaceSide::GetFaceWires( F, *_mesh, /*skipMediumNodes=*/true, + error, viscousMesh ); + error = AddSegmentsToMesh( *_ngMesh, occgeo, wires, helper, nodeVec ); + + if ( !error ) error = SMESH_ComputeError::New(); + } + initState = NETGENPlugin_ngMeshInfo(_ngMesh); + } + + // Let netgen compute 2D mesh + startWith = netgen::MESHCONST_MESHSURFACE; + endWith = _optimize ? netgen::MESHCONST_OPTSURFACE : netgen::MESHCONST_MESHSURFACE; + try + { + OCC_CATCH_SIGNALS; +#ifdef NETGEN_V5 + err = netgen::OCCGenerateMesh(occgeo, _ngMesh, mparams, startWith, endWith); +#else + err = netgen::OCCGenerateMesh(occgeo, _ngMesh, startWith, endWith, optstr); +#endif + if(netgen::multithread.terminate) + return false; + + comment << text (err); + } + catch (Standard_Failure& ex) + { + comment << text(ex); + //err = 1; -- try to make volumes anyway + } + catch (netgen::NgException exc) + { + comment << text(exc); + //err = 1; -- try to make volumes anyway + } + } + if ( _isVolume ) + { + doneTime += faceMeshingTime + ( _optimize ? faceOptimizTime : 0 ); + _ticTime = doneTime / _totalTime / _progressTic; + } + // --------------------- + // generate volume mesh + // --------------------- + // Fill _ngMesh with nodes and faces of computed 2D submeshes + if ( !err && _isVolume && ( !meshedSM[ MeshDim_2D ].empty() || mparams.quad )) + { + // load SMESH with computed segments and faces + FillSMesh( occgeo, *_ngMesh, initState, *_mesh, nodeVec, comment, &quadHelper ); + + // compute pyramids on quadrangles + SMESH_ProxyMesh::Ptr proxyMesh; + if ( _mesh->NbQuadrangles() > 0 ) + for ( int iS = 1; iS <= occgeo.somap.Extent(); ++iS ) + { + StdMeshers_QuadToTriaAdaptor* Adaptor = new StdMeshers_QuadToTriaAdaptor; + proxyMesh.reset( Adaptor ); + + int nbPyrams = _mesh->NbPyramids(); + Adaptor->Compute( *_mesh, occgeo.somap(iS) ); + if ( nbPyrams != _mesh->NbPyramids() ) + { + list< SMESH_subMesh* > quadFaceSM; + for (TopExp_Explorer face(occgeo.somap(iS), TopAbs_FACE); face.More(); face.Next()) + if ( Adaptor->GetProxySubMesh( face.Current() )) + { + quadFaceSM.push_back( _mesh->GetSubMesh( face.Current() )); + meshedSM[ MeshDim_2D ].remove( quadFaceSM.back() ); + } + FillNgMesh(occgeo, *_ngMesh, nodeVec, quadFaceSM, &quadHelper, proxyMesh); + } + } + // fill _ngMesh with faces of sub-meshes + err = ! ( FillNgMesh(occgeo, *_ngMesh, nodeVec, meshedSM[ MeshDim_2D ], &quadHelper)); + initState = NETGENPlugin_ngMeshInfo(_ngMesh); + //toPython( _ngMesh, "/tmp/ngPython.py"); + } + if (!err && _isVolume) + { + // Pass 3D simple parameters to NETGEN + const NETGENPlugin_SimpleHypothesis_3D* simple3d = + dynamic_cast< const NETGENPlugin_SimpleHypothesis_3D* > ( _simpleHyp ); + if ( simple3d ) { + if ( double vol = simple3d->GetMaxElementVolume() ) { + // max volume + mparams.maxh = pow( 72, 1/6. ) * pow( vol, 1/3. ); + mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 ); + } + else { + // length from faces + mparams.maxh = _ngMesh->AverageH(); + } + _ngMesh->SetGlobalH (mparams.maxh); + mparams.grading = 0.4; +#ifdef NETGEN_V5 + _ngMesh->CalcLocalH(mparams.grading); +#else + _ngMesh->CalcLocalH(); +#endif + } + // Care of vertices internal in solids and internal faces (issue 0020676) + if ( internals.hasInternalVertexInSolid() || internals.hasInternalFaces() ) + { + // store computed faces in SMESH in order not to create SMESH + // faces for ng faces added here + FillSMesh( occgeo, *_ngMesh, initState, *_mesh, nodeVec, comment, &quadHelper ); + // add ng faces to solids with internal vertices + AddIntVerticesInSolids( occgeo, *_ngMesh, nodeVec, internals ); + // duplicate mesh faces on internal faces + FixIntFaces( occgeo, *_ngMesh, internals ); + initState = NETGENPlugin_ngMeshInfo(_ngMesh); + } + // Let netgen compute 3D mesh + startWith = endWith = netgen::MESHCONST_MESHVOLUME; + try + { + OCC_CATCH_SIGNALS; +#ifdef NETGEN_V5 + err = netgen::OCCGenerateMesh(occgeo, _ngMesh, mparams, startWith, endWith); +#else + err = netgen::OCCGenerateMesh(occgeo, _ngMesh, startWith, endWith, optstr); +#endif + if(netgen::multithread.terminate) + return false; + + if ( comment.empty() ) // do not overwrite a previos error + comment << text(err); + } + catch (Standard_Failure& ex) + { + if ( comment.empty() ) // do not overwrite a previos error + comment << text(ex); + err = 1; + } + catch (netgen::NgException exc) + { + if ( comment.empty() ) // do not overwrite a previos error + comment << text(exc); + err = 1; + } + _ticTime = ( doneTime += voluMeshingTime ) / _totalTime / _progressTic; + + // Let netgen optimize 3D mesh + if ( !err && _optimize ) + { + startWith = endWith = netgen::MESHCONST_OPTVOLUME; + try + { + OCC_CATCH_SIGNALS; +#ifdef NETGEN_V5 + err = netgen::OCCGenerateMesh(occgeo, _ngMesh, mparams, startWith, endWith); +#else + err = netgen::OCCGenerateMesh(occgeo, _ngMesh, startWith, endWith, optstr); +#endif + if(netgen::multithread.terminate) + return false; + + if ( comment.empty() ) // do not overwrite a previos error + comment << text(err); + } + catch (Standard_Failure& ex) + { + if ( comment.empty() ) // do not overwrite a previos error + comment << text(ex); + } + catch (netgen::NgException exc) + { + if ( comment.empty() ) // do not overwrite a previos error + comment << text(exc); + } + } + } + if (!err && mparams.secondorder > 0) + { + try + { + OCC_CATCH_SIGNALS; + if ( !meshedSM[ MeshDim_1D ].empty() ) + { + // remove segments not attached to geometry (IPAL0052479) + for (int i = 1; i <= _ngMesh->GetNSeg(); ++i) + { + const netgen::Segment & seg = _ngMesh->LineSegment (i); + if ( seg.epgeominfo[ 0 ].edgenr == 0 ) + _ngMesh->DeleteSegment( i ); + } + _ngMesh->Compress(); + } + // convert to quadratic + netgen::OCCRefinementSurfaces ref (occgeo); + ref.MakeSecondOrder (*_ngMesh); + + // care of elements already loaded to SMESH + // if ( initState._nbSegments > 0 ) + // makeQuadratic( occgeo.emap, _mesh ); + // if ( initState._nbFaces > 0 ) + // makeQuadratic( occgeo.fmap, _mesh ); + } + catch (Standard_Failure& ex) + { + if ( comment.empty() ) // do not overwrite a previos error + comment << "Exception in netgen at passing to 2nd order "; + } + catch (netgen::NgException exc) + { + if ( comment.empty() ) // do not overwrite a previos error + comment << exc.What(); + } + } + } + + _ticTime = 0.98 / _progressTic; + + int nbNod = _ngMesh->GetNP(); + int nbSeg = _ngMesh->GetNSeg(); + int nbFac = _ngMesh->GetNSE(); + int nbVol = _ngMesh->GetNE(); + bool isOK = ( !err && (_isVolume ? (nbVol > 0) : (nbFac > 0)) ); + + MESSAGE((err ? "Mesh Generation failure" : "End of Mesh Generation") << + ", nb nodes: " << nbNod << + ", nb segments: " << nbSeg << + ", nb faces: " << nbFac << + ", nb volumes: " << nbVol); + + // Feed back the SMESHDS with the generated Nodes and Elements + if ( true /*isOK*/ ) // get whatever built + { + FillSMesh( occgeo, *_ngMesh, initState, *_mesh, nodeVec, comment, &quadHelper ); + + if ( quadHelper.GetIsQuadratic() ) // remove free nodes + for ( size_t i = 0; i < nodeVec.size(); ++i ) + if ( nodeVec[i] && nodeVec[i]->NbInverseElements() == 0 ) + _mesh->GetMeshDS()->RemoveFreeNode( nodeVec[i], 0, /*fromGroups=*/false ); + } + SMESH_ComputeErrorPtr readErr = ReadErrors(nodeVec); + if ( readErr && !readErr->myBadElements.empty() ) + { + error = readErr; + if ( !comment.empty() && !readErr->myComment.empty() ) comment += "\n"; + comment += readErr->myComment; + } + if ( error->IsOK() && ( !isOK || comment.size() > 0 )) + error->myName = COMPERR_ALGO_FAILED; + if ( !comment.empty() ) + error->myComment = comment; + + // SetIsAlwaysComputed( true ) to empty sub-meshes, which + // appear if the geometry contains coincident sub-shape due + // to bool merge_solids = 1; in netgen/libsrc/occ/occgenmesh.cpp + const int nbMaps = 2; + const TopTools_IndexedMapOfShape* geoMaps[nbMaps] = + { & occgeo.vmap, & occgeo.emap/*, & occgeo.fmap*/ }; + for ( int iMap = 0; iMap < nbMaps; ++iMap ) + for (int i = 1; i <= geoMaps[iMap]->Extent(); i++) + if ( SMESH_subMesh* sm = _mesh->GetSubMeshContaining( geoMaps[iMap]->FindKey(i))) + if ( !sm->IsMeshComputed() ) + sm->SetIsAlwaysComputed( true ); + + // set bad compute error to subshapes of all failed sub-shapes + if ( !error->IsOK() ) + { + bool pb2D = false, pb3D = false; + for (int i = 1; i <= occgeo.fmap.Extent(); i++) { + int status = occgeo.facemeshstatus[i-1]; + if (status == 1 ) continue; + if ( SMESH_subMesh* sm = _mesh->GetSubMeshContaining( occgeo.fmap( i ))) { + SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); + if ( !smError || smError->IsOK() ) { + if ( status == -1 ) + smError.reset( new SMESH_ComputeError( *error )); + else + smError.reset( new SMESH_ComputeError( COMPERR_ALGO_FAILED, "Ignored" )); + if ( SMESH_Algo::GetMeshError( sm ) == SMESH_Algo::MEr_OK ) + smError->myName = COMPERR_WARNING; + } + pb2D = pb2D || smError->IsKO(); + } + } + if ( !pb2D ) // all faces are OK + for (int i = 1; i <= occgeo.somap.Extent(); i++) + if ( SMESH_subMesh* sm = _mesh->GetSubMeshContaining( occgeo.somap( i ))) + { + bool smComputed = nbVol && !sm->IsEmpty(); + if ( smComputed && internals.hasInternalVertexInSolid( sm->GetId() )) + { + int nbIntV = internals.getSolidsWithVertices().find( sm->GetId() )->second.size(); + SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); + smComputed = ( smDS->NbElements() > 0 || smDS->NbNodes() > nbIntV ); + } + SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); + if ( !smComputed && ( !smError || smError->IsOK() )) + { + smError.reset( new SMESH_ComputeError( *error )); + if ( nbVol && SMESH_Algo::GetMeshError( sm ) == SMESH_Algo::MEr_OK ) + { + smError->myName = COMPERR_WARNING; + } + else if ( !smError->myBadElements.empty() ) // bad surface mesh + { + if ( !hasBadElemOnSolid( smError->myBadElements, sm )) + smError.reset(); + } + } + pb3D = pb3D || ( smError && smError->IsKO() ); + } + if ( !pb2D && !pb3D ) + err = 0; // no fatal errors, only warnings + } + + ngLib._isComputeOk = !err; + + return !err; +} + +//============================================================================= +/*! + * Evaluate + */ +//============================================================================= +bool NETGENPlugin_Mesher::Evaluate(MapShapeNbElems& aResMap) +{ + netgen::MeshingParameters& mparams = netgen::mparam; + + + // ------------------------- + // Prepare OCC geometry + // ------------------------- + netgen::OCCGeometry occgeo; + list< SMESH_subMesh* > meshedSM[4]; // for 0-3 dimensions + NETGENPlugin_Internals internals( *_mesh, _shape, _isVolume ); + PrepareOCCgeometry( occgeo, _shape, *_mesh, meshedSM, &internals ); + + bool tooManyElems = false; + const int hugeNb = std::numeric_limits::max() / 100; + + // ---------------- + // evaluate 1D + // ---------------- + // pass 1D simple parameters to NETGEN + if ( _simpleHyp ) + { + // not to RestrictLocalH() according to curvature during MESHCONST_ANALYSE + mparams.uselocalh = false; + mparams.grading = 0.8; // not limitited size growth + + if ( _simpleHyp->GetNumberOfSegments() ) + // nb of segments + mparams.maxh = occgeo.boundingbox.Diam(); + else + // segment length + mparams.maxh = _simpleHyp->GetLocalLength(); + } + + if ( mparams.maxh == 0.0 ) + mparams.maxh = occgeo.boundingbox.Diam(); + if ( _simpleHyp || ( mparams.minh == 0.0 && _fineness != NETGENPlugin_Hypothesis::UserDefined)) + mparams.minh = GetDefaultMinSize( _shape, mparams.maxh ); + + // let netgen create _ngMesh and calculate element size on not meshed shapes + NETGENPlugin_NetgenLibWrapper ngLib; + netgen::Mesh *ngMesh = NULL; +#ifndef NETGEN_V5 + char *optstr = 0; +#endif + int startWith = netgen::MESHCONST_ANALYSE; + int endWith = netgen::MESHCONST_MESHEDGES; +#ifdef NETGEN_V5 + int err = netgen::OCCGenerateMesh(occgeo, ngMesh, mparams, startWith, endWith); +#else + int err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); +#endif + + if(netgen::multithread.terminate) + return false; + + ngLib.setMesh(( Ng_Mesh*) ngMesh ); + if (err) { + if ( SMESH_subMesh* sm = _mesh->GetSubMeshContaining( _shape )) + sm->GetComputeError().reset( new SMESH_ComputeError( COMPERR_ALGO_FAILED )); + return false; + } + if ( _simpleHyp ) + { + // Pass 1D simple parameters to NETGEN + // -------------------------------- + int nbSeg = _simpleHyp->GetNumberOfSegments(); + double segSize = _simpleHyp->GetLocalLength(); + for ( int iE = 1; iE <= occgeo.emap.Extent(); ++iE ) + { + const TopoDS_Edge& e = TopoDS::Edge( occgeo.emap(iE)); + if ( nbSeg ) + segSize = SMESH_Algo::EdgeLength( e ) / ( nbSeg - 0.4 ); + setLocalSize( e, segSize, *ngMesh ); + } + } + else // if ( ! _simpleHyp ) + { + // Local size on vertices and edges + // -------------------------------- + for(std::map::const_iterator it=EdgeId2LocalSize.begin(); it!=EdgeId2LocalSize.end(); it++) + { + int key = (*it).first; + double hi = (*it).second; + const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key); + const TopoDS_Edge& e = TopoDS::Edge(shape); + setLocalSize( e, hi, *ngMesh ); + } + for(std::map::const_iterator it=VertexId2LocalSize.begin(); it!=VertexId2LocalSize.end(); it++) + { + int key = (*it).first; + double hi = (*it).second; + const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key); + const TopoDS_Vertex& v = TopoDS::Vertex(shape); + gp_Pnt p = BRep_Tool::Pnt(v); + NETGENPlugin_Mesher::RestrictLocalSize( *ngMesh, p.XYZ(), hi ); + } + for(map::const_iterator it=FaceId2LocalSize.begin(); + it!=FaceId2LocalSize.end(); it++) + { + int key = (*it).first; + double val = (*it).second; + const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key); + int faceNgID = occgeo.fmap.FindIndex(shape); + occgeo.SetFaceMaxH(faceNgID, val); + for ( TopExp_Explorer edgeExp( shape, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() ) + setLocalSize( TopoDS::Edge( edgeExp.Current() ), val, *ngMesh ); + } + } + // calculate total nb of segments and length of edges + double fullLen = 0.0; + int fullNbSeg = 0; + int entity = mparams.secondorder > 0 ? SMDSEntity_Quad_Edge : SMDSEntity_Edge; + TopTools_DataMapOfShapeInteger Edge2NbSeg; + for (TopExp_Explorer exp(_shape, TopAbs_EDGE); exp.More(); exp.Next()) + { + TopoDS_Edge E = TopoDS::Edge( exp.Current() ); + if( !Edge2NbSeg.Bind(E,0) ) + continue; + + double aLen = SMESH_Algo::EdgeLength(E); + fullLen += aLen; + + vector& aVec = aResMap[_mesh->GetSubMesh(E)]; + if ( aVec.empty() ) + aVec.resize( SMDSEntity_Last, 0); + else + fullNbSeg += aVec[ entity ]; + } + + // store nb of segments computed by Netgen + NCollection_Map linkMap; + for (int i = 1; i <= ngMesh->GetNSeg(); ++i ) + { + const netgen::Segment& seg = ngMesh->LineSegment(i); + Link link(seg[0], seg[1]); + if ( !linkMap.Add( link )) continue; + int aGeomEdgeInd = seg.epgeominfo[0].edgenr; + if (aGeomEdgeInd > 0 && aGeomEdgeInd <= occgeo.emap.Extent()) + { + vector& aVec = aResMap[_mesh->GetSubMesh(occgeo.emap(aGeomEdgeInd))]; + aVec[ entity ]++; + } + } + // store nb of nodes on edges computed by Netgen + TopTools_DataMapIteratorOfDataMapOfShapeInteger Edge2NbSegIt(Edge2NbSeg); + for (; Edge2NbSegIt.More(); Edge2NbSegIt.Next()) + { + vector& aVec = aResMap[_mesh->GetSubMesh(Edge2NbSegIt.Key())]; + if ( aVec[ entity ] > 1 && aVec[ SMDSEntity_Node ] == 0 ) + aVec[SMDSEntity_Node] = mparams.secondorder > 0 ? 2*aVec[ entity ]-1 : aVec[ entity ]-1; + + fullNbSeg += aVec[ entity ]; + Edge2NbSeg( Edge2NbSegIt.Key() ) = aVec[ entity ]; + } + if ( fullNbSeg == 0 ) + return false; + + // ---------------- + // evaluate 2D + // ---------------- + if ( _simpleHyp ) { + if ( double area = _simpleHyp->GetMaxElementArea() ) { + // face area + mparams.maxh = sqrt(2. * area/sqrt(3.0)); + mparams.grading = 0.4; // moderate size growth + } + else { + // length from edges + mparams.maxh = fullLen/fullNbSeg; + mparams.grading = 0.2; // slow size growth + } + } + mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 ); + mparams.maxh = min( mparams.maxh, fullLen/fullNbSeg * (1. + mparams.grading)); + + for (TopExp_Explorer exp(_shape, TopAbs_FACE); exp.More(); exp.Next()) + { + TopoDS_Face F = TopoDS::Face( exp.Current() ); + SMESH_subMesh *sm = _mesh->GetSubMesh(F); + GProp_GProps G; + BRepGProp::SurfaceProperties(F,G); + double anArea = G.Mass(); + tooManyElems = tooManyElems || ( anArea/hugeNb > mparams.maxh*mparams.maxh ); + int nb1d = 0; + if ( !tooManyElems ) + { + TopTools_MapOfShape egdes; + for (TopExp_Explorer exp1(F,TopAbs_EDGE); exp1.More(); exp1.Next()) + if ( egdes.Add( exp1.Current() )) + nb1d += Edge2NbSeg.Find(exp1.Current()); + } + int nbFaces = tooManyElems ? hugeNb : int( 4*anArea / (mparams.maxh*mparams.maxh*sqrt(3.))); + int nbNodes = tooManyElems ? hugeNb : (( nbFaces*3 - (nb1d-1)*2 ) / 6 + 1 ); + + vector aVec(SMDSEntity_Last, 0); + if( mparams.secondorder > 0 ) { + int nb1d_in = (nbFaces*3 - nb1d) / 2; + aVec[SMDSEntity_Node] = nbNodes + nb1d_in; + aVec[SMDSEntity_Quad_Triangle] = nbFaces; + } + else { + aVec[SMDSEntity_Node] = Max ( nbNodes, 0 ); + aVec[SMDSEntity_Triangle] = nbFaces; + } + aResMap[sm].swap(aVec); + } + + // ---------------- + // evaluate 3D + // ---------------- + if(_isVolume) { + // pass 3D simple parameters to NETGEN + const NETGENPlugin_SimpleHypothesis_3D* simple3d = + dynamic_cast< const NETGENPlugin_SimpleHypothesis_3D* > ( _simpleHyp ); + if ( simple3d ) { + if ( double vol = simple3d->GetMaxElementVolume() ) { + // max volume + mparams.maxh = pow( 72, 1/6. ) * pow( vol, 1/3. ); + mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 ); + } + else { + // using previous length from faces + } + mparams.grading = 0.4; + mparams.maxh = min( mparams.maxh, fullLen/fullNbSeg * (1. + mparams.grading)); + } + GProp_GProps G; + BRepGProp::VolumeProperties(_shape,G); + double aVolume = G.Mass(); + double tetrVol = 0.1179*mparams.maxh*mparams.maxh*mparams.maxh; + tooManyElems = tooManyElems || ( aVolume/hugeNb > tetrVol ); + int nbVols = tooManyElems ? hugeNb : int(aVolume/tetrVol); + int nb1d_in = int(( nbVols*6 - fullNbSeg ) / 6 ); + vector aVec(SMDSEntity_Last, 0 ); + if ( tooManyElems ) // avoid FPE + { + aVec[SMDSEntity_Node] = hugeNb; + aVec[ mparams.secondorder > 0 ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra] = hugeNb; + } + else + { + if( mparams.secondorder > 0 ) { + aVec[SMDSEntity_Node] = nb1d_in/3 + 1 + nb1d_in; + aVec[SMDSEntity_Quad_Tetra] = nbVols; + } + else { + aVec[SMDSEntity_Node] = nb1d_in/3 + 1; + aVec[SMDSEntity_Tetra] = nbVols; + } + } + SMESH_subMesh *sm = _mesh->GetSubMesh(_shape); + aResMap[sm].swap(aVec); + } + + return true; +} + +double NETGENPlugin_Mesher::GetProgress(const SMESH_Algo* holder, + const int * algoProgressTic, + const double * algoProgress) const +{ + ((int&) _progressTic ) = *algoProgressTic + 1; + + if ( !_occgeom ) return 0; + + double progress = -1; + if ( !_isVolume ) + { + if ( _ticTime < 0 && netgen::multithread.task[0] == 'O'/*Optimizing surface*/ ) + { + ((double&) _ticTime ) = edgeFaceMeshingTime / _totalTime / _progressTic; + } + else if ( !_optimize /*&& _occgeom->fmap.Extent() > 1*/ ) + { + int doneShapeIndex = -1; + while ( doneShapeIndex+1 < _occgeom->facemeshstatus.Size() && + _occgeom->facemeshstatus[ doneShapeIndex+1 ]) + doneShapeIndex++; + if ( doneShapeIndex+1 != _curShapeIndex ) + { + ((int&) _curShapeIndex) = doneShapeIndex+1; + double doneShapeRate = _curShapeIndex / double( _occgeom->fmap.Extent() ); + double doneTime = edgeMeshingTime + doneShapeRate * faceMeshingTime; + ((double&) _ticTime) = doneTime / _totalTime / _progressTic; + // cout << "shape " << _curShapeIndex << " _ticTime " << _ticTime + // << " " << doneTime / _totalTime / _progressTic << endl; + } + } + } + else if ( !_optimize && _occgeom->somap.Extent() > 1 ) + { + int curShapeIndex = _curShapeIndex; + if ( _ngMesh->GetNE() > 0 ) + { + netgen::Element el = (*_ngMesh)[netgen::ElementIndex( _ngMesh->GetNE()-1 )]; + curShapeIndex = el.GetIndex(); + } + if ( curShapeIndex != _curShapeIndex ) + { + ((int&) _curShapeIndex) = curShapeIndex; + double doneShapeRate = _curShapeIndex / double( _occgeom->somap.Extent() ); + double doneTime = edgeFaceMeshingTime + doneShapeRate * voluMeshingTime; + ((double&) _ticTime) = doneTime / _totalTime / _progressTic; + // cout << "shape " << _curShapeIndex << " _ticTime " << _ticTime + // << " " << doneTime / _totalTime / _progressTic << endl; + } + } + if ( _ticTime > 0 ) + progress = Max( *algoProgressTic * _ticTime, *algoProgress ); + if ( progress > 0 ) + { + ((int&) *algoProgressTic )++; + ((double&) *algoProgress) = progress; + } + //cout << progress << " " << *algoProgressTic << " " << netgen::multithread.task << " "<< _ticTime << endl; + + return Min( progress, 0.99 ); +} + +//================================================================================ +/*! + * \brief Remove "test.out" and "problemfaces" files in current directory + */ +//================================================================================ + +void NETGENPlugin_Mesher::RemoveTmpFiles() +{ + bool rm = SMESH_File("test.out").remove() ; +#ifndef WIN32 + if (rm && netgen::testout) + { + delete netgen::testout; + netgen::testout = 0; + } +#endif + SMESH_File("problemfaces").remove(); + SMESH_File("occmesh.rep").remove(); +} + +//================================================================================ +/*! + * \brief Read mesh entities preventing successful computation from "test.out" file + */ +//================================================================================ + +SMESH_ComputeErrorPtr +NETGENPlugin_Mesher::ReadErrors(const vector& nodeVec) +{ + SMESH_ComputeErrorPtr err = SMESH_ComputeError::New + (COMPERR_BAD_INPUT_MESH, "Some edges multiple times in surface mesh"); + SMESH_File file("test.out"); + vector two(2); + vector three1(3), three2(3); + const char* badEdgeStr = " multiple times in surface mesh"; + const int badEdgeStrLen = strlen( badEdgeStr ); + + while( !file.eof() ) + { + if ( strncmp( file, "Edge ", 5 ) == 0 && + file.getInts( two ) && + strncmp( file, badEdgeStr, badEdgeStrLen ) == 0 && + two[0] < nodeVec.size() && two[1] < nodeVec.size()) + { + err->myBadElements.push_back( new SMDS_LinearEdge( nodeVec[ two[0]], nodeVec[ two[1]] )); + file += badEdgeStrLen; + } + else if ( strncmp( file, "Intersecting: ", 14 ) == 0 ) + { +// Intersecting: +// openelement 18 with open element 126 +// 41 36 38 +// 69 70 72 + file.getLine(); + const char* pos = file; + bool ok = ( strncmp( file, "openelement ", 12 ) == 0 ); + ok = ok && file.getInts( two ); + ok = ok && file.getInts( three1 ); + ok = ok && file.getInts( three2 ); + for ( int i = 0; ok && i < 3; ++i ) + ok = ( three1[i] < nodeVec.size() && nodeVec[ three1[i]]); + for ( int i = 0; ok && i < 3; ++i ) + ok = ( three2[i] < nodeVec.size() && nodeVec[ three2[i]]); + if ( ok ) + { + err->myBadElements.push_back( new SMDS_FaceOfNodes( nodeVec[ three1[0]], + nodeVec[ three1[1]], + nodeVec[ three1[2]])); + err->myBadElements.push_back( new SMDS_FaceOfNodes( nodeVec[ three2[0]], + nodeVec[ three2[1]], + nodeVec[ three2[2]])); + err->myComment = "Intersecting triangles"; + } + else + { + file.setPos( pos ); + } + } + else + { + ++file; + } + } + +#ifdef _DEBUG_ + size_t nbBadElems = err->myBadElements.size(); + nbBadElems = 0; +#endif + + return err; +} + +//================================================================================ +/*! + * \brief Write a python script creating an equivalent SALOME mesh. + * This is useful to see what mesh is passed as input for the next step of mesh + * generation (of mesh of higher dimension) + */ +//================================================================================ + +void NETGENPlugin_Mesher::toPython( const netgen::Mesh* ngMesh, + const std::string& pyFile) +{ + ofstream outfile(pyFile.c_str(), ios::out); + if ( !outfile ) return; + + outfile << "import SMESH" << endl + << "from salome.smesh import smeshBuilder" << endl + << "smesh = smeshBuilder.New(salome.myStudy)" << endl + << "mesh = smesh.Mesh()" << endl << endl; + + using namespace netgen; + PointIndex pi; + for (pi = PointIndex::BASE; + pi < ngMesh->GetNP()+PointIndex::BASE; pi++) + { + outfile << "mesh.AddNode( "; + outfile << (*ngMesh)[pi](0) << ", "; + outfile << (*ngMesh)[pi](1) << ", "; + outfile << (*ngMesh)[pi](2) << ") ## "<< pi << endl; + } + + int nbDom = ngMesh->GetNDomains(); + for ( int i = 0; i < nbDom; ++i ) + outfile<< "grp" << i+1 << " = mesh.CreateEmptyGroup( SMESH.FACE, 'domain"<< i+1 << "')"<< endl; + + SurfaceElementIndex sei; + for (sei = 0; sei < ngMesh->GetNSE(); sei++) + { + outfile << "mesh.AddFace([ "; + Element2d sel = (*ngMesh)[sei]; + for (int j = 0; j < sel.GetNP(); j++) + outfile << sel[j] << ( j+1 < sel.GetNP() ? ", " : " ])"); + if ( sel.IsDeleted() ) outfile << " ## IsDeleted "; + outfile << endl; + + if ((*ngMesh)[sei].GetIndex()) + { + if ( int dom1 = ngMesh->GetFaceDescriptor((*ngMesh)[sei].GetIndex ()).DomainIn()) + outfile << "grp"<< dom1 <<".Add([ " << (int)sei+1 << " ])" << endl; + if ( int dom2 = ngMesh->GetFaceDescriptor((*ngMesh)[sei].GetIndex ()).DomainOut()) + outfile << "grp"<< dom2 <<".Add([ " << (int)sei+1 << " ])" << endl; + } + } + + for (ElementIndex ei = 0; ei < ngMesh->GetNE(); ei++) + { + Element el = (*ngMesh)[ei]; + outfile << "mesh.AddVolume([ "; + for (int j = 0; j < el.GetNP(); j++) + outfile << el[j] << ( j+1 < el.GetNP() ? ", " : " ])"); + outfile << endl; + } + + for (int i = 1; i <= ngMesh->GetNSeg(); i++) + { + const Segment & seg = ngMesh->LineSegment (i); + outfile << "mesh.AddEdge([ " + << seg[0] << ", " + << seg[1] << " ])" << endl; + } + cout << "Write " << pyFile << endl; +} + +//================================================================================ +/*! + * \brief Constructor of NETGENPlugin_ngMeshInfo + */ +//================================================================================ + +NETGENPlugin_ngMeshInfo::NETGENPlugin_ngMeshInfo( netgen::Mesh* ngMesh): + _copyOfLocalH(0) +{ + if ( ngMesh ) + { + _nbNodes = ngMesh->GetNP(); + _nbSegments = ngMesh->GetNSeg(); + _nbFaces = ngMesh->GetNSE(); + _nbVolumes = ngMesh->GetNE(); + } + else + { + _nbNodes = _nbSegments = _nbFaces = _nbVolumes = 0; + } +} + +//================================================================================ +/*! + * \brief Copy LocalH member from one netgen mesh to another + */ +//================================================================================ + +void NETGENPlugin_ngMeshInfo::transferLocalH( netgen::Mesh* fromMesh, + netgen::Mesh* toMesh ) +{ + if ( !fromMesh->LocalHFunctionGenerated() ) return; + if ( !toMesh->LocalHFunctionGenerated() ) +#ifdef NETGEN_V5 + toMesh->CalcLocalH(netgen::mparam.grading); +#else + toMesh->CalcLocalH(); +#endif + + const size_t size = sizeof( netgen::LocalH ); + _copyOfLocalH = new char[ size ]; + memcpy( (void*)_copyOfLocalH, (void*)&toMesh->LocalHFunction(), size ); + memcpy( (void*)&toMesh->LocalHFunction(), (void*)&fromMesh->LocalHFunction(), size ); +} + +//================================================================================ +/*! + * \brief Restore LocalH member of a netgen mesh + */ +//================================================================================ + +void NETGENPlugin_ngMeshInfo::restoreLocalH( netgen::Mesh* toMesh ) +{ + if ( _copyOfLocalH ) + { + const size_t size = sizeof( netgen::LocalH ); + memcpy( (void*)&toMesh->LocalHFunction(), (void*)_copyOfLocalH, size ); + delete [] _copyOfLocalH; + _copyOfLocalH = 0; + } +} + +//================================================================================ +/*! + * \brief Find "internal" sub-shapes + */ +//================================================================================ + +NETGENPlugin_Internals::NETGENPlugin_Internals( SMESH_Mesh& mesh, + const TopoDS_Shape& shape, + bool is3D ) + : _mesh( mesh ), _is3D( is3D ) +{ + SMESHDS_Mesh* meshDS = mesh.GetMeshDS(); + + TopExp_Explorer f,e; + for ( f.Init( shape, TopAbs_FACE ); f.More(); f.Next() ) + { + int faceID = meshDS->ShapeToIndex( f.Current() ); + + // find not computed internal edges + + for ( e.Init( f.Current().Oriented(TopAbs_FORWARD), TopAbs_EDGE ); e.More(); e.Next() ) + if ( e.Current().Orientation() == TopAbs_INTERNAL ) + { + SMESH_subMesh* eSM = mesh.GetSubMesh( e.Current() ); + if ( eSM->IsEmpty() ) + { + _e2face.insert( make_pair( eSM->GetId(), faceID )); + for ( TopoDS_Iterator v(e.Current()); v.More(); v.Next() ) + _e2face.insert( make_pair( meshDS->ShapeToIndex( v.Value() ), faceID )); + } + } + + // find internal vertices in a face + set intVV; // issue 0020850 where same vertex is twice in a face + for ( TopoDS_Iterator fSub( f.Current() ); fSub.More(); fSub.Next()) + if ( fSub.Value().ShapeType() == TopAbs_VERTEX ) + { + int vID = meshDS->ShapeToIndex( fSub.Value() ); + if ( intVV.insert( vID ).second ) + _f2v[ faceID ].push_back( vID ); + } + + if ( is3D ) + { + // find internal faces and their subshapes where nodes are to be doubled + // to make a crack with non-sewed borders + + if ( f.Current().Orientation() == TopAbs_INTERNAL ) + { + _intShapes.insert( meshDS->ShapeToIndex( f.Current() )); + + // egdes + list< TopoDS_Shape > edges; + for ( e.Init( f.Current(), TopAbs_EDGE ); e.More(); e.Next()) + if ( SMESH_MesherHelper::NbAncestors( e.Current(), mesh, TopAbs_FACE ) > 1 ) + { + _intShapes.insert( meshDS->ShapeToIndex( e.Current() )); + edges.push_back( e.Current() ); + // find border faces + PShapeIteratorPtr fIt = + SMESH_MesherHelper::GetAncestors( edges.back(),mesh,TopAbs_FACE ); + while ( const TopoDS_Shape* pFace = fIt->next() ) + if ( !pFace->IsSame( f.Current() )) + _borderFaces.insert( meshDS->ShapeToIndex( *pFace )); + } + // vertices + // we consider vertex internal if it is shared by more than one internal edge + list< TopoDS_Shape >::iterator edge = edges.begin(); + for ( ; edge != edges.end(); ++edge ) + for ( TopoDS_Iterator v( *edge ); v.More(); v.Next() ) + { + set internalEdges; + PShapeIteratorPtr eIt = + SMESH_MesherHelper::GetAncestors( v.Value(),mesh,TopAbs_EDGE ); + while ( const TopoDS_Shape* pEdge = eIt->next() ) + { + int edgeID = meshDS->ShapeToIndex( *pEdge ); + if ( isInternalShape( edgeID )) + internalEdges.insert( edgeID ); + } + if ( internalEdges.size() > 1 ) + _intShapes.insert( meshDS->ShapeToIndex( v.Value() )); + } + } + } + } // loop on geom faces + + // find vertices internal in solids + if ( is3D ) + { + for ( TopExp_Explorer so(shape, TopAbs_SOLID); so.More(); so.Next()) + { + int soID = meshDS->ShapeToIndex( so.Current() ); + for ( TopoDS_Iterator soSub( so.Current() ); soSub.More(); soSub.Next()) + if ( soSub.Value().ShapeType() == TopAbs_VERTEX ) + _s2v[ soID ].push_back( meshDS->ShapeToIndex( soSub.Value() )); + } + } +} + +//================================================================================ +/*! + * \brief Find mesh faces on non-internal geom faces sharing internal edge + * some nodes of which are to be doubled to make the second border of the "crack" + */ +//================================================================================ + +void NETGENPlugin_Internals::findBorderElements( TIDSortedElemSet & borderElems ) +{ + if ( _intShapes.empty() ) return; + + SMESH_Mesh& mesh = const_cast(_mesh); + SMESHDS_Mesh* meshDS = mesh.GetMeshDS(); + + // loop on internal geom edges + set::const_iterator intShapeId = _intShapes.begin(); + for ( ; intShapeId != _intShapes.end(); ++intShapeId ) + { + const TopoDS_Shape& s = meshDS->IndexToShape( *intShapeId ); + if ( s.ShapeType() != TopAbs_EDGE ) continue; + + // get internal and non-internal geom faces sharing the internal edge + int intFace = 0; + set::iterator bordFace = _borderFaces.end(); + PShapeIteratorPtr faces = SMESH_MesherHelper::GetAncestors( s, _mesh, TopAbs_FACE ); + while ( const TopoDS_Shape* pFace = faces->next() ) + { + int faceID = meshDS->ShapeToIndex( *pFace ); + if ( isInternalShape( faceID )) + intFace = faceID; + else + bordFace = _borderFaces.insert( faceID ).first; + } + if ( bordFace == _borderFaces.end() || !intFace ) continue; + + // get all links of mesh faces on internal geom face sharing nodes on edge + set< SMESH_OrientedLink > links; //!< links of faces on internal geom face + list suspectFaces[2]; //!< mesh faces on border geom faces + int nbSuspectFaces = 0; + SMESHDS_SubMesh* intFaceSM = meshDS->MeshElements( intFace ); + if ( !intFaceSM || intFaceSM->NbElements() == 0 ) continue; + SMESH_subMeshIteratorPtr smIt = mesh.GetSubMesh( s )->getDependsOnIterator(true,true); + while ( smIt->more() ) + { + SMESHDS_SubMesh* sm = smIt->next()->GetSubMeshDS(); + if ( !sm ) continue; + SMDS_NodeIteratorPtr nIt = sm->GetNodes(); + while ( nIt->more() ) + { + const SMDS_MeshNode* nOnEdge = nIt->next(); + SMDS_ElemIteratorPtr fIt = nOnEdge->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + const int nbNodes = f->NbCornerNodes(); + if ( intFaceSM->Contains( f )) + { + for ( int i = 0; i < nbNodes; ++i ) + links.insert( SMESH_OrientedLink( f->GetNode(i), f->GetNode((i+1)%nbNodes))); + } + else + { + int nbDblNodes = 0; + for ( int i = 0; i < nbNodes; ++i ) + nbDblNodes += isInternalShape( f->GetNode(i)->getshapeId() ); + if ( nbDblNodes ) + suspectFaces[ nbDblNodes < 2 ].push_back( f ); + nbSuspectFaces++; + } + } + } + } + // suspectFaces[0] having link with same orientation as mesh faces on + // the internal geom face are . suspectFaces[1] have + // only one node on edge , we decide on them later (at the 2nd loop) + // by links of found at the 1st and 2nd loops + set< SMESH_OrientedLink > borderLinks; + for ( int isPostponed = 0; isPostponed < 2; ++isPostponed ) + { + list::iterator fIt = suspectFaces[isPostponed].begin(); + for ( int nbF = 0; fIt != suspectFaces[isPostponed].end(); ++fIt, ++nbF ) + { + const SMDS_MeshElement* f = *fIt; + bool isBorder = false, linkFound = false, borderLinkFound = false; + list< SMESH_OrientedLink > faceLinks; + int nbNodes = f->NbCornerNodes(); + for ( int i = 0; i < nbNodes; ++i ) + { + SMESH_OrientedLink link( f->GetNode(i), f->GetNode((i+1)%nbNodes)); + faceLinks.push_back( link ); + if ( !linkFound ) + { + set< SMESH_OrientedLink >::iterator foundLink = links.find( link ); + if ( foundLink != links.end() ) + { + linkFound= true; + isBorder = ( foundLink->_reversed == link._reversed ); + if ( !isBorder && !isPostponed ) break; + faceLinks.pop_back(); + } + else if ( isPostponed && !borderLinkFound ) + { + foundLink = borderLinks.find( link ); + if ( foundLink != borderLinks.end() ) + { + borderLinkFound = true; + isBorder = ( foundLink->_reversed != link._reversed ); + } + } + } + } + if ( isBorder ) + { + borderElems.insert( f ); + borderLinks.insert( faceLinks.begin(), faceLinks.end() ); + } + else if ( !linkFound && !borderLinkFound ) + { + suspectFaces[1].push_back( f ); + if ( nbF > 2 * nbSuspectFaces ) + break; // dead loop protection + } + } + } + } +} + +//================================================================================ +/*! + * \brief put internal shapes in maps and fill in submeshes to precompute + */ +//================================================================================ + +void NETGENPlugin_Internals::getInternalEdges( TopTools_IndexedMapOfShape& fmap, + TopTools_IndexedMapOfShape& emap, + TopTools_IndexedMapOfShape& vmap, + list< SMESH_subMesh* > smToPrecompute[]) +{ + if ( !hasInternalEdges() ) return; + map::const_iterator ev_face = _e2face.begin(); + for ( ; ev_face != _e2face.end(); ++ev_face ) + { + const TopoDS_Shape& ev = _mesh.GetMeshDS()->IndexToShape( ev_face->first ); + const TopoDS_Shape& face = _mesh.GetMeshDS()->IndexToShape( ev_face->second ); + + ( ev.ShapeType() == TopAbs_EDGE ? emap : vmap ).Add( ev ); + fmap.Add( face ); + //cout<<"INTERNAL EDGE or VERTEX "<first<<" on face "<second<first )); + } +} + +//================================================================================ +/*! + * \brief return shapes and submeshes to be meshed and already meshed boundary submeshes + */ +//================================================================================ + +void NETGENPlugin_Internals::getInternalFaces( TopTools_IndexedMapOfShape& fmap, + TopTools_IndexedMapOfShape& emap, + list< SMESH_subMesh* >& intFaceSM, + list< SMESH_subMesh* >& boundarySM) +{ + if ( !hasInternalFaces() ) return; + + // and are for not yet meshed shapes + // is for submeshes of faces + // is for meshed edges and vertices + + intFaceSM.clear(); + boundarySM.clear(); + + set shapeIDs ( _intShapes ); + if ( !_borderFaces.empty() ) + shapeIDs.insert( _borderFaces.begin(), _borderFaces.end() ); + + set::const_iterator intS = shapeIDs.begin(); + for ( ; intS != shapeIDs.end(); ++intS ) + { + SMESH_subMesh* sm = _mesh.GetSubMeshContaining( *intS ); + + if ( sm->GetSubShape().ShapeType() != TopAbs_FACE ) continue; + + intFaceSM.push_back( sm ); + + // add submeshes of not computed internal faces + if ( !sm->IsEmpty() ) continue; + + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(true,true); + while ( smIt->more() ) + { + sm = smIt->next(); + const TopoDS_Shape& s = sm->GetSubShape(); + + if ( sm->IsEmpty() ) + { + // not yet meshed + switch ( s.ShapeType() ) { + case TopAbs_FACE: fmap.Add ( s ); break; + case TopAbs_EDGE: emap.Add ( s ); break; + default:; + } + } + else + { + if ( s.ShapeType() != TopAbs_FACE ) + boundarySM.push_back( sm ); + } + } + } +} + +//================================================================================ +/*! + * \brief Return true if given shape is to be precomputed in order to be correctly + * added to netgen mesh + */ +//================================================================================ + +bool NETGENPlugin_Internals::isShapeToPrecompute(const TopoDS_Shape& s) +{ + int shapeID = _mesh.GetMeshDS()->ShapeToIndex( s ); + switch ( s.ShapeType() ) { + case TopAbs_FACE : break; //return isInternalShape( shapeID ) || isBorderFace( shapeID ); + case TopAbs_EDGE : return isInternalEdge( shapeID ); + case TopAbs_VERTEX: break; + default:; + } + return false; +} + +//================================================================================ +/*! + * \brief Return SMESH + */ +//================================================================================ + +SMESH_Mesh& NETGENPlugin_Internals::getMesh() const +{ + return const_cast( _mesh ); +} + +//================================================================================ +/*! + * \brief Initialize netgen library + */ +//================================================================================ + +NETGENPlugin_NetgenLibWrapper::NETGENPlugin_NetgenLibWrapper() +{ + Ng_Init(); + + _isComputeOk = false; + _coutBuffer = NULL; + if ( !getenv( "KEEP_NETGEN_OUTPUT" )) + { + // redirect all netgen output (mycout,myerr,cout) to _outputFileName + _outputFileName = getOutputFileName(); + netgen::mycout = new ofstream ( _outputFileName.c_str() ); + netgen::myerr = netgen::mycout; + _coutBuffer = std::cout.rdbuf(); +#ifdef _DEBUG_ + cout << "NOTE: netgen output is redirected to file " << _outputFileName << endl; +#else + std::cout.rdbuf( netgen::mycout->rdbuf() ); +#endif + } + + _ngMesh = Ng_NewMesh(); +} + +//================================================================================ +/*! + * \brief Finish using netgen library + */ +//================================================================================ + +NETGENPlugin_NetgenLibWrapper::~NETGENPlugin_NetgenLibWrapper() +{ + Ng_DeleteMesh( _ngMesh ); + Ng_Exit(); + NETGENPlugin_Mesher::RemoveTmpFiles(); + if ( _coutBuffer ) + std::cout.rdbuf( _coutBuffer ); +#ifdef _DEBUG_ + if( _isComputeOk ) +#endif + removeOutputFile(); +} + +//================================================================================ +/*! + * \brief Set netgen mesh to delete at destruction + */ +//================================================================================ + +void NETGENPlugin_NetgenLibWrapper::setMesh( Ng_Mesh* mesh ) +{ + if ( _ngMesh ) + Ng_DeleteMesh( _ngMesh ); + _ngMesh = mesh; +} + +//================================================================================ +/*! + * \brief Return a unique file name + */ +//================================================================================ + +std::string NETGENPlugin_NetgenLibWrapper::getOutputFileName() +{ +// std::string aTmpDir = SALOMEDS_Tool::GetTmpDir(); + std::string aTmpDir = "/tmp"; + + TCollection_AsciiString aGenericName = (char*)aTmpDir.c_str(); + aGenericName += "NETGEN_"; +#ifndef WIN32 + aGenericName += getpid(); +#else + aGenericName += _getpid(); +#endif + aGenericName += "_"; + aGenericName += Abs((Standard_Integer)(long) aGenericName.ToCString()); + aGenericName += ".out"; + + return aGenericName.ToCString(); +} + +//================================================================================ +/*! + * \brief Remove file with netgen output + */ +//================================================================================ + +void NETGENPlugin_NetgenLibWrapper::removeOutputFile() +{ +/* if ( !_outputFileName.empty() ) + { + if ( netgen::mycout ) + { + delete netgen::mycout; + netgen::mycout = 0; + netgen::myerr = 0; + } + string tmpDir = SALOMEDS_Tool::GetDirFromPath ( _outputFileName ); + string aFileName = SALOMEDS_Tool::GetNameFromPath( _outputFileName ) + ".out"; + SALOMEDS::ListOfFileNames_var aFiles = new SALOMEDS::ListOfFileNames; + aFiles->length(1); + aFiles[0] = aFileName.c_str(); + + SALOMEDS_Tool::RemoveTemporaryFiles( tmpDir.c_str(), aFiles.in(), true ); + } +*/ } diff --git a/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_NETGEN_2D.cpp b/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_NETGEN_2D.cpp index 9415cf4768fb..6e52d3ecc703 100644 --- a/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_NETGEN_2D.cpp +++ b/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_NETGEN_2D.cpp @@ -1,30 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // NETGENPlugin : C++ implementation // File : NETGENPlugin_NETGEN_2D.cxx // Author : Michael Sazonov (OCN) // Date : 20/03/2006 // Project : SALOME -// $Header: /home/server/cvs/NETGENPLUGIN/NETGENPLUGIN_SRC/src/NETGENPlugin/NETGENPlugin_NETGEN_2D.cxx,v 1.4.2.2 2008/11/27 14:29:44 abd Exp $ //============================================================================= // #include "NETGENPlugin_NETGEN_2D.hxx" @@ -32,14 +32,20 @@ #include "NETGENPlugin_SimpleHypothesis_2D.hxx" #include "NETGENPlugin_Mesher.hxx" +#include +#include #include #include -#include -#include +#include #include #include +namespace nglib { +#include +} +#include + using namespace std; //============================================================================= @@ -57,10 +63,11 @@ NETGENPlugin_NETGEN_2D::NETGENPlugin_NETGEN_2D(int hypId, int studyId, _shapeType = (1 << TopAbs_FACE); // 1 bit /shape type _compatibleHypothesis.push_back("NETGEN_Parameters_2D"); _compatibleHypothesis.push_back("NETGEN_SimpleParameters_2D"); - _requireDescretBoundary = false; - _onlyUnaryInput = false; - _hypothesis = NULL; - _supportSubmeshes = true; + _compatibleHypothesis.push_back( StdMeshers_ViscousLayers2D::GetHypType() ); + _requireDiscreteBoundary = false; + _onlyUnaryInput = false; + _hypothesis = NULL; + _supportSubmeshes = true; } //============================================================================= @@ -80,35 +87,34 @@ NETGENPlugin_NETGEN_2D::~NETGENPlugin_NETGEN_2D() */ //============================================================================= -bool NETGENPlugin_NETGEN_2D::CheckHypothesis - (SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape, - SMESH_Hypothesis::Hypothesis_Status& aStatus) +bool NETGENPlugin_NETGEN_2D::CheckHypothesis (SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + Hypothesis_Status& aStatus) { - _hypothesis = NULL; + _hypothesis = NULL; + _isViscousLayers2D = false; + _mesher = NULL; - const list& hyps = GetUsedHypothesis(aMesh, aShape); - int nbHyp = hyps.size(); - if (!nbHyp) - { - aStatus = SMESH_Hypothesis::HYP_OK; - return true; // can work with no hypothesis - } - // use only the first hypothesis - const SMESHDS_Hypothesis* theHyp = hyps.front(); + // can work with no hypothesis + aStatus = SMESH_Hypothesis::HYP_OK; - string hypName = theHyp->GetName(); - if ( find( _compatibleHypothesis.begin(), _compatibleHypothesis.end(), - hypName ) != _compatibleHypothesis.end() ) - { - _hypothesis = theHyp; - aStatus = SMESH_Hypothesis::HYP_OK; - } - else + const list& hyps = GetUsedHypothesis(aMesh, aShape, /*skipAux=*/false); + list::const_iterator h = hyps.begin(); + for ( ; h != hyps.end(); ++h ) { - aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + const SMESHDS_Hypothesis* theHyp = *h; + string hypName = theHyp->GetName(); + if ( hypName == StdMeshers_ViscousLayers2D::GetHypType() ) + _isViscousLayers2D = true; + else if ( _hypothesis ) + aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + else + _hypothesis = theHyp; } + if ( aStatus == HYP_OK && _isViscousLayers2D ) + error( StdMeshers_ViscousLayers2D::CheckHypothesis( aMesh, aShape, aStatus )); + return aStatus == SMESH_Hypothesis::HYP_OK; } @@ -121,11 +127,52 @@ bool NETGENPlugin_NETGEN_2D::CheckHypothesis bool NETGENPlugin_NETGEN_2D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { - //SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); + netgen::multithread.terminate = 0; - NETGENPlugin_Mesher mesher(&aMesh, aShape, false); -// NETGENPlugin_Mesher mesher(meshDS, aShape, false); + NETGENPlugin_Mesher mesher(&aMesh, aShape, /*is3D = */false); mesher.SetParameters(dynamic_cast(_hypothesis)); mesher.SetParameters(dynamic_cast(_hypothesis)); + mesher.SetViscousLayers2DAssigned( _isViscousLayers2D ); + mesher.SetSelfPointer( &_mesher ); return mesher.Compute(); } + +//============================================================================= +/*! + * Terminate Compute() + */ +//============================================================================= + +void NETGENPlugin_NETGEN_2D::CancelCompute() +{ + SMESH_Algo::CancelCompute(); + netgen::multithread.terminate = 1; +} + +//================================================================================ +/*! + * \brief Return progress of Compute() [0.,1] + */ +//================================================================================ + +double NETGENPlugin_NETGEN_2D::GetProgress() const +{ + return _mesher ? _mesher->GetProgress(this, &_progressTic, &_progress) : 0; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +bool NETGENPlugin_NETGEN_2D::Evaluate(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + MapShapeNbElems& aResMap) +{ + + NETGENPlugin_Mesher mesher(&aMesh, aShape, false); + mesher.SetParameters(dynamic_cast(_hypothesis)); + mesher.SetParameters(dynamic_cast(_hypothesis)); + return mesher.Evaluate(aResMap); +} diff --git a/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_NETGEN_2D3D.cpp b/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_NETGEN_2D3D.cpp index 2db892e1e01e..3fd01d61d297 100644 --- a/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_NETGEN_2D3D.cpp +++ b/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_NETGEN_2D3D.cpp @@ -1,35 +1,35 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // NETGENPlugin : C++ implementation // File : NETGENPlugin_NETGEN_2D3D.cxx // Author : Michael Sazonov (OCN) // Date : 20/03/2006 // Project : SALOME -// $Header: /home/server/cvs/NETGENPLUGIN/NETGENPLUGIN_SRC/src/NETGENPlugin/NETGENPlugin_NETGEN_2D3D.cxx,v 1.4.2.2 2008/11/27 14:29:44 abd Exp $ //============================================================================= // #include "NETGENPlugin_NETGEN_2D3D.hxx" #include "NETGENPlugin_Hypothesis.hxx" -#include "NETGENPlugin_SimpleHypothesis_2D.hxx" +#include "NETGENPlugin_SimpleHypothesis_3D.hxx" #include "NETGENPlugin_Mesher.hxx" #include @@ -40,6 +40,11 @@ #include +namespace nglib { +#include +} +#include + using namespace std; //============================================================================= @@ -57,7 +62,7 @@ NETGENPlugin_NETGEN_2D3D::NETGENPlugin_NETGEN_2D3D(int hypId, int studyId, _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);// 1 bit /shape type _compatibleHypothesis.push_back("NETGEN_Parameters"); _compatibleHypothesis.push_back("NETGEN_SimpleParameters_3D"); - _requireDescretBoundary = false; + _requireDiscreteBoundary = false; _onlyUnaryInput = false; _hypothesis = NULL; _supportSubmeshes = true; @@ -88,6 +93,7 @@ bool NETGENPlugin_NETGEN_2D3D::CheckHypothesis MESSAGE("NETGENPlugin_NETGEN_2D3D::CheckHypothesis"); _hypothesis = NULL; + _mesher = NULL; const list& hyps = GetUsedHypothesis(aMesh, aShape); int nbHyp = hyps.size(); @@ -117,18 +123,63 @@ bool NETGENPlugin_NETGEN_2D3D::CheckHypothesis //============================================================================= /*! - *Here we are going to use the NETGEN mesher + * Here we are going to use the NETGEN mesher */ //============================================================================= bool NETGENPlugin_NETGEN_2D3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { -// SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); + netgen::multithread.terminate = 0; NETGENPlugin_Mesher mesher(&aMesh, aShape, true); -// NETGENPlugin_Mesher mesher(meshDS, aShape, true); mesher.SetParameters(dynamic_cast(_hypothesis)); - mesher.SetParameters(dynamic_cast(_hypothesis)); + mesher.SetParameters(dynamic_cast(_hypothesis)); + mesher.SetSelfPointer( &_mesher ); return mesher.Compute(); } + +//============================================================================= +/*! + * + */ +//============================================================================= + +void NETGENPlugin_NETGEN_2D3D::CancelCompute() +{ + SMESH_Algo::CancelCompute(); + netgen::multithread.terminate = 1; +} + +//================================================================================ +/*! + * \brief Return progress of Compute() [0.,1] + */ +//================================================================================ + +double NETGENPlugin_NETGEN_2D3D::GetProgress() const +{ + double & progress = (double &)_progress; + if ( _mesher ) + progress = _mesher->GetProgress(this, &_progressTic, &_progress); + else if ( _progress > 0.001 ) + progress = 0.99; + + return _progress; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +bool NETGENPlugin_NETGEN_2D3D::Evaluate(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + MapShapeNbElems& aResMap) +{ + NETGENPlugin_Mesher mesher(&aMesh, aShape, true); + mesher.SetParameters(dynamic_cast(_hypothesis)); + mesher.SetParameters(dynamic_cast(_hypothesis)); + return mesher.Evaluate(aResMap); +} diff --git a/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_ONLY.cpp b/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_ONLY.cpp index 50006ac5d7c0..81756f818b57 100644 --- a/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_ONLY.cpp +++ b/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_ONLY.cpp @@ -1,24 +1,22 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 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, or (at your option) any later version. // -// 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. // -// 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 // -// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : NETGENPlugin_NETGEN_2D_ONLY.cxx // Author : Edward AGAPOV (OCC) // Project : SALOME @@ -26,34 +24,35 @@ #include "NETGENPlugin_NETGEN_2D_ONLY.hxx" #include "NETGENPlugin_Mesher.hxx" - -#include "SMDS_MeshElement.hxx" -#include "SMDS_MeshNode.hxx" -#include "SMESHDS_Mesh.hxx" -#include "SMESH_Comment.hxx" -#include "SMESH_Gen.hxx" -#include "SMESH_Mesh.hxx" -#include "SMESH_MesherHelper.hxx" -#include "StdMeshers_FaceSide.hxx" -#include "StdMeshers_MaxElementArea.hxx" -#include "StdMeshers_LengthFromEdges.hxx" -#include "StdMeshers_QuadranglePreference.hxx" - +#include "NETGENPlugin_Hypothesis_2D.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include #include -#include "utilities.h" +#include #include #include +#include /* Netgen include files */ -#ifdef _MSC_VER -#pragma warning(disable : 4067) -#endif - namespace nglib { #include } @@ -66,11 +65,12 @@ namespace nglib { //#include namespace netgen { #ifdef NETGEN_V5 - DLL_HEADER extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, MeshingParameters&, int, int); + extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, MeshingParameters&, int, int); #else - DLL_HEADER extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, int, int, char*); + extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, int, int, char*); #endif - DLL_HEADER extern MeshingParameters mparam; + extern MeshingParameters mparam; + extern void OCCSetLocalMeshSize(OCCGeometry & geom, Mesh & mesh); } using namespace std; @@ -83,22 +83,26 @@ using namespace nglib; */ //============================================================================= -NETGENPlugin_NETGEN_2D_ONLY::NETGENPlugin_NETGEN_2D_ONLY(int hypId, int studyId, +NETGENPlugin_NETGEN_2D_ONLY::NETGENPlugin_NETGEN_2D_ONLY(int hypId, + int studyId, SMESH_Gen* gen) : SMESH_2D_Algo(hypId, studyId, gen) { - MESSAGE("NETGENPlugin_NETGEN_2D_ONLY::NETGENPlugin_NETGEN_2D_ONLY"); _name = "NETGEN_2D_ONLY"; - + _shapeType = (1 << TopAbs_FACE);// 1 bit /shape type + _onlyUnaryInput = false; // treat all FACEs at once _compatibleHypothesis.push_back("MaxElementArea"); _compatibleHypothesis.push_back("LengthFromEdges"); _compatibleHypothesis.push_back("QuadranglePreference"); + _compatibleHypothesis.push_back("NETGEN_Parameters_2D"); + _compatibleHypothesis.push_back("ViscousLayers2D"); - _hypMaxElementArea = 0; - _hypLengthFromEdges = 0; + _hypMaxElementArea = 0; + _hypLengthFromEdges = 0; _hypQuadranglePreference = 0; + _hypParameters = 0; } //============================================================================= @@ -125,6 +129,8 @@ bool NETGENPlugin_NETGEN_2D_ONLY::CheckHypothesis (SMESH_Mesh& aMesh, _hypMaxElementArea = 0; _hypLengthFromEdges = 0; _hypQuadranglePreference = 0; + _hypParameters = 0; + _progressByTic = -1; const list& hyps = GetUsedHypothesis(aMesh, aShape, false); @@ -136,6 +142,7 @@ bool NETGENPlugin_NETGEN_2D_ONLY::CheckHypothesis (SMESH_Mesh& aMesh, aStatus = HYP_MISSING; + bool hasVL = false; list::const_iterator ith; for (ith = hyps.begin(); ith != hyps.end(); ++ith ) { @@ -149,143 +156,69 @@ bool NETGENPlugin_NETGEN_2D_ONLY::CheckHypothesis (SMESH_Mesh& aMesh, _hypLengthFromEdges = static_cast (hyp); else if ( hypName == "QuadranglePreference" ) _hypQuadranglePreference = static_cast(hyp); + else if ( hypName == "NETGEN_Parameters_2D" ) + _hypParameters = static_cast(hyp); + else if ( hypName == StdMeshers_ViscousLayers2D::GetHypType() ) + hasVL = true; else { aStatus = HYP_INCOMPATIBLE; return false; } } - if ( _hypMaxElementArea && _hypLengthFromEdges ) { + int nbHyps = bool(_hypMaxElementArea) + bool(_hypLengthFromEdges) + bool(_hypParameters ); + if ( nbHyps > 1 ) aStatus = HYP_CONCURENT; - return false; - } - - if ( _hypMaxElementArea || _hypLengthFromEdges ) + else if ( hasVL ) + error( StdMeshers_ViscousLayers2D::CheckHypothesis( aMesh, aShape, aStatus )); + else aStatus = HYP_OK; - return aStatus == HYP_OK; -} - -//================================================================================ -/*! - * \brief Fill netgen mesh with segments - * \retval SMESH_ComputeErrorPtr - error description - */ -//================================================================================ - -static TError AddSegmentsToMesh(netgen::Mesh& ngMesh, - OCCGeometry& geom, - const TSideVector& wires, - SMESH_MesherHelper& helper, - vector< const SMDS_MeshNode* > & nodeVec) -{ - // ---------------------------- - // Check wires and count nodes - // ---------------------------- - int nbNodes = 0; - for ( int iW = 0; iW < wires.size(); ++iW ) + if ( aStatus == HYP_OK && _hypParameters && _hypQuadranglePreference ) { - StdMeshers_FaceSidePtr wire = wires[ iW ]; - if ( wire->MissVertexNode() ) - return TError - (new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH, "Missing nodes on vertices")); - - const vector& uvPtVec = wire->GetUVPtStruct(); - if ( uvPtVec.size() != wire->NbPoints() ) - return TError - (new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH, - SMESH_Comment("Unexpected nb of points on wire ") << iW - << ": " << uvPtVec.size()<<" != "<NbPoints())); - nbNodes += wire->NbSegments(); + aStatus = HYP_INCOMPAT_HYPS; + return error(SMESH_Comment("\"") << _hypQuadranglePreference->GetName() + << "\" and \"" << _hypParameters->GetName() + << "\" are incompatible hypotheses"); } - nodeVec.reserve( nbNodes ); - - // ----------------- - // Fill netgen mesh - // ----------------- - -// netgen::Box<3> bb = geom.GetBoundingBox(); -// bb.Increase (bb.Diam()/10); -// ngMesh.SetLocalH (bb.PMin(), bb.PMax(), 0.5); // set grading - const int faceID = 1, solidID = 0; - ngMesh.AddFaceDescriptor (FaceDescriptor(faceID, solidID, solidID, 0)); + return ( aStatus == HYP_OK ); +} - for ( int iW = 0; iW < wires.size(); ++iW ) +namespace +{ + void limitSize( netgen::Mesh* ngMesh, + const double maxh ) { - StdMeshers_FaceSidePtr wire = wires[ iW ]; - const vector& uvPtVec = wire->GetUVPtStruct(); - - int firstPointID = ngMesh.GetNP() + 1; - int edgeID = 1, posID = -2; - for ( int i = 0; i < wire->NbSegments(); ++i ) // loop on segments + // get bnd box + netgen::Point3d pmin, pmax; + ngMesh->GetBox( pmin, pmax, 0 ); + const double dx = pmax.X() - pmin.X(); + const double dy = pmax.Y() - pmin.Y(); + const double dz = pmax.Z() - pmin.Z(); + + const int nbX = Max( 2, int( dx / maxh * 3 )); + const int nbY = Max( 2, int( dy / maxh * 3 )); + const int nbZ = Max( 2, int( dz / maxh * 3 )); + + if ( ! & ngMesh->LocalHFunction() ) + ngMesh->SetLocalH( pmin, pmax, 0.1 ); + + netgen::Point3d p; + for ( int i = 0; i <= nbX; ++i ) { - // Add the first point of a segment - const SMDS_MeshNode * n = uvPtVec[ i ].node; - const int posShapeID = n->GetPosition()->GetShapeId(); - - // skip nodes on degenerated edges - if ( helper.IsDegenShape( posShapeID ) && - helper.IsDegenShape( uvPtVec[ i+1 ].node->GetPosition()->GetShapeId() )) - continue; - - nodeVec.push_back( n ); - - MeshPoint mp( Point<3> (n->X(), n->Y(), n->Z()) ); - ngMesh.AddPoint ( mp, 1, EDGEPOINT ); - - // Add the segment - Segment seg; - - seg.pnums[0] = ngMesh.GetNP(); // ng node id - seg.pnums[1] = seg.pnums[0] + 1; // ng node id - seg.edgenr = ngMesh.GetNSeg() + 1;// segment id - seg.si = faceID; // = geom.fmap.FindIndex (face); - - for ( int iEnd = 0; iEnd < 2; ++iEnd) + p.X() = pmin.X() + i * dx / nbX; + for ( int j = 0; j <= nbY; ++j ) { - const UVPtStruct& pnt = uvPtVec[ i + iEnd ]; - - seg.epgeominfo[ iEnd ].dist = pnt.param; // param on curve - seg.epgeominfo[ iEnd ].u = pnt.u; - seg.epgeominfo[ iEnd ].v = pnt.v; - - // find out edge id and node parameter on edge - bool onVertex = ( pnt.node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX ); - if ( onVertex || posShapeID != posID ) + p.Y() = pmin.Y() + j * dy / nbY; + for ( int k = 0; k <= nbZ; ++k ) { - // get edge id - double normParam = pnt.normParam; - if ( onVertex ) - normParam = 0.5 * ( uvPtVec[ i ].normParam + uvPtVec[ i+1 ].normParam ); - const TopoDS_Edge& edge = wire->Edge( wire->EdgeIndex( normParam )); - edgeID = geom.emap.FindIndex( edge ); - posID = posShapeID; - if ( onVertex ) // param on curve is different on each of two edges - seg.epgeominfo[ iEnd ].dist = helper.GetNodeU( edge, pnt.node ); + p.Z() = pmin.Z() + k * dz / nbZ; + ngMesh->RestrictLocalH( p, maxh ); } - seg.epgeominfo[ iEnd ].edgenr = edgeID; // = geom.emap.FindIndex(edge); } - - ngMesh.AddSegment (seg); - -// cout << "Segment: " << seg.edgenr << endl -// << "\tp1: " << seg.p1 << endl -// << "\tp2: " << seg.p2 << endl -// << "\tp0 param: " << seg.epgeominfo[ 0 ].dist << endl -// << "\tp0 uv: " << seg.epgeominfo[ 0 ].u <<", "<< seg.epgeominfo[ 0 ].v << endl -// << "\tp0 edge: " << seg.epgeominfo[ 0 ].edgenr << endl -// << "\tp1 param: " << seg.epgeominfo[ 1 ].dist << endl -// << "\tp1 uv: " << seg.epgeominfo[ 1 ].u <<", "<< seg.epgeominfo[ 1 ].v << endl -// << "\tp1 edge: " << seg.epgeominfo[ 1 ].edgenr << endl; } - Segment& seg = ngMesh.LineSegment( ngMesh.GetNSeg() ); - seg.pnums[1] = firstPointID; } - - ngMesh.CalcSurfacesOfNode(); - - return TError(); } //============================================================================= @@ -297,163 +230,479 @@ static TError AddSegmentsToMesh(netgen::Mesh& ngMesh, bool NETGENPlugin_NETGEN_2D_ONLY::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { - MESSAGE("NETGENPlugin_NETGEN_2D_ONLY::Compute()"); + netgen::multithread.terminate = 0; + //netgen::multithread.task = "Surface meshing"; SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); - int faceID = meshDS->ShapeToIndex( aShape ); - SMESH_MesherHelper helper(aMesh); - _quadraticMesh = helper.IsQuadraticSubMesh(aShape); helper.SetElementsOnShape( true ); - const bool ignoreMediumNodes = _quadraticMesh; - - // ------------------------ - // get all edges of a face - // ------------------------ - const TopoDS_Face F = TopoDS::Face( aShape.Oriented( TopAbs_FORWARD )); - TError problem; - TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, aMesh, ignoreMediumNodes, problem ); - if ( problem && !problem->IsOK() ) - return error( problem ); - int nbWires = wires.size(); - if ( nbWires == 0 ) - return error( "Problem in StdMeshers_FaceSide::GetFaceWires()"); - if ( wires[0]->NbSegments() < 3 ) // ex: a circle with 2 segments - return error(COMPERR_BAD_INPUT_MESH, - SMESH_Comment("Too few segments: ")<NbSegments()); - - // ------------------------- - // Make input netgen mesh - // ------------------------- - - Ng_Init(); - netgen::Mesh * ngMesh = new netgen::Mesh (); - - netgen::OCCGeometry occgeo; - NETGENPlugin_Mesher::PrepareOCCgeometry( occgeo, F, aMesh ); - occgeo.fmap.Clear(); // face can be reversed, which is wrong in this case (issue 19978) - occgeo.fmap.Add( F ); - vector< const SMDS_MeshNode* > nodeVec; - problem = AddSegmentsToMesh( *ngMesh, occgeo, wires, helper, nodeVec ); - if ( problem && !problem->IsOK() ) { - delete ngMesh; Ng_Exit(); - return error( problem ); + NETGENPlugin_NetgenLibWrapper ngLib; + ngLib._isComputeOk = false; + + netgen::Mesh ngMeshNoLocSize; + netgen::Mesh * ngMeshes[2] = { (netgen::Mesh*) ngLib._ngMesh, & ngMeshNoLocSize }; + netgen::OCCGeometry occgeoComm; + + // min / max sizes are set as follows: + // if ( _hypParameters ) + // min and max are defined by the user + // else if ( _hypLengthFromEdges ) + // min = aMesher.GetDefaultMinSize() + // max = average segment len of a FACE + // else if ( _hypMaxElementArea ) + // min = aMesher.GetDefaultMinSize() + // max = f( _hypMaxElementArea ) + // else + // min = aMesher.GetDefaultMinSize() + // max = max segment len of a FACE + + NETGENPlugin_Mesher aMesher( &aMesh, aShape, /*isVolume=*/false); + aMesher.SetParameters( _hypParameters ); // _hypParameters -> netgen::mparam + const bool toOptimize = _hypParameters ? _hypParameters->GetOptimize() : true; + if ( _hypMaxElementArea ) + { + netgen::mparam.maxh = sqrt( 2. * _hypMaxElementArea->GetMaxArea() / sqrt(3.0) ); } + if ( _hypQuadranglePreference ) + netgen::mparam.quad = true; - // -------------------- - // compute edge length - // -------------------- + // local size is common for all FACEs in aShape? + const bool isCommonLocalSize = ( !_hypLengthFromEdges && !_hypMaxElementArea && netgen::mparam.uselocalh ); + const bool isDefaultHyp = ( !_hypLengthFromEdges && !_hypMaxElementArea && !_hypParameters ); - double edgeLength = 0; - if (_hypLengthFromEdges || (!_hypLengthFromEdges && !_hypMaxElementArea)) + if ( isCommonLocalSize ) // compute common local size in ngMeshes[0] { - int nbSegments = 0; - for ( int iW = 0; iW < nbWires; ++iW ) + //list< SMESH_subMesh* > meshedSM[4]; --> all sub-shapes are added to occgeoComm + aMesher.PrepareOCCgeometry( occgeoComm, aShape, aMesh );//, meshedSM ); + + // local size set at MESHCONST_ANALYSE step depends on + // minh, face_maxh, grading and curvaturesafety; find minh if not set by the user + if ( !_hypParameters || netgen::mparam.minh < DBL_MIN ) { - edgeLength += wires[ iW ]->Length(); - nbSegments += wires[ iW ]->NbSegments(); + if ( !_hypParameters ) + netgen::mparam.maxh = occgeoComm.GetBoundingBox().Diam() / 3.; + netgen::mparam.minh = aMesher.GetDefaultMinSize( aShape, netgen::mparam.maxh ); + } + // set local size depending on curvature and NOT closeness of EDGEs + netgen::occparam.resthcloseedgeenable = false; + //netgen::occparam.resthcloseedgefac = 1.0 + netgen::mparam.grading; + occgeoComm.face_maxh = netgen::mparam.maxh; + netgen::OCCSetLocalMeshSize( occgeoComm, *ngMeshes[0] ); + occgeoComm.emap.Clear(); + occgeoComm.vmap.Clear(); + + // set local size according to size of existing segments + const double factor = netgen::occparam.resthcloseedgefac; + TopTools_IndexedMapOfShape edgeMap; + TopExp::MapShapes( aMesh.GetShapeToMesh(), TopAbs_EDGE, edgeMap ); + for ( int iE = 1; iE <= edgeMap.Extent(); ++iE ) + { + const TopoDS_Shape& edge = edgeMap( iE ); + if ( SMESH_Algo::isDegenerated( TopoDS::Edge( edge ))/* || + helper.IsSubShape( edge, aShape )*/) + continue; + SMESHDS_SubMesh* smDS = meshDS->MeshElements( edge ); + if ( !smDS ) continue; + SMDS_ElemIteratorPtr segIt = smDS->GetElements(); + while ( segIt->more() ) + { + const SMDS_MeshElement* seg = segIt->next(); + SMESH_TNodeXYZ n1 = seg->GetNode(0); + SMESH_TNodeXYZ n2 = seg->GetNode(1); + gp_XYZ p = 0.5 * ( n1 + n2 ); + netgen::Point3d pi(p.X(), p.Y(), p.Z()); + ngMeshes[0]->RestrictLocalH( pi, factor * ( n1 - n2 ).Modulus() ); + } } - if ( nbSegments ) - edgeLength /= nbSegments; } - if ( _hypMaxElementArea ) + netgen::mparam.uselocalh = toOptimize; // restore as it is used at surface optimization + + // ================== + // Loop on all FACEs + // ================== + + vector< const SMDS_MeshNode* > nodeVec; + + TopExp_Explorer fExp( aShape, TopAbs_FACE ); + for ( int iF = 0; fExp.More(); fExp.Next(), ++iF ) { - double maxArea = _hypMaxElementArea->GetMaxArea(); - edgeLength = sqrt(2. * maxArea/sqrt(3.0)); - } - if ( edgeLength < DBL_MIN ) - edgeLength = occgeo.GetBoundingBox().Diam(); + TopoDS_Face F = TopoDS::Face( fExp.Current() /*.Oriented( TopAbs_FORWARD )*/); + int faceID = meshDS->ShapeToIndex( F ); + SMESH_ComputeErrorPtr& faceErr = aMesh.GetSubMesh( F )->GetComputeError(); + + _quadraticMesh = helper.IsQuadraticSubMesh( F ); + const bool ignoreMediumNodes = _quadraticMesh; + + // build viscous layers if required + if ( F.Orientation() != TopAbs_FORWARD && + F.Orientation() != TopAbs_REVERSED ) + F.Orientation( TopAbs_FORWARD ); // avoid pb with TopAbs_INTERNAL + SMESH_ProxyMesh::Ptr proxyMesh = StdMeshers_ViscousLayers2D::Compute( aMesh, F ); + if ( !proxyMesh ) + continue; + + // ------------------------ + // get all EDGEs of a FACE + // ------------------------ + TSideVector wires = + StdMeshers_FaceSide::GetFaceWires( F, aMesh, ignoreMediumNodes, faceErr, proxyMesh ); + if ( faceErr && !faceErr->IsOK() ) + continue; + int nbWires = wires.size(); + if ( nbWires == 0 ) + { + faceErr.reset + ( new SMESH_ComputeError + ( COMPERR_ALGO_FAILED, "Problem in StdMeshers_FaceSide::GetFaceWires()" )); + continue; + } + if ( wires[0]->NbSegments() < 3 ) // ex: a circle with 2 segments + { + faceErr.reset + ( new SMESH_ComputeError + ( COMPERR_BAD_INPUT_MESH, SMESH_Comment("Too few segments: ")<NbSegments()) ); + continue; + } + + // ---------------------- + // compute maxh of a FACE + // ---------------------- + + if ( !_hypParameters ) + { + double edgeLength = 0; + if (_hypLengthFromEdges ) + { + // compute edgeLength as an average segment length + int nbSegments = 0; + for ( int iW = 0; iW < nbWires; ++iW ) + { + edgeLength += wires[ iW ]->Length(); + nbSegments += wires[ iW ]->NbSegments(); + } + if ( nbSegments ) + edgeLength /= nbSegments; + netgen::mparam.maxh = edgeLength; + } + else if ( isDefaultHyp ) + { + // set edgeLength by a longest segment + double maxSeg2 = 0; + for ( int iW = 0; iW < nbWires; ++iW ) + { + const UVPtStructVec& points = wires[ iW ]->GetUVPtStruct(); + if ( points.empty() ) + return error( COMPERR_BAD_INPUT_MESH ); + gp_Pnt pPrev = SMESH_TNodeXYZ( points[0].node ); + for ( size_t i = 1; i < points.size(); ++i ) + { + gp_Pnt p = SMESH_TNodeXYZ( points[i].node ); + maxSeg2 = Max( maxSeg2, p.SquareDistance( pPrev )); + pPrev = p; + } + } + edgeLength = sqrt( maxSeg2 ) * 1.05; + netgen::mparam.maxh = edgeLength; + } + if ( netgen::mparam.maxh < DBL_MIN ) + netgen::mparam.maxh = occgeoComm.GetBoundingBox().Diam(); - //cout << " edgeLength = " << edgeLength << endl; + if ( !isCommonLocalSize ) + { + netgen::mparam.minh = aMesher.GetDefaultMinSize( F, netgen::mparam.maxh ); + } + } - netgen::mparam.maxh = edgeLength; - netgen::mparam.quad = _hypQuadranglePreference ? 1 : 0; - //ngMesh->SetGlobalH ( edgeLength ); + // prepare occgeom + netgen::OCCGeometry occgeom; + occgeom.shape = F; + occgeom.fmap.Add( F ); + occgeom.CalcBoundingBox(); + occgeom.facemeshstatus.SetSize(1); + occgeom.facemeshstatus = 0; + occgeom.face_maxh_modified.SetSize(1); + occgeom.face_maxh_modified = 0; + occgeom.face_maxh.SetSize(1); + occgeom.face_maxh = netgen::mparam.maxh; + + // ------------------------- + // Fill netgen mesh + // ------------------------- + + // MESHCONST_ANALYSE step may lead to a failure, so we make an attempt + // w/o MESHCONST_ANALYSE at the second loop + int err = 0; + enum { LOC_SIZE, NO_LOC_SIZE }; + int iLoop = isCommonLocalSize ? 0 : 1; + for ( ; iLoop < 2; iLoop++ ) + { + //bool isMESHCONST_ANALYSE = false; + InitComputeError(); - // ------------------------- - // Generate surface mesh - // ------------------------- + netgen::Mesh * ngMesh = ngMeshes[ iLoop ]; + ngMesh->DeleteMesh(); - char *optstr = 0; - int startWith = MESHCONST_MESHSURFACE; - int endWith = MESHCONST_OPTSURFACE; - int err = 1; + if ( iLoop == NO_LOC_SIZE ) + { + ngMesh->SetGlobalH ( mparam.maxh ); + ngMesh->SetMinimalH( mparam.minh ); + Box<3> bb = occgeom.GetBoundingBox(); + bb.Increase (bb.Diam()/10); + ngMesh->SetLocalH (bb.PMin(), bb.PMax(), mparam.grading); + } + + nodeVec.clear(); + faceErr = aMesher.AddSegmentsToMesh( *ngMesh, occgeom, wires, helper, nodeVec, + /*overrideMinH=*/!_hypParameters); + if ( faceErr && !faceErr->IsOK() ) + break; + + //if ( !isCommonLocalSize ) + //limitSize( ngMesh, mparam.maxh * 0.8); + + // ------------------------- + // Generate surface mesh + // ------------------------- + + const int startWith = MESHCONST_MESHSURFACE; + const int endWith = toOptimize ? MESHCONST_OPTSURFACE : MESHCONST_MESHSURFACE; + + SMESH_Comment str; + try { + OCC_CATCH_SIGNALS; - try { -#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 - OCC_CATCH_SIGNALS; -#endif #ifdef NETGEN_V5 - err = netgen::OCCGenerateMesh(occgeo, ngMesh,netgen::mparam, startWith, endWith); + err = netgen::OCCGenerateMesh(occgeom, ngMesh, netgen::mparam, startWith, endWith); #else - err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); + char *optstr = 0; + err = netgen::OCCGenerateMesh(occgeom, ngMesh, startWith, endWith, optstr); #endif - } - catch (Standard_Failure& ex) { - string comment = ex.DynamicType()->Name(); - if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) { - comment += ": "; - comment += ex.GetMessageString(); - } - error(COMPERR_OCC_EXCEPTION, comment); - } - catch (NgException exc) { - error( SMESH_Comment("NgException: ") << exc.What() ); - } - catch (...) { - error(COMPERR_EXCEPTION,"Exception in netgen::OCCGenerateMesh()"); - } + if ( netgen::multithread.terminate ) + return false; + if ( err ) + str << "Error in netgen::OCCGenerateMesh() at " << netgen::multithread.task; + } + catch (Standard_Failure& ex) + { + err = 1; + str << "Exception in netgen::OCCGenerateMesh()" + << " at " << netgen::multithread.task + << ": " << ex.DynamicType()->Name(); + if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) + str << ": " << ex.GetMessageString(); + } + catch (...) { + err = 1; + str << "Exception in netgen::OCCGenerateMesh()" + << " at " << netgen::multithread.task; + } + if ( err ) + { + if ( aMesher.FixFaceMesh( occgeom, *ngMesh, 1 )) + break; + if ( iLoop == LOC_SIZE ) + { + netgen::mparam.minh = netgen::mparam.maxh; + netgen::mparam.maxh = 0; + for ( int iW = 0; iW < wires.size(); ++iW ) + { + StdMeshers_FaceSidePtr wire = wires[ iW ]; + const vector& uvPtVec = wire->GetUVPtStruct(); + for ( size_t iP = 1; iP < uvPtVec.size(); ++iP ) + { + SMESH_TNodeXYZ p( uvPtVec[ iP ].node ); + netgen::Point3d np( p.X(),p.Y(),p.Z()); + double segLen = p.Distance( uvPtVec[ iP-1 ].node ); + double size = ngMesh->GetH( np ); + netgen::mparam.minh = Min( netgen::mparam.minh, size ); + netgen::mparam.maxh = Max( netgen::mparam.maxh, segLen ); + } + } + //cerr << "min " << netgen::mparam.minh << " max " << netgen::mparam.maxh << endl; + netgen::mparam.minh *= 0.9; + netgen::mparam.maxh *= 1.1; + continue; + } + else + { + faceErr.reset( new SMESH_ComputeError( COMPERR_ALGO_FAILED, str )); + } + } - // ---------------------------------------------------- - // Fill the SMESHDS with the generated nodes and faces - // ---------------------------------------------------- - int nbNodes = ngMesh->GetNP(); - int nbFaces = ngMesh->GetNSE(); + // ---------------------------------------------------- + // Fill the SMESHDS with the generated nodes and faces + // ---------------------------------------------------- - int nbInputNodes = nodeVec.size(); - nodeVec.resize( nbNodes, 0 ); + int nbNodes = ngMesh->GetNP(); + int nbFaces = ngMesh->GetNSE(); - // add nodes - for ( int i = nbInputNodes + 1; i <= nbNodes; ++i ) - { - const MeshPoint& ngPoint = ngMesh->Point(i); - SMDS_MeshNode * node = meshDS->AddNode(ngPoint(0), ngPoint(1), ngPoint(2)); - nodeVec[ i-1 ] = node; - } + int nbInputNodes = nodeVec.size()-1; + nodeVec.resize( nbNodes+1, 0 ); - // create faces - bool reverse = ( aShape.Orientation() == TopAbs_REVERSED ); - for ( int i = 1; i <= nbFaces ; ++i ) - { - const Element2d& elem = ngMesh->SurfaceElement(i); - vector nodes( elem.GetNP() ); - for (int j=1; j <= elem.GetNP(); ++j) - { - int pind = elem.PNum(j); - const SMDS_MeshNode* node = nodeVec.at(pind-1); - if ( reverse ) - nodes[ nodes.size()-j ] = node; - else - nodes[ j-1 ] = node; - if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE ) + // add nodes + for ( int ngID = nbInputNodes + 1; ngID <= nbNodes; ++ngID ) { - const PointGeomInfo& pgi = elem.GeomInfoPi(j); - meshDS->SetNodeOnFace((SMDS_MeshNode*)node, faceID, pgi.u, pgi.v); + const MeshPoint& ngPoint = ngMesh->Point( ngID ); + SMDS_MeshNode * node = meshDS->AddNode(ngPoint(0), ngPoint(1), ngPoint(2)); + nodeVec[ ngID ] = node; + } + + // create faces + int i,j; + vector nodes; + for ( i = 1; i <= nbFaces ; ++i ) + { + const Element2d& elem = ngMesh->SurfaceElement(i); + nodes.resize( elem.GetNP() ); + for (j=1; j <= elem.GetNP(); ++j) + { + int pind = elem.PNum(j); + if ( pind < 1 ) + break; + nodes[ j-1 ] = nodeVec[ pind ]; + if ( nodes[ j-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE ) + { + const PointGeomInfo& pgi = elem.GeomInfoPi(j); + meshDS->SetNodeOnFace( nodes[ j-1 ], faceID, pgi.u, pgi.v); + } + } + if ( j > elem.GetNP() ) + { + SMDS_MeshFace* face = 0; + if ( elem.GetType() == TRIG ) + face = helper.AddFace(nodes[0],nodes[1],nodes[2]); + else + face = helper.AddFace(nodes[0],nodes[1],nodes[2],nodes[3]); + } } + + break; + } // two attempts + } // loop on FACEs + + return true; +} + +void NETGENPlugin_NETGEN_2D_ONLY::CancelCompute() +{ + SMESH_Algo::CancelCompute(); + netgen::multithread.terminate = 1; +} + +//================================================================================ +/*! + * \brief Return progress of Compute() [0.,1] + */ +//================================================================================ + +double NETGENPlugin_NETGEN_2D_ONLY::GetProgress() const +{ + return -1; + // const char* task1 = "Surface meshing"; + // //const char* task2 = "Optimizing surface"; + // double& progress = const_cast( this )->_progress; + // if ( _progressByTic < 0. && + // strncmp( netgen::multithread.task, task1, 3 ) == 0 ) + // { + // progress = Min( 0.25, SMESH_Algo::GetProgressByTic() ); // [0, 0.25] + // } + // else //if ( strncmp( netgen::multithread.task, task2, 3 ) == 0) + // { + // if ( _progressByTic < 0 ) + // { + // NETGENPlugin_NETGEN_2D_ONLY* me = (NETGENPlugin_NETGEN_2D_ONLY*) this; + // me->_progressByTic = 0.25 / (_progressTic+1); + // } + // const_cast( this )->_progressTic++; + // progress = Max( progress, _progressByTic * _progressTic ); + // } + // //cout << netgen::multithread.task << " " << _progressTic << endl; + // return Min( progress, 0.99 ); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +bool NETGENPlugin_NETGEN_2D_ONLY::Evaluate(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + MapShapeNbElems& aResMap) +{ + TopoDS_Face F = TopoDS::Face(aShape); + if(F.IsNull()) + return false; + + // collect info from edges + int nb0d = 0, nb1d = 0; + bool IsQuadratic = false; + bool IsFirst = true; + double fullLen = 0.0; + TopTools_MapOfShape tmpMap; + for (TopExp_Explorer exp(F, TopAbs_EDGE); exp.More(); exp.Next()) { + TopoDS_Edge E = TopoDS::Edge(exp.Current()); + if( tmpMap.Contains(E) ) + continue; + tmpMap.Add(E); + SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current()); + MapShapeNbElemsItr anIt = aResMap.find(aSubMesh); + if( anIt==aResMap.end() ) { + SMESH_subMesh *sm = aMesh.GetSubMesh(F); + SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); + smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); + return false; + } + std::vector aVec = (*anIt).second; + nb0d += aVec[SMDSEntity_Node]; + nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]); + double aLen = SMESH_Algo::EdgeLength(E); + fullLen += aLen; + if(IsFirst) { + IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]); + IsFirst = false; } - SMDS_MeshFace* face = 0; - if ( elem.GetType() == TRIG ) - face = helper.AddFace(nodes[0],nodes[1],nodes[2]); - else - face = helper.AddFace(nodes[0],nodes[1],nodes[2],nodes[3]); } + tmpMap.Clear(); - Ng_DeleteMesh((nglib::Ng_Mesh*)ngMesh); - Ng_Exit(); + // compute edge length + double ELen = 0; + if (_hypLengthFromEdges || !_hypLengthFromEdges && !_hypMaxElementArea) { + if ( nb1d > 0 ) + ELen = fullLen / nb1d; + } + if ( _hypMaxElementArea ) { + double maxArea = _hypMaxElementArea->GetMaxArea(); + ELen = sqrt(2. * maxArea/sqrt(3.0)); + } + GProp_GProps G; + BRepGProp::SurfaceProperties(F,G); + double anArea = G.Mass(); - NETGENPlugin_Mesher::RemoveTmpFiles(); + const int hugeNb = numeric_limits::max()/10; + if ( anArea / hugeNb > ELen*ELen ) + { + SMESH_subMesh *sm = aMesh.GetSubMesh(F); + SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); + smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated.\nToo small element length",this)); + return false; + } + int nbFaces = (int) ( anArea / ( ELen*ELen*sqrt(3.) / 4 ) ); + int nbNodes = (int) ( ( nbFaces*3 - (nb1d-1)*2 ) / 6 + 1 ); + std::vector aVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include +#include #include #include +#include #include #include #include -#include "utilities.h" +#include #include #include @@ -59,13 +66,23 @@ /* Netgen include files */ -#ifdef _MSC_VER -#pragma warning(disable : 4067) -#endif +#ifndef OCCGEOMETRY +#define OCCGEOMETRY +#endif +#include namespace nglib { #include } +namespace netgen { +#ifdef NETGEN_V5 + extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, MeshingParameters&, int, int); +#else + extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, int, int, char*); +#endif + extern MeshingParameters mparam; + extern volatile multithreadt multithread; +} using namespace nglib; using namespace std; @@ -76,17 +93,21 @@ using namespace std; //============================================================================= NETGENPlugin_NETGEN_3D::NETGENPlugin_NETGEN_3D(int hypId, int studyId, - SMESH_Gen* gen) + SMESH_Gen* gen) : SMESH_3D_Algo(hypId, studyId, gen) { MESSAGE("NETGENPlugin_NETGEN_3D::NETGENPlugin_NETGEN_3D"); _name = "NETGEN_3D"; _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);// 1 bit /shape type _compatibleHypothesis.push_back("MaxElementVolume"); + _compatibleHypothesis.push_back("NETGEN_Parameters"); + _compatibleHypothesis.push_back("ViscousLayers"); _maxElementVolume = 0.; _hypMaxElementVolume = NULL; + _hypParameters = NULL; + _viscousLayersHyp = NULL; _requireShape = false; // can work without shape } @@ -108,47 +129,59 @@ NETGENPlugin_NETGEN_3D::~NETGENPlugin_NETGEN_3D() */ //============================================================================= -bool NETGENPlugin_NETGEN_3D::CheckHypothesis - (SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape, - SMESH_Hypothesis::Hypothesis_Status& aStatus) +bool NETGENPlugin_NETGEN_3D::CheckHypothesis (SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + Hypothesis_Status& aStatus) { MESSAGE("NETGENPlugin_NETGEN_3D::CheckHypothesis"); _hypMaxElementVolume = NULL; + _hypParameters = NULL; + _viscousLayersHyp = NULL; _maxElementVolume = DBL_MAX; + // for correct work of GetProgress(): + netgen::multithread.percent = 0.; + netgen::multithread.task = "Volume meshing"; + _progressByTic = -1.; + list::const_iterator itl; const SMESHDS_Hypothesis* theHyp; - const list& hyps = GetUsedHypothesis(aMesh, aShape); - int nbHyp = hyps.size(); - if (!nbHyp) + const list& hyps = + GetUsedHypothesis(aMesh, aShape, /*ignoreAuxiliary=*/false); + list ::const_iterator h = hyps.begin(); + if ( h == hyps.end()) { aStatus = SMESH_Hypothesis::HYP_OK; - //aStatus = SMESH_Hypothesis::HYP_MISSING; return true; // can work with no hypothesis } - itl = hyps.begin(); - theHyp = (*itl); // use only the first hypothesis - - string hypName = theHyp->GetName(); - - bool isOk = false; - - if (hypName == "MaxElementVolume") + aStatus = HYP_OK; + for ( ; h != hyps.end(); ++h ) { - _hypMaxElementVolume = static_cast (theHyp); - ASSERT(_hypMaxElementVolume); - _maxElementVolume = _hypMaxElementVolume->GetMaxVolume(); - isOk =true; - aStatus = SMESH_Hypothesis::HYP_OK; + if ( !_hypMaxElementVolume ) + _hypMaxElementVolume = dynamic_cast< const StdMeshers_MaxElementVolume*> ( *h ); + if ( !_viscousLayersHyp ) // several _viscousLayersHyp's allowed + _viscousLayersHyp = dynamic_cast< const StdMeshers_ViscousLayers*> ( *h ); + if ( ! _hypParameters ) + _hypParameters = dynamic_cast< const NETGENPlugin_Hypothesis*> ( *h ); + + if ( *h != _hypMaxElementVolume && + *h != _viscousLayersHyp && + *h != _hypParameters && + !dynamic_cast< const StdMeshers_ViscousLayers*>(*h)) // several VL hyps allowed + aStatus = HYP_INCOMPATIBLE; } - else - aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + if ( _hypMaxElementVolume && _hypParameters ) + aStatus = HYP_INCOMPATIBLE; + else if ( aStatus == HYP_OK && _viscousLayersHyp ) + error( _viscousLayersHyp->CheckHypothesis( aMesh, aShape, aStatus )); + + if ( _hypMaxElementVolume ) + _maxElementVolume = _hypMaxElementVolume->GetMaxVolume(); - return isOk; + return aStatus == HYP_OK; } //============================================================================= @@ -160,237 +193,324 @@ bool NETGENPlugin_NETGEN_3D::CheckHypothesis bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { - MESSAGE("NETGENPlugin_NETGEN_3D::Compute with maxElmentsize = " << _maxElementVolume); + netgen::multithread.terminate = 0; + netgen::multithread.task = "Volume meshing"; + _progressByTic = -1.; SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); - const int invalid_ID = -1; + SMESH_MesherHelper helper(aMesh); + bool _quadraticMesh = helper.IsQuadraticSubMesh(aShape); + helper.SetElementsOnShape( true ); - SMESH::Controls::Area areaControl; - SMESH::Controls::TSequenceOfXYZ nodesCoords; + int Netgen_NbOfNodes = 0; + double Netgen_point[3]; + int Netgen_triangle[3]; - // ------------------------------------------------------------------- - // get triangles on aShell and make a map of nodes to Netgen node IDs - // ------------------------------------------------------------------- + NETGENPlugin_NetgenLibWrapper ngLib; + Ng_Mesh * Netgen_mesh = ngLib._ngMesh; - SMESH_MesherHelper helper(aMesh); - SMESH_MesherHelper* myTool = &helper; - bool _quadraticMesh = myTool->IsQuadraticSubMesh(aShape); + // vector of nodes in which node index == netgen ID + vector< const SMDS_MeshNode* > nodeVec; + { + const int invalid_ID = -1; - typedef map< const SMDS_MeshNode*, int, TIDCompare > TNodeToIDMap; - TNodeToIDMap nodeToNetgenID; - list< const SMDS_MeshElement* > triangles; - list< bool > isReversed; // orientation of triangles + SMESH::Controls::Area areaControl; + SMESH::Controls::TSequenceOfXYZ nodesCoords; - TopAbs_ShapeEnum mainType = aMesh.GetShapeToMesh().ShapeType(); - bool checkReverse = ( mainType == TopAbs_COMPOUND || mainType == TopAbs_COMPSOLID ); + // maps nodes to ng ID + typedef map< const SMDS_MeshNode*, int, TIDCompare > TNodeToIDMap; + typedef TNodeToIDMap::value_type TN2ID; + TNodeToIDMap nodeToNetgenID; - // for the degeneraged edge: ignore all but one node on it; - // map storing ids of degen edges and vertices and their netgen id: - map< int, int* > degenShapeIdToPtrNgId; - map< int, int* >::iterator shId_ngId; - list< int > degenNgIds; + // find internal shapes + NETGENPlugin_Internals internals( aMesh, aShape, /*is3D=*/true ); - StdMeshers_QuadToTriaAdaptor Adaptor; - Adaptor.Compute(aMesh,aShape); + // --------------------------------- + // Feed the Netgen with surface mesh + // --------------------------------- - for (TopExp_Explorer exp(aShape,TopAbs_FACE);exp.More();exp.Next()) - { - const TopoDS_Shape& aShapeFace = exp.Current(); - const SMESHDS_SubMesh * aSubMeshDSFace = meshDS->MeshElements( aShapeFace ); - if ( aSubMeshDSFace ) + TopAbs_ShapeEnum mainType = aMesh.GetShapeToMesh().ShapeType(); + bool checkReverse = ( mainType == TopAbs_COMPOUND || mainType == TopAbs_COMPSOLID ); + + SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( aMesh )); + if ( _viscousLayersHyp ) { + netgen::multithread.percent = 3; + proxyMesh = _viscousLayersHyp->Compute( aMesh, aShape ); + if ( !proxyMesh ) + return false; + } + if ( aMesh.NbQuadrangles() > 0 ) + { + netgen::multithread.percent = 6; + StdMeshers_QuadToTriaAdaptor* Adaptor = new StdMeshers_QuadToTriaAdaptor; + Adaptor->Compute(aMesh,aShape,proxyMesh.get()); + proxyMesh.reset( Adaptor ); + } + + for ( TopExp_Explorer exFa( aShape, TopAbs_FACE ); exFa.More(); exFa.Next()) + { + const TopoDS_Shape& aShapeFace = exFa.Current(); + int faceID = meshDS->ShapeToIndex( aShapeFace ); + bool isInternalFace = internals.isInternalShape( faceID ); bool isRev = false; - if ( checkReverse && helper.NbAncestors(aShapeFace, aMesh, aShape.ShapeType()) > 1 ) + if ( checkReverse && !isInternalFace && + helper.NbAncestors(aShapeFace, aMesh, aShape.ShapeType()) > 1 ) // IsReversedSubMesh() can work wrong on strongly curved faces, // so we use it as less as possible - isRev = SMESH_Algo::IsReversedSubMesh( TopoDS::Face(aShapeFace), meshDS ); + isRev = helper.IsReversedSubMesh( TopoDS::Face( aShapeFace )); + const SMESHDS_SubMesh * aSubMeshDSFace = proxyMesh->GetSubMesh( aShapeFace ); + if ( !aSubMeshDSFace ) continue; SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements(); - while ( iteratorElem->more() ) // loop on elements on a face + while ( iteratorElem->more() ) // loop on elements on a geom face { - // check element + // check mesh face const SMDS_MeshElement* elem = iteratorElem->next(); if ( !elem ) return error( COMPERR_BAD_INPUT_MESH, "Null element encounters"); - bool isTraingle = ( elem->NbNodes()==3 || (_quadraticMesh && elem->NbNodes()==6 )); - if ( !isTraingle ) { - //return error( COMPERR_BAD_INPUT_MESH, - // SMESH_Comment("Not triangle element ")<GetID()); - // using adaptor - const list* faces = Adaptor.GetTriangles(elem); - if(faces==0) { - return error( COMPERR_BAD_INPUT_MESH, - SMESH_Comment("Not triangles in adaptor for element ")<GetID()); + if ( elem->NbCornerNodes() != 3 ) + return error( COMPERR_BAD_INPUT_MESH, "Not triangle element encounters"); + + // Add nodes of triangles and triangles them-selves to netgen mesh + + // add three nodes of triangle + bool hasDegen = false; + for ( int iN = 0; iN < 3; ++iN ) + { + const SMDS_MeshNode* node = elem->GetNode( iN ); + const int shapeID = node->getshapeId(); + if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_EDGE && + helper.IsDegenShape( shapeID )) + { + // ignore all nodes on degeneraged edge and use node on its vertex instead + TopoDS_Shape vertex = TopoDS_Iterator( meshDS->IndexToShape( shapeID )).Value(); + node = SMESH_Algo::VertexNode( TopoDS::Vertex( vertex ), meshDS ); + hasDegen = true; } - list::const_iterator itf = faces->begin(); - for(; itf!=faces->end(); itf++ ) { - triangles.push_back( (*itf) ); - isReversed.push_back( isRev ); - // put triange's nodes to nodeToNetgenID map - SMDS_ElemIteratorPtr triangleNodesIt = (*itf)->nodesIterator(); - while ( triangleNodesIt->more() ) { - const SMDS_MeshNode * node = - static_cast(triangleNodesIt->next()); - if(myTool->IsMedium(node)) - continue; - nodeToNetgenID.insert( make_pair( node, invalid_ID )); - } + int& ngID = nodeToNetgenID.insert(TN2ID( node, invalid_ID )).first->second; + if ( ngID == invalid_ID ) + { + ngID = ++Netgen_NbOfNodes; + Netgen_point [ 0 ] = node->X(); + Netgen_point [ 1 ] = node->Y(); + Netgen_point [ 2 ] = node->Z(); + Ng_AddPoint(Netgen_mesh, Netgen_point); } + Netgen_triangle[ isRev ? 2-iN : iN ] = ngID; } - else { - // keep a triangle - triangles.push_back( elem ); - isReversed.push_back( isRev ); - // put elem nodes to nodeToNetgenID map - SMDS_ElemIteratorPtr triangleNodesIt = elem->nodesIterator(); - while ( triangleNodesIt->more() ) { - const SMDS_MeshNode * node = - static_cast(triangleNodesIt->next()); - if(myTool->IsMedium(node)) - continue; - nodeToNetgenID.insert( make_pair( node, invalid_ID )); - } + // add triangle + if ( hasDegen && (Netgen_triangle[0] == Netgen_triangle[1] || + Netgen_triangle[0] == Netgen_triangle[2] || + Netgen_triangle[2] == Netgen_triangle[1] )) + continue; + + Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle); + + if ( isInternalFace && !proxyMesh->IsTemporary( elem )) + { + swap( Netgen_triangle[1], Netgen_triangle[2] ); + Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle); } -#ifdef _DEBUG_ - // check if a trainge is degenerated - areaControl.GetPoints( elem, nodesCoords ); - double area = areaControl.GetValue( nodesCoords ); - if ( area <= DBL_MIN ) { - MESSAGE( "Warning: Degenerated " << elem ); + } // loop on elements on a face + } // loop on faces of a SOLID or SHELL + + // insert old nodes into nodeVec + nodeVec.resize( nodeToNetgenID.size() + 1, 0 ); + TNodeToIDMap::iterator n_id = nodeToNetgenID.begin(); + for ( ; n_id != nodeToNetgenID.end(); ++n_id ) + nodeVec[ n_id->second ] = n_id->first; + nodeToNetgenID.clear(); + + if ( internals.hasInternalVertexInSolid() ) + { + netgen::OCCGeometry occgeo; + NETGENPlugin_Mesher::AddIntVerticesInSolids( occgeo, + (netgen::Mesh&) *Netgen_mesh, + nodeVec, + internals); + } + } + + // ------------------------- + // Generate the volume mesh + // ------------------------- + + return ( ngLib._isComputeOk = compute( aMesh, helper, nodeVec, Netgen_mesh)); +} + +namespace +{ + void limitVolumeSize( netgen::Mesh* ngMesh, + double maxh ) + { + // get average h of faces + double faceh = 0; + int nbh = 0; + for (int i = 1; i <= ngMesh->GetNSE(); i++) + { + const netgen::Element2d& face = ngMesh->SurfaceElement(i); + for (int j=1; j <= face.GetNP(); ++j) + { + const netgen::PointIndex & i1 = face.PNumMod(j); + const netgen::PointIndex & i2 = face.PNumMod(j+1); + if ( i1 < i2 ) + { + const netgen::Point3d & p1 = ngMesh->Point( i1 ); + const netgen::Point3d & p2 = ngMesh->Point( i2 ); + faceh += netgen::Dist2( p1, p2 ); + nbh++; } -#endif } - // look for degeneraged edges and vetices - for (TopExp_Explorer expE(aShapeFace,TopAbs_EDGE);expE.More();expE.Next()) + } + faceh = Sqrt( faceh / nbh ); + + double compareh; + if ( faceh < 0.5 * maxh ) compareh = -1; + else if ( faceh > 1.5 * maxh ) compareh = 1; + else compareh = 0; + // cerr << "faceh " << faceh << endl; + // cerr << "init maxh " << maxh << endl; + // cerr << "compareh " << compareh << endl; + + if ( compareh > 0 ) + maxh *= 1.2; + else + maxh *= 0.8; + // cerr << "maxh " << maxh << endl; + + // get bnd box + netgen::Point3d pmin, pmax; + ngMesh->GetBox( pmin, pmax, 0 ); + const double dx = pmax.X() - pmin.X(); + const double dy = pmax.Y() - pmin.Y(); + const double dz = pmax.Z() - pmin.Z(); + + if ( ! & ngMesh->LocalHFunction() ) + ngMesh->SetLocalH( pmin, pmax, compareh <= 0 ? 0.1 : 0.5 ); + + // adjusted by SALOME_TESTS/Grids/smesh/bugs_08/I8 + const int nbX = Max( 2, int( dx / maxh * 2 )); + const int nbY = Max( 2, int( dy / maxh * 2 )); + const int nbZ = Max( 2, int( dz / maxh * 2 )); + + netgen::Point3d p; + for ( int i = 0; i <= nbX; ++i ) + { + p.X() = pmin.X() + i * dx / nbX; + for ( int j = 0; j <= nbY; ++j ) { - TopoDS_Edge aShapeEdge = TopoDS::Edge( expE.Current() ); - if ( BRep_Tool::Degenerated( aShapeEdge )) + p.Y() = pmin.Y() + j * dy / nbY; + for ( int k = 0; k <= nbZ; ++k ) { - degenNgIds.push_back( invalid_ID ); - int* ptrIdOnEdge = & degenNgIds.back(); - // remember edge id - int edgeID = meshDS->ShapeToIndex( aShapeEdge ); - degenShapeIdToPtrNgId.insert( make_pair( edgeID, ptrIdOnEdge )); - // remember vertex id - int vertexID = meshDS->ShapeToIndex( TopExp::FirstVertex( aShapeEdge )); - degenShapeIdToPtrNgId.insert( make_pair( vertexID, ptrIdOnEdge )); + p.Z() = pmin.Z() + k * dz / nbZ; + ngMesh->RestrictLocalH( p, maxh ); } } } } - // --------------------------------- - // Feed the Netgen with surface mesh - // --------------------------------- +} - int Netgen_NbOfNodes = 0; - int Netgen_param2ndOrder = 0; - double Netgen_paramFine = 1.; - double Netgen_paramSize = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. ); +//================================================================================ +/*! + * \brief set parameters and generate the volume mesh + */ +//================================================================================ - double Netgen_point[3]; - int Netgen_triangle[3]; - int Netgen_tetrahedron[4]; +bool NETGENPlugin_NETGEN_3D::compute(SMESH_Mesh& aMesh, + SMESH_MesherHelper& helper, + vector< const SMDS_MeshNode* >& nodeVec, + Ng_Mesh * Netgen_mesh) +{ + netgen::multithread.terminate = 0; - Ng_Init(); + netgen::Mesh* ngMesh = (netgen::Mesh*)Netgen_mesh; + int Netgen_NbOfNodes = Ng_GetNP(Netgen_mesh); - Ng_Mesh * Netgen_mesh = Ng_NewMesh(); +#ifndef NETGEN_V5 + char *optstr = 0; +#endif + int startWith = netgen::MESHCONST_MESHVOLUME; + int endWith = netgen::MESHCONST_OPTVOLUME; + int err = 1; - // set nodes and remember thier netgen IDs - bool isDegen = false, hasDegen = !degenShapeIdToPtrNgId.empty(); - TNodeToIDMap::iterator n_id = nodeToNetgenID.begin(); - for ( ; n_id != nodeToNetgenID.end(); ++n_id ) + NETGENPlugin_Mesher aMesher( &aMesh, helper.GetSubShape(), /*isVolume=*/true ); + netgen::OCCGeometry occgeo; + + if ( _hypParameters ) { - const SMDS_MeshNode* node = n_id->first; - - // ignore nodes on degenerated edge - if ( hasDegen ) { - int shapeId = node->GetPosition()->GetShapeId(); - shId_ngId = degenShapeIdToPtrNgId.find( shapeId ); - isDegen = ( shId_ngId != degenShapeIdToPtrNgId.end() ); - if ( isDegen && *(shId_ngId->second) != invalid_ID ) { - n_id->second = *(shId_ngId->second); - continue; - } - } - Netgen_point [ 0 ] = node->X(); - Netgen_point [ 1 ] = node->Y(); - Netgen_point [ 2 ] = node->Z(); - Ng_AddPoint(Netgen_mesh, Netgen_point); - n_id->second = ++Netgen_NbOfNodes; // set netgen ID - - if ( isDegen ) // all nodes on a degen edge get one netgen ID - *(shId_ngId->second) = n_id->second; + aMesher.SetParameters( _hypParameters ); + if ( !_hypParameters->GetOptimize() ) + endWith = netgen::MESHCONST_MESHVOLUME; } - - // set triangles - list< const SMDS_MeshElement* >::iterator tria = triangles.begin(); - list< bool >::iterator reverse = isReversed.begin(); - for ( ; tria != triangles.end(); ++tria, ++reverse ) + else if ( _hypMaxElementVolume ) { - int i = 0; - SMDS_ElemIteratorPtr triangleNodesIt = (*tria)->nodesIterator(); - while ( triangleNodesIt->more() ) { - const SMDS_MeshNode * node = - static_cast(triangleNodesIt->next()); - if(myTool->IsMedium(node)) - continue; - Netgen_triangle[ *reverse ? 2 - i : i ] = nodeToNetgenID[ node ]; - ++i; - } - if ( !hasDegen || - // ignore degenerated triangles, they have 2 or 3 same ids - (Netgen_triangle[0] != Netgen_triangle[1] && - Netgen_triangle[0] != Netgen_triangle[2] && - Netgen_triangle[2] != Netgen_triangle[1] )) - { - Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle); - } + netgen::mparam.maxh = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. ); + // limitVolumeSize( ngMesh, netgen::mparam.maxh ); // result is unpredictable + } + else if ( aMesh.HasShapeToMesh() ) + { + aMesher.PrepareOCCgeometry( occgeo, helper.GetSubShape(), aMesh ); + netgen::mparam.maxh = occgeo.GetBoundingBox().Diam()/2; + } + else + { + netgen::Point3d pmin, pmax; + ngMesh->GetBox (pmin, pmax); + netgen::mparam.maxh = Dist(pmin, pmax)/2; } - // ------------------------- - // Generate the volume mesh - // ------------------------- + if ( !_hypParameters && aMesh.HasShapeToMesh() ) + { + netgen::mparam.minh = aMesher.GetDefaultMinSize( helper.GetSubShape(), netgen::mparam.maxh ); + } - Ng_Meshing_Parameters Netgen_param; + try + { + OCC_CATCH_SIGNALS; #ifdef NETGEN_V5 - Netgen_param.second_order = Netgen_param2ndOrder; -#endif - Netgen_param.fineness = Netgen_paramFine; - Netgen_param.maxh = Netgen_paramSize; - - Ng_Result status; - - try { -#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 - OCC_CATCH_SIGNALS; + ngMesh->CalcLocalH(netgen::mparam.grading); + err = netgen::OCCGenerateMesh(occgeo, ngMesh, netgen::mparam, startWith, endWith); +#else + ngMesh->CalcLocalH(); + err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); #endif - status = Ng_GenerateVolumeMesh(Netgen_mesh, &Netgen_param); + if(netgen::multithread.terminate) + return false; + if ( err ) + error(SMESH_Comment("Error in netgen::OCCGenerateMesh() at ") << netgen::multithread.task); } - catch (Standard_Failure& exc) { - error(COMPERR_OCC_EXCEPTION, exc.GetMessageString()); - status = NG_VOLUME_FAILURE; + catch (Standard_Failure& ex) + { + SMESH_Comment str("Exception in netgen::OCCGenerateMesh()"); + str << " at " << netgen::multithread.task + << ": " << ex.DynamicType()->Name(); + if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) + str << ": " << ex.GetMessageString(); + error(str); } - catch (...) { - error("Exception in Ng_GenerateVolumeMesh()"); - status = NG_VOLUME_FAILURE; + catch (netgen::NgException exc) + { + SMESH_Comment str("NgException"); + if ( strlen( netgen::multithread.task ) > 0 ) + str << " at " << netgen::multithread.task; + str << ": " << exc.What(); + error(str); } - if ( GetComputeError()->IsOK() ) { - switch ( status ) { - case NG_SURFACE_INPUT_ERROR:error( status, "NG_SURFACE_INPUT_ERROR"); - case NG_VOLUME_FAILURE: error( status, "NG_VOLUME_FAILURE"); - case NG_STL_INPUT_ERROR: error( status, "NG_STL_INPUT_ERROR"); - case NG_SURFACE_FAILURE: error( status, "NG_SURFACE_FAILURE"); - case NG_FILE_NOT_FOUND: error( status, "NG_FILE_NOT_FOUND"); - }; + catch (...) + { + SMESH_Comment str("Exception in netgen::OCCGenerateMesh()"); + if ( strlen( netgen::multithread.task ) > 0 ) + str << " at " << netgen::multithread.task; + error(str); } int Netgen_NbOfNodesNew = Ng_GetNP(Netgen_mesh); + int Netgen_NbOfTetra = Ng_GetNE(Netgen_mesh); - int Netgen_NbOfTetra = Ng_GetNE(Netgen_mesh); - - MESSAGE("End of Volume Mesh Generation. status=" << status << + MESSAGE("End of Volume Mesh Generation. err=" << err << ", nb new nodes: " << Netgen_NbOfNodesNew - Netgen_NbOfNodes << ", nb tetra: " << Netgen_NbOfTetra); @@ -398,118 +518,68 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh, // Feed back the SMESHDS with the generated Nodes and Volume Elements // ------------------------------------------------------------------- + if ( err ) + { + SMESH_ComputeErrorPtr ce = NETGENPlugin_Mesher::ReadErrors(nodeVec); + if ( ce && !ce->myBadElements.empty() ) + error( ce ); + } + bool isOK = ( /*status == NG_OK &&*/ Netgen_NbOfTetra > 0 );// get whatever built if ( isOK ) { - // vector of nodes in which node index == netgen ID - vector< const SMDS_MeshNode* > nodeVec ( Netgen_NbOfNodesNew + 1 ); - // insert old nodes into nodeVec - for ( n_id = nodeToNetgenID.begin(); n_id != nodeToNetgenID.end(); ++n_id ) { - nodeVec.at( n_id->second ) = n_id->first; - } + double Netgen_point[3]; + int Netgen_tetrahedron[4]; + // create and insert new nodes into nodeVec + nodeVec.resize( Netgen_NbOfNodesNew + 1, 0 ); int nodeIndex = Netgen_NbOfNodes + 1; - int shapeID = meshDS->ShapeToIndex( aShape ); for ( ; nodeIndex <= Netgen_NbOfNodesNew; ++nodeIndex ) { Ng_GetPoint( Netgen_mesh, nodeIndex, Netgen_point ); - SMDS_MeshNode * node = meshDS->AddNode(Netgen_point[0], - Netgen_point[1], - Netgen_point[2]); - meshDS->SetNodeInVolume(node, shapeID); - nodeVec.at(nodeIndex) = node; + nodeVec.at(nodeIndex) = helper.AddNode(Netgen_point[0], Netgen_point[1], Netgen_point[2]); } // create tetrahedrons for ( int elemIndex = 1; elemIndex <= Netgen_NbOfTetra; ++elemIndex ) { Ng_GetVolumeElement(Netgen_mesh, elemIndex, Netgen_tetrahedron); - SMDS_MeshVolume * elt = myTool->AddVolume (nodeVec.at( Netgen_tetrahedron[0] ), - nodeVec.at( Netgen_tetrahedron[1] ), - nodeVec.at( Netgen_tetrahedron[2] ), - nodeVec.at( Netgen_tetrahedron[3] )); - meshDS->SetMeshElementOnShape(elt, shapeID ); + try + { + helper.AddVolume (nodeVec.at( Netgen_tetrahedron[0] ), + nodeVec.at( Netgen_tetrahedron[1] ), + nodeVec.at( Netgen_tetrahedron[2] ), + nodeVec.at( Netgen_tetrahedron[3] )); + } + catch (...) + { + } } } - Ng_DeleteMesh(Netgen_mesh); - Ng_Exit(); - - NETGENPlugin_Mesher::RemoveTmpFiles(); - - return (status == NG_OK); + return !err; } -bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh, +//================================================================================ +/*! + * \brief Compute tetrahedral mesh from 2D mesh without geometry + */ +//================================================================================ + +bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh, SMESH_MesherHelper* aHelper) { - MESSAGE("NETGENPlugin_NETGEN_3D::Compute with maxElmentsize = " << _maxElementVolume); const int invalid_ID = -1; - bool _quadraticMesh = false; - typedef map< const SMDS_MeshNode*, int, TIDCompare > TNodeToIDMap; - TNodeToIDMap nodeToNetgenID; - list< const SMDS_MeshElement* > triangles; - SMESHDS_Mesh* MeshDS = aHelper->GetMeshDS(); + + netgen::multithread.terminate = 0; + _progressByTic = -1.; SMESH_MesherHelper::MType MeshType = aHelper->IsQuadraticMesh(); - - if(MeshType == SMESH_MesherHelper::COMP) + if ( MeshType == SMESH_MesherHelper::COMP ) return error( COMPERR_BAD_INPUT_MESH, - SMESH_Comment("Mesh with linear and quadratic elements given.")); - else if (MeshType == SMESH_MesherHelper::QUADRATIC) - _quadraticMesh = true; - - StdMeshers_QuadToTriaAdaptor Adaptor; - Adaptor.Compute(aMesh); - - SMDS_FaceIteratorPtr fIt = MeshDS->facesIterator(); - TIDSortedElemSet sortedFaces; // 0020279: control the "random" use when using mesh algorithms - while( fIt->more()) sortedFaces.insert( fIt->next() ); - - TIDSortedElemSet::iterator itFace = sortedFaces.begin(), fEnd = sortedFaces.end(); - for ( ; itFace != fEnd; ++itFace ) { - // check element - const SMDS_MeshElement* elem = *itFace; - if ( !elem ) - return error( COMPERR_BAD_INPUT_MESH, "Null element encounters"); - bool isTraingle = ( elem->NbNodes()==3 || (_quadraticMesh && elem->NbNodes()==6 )); - if ( !isTraingle ) { - //return error( COMPERR_BAD_INPUT_MESH, - // SMESH_Comment("Not triangle element ")<GetID()); - // using adaptor - const list* faces = Adaptor.GetTriangles(elem); - if(faces==0) { - return error( COMPERR_BAD_INPUT_MESH, - SMESH_Comment("Not triangles in adaptor for element ")<GetID()); - } - list::const_iterator itf = faces->begin(); - for(; itf!=faces->end(); itf++ ) { - triangles.push_back( (*itf) ); - // put triange's nodes to nodeToNetgenID map - SMDS_ElemIteratorPtr triangleNodesIt = (*itf)->nodesIterator(); - while ( triangleNodesIt->more() ) { - const SMDS_MeshNode * node = - static_cast(triangleNodesIt->next()); - if(aHelper->IsMedium(node)) - continue; - nodeToNetgenID.insert( make_pair( node, invalid_ID )); - } - } - } - else { - // keep a triangle - triangles.push_back( elem ); - // put elem nodes to nodeToNetgenID map - SMDS_ElemIteratorPtr triangleNodesIt = elem->nodesIterator(); - while ( triangleNodesIt->more() ) { - const SMDS_MeshNode * node = - static_cast(triangleNodesIt->next()); - if(aHelper->IsMedium(node)) - continue; - nodeToNetgenID.insert( make_pair( node, invalid_ID )); - } - } - } + SMESH_Comment("Mesh with linear and quadratic elements given")); + + aHelper->SetIsQuadratic( MeshType == SMESH_MesherHelper::QUADRATIC ); // --------------------------------- // Feed the Netgen with surface mesh @@ -519,128 +589,194 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh, int Netgen_param2ndOrder = 0; double Netgen_paramFine = 1.; double Netgen_paramSize = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. ); - + double Netgen_point[3]; int Netgen_triangle[3]; int Netgen_tetrahedron[4]; - Ng_Init(); + NETGENPlugin_NetgenLibWrapper ngLib; + Ng_Mesh * Netgen_mesh = ngLib._ngMesh; - Ng_Mesh * Netgen_mesh = Ng_NewMesh(); - - // set nodes and remember thier netgen IDs - - TNodeToIDMap::iterator n_id = nodeToNetgenID.begin(); - for ( ; n_id != nodeToNetgenID.end(); ++n_id ) + SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( aMesh )); + if ( aMesh.NbQuadrangles() > 0 ) { - const SMDS_MeshNode* node = n_id->first; - - Netgen_point [ 0 ] = node->X(); - Netgen_point [ 1 ] = node->Y(); - Netgen_point [ 2 ] = node->Z(); - Ng_AddPoint(Netgen_mesh, Netgen_point); - n_id->second = ++Netgen_NbOfNodes; // set netgen ID - + StdMeshers_QuadToTriaAdaptor* Adaptor = new StdMeshers_QuadToTriaAdaptor; + Adaptor->Compute(aMesh); + proxyMesh.reset( Adaptor ); } - // set triangles - list< const SMDS_MeshElement* >::iterator tria = triangles.begin(); - for ( ; tria != triangles.end(); ++tria) + // maps nodes to ng ID + typedef map< const SMDS_MeshNode*, int, TIDCompare > TNodeToIDMap; + typedef TNodeToIDMap::value_type TN2ID; + TNodeToIDMap nodeToNetgenID; + + SMDS_ElemIteratorPtr fIt = proxyMesh->GetFaces(); + while( fIt->more()) { - int i = 0; - SMDS_ElemIteratorPtr triangleNodesIt = (*tria)->nodesIterator(); - while ( triangleNodesIt->more() ) { - const SMDS_MeshNode * node = - static_cast(triangleNodesIt->next()); - if(aHelper->IsMedium(node)) - continue; - Netgen_triangle[ i ] = nodeToNetgenID[ node ]; - ++i; + // check element + const SMDS_MeshElement* elem = fIt->next(); + if ( !elem ) + return error( COMPERR_BAD_INPUT_MESH, "Null element encounters"); + if ( elem->NbCornerNodes() != 3 ) + return error( COMPERR_BAD_INPUT_MESH, "Not triangle element encounters"); + + // add three nodes of triangle + for ( int iN = 0; iN < 3; ++iN ) + { + const SMDS_MeshNode* node = elem->GetNode( iN ); + int& ngID = nodeToNetgenID.insert(TN2ID( node, invalid_ID )).first->second; + if ( ngID == invalid_ID ) + { + ngID = ++Netgen_NbOfNodes; + Netgen_point [ 0 ] = node->X(); + Netgen_point [ 1 ] = node->Y(); + Netgen_point [ 2 ] = node->Z(); + Ng_AddPoint(Netgen_mesh, Netgen_point); + } + Netgen_triangle[ iN ] = ngID; } - Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle); } + proxyMesh.reset(); // delete tmp faces + + // vector of nodes in which node index == netgen ID + vector< const SMDS_MeshNode* > nodeVec ( nodeToNetgenID.size() + 1 ); + // insert old nodes into nodeVec + TNodeToIDMap::iterator n_id = nodeToNetgenID.begin(); + for ( ; n_id != nodeToNetgenID.end(); ++n_id ) + nodeVec.at( n_id->second ) = n_id->first; + nodeToNetgenID.clear(); // ------------------------- // Generate the volume mesh // ------------------------- - Ng_Meshing_Parameters Netgen_param; + return ( ngLib._isComputeOk = compute( aMesh, *aHelper, nodeVec, Netgen_mesh)); +} -#ifdef NETGEN_V5 - Netgen_param.second_order = Netgen_param2ndOrder; -#endif - Netgen_param.fineness = Netgen_paramFine; - Netgen_param.maxh = Netgen_paramSize; +void NETGENPlugin_NETGEN_3D::CancelCompute() +{ + SMESH_Algo::CancelCompute(); + netgen::multithread.terminate = 1; +} - Ng_Result status; +//================================================================================ +/*! + * \brief Return Compute progress + */ +//================================================================================ - try { -#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 - OCC_CATCH_SIGNALS; -#endif - status = Ng_GenerateVolumeMesh(Netgen_mesh, &Netgen_param); - } - catch (Standard_Failure& exc) { - error(COMPERR_OCC_EXCEPTION, exc.GetMessageString()); - status = NG_VOLUME_FAILURE; - } - catch (...) { - error("Bad mesh input!!!"); - status = NG_VOLUME_FAILURE; +double NETGENPlugin_NETGEN_3D::GetProgress() const +{ + double res; + const char* volMeshing = "Volume meshing"; + const char* dlnMeshing = "Delaunay meshing"; + const double meshingRatio = 0.15; + const_cast( this )->_progressTic++; + + if ( _progressByTic < 0. && + ( strncmp( netgen::multithread.task, dlnMeshing, 3 ) == 0 || + strncmp( netgen::multithread.task, volMeshing, 3 ) == 0 )) + { + res = 0.001 + meshingRatio * netgen::multithread.percent / 100.; + //cout << netgen::multithread.task << " " <<_progressTic << "-" << netgen::multithread.percent << endl; } - if ( GetComputeError()->IsOK() ) { - error( status, "Bad mesh input!!!"); + else // different otimizations + { + if ( _progressByTic < 0. ) + ((NETGENPlugin_NETGEN_3D*)this)->_progressByTic = meshingRatio / _progressTic; + res = _progressByTic * _progressTic; + //cout << netgen::multithread.task << " " << _progressTic << " " << res << endl; } + return Min ( res, 0.98 ); +} - int Netgen_NbOfNodesNew = Ng_GetNP(Netgen_mesh); - - int Netgen_NbOfTetra = Ng_GetNE(Netgen_mesh); - - MESSAGE("End of Volume Mesh Generation. status=" << status << - ", nb new nodes: " << Netgen_NbOfNodesNew - Netgen_NbOfNodes << - ", nb tetra: " << Netgen_NbOfTetra); - - // ------------------------------------------------------------------- - // Feed back the SMESHDS with the generated Nodes and Volume Elements - // ------------------------------------------------------------------- +//============================================================================= +/*! + * + */ +//============================================================================= - bool isOK = ( Netgen_NbOfTetra > 0 );// get whatever built - if ( isOK ) - { - // vector of nodes in which node index == netgen ID - vector< const SMDS_MeshNode* > nodeVec ( Netgen_NbOfNodesNew + 1 ); - // insert old nodes into nodeVec - for ( n_id = nodeToNetgenID.begin(); n_id != nodeToNetgenID.end(); ++n_id ) { - nodeVec.at( n_id->second ) = n_id->first; - } - // create and insert new nodes into nodeVec - int nodeIndex = Netgen_NbOfNodes + 1; - - for ( ; nodeIndex <= Netgen_NbOfNodesNew; ++nodeIndex ) - { - Ng_GetPoint( Netgen_mesh, nodeIndex, Netgen_point ); - SMDS_MeshNode * node = aHelper->AddNode(Netgen_point[0], - Netgen_point[1], - Netgen_point[2]); - nodeVec.at(nodeIndex) = node; +bool NETGENPlugin_NETGEN_3D::Evaluate(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + MapShapeNbElems& aResMap) +{ + int nbtri = 0, nbqua = 0; + double fullArea = 0.0; + for (TopExp_Explorer expF(aShape, TopAbs_FACE); expF.More(); expF.Next()) { + TopoDS_Face F = TopoDS::Face( expF.Current() ); + SMESH_subMesh *sm = aMesh.GetSubMesh(F); + MapShapeNbElemsItr anIt = aResMap.find(sm); + if( anIt==aResMap.end() ) { + SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); + smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); + return false; } + std::vector aVec = (*anIt).second; + nbtri += Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]); + nbqua += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); + GProp_GProps G; + BRepGProp::SurfaceProperties(F,G); + double anArea = G.Mass(); + fullArea += anArea; + } - // create tetrahedrons - for ( int elemIndex = 1; elemIndex <= Netgen_NbOfTetra; ++elemIndex ) - { - Ng_GetVolumeElement(Netgen_mesh, elemIndex, Netgen_tetrahedron); - aHelper->AddVolume (nodeVec.at( Netgen_tetrahedron[0] ), - nodeVec.at( Netgen_tetrahedron[1] ), - nodeVec.at( Netgen_tetrahedron[2] ), - nodeVec.at( Netgen_tetrahedron[3] )); + // collect info from edges + int nb0d_e = 0, nb1d_e = 0; + bool IsQuadratic = false; + bool IsFirst = true; + TopTools_MapOfShape tmpMap; + for (TopExp_Explorer expF(aShape, TopAbs_EDGE); expF.More(); expF.Next()) { + TopoDS_Edge E = TopoDS::Edge(expF.Current()); + if( tmpMap.Contains(E) ) + continue; + tmpMap.Add(E); + SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(expF.Current()); + MapShapeNbElemsItr anIt = aResMap.find(aSubMesh); + if( anIt==aResMap.end() ) { + SMESH_ComputeErrorPtr& smError = aSubMesh->GetComputeError(); + smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED, + "Submesh can not be evaluated",this)); + return false; + } + std::vector aVec = (*anIt).second; + nb0d_e += aVec[SMDSEntity_Node]; + nb1d_e += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]); + if(IsFirst) { + IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]); + IsFirst = false; } } - - Ng_DeleteMesh(Netgen_mesh); - Ng_Exit(); - - NETGENPlugin_Mesher::RemoveTmpFiles(); + tmpMap.Clear(); + + double ELen_face = sqrt(2.* ( fullArea/(nbtri+nbqua*2) ) / sqrt(3.0) ); + double ELen_vol = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. ); + double ELen = Min(ELen_vol,ELen_face*2); + + GProp_GProps G; + BRepGProp::VolumeProperties(aShape,G); + double aVolume = G.Mass(); + double tetrVol = 0.1179*ELen*ELen*ELen; + double CoeffQuality = 0.9; + int nbVols = int( aVolume/tetrVol/CoeffQuality ); + int nb1d_f = (nbtri*3 + nbqua*4 - nb1d_e) / 2; + int nb1d_in = (nbVols*6 - nb1d_e - nb1d_f ) / 5; + std::vector aVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; i> val).bad(); + isOK = (bool)(load >> val); if (isOK) _nbSegments = (int) val; else load.clear(ios::badbit | load.rdstate()); - isOK = !(load >> val).bad(); + isOK = (bool)(load >> val); if (isOK) _segmentLength = val; else load.clear(ios::badbit | load.rdstate()); - isOK = !(load >> val).bad(); + isOK = (bool)(load >> val); if (isOK) _area = val; else load.clear(ios::badbit | load.rdstate()); + load >> _allowQuad; + return load; } @@ -221,3 +246,4 @@ bool NETGENPlugin_SimpleHypothesis_2D::SetParametersByDefaults(const TDefaults& _segmentLength = dflts._elemLength; return _nbSegments && _segmentLength > 0; } + diff --git a/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_SimpleHypothesis_3D.cpp b/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_SimpleHypothesis_3D.cpp index b8a18854d9be..b5d73021373d 100644 --- a/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_SimpleHypothesis_3D.cpp +++ b/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_SimpleHypothesis_3D.cpp @@ -1,24 +1,22 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 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, or (at your option) any later version. // -// 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. // -// 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 // -// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // NETGENPlugin : C++ implementation // File : NETGENPlugin_SimpleHypothesis_3D.cxx // Author : Edward AGAPOV @@ -108,7 +106,7 @@ istream & NETGENPlugin_SimpleHypothesis_3D::LoadFrom(istream & load) bool isOK = true; double val; - isOK = !(load >> val).bad(); + isOK = (bool)(load >> val); if (isOK) _volume = val; else diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_BallElement.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_BallElement.cpp new file mode 100644 index 000000000000..299093c94f6e --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_BallElement.cpp @@ -0,0 +1,102 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMDS : implementaion of Salome mesh data structure +// Module : SMESH +// File : SMDS_BallElement.cxx +// Author : Edward AGAPOV (eap) + +#include "SMDS_BallElement.hxx" + +#include "SMDS_ElemIterator.hxx" +#include "SMDS_Mesh.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMDS_VtkCellIterator.hxx" + +SMDS_BallElement::SMDS_BallElement() +{ + SMDS_MeshCell::init(); +} + +SMDS_BallElement::SMDS_BallElement (const SMDS_MeshNode * node, double diameter) +{ + init( node->getVtkId(), diameter, SMDS_Mesh::_meshList[ node->getMeshId() ] ); +} + +SMDS_BallElement::SMDS_BallElement(vtkIdType nodeId, double diameter, SMDS_Mesh* mesh) +{ + init( nodeId, diameter, mesh ); +} + +void SMDS_BallElement::init(vtkIdType nodeId, double diameter, SMDS_Mesh* mesh) +{ + SMDS_MeshCell::init(); + SMDS_UnstructuredGrid* grid = mesh->getGrid(); + myVtkID = grid->InsertNextLinkedCell( GetVtkType(), 1, &nodeId ); + myMeshId = mesh->getMeshId(); + grid->SetBallDiameter( myVtkID, diameter ); + mesh->setMyModified(); +} + +double SMDS_BallElement::GetDiameter() const +{ + return SMDS_Mesh::_meshList[myMeshId]->getGrid()->GetBallDiameter( myVtkID ); +} + +void SMDS_BallElement::SetDiameter(double diameter) +{ + SMDS_Mesh::_meshList[myMeshId]->getGrid()->SetBallDiameter( myVtkID, diameter ); +} + +bool SMDS_BallElement::ChangeNode (const SMDS_MeshNode * node) +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(myVtkID, npts, pts); + pts[0] = node->getVtkId(); + SMDS_Mesh::_meshList[myMeshId]->setMyModified(); + return true; +} + +void SMDS_BallElement::Print (std::ostream & OS) const +{ + OS << "ball<" << GetID() << "> : "; +} + +const SMDS_MeshNode* SMDS_BallElement::GetNode (const int ind) const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType npts, *pts; + grid->GetCellPoints( myVtkID, npts, pts ); + return SMDS_Mesh::_meshList[myMeshId]->FindNodeVtk( pts[ 0 ]); +} + +SMDS_ElemIteratorPtr SMDS_BallElement::elementsIterator (SMDSAbs_ElementType type) const +{ + switch (type) + { + case SMDSAbs_Node: + return SMDS_ElemIteratorPtr(new SMDS_VtkCellIterator(SMDS_Mesh::_meshList[myMeshId], myVtkID, GetEntityType())); + default: + ; + return SMDS_ElemIteratorPtr((SMDS_ElemIterator*) NULL); + } +} + diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_Downward.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_Downward.cpp new file mode 100644 index 000000000000..d6049c0bd198 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_Downward.cpp @@ -0,0 +1,2245 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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: SMDS_Downward.cxx +// Created: Jun 3, 2010 +// Author: prascle + +#include "SMDS_Downward.hxx" +#include "SMDS_Mesh.hxx" +#include "utilities.h" + +#include +#include + +#include + +using namespace std; + +// --------------------------------------------------------------------------- + +vector SMDS_Downward::_cellDimension; + +/*! get the dimension of a cell (1,2,3 for 1D, 2D 3D) given the vtk cell type + * + * @param cellType vtk cell type @see vtkCellType.h + * @return 1,2 or 3 + */ +int SMDS_Downward::getCellDimension(unsigned char cellType) +{ + if (_cellDimension.empty()) + { + _cellDimension.resize(VTK_MAXTYPE + 1, 0); + _cellDimension[VTK_LINE] = 1; + _cellDimension[VTK_QUADRATIC_EDGE] = 1; + _cellDimension[VTK_TRIANGLE] = 2; + _cellDimension[VTK_QUADRATIC_TRIANGLE] = 2; + _cellDimension[VTK_BIQUADRATIC_TRIANGLE] = 2; + _cellDimension[VTK_QUAD] = 2; + _cellDimension[VTK_QUADRATIC_QUAD] = 2; + _cellDimension[VTK_BIQUADRATIC_QUAD] = 2; + _cellDimension[VTK_TETRA] = 3; + _cellDimension[VTK_QUADRATIC_TETRA] = 3; + _cellDimension[VTK_HEXAHEDRON] = 3; + _cellDimension[VTK_QUADRATIC_HEXAHEDRON] = 3; + _cellDimension[VTK_TRIQUADRATIC_HEXAHEDRON] = 3; + _cellDimension[VTK_WEDGE] = 3; + _cellDimension[VTK_QUADRATIC_WEDGE] = 3; + _cellDimension[VTK_PYRAMID] = 3; + _cellDimension[VTK_QUADRATIC_PYRAMID] = 3; + _cellDimension[VTK_HEXAGONAL_PRISM] = 3; + } + return _cellDimension[cellType]; +} + +// --------------------------------------------------------------------------- + +/*! Generic constructor for all the downward connectivity structures (one per vtk cell type). + * The static structure for cell dimension is set only once. + * @param grid unstructured grid associated to the mesh. + * @param nbDownCells number of downward entities associated to this vtk type of cell. + * @return + */ +SMDS_Downward::SMDS_Downward(SMDS_UnstructuredGrid *grid, int nbDownCells) : + _grid(grid), _nbDownCells(nbDownCells) +{ + this->_maxId = 0; + this->_cellIds.clear(); + this->_cellTypes.clear(); + if (_cellDimension.empty()) + getCellDimension( VTK_LINE ); +} + +SMDS_Downward::~SMDS_Downward() +{ +} + +/*! Give or create an entry for downward connectivity structure relative to a cell. + * If the entry already exists, just return its id, otherwise, create it. + * The internal storage memory is allocated if needed. + * The SMDS_UnstructuredGrid::_cellIdToDownId vector is completed for vtkUnstructuredGrid cells. + * @param vtkId for a vtkUnstructuredGrid cell or -1 (default) for a created downward cell. + * @return the rank in downward[vtkType] structure. + */ +int SMDS_Downward::addCell(int vtkId) +{ + int localId = -1; + if (vtkId >= 0) + localId = _grid->CellIdToDownId(vtkId); + if (localId >= 0) + return localId; + + localId = this->_maxId; + this->_maxId++; + this->allocate(_maxId); + if (vtkId >= 0) + { + this->_vtkCellIds[localId] = vtkId; + _grid->setCellIdToDownId(vtkId, localId); + } + this->initCell(localId); + return localId; +} + +/*! generic method do nothing. see derived methods + * + * @param cellId + */ +void SMDS_Downward::initCell(int cellId) +{ +} + +/*! Get the number of downward entities associated to a cell (always the same for a given vtk type of cell) + * + * @param cellId not used here. + * @return + */ +int SMDS_Downward::getNumberOfDownCells(int cellId) +{ + return _nbDownCells; +} + +/*! get a pointer on the downward entities id's associated to a cell. + * @see SMDS_Downward::getNumberOfDownCells for the number of downward entities. + * @see SMDS_Downward::getDownTypes for the vtk cell types associated to the downward entities. + * @param cellId index of the cell in the downward structure relative to a given vtk cell type. + * @return table of downward entities id's. + */ +const int* SMDS_Downward::getDownCells(int cellId) +{ + //ASSERT((cellId >=0) && (cellId < _maxId)); + return &_cellIds[_nbDownCells * cellId]; +} + +/*! get a list of vtk cell types associated to downward entities of a given cell, in the same order + * than the downward entities id's list (@see SMDS_Downward::getDownCells). + * + * @param cellId index of the cell in the downward structure relative to a vtk cell type. + * @return table of downward entities types. + */ +const unsigned char* SMDS_Downward::getDownTypes(int cellId) +{ + return &_cellTypes[0]; +} + +/*! add a downward entity of dimension n-1 (cell or node) to a given cell. + * Actual implementation is done in derived methods. + * @param cellId index of the parent cell (dimension n) in the downward structure relative to a vtk cell type. + * @param lowCellId index of the children cell to add (dimension n-1) + * @param aType vtk cell type of the cell to add (needed to find the SMDS_Downward structure containing the cell to add). + */ +void SMDS_Downward::addDownCell(int cellId, int lowCellId, unsigned char aType) +{ + ASSERT(0); // must be re-implemented in derived class +} + +/*! add a downward entity of dimension n+1 to a given cell. + * Actual implementation is done in derived methods. + * @param cellId index of the children cell (dimension n) in the downward structure relative to a vtk cell type. + * @param upCellId index of the parent cell to add (dimension n+1) + * @param aType vtk cell type of the cell to add (needed to find the SMDS_Downward structure containing the cell to add). + */ +void SMDS_Downward::addUpCell(int cellId, int upCellId, unsigned char aType) +{ + ASSERT(0); // must be re-implemented in derived class +} + +int SMDS_Downward::getNodeSet(int cellId, int* nodeSet) +{ + return 0; +} + +// --------------------------------------------------------------------------- + +SMDS_Down1D::SMDS_Down1D(SMDS_UnstructuredGrid *grid, int nbDownCells) : + SMDS_Downward(grid, nbDownCells) +{ + _upCellIdsVector.clear(); + _upCellTypesVector.clear(); + _upCellIds.clear(); + _upCellTypes.clear(); + _upCellIndex.clear(); +} + +SMDS_Down1D::~SMDS_Down1D() +{ +} + +/*! clear vectors used to reference 2D cells containing the edge + * + * @param cellId + */ +void SMDS_Down1D::initCell(int cellId) +{ + _upCellIdsVector[cellId].clear(); + _upCellTypesVector[cellId].clear(); +} + +/*! Resize the downward connectivity storage vector if needed. + * + * @param nbElems total number of elements of the same type required + */ +void SMDS_Down1D::allocate(int nbElems) +{ + if (nbElems >= _vtkCellIds.size()) + { + _vtkCellIds.resize(nbElems + SMDS_Mesh::chunkSize, -1); + _cellIds.resize(_nbDownCells * (nbElems + SMDS_Mesh::chunkSize), -1); + _upCellIdsVector.resize(nbElems + SMDS_Mesh::chunkSize); + _upCellTypesVector.resize(nbElems + SMDS_Mesh::chunkSize); + } +} + +void SMDS_Down1D::compactStorage() +{ + _cellIds.resize(_nbDownCells * _maxId); + _vtkCellIds.resize(_maxId); + + int sizeUpCells = 0; + for (int i = 0; i < _maxId; i++) + sizeUpCells += _upCellIdsVector[i].size(); + _upCellIds.resize(sizeUpCells, -1); + _upCellTypes.resize(sizeUpCells); + _upCellIndex.resize(_maxId + 1, -1); // id and types of rank i correspond to [ _upCellIndex[i], _upCellIndex[i+1] [ + int current = 0; + for (int i = 0; i < _maxId; i++) + { + _upCellIndex[i] = current; + for (int j = 0; j < _upCellIdsVector[i].size(); j++) + { + _upCellIds[current] = _upCellIdsVector[i][j]; + _upCellTypes[current] = _upCellTypesVector[i][j]; + current++; + } + } + _upCellIndex[_maxId] = current; + + _upCellIdsVector.clear(); + _upCellTypesVector.clear(); +} + +void SMDS_Down1D::addUpCell(int cellId, int upCellId, unsigned char aType) +{ + //ASSERT((cellId >=0) && (cellId < _maxId)); + int nbFaces = _upCellIdsVector[cellId].size(); + for (int i = 0; i < nbFaces; i++) + { + if ((_upCellIdsVector[cellId][i] == upCellId) && (_upCellTypesVector[cellId][i] == aType)) + { + return; // already done + } + } + _upCellIdsVector[cellId].push_back(upCellId); + _upCellTypesVector[cellId].push_back(aType); +} + +int SMDS_Down1D::getNumberOfUpCells(int cellId) +{ + //ASSERT((cellId >=0) && (cellId < _maxId)); + return _upCellIndex[cellId + 1] - _upCellIndex[cellId]; +} + +const int* SMDS_Down1D::getUpCells(int cellId) +{ + //ASSERT((cellId >=0) && (cellId < _maxId)); + return &_upCellIds[_upCellIndex[cellId]]; +} + +const unsigned char* SMDS_Down1D::getUpTypes(int cellId) +{ + //ASSERT((cellId >=0) && (cellId < _maxId)); + return &_upCellTypes[_upCellIndex[cellId]]; +} + +void SMDS_Down1D::getNodeIds(int cellId, std::set& nodeSet) +{ + for (int i = 0; i < _nbDownCells; i++) + nodeSet.insert(_cellIds[_nbDownCells * cellId + i]); +} + +int SMDS_Down1D::getNodeSet(int cellId, int* nodeSet) +{ + for (int i = 0; i < _nbDownCells; i++) + nodeSet[i] = _cellIds[_nbDownCells * cellId + i]; + return _nbDownCells; +} + +void SMDS_Down1D::setNodes(int cellId, int vtkId) +{ + vtkIdType npts = 0; + vtkIdType *pts; // will refer to the point id's of the face + _grid->GetCellPoints(vtkId, npts, pts); + // MESSAGE(vtkId << " " << npts << " " << _nbDownCells); + //ASSERT(npts == _nbDownCells); + for (int i = 0; i < npts; i++) + { + _cellIds[_nbDownCells * cellId + i] = pts[i]; + } +} + +void SMDS_Down1D::setNodes(int cellId, const int* nodeIds) +{ + //ASSERT(nodeIds.size() == _nbDownCells); + for (int i = 0; i < _nbDownCells; i++) + { + _cellIds[_nbDownCells * cellId + i] = nodeIds[i]; + } +} + +/*! Build the list of vtkUnstructuredGrid cells containing the edge. + * We keep in the list the cells that contains all the nodes, we keep only volumes and faces. + * @param cellId id of the edge in the downward structure + * @param vtkIds vector of vtk id's + * @return number of vtk cells (size of vector) + */ +int SMDS_Down1D::computeVtkCells(int cellId, std::vector& vtkIds) +{ + vtkIds.clear(); + + // --- find all the cells the points belong to, and how many of the points belong to a given cell + + int *pts = &_cellIds[_nbDownCells * cellId]; + int ncells = this->computeVtkCells(pts, vtkIds); + return ncells; +} + +/*! Build the list of vtkUnstructuredGrid cells containing the edge. + * + * @param pts list of points id's defining an edge + * @param vtkIds vector of vtk id's + * @return number of vtk cells (size of vector) + */ +int SMDS_Down1D::computeVtkCells(int *pts, std::vector& vtkIds) +{ + + // --- find all the cells the points belong to, and how many of the points belong to a given cell + + int cellIds[1000]; + int cellCnt[1000]; + int cnt = 0; + for (int i = 0; i < _nbDownCells; i++) + { + vtkIdType point = pts[i]; + int numCells = _grid->GetLinks()->GetNcells(point); + vtkIdType *cells = _grid->GetLinks()->GetCells(point); + for (int j = 0; j < numCells; j++) + { + int vtkCellId = cells[j]; + bool found = false; + for (int k = 0; k < cnt; k++) + { + if (cellIds[k] == vtkCellId) + { + cellCnt[k] += 1; + found = true; + break; + } + } + if (!found) + { + cellIds[cnt] = vtkCellId; + cellCnt[cnt] = 1; + // TODO ASSERT(cnt<1000); + cnt++; + } + } + } + + // --- find the face and volume cells: they contains all the points and are of type volume or face + + int ncells = 0; + for (int i = 0; i < cnt; i++) + { + if (cellCnt[i] == _nbDownCells) + { + int vtkElemId = cellIds[i]; + int vtkType = _grid->GetCellType(vtkElemId); + if (SMDS_Downward::getCellDimension(vtkType) > 1) + { + vtkIds.push_back(vtkElemId); + ncells++; + } + } + } + + return ncells; +} + +/*! Build the list of downward faces from a list of vtk cells. + * + * @param cellId id of the edge in the downward structure + * @param vtkIds vector of vtk id's + * @param downFaces vector of face id's in downward structures + * @param downTypes vector of face types + * @return number of downward faces + */ +int SMDS_Down1D::computeFaces(int cellId, int* vtkIds, int nbcells, int* downFaces, unsigned char* downTypes) +{ + int *pts = &_cellIds[_nbDownCells * cellId]; + int nbFaces = this->computeFaces(pts, vtkIds, nbcells, downFaces, downTypes); + return nbFaces; +} + +/*! Build the list of downward faces from a list of vtk cells. + * + * @param pts list of points id's defining an edge + * @param vtkIds vector of vtk id's + * @param downFaces vector of face id's in downward structures + * @param downTypes vector of face types + * @return number of downward faces + */ +int SMDS_Down1D::computeFaces(int* pts, int* vtkIds, int nbcells, int* downFaces, unsigned char* downTypes) +{ + int cnt = 0; + for (int i = 0; i < nbcells; i++) + { + int vtkId = vtkIds[i]; + int vtkType = _grid->GetCellType(vtkId); + if (SMDS_Downward::getCellDimension(vtkType) == 2) + { + int faceId = _grid->CellIdToDownId(vtkId); + downFaces[cnt] = faceId; + downTypes[cnt] = vtkType; + cnt++; + } + else if (SMDS_Downward::getCellDimension(vtkType) == 3) + { + int volId = _grid->CellIdToDownId(vtkId); + SMDS_Downward * downvol = _grid->getDownArray(vtkType); + //const int *downIds = downvol->getDownCells(volId); + const unsigned char* downTypesVol = downvol->getDownTypes(volId); + int nbFaces = downvol->getNumberOfDownCells(volId); + const int* faceIds = downvol->getDownCells(volId); + for (int n = 0; n < nbFaces; n++) + { + SMDS_Down2D *downFace = static_cast (_grid->getDownArray(downTypesVol[n])); + bool isInFace = downFace->isInFace(faceIds[n], pts, _nbDownCells); + if (isInFace) + { + bool alreadySet = false; + for (int k = 0; k < cnt; k++) + if (faceIds[n] == downFaces[k]) + { + alreadySet = true; + break; + } + if (!alreadySet) + { + downFaces[cnt] = faceIds[n]; + downTypes[cnt] = downTypesVol[n]; + cnt++; + } + } + } + } + } + return cnt; +} + +// --------------------------------------------------------------------------- + +SMDS_Down2D::SMDS_Down2D(SMDS_UnstructuredGrid *grid, int nbDownCells) : + SMDS_Downward(grid, nbDownCells) +{ + _upCellIds.clear(); + _upCellTypes.clear(); + _tempNodes.clear(); + _nbNodes = 0; +} + +SMDS_Down2D::~SMDS_Down2D() +{ +} + +int SMDS_Down2D::getNumberOfUpCells(int cellId) +{ + int nbup = 0; + if (_upCellIds[2 * cellId] >= 0) + nbup++; + if (_upCellIds[2 * cellId + 1] >= 0) + nbup++; + return nbup; +} + +const int* SMDS_Down2D::getUpCells(int cellId) +{ + //ASSERT((cellId >=0) && (cellId < _maxId)); + return &_upCellIds[2 * cellId]; +} + +const unsigned char* SMDS_Down2D::getUpTypes(int cellId) +{ + //ASSERT((cellId >=0) && (cellId < _maxId)); + return &_upCellTypes[2 * cellId]; +} + +void SMDS_Down2D::getNodeIds(int cellId, std::set& nodeSet) +{ + for (int i = 0; i < _nbDownCells; i++) + { + int downCellId = _cellIds[_nbDownCells * cellId + i]; + unsigned char cellType = _cellTypes[i]; + this->_grid->getDownArray(cellType)->getNodeIds(downCellId, nodeSet); + } +} + +/*! Find in vtkUnstructuredGrid the volumes containing a face already stored in vtkUnstructuredGrid. + * Search the volumes containing a face, to store the info in SMDS_Down2D for later uses + * with SMDS_Down2D::getUpCells and SMDS_Down2D::getUpTypes. + * A face belongs to 0, 1 or 2 volumes, identified by their id in vtkUnstructuredGrid. + * @param cellId the face cell id in vkUnstructuredGrid + * @param ids a couple of vtkId, initialized at -1 (no parent volume) + * @return number of volumes (0, 1 or 2) + */ +int SMDS_Down2D::computeVolumeIds(int cellId, int* ids) +{ + // --- find point id's of the face + + vtkIdType npts = 0; + vtkIdType *pts; // will refer to the point id's of the face + _grid->GetCellPoints(cellId, npts, pts); + vector nodes; + for (int i = 0; i < npts; i++) + nodes.push_back(pts[i]); + int nvol = this->computeVolumeIdsFromNodesFace(&nodes[0], npts, ids); + return nvol; +} + +/*! Find in vtkUnstructuredGrid the volumes containing a face described by it's nodes + * Search the volumes containing a face, to store the info in SMDS_Down2D for later uses + * with SMDS_Down2D::getUpCells and SMDS_Down2D::getUpTypes. + * A face belongs to 0, 1 or 2 volumes, identified by their id in vtkUnstructuredGrid. + * @param faceByNodes + * @param ids a couple of vtkId, initialized at -1 (no parent volume) + * @return number of volumes (0, 1 or 2) + */ +int SMDS_Down2D::computeVolumeIds(ElemByNodesType& faceByNodes, int* ids) +{ + int nvol = this->computeVolumeIdsFromNodesFace(&faceByNodes.nodeIds[0], faceByNodes.nbNodes, ids); + return nvol; +} + +/*! Find in vtkUnstructuredGrid the volumes containing a face described by it's nodes + * Search the volumes containing a face, to store the info in SMDS_Down2D for later uses + * with SMDS_Down2D::getUpCells and SMDS_Down2D::getUpTypes. + * A face belongs to 0, 1 or 2 volumes, identified by their id in vtkUnstructuredGrid. + * @param pts array of vtk node id's + * @param npts number of nodes + * @param ids + * @return number of volumes (0, 1 or 2) + */ +int SMDS_Down2D::computeVolumeIdsFromNodesFace(int* pts, int npts, int* ids) +{ + + // --- find all the cells the points belong to, and how many of the points belong to a given cell + + int cellIds[1000]; + int cellCnt[1000]; + int cnt = 0; + for (int i = 0; i < npts; i++) + { + vtkIdType point = pts[i]; + int numCells = _grid->GetLinks()->GetNcells(point); + //MESSAGE("cells pour " << i << " " << numCells); + vtkIdType *cells = _grid->GetLinks()->GetCells(point); + for (int j = 0; j < numCells; j++) + { + int vtkCellId = cells[j]; + bool found = false; + for (int k = 0; k < cnt; k++) + { + if (cellIds[k] == vtkCellId) + { + cellCnt[k] += 1; + found = true; + break; + } + } + if (!found) + { + cellIds[cnt] = vtkCellId; + cellCnt[cnt] = 1; + // TODO ASSERT(cnt<1000); + cnt++; + } + } + } + + // --- find the volume cells: they contains all the points and are of type volume + + int nvol = 0; + for (int i = 0; i < cnt; i++) + { + //MESSAGE("cell " << cellIds[i] << " points " << cellCnt[i]); + if (cellCnt[i] == npts) + { + int vtkElemId = cellIds[i]; + int vtkType = _grid->GetCellType(vtkElemId); + if (SMDS_Downward::getCellDimension(vtkType) == 3) + { + ids[nvol] = vtkElemId; // store the volume id in given vector + nvol++; + } + } + if (nvol == 2) + break; + } + + return nvol; +} + +void SMDS_Down2D::setTempNodes(int cellId, int vtkId) +{ + vtkIdType npts = 0; + vtkIdType *pts; // will refer to the point id's of the face + _grid->GetCellPoints(vtkId, npts, pts); + // MESSAGE(vtkId << " " << npts << " " << _nbNodes); + //ASSERT(npts == _nbNodes); + for (int i = 0; i < npts; i++) + { + _tempNodes[_nbNodes * cellId + i] = pts[i]; + } +} + +void SMDS_Down2D::setTempNodes(int cellId, ElemByNodesType& faceByNodes) +{ + for (int i = 0; i < faceByNodes.nbNodes; i++) + _tempNodes[_nbNodes * cellId + i] = faceByNodes.nodeIds[i]; +} + +/*! Find if all the nodes belongs to the face. + * + * @param cellId the face cell Id + * @param nodeSet set of node id's to be found in the face list of nodes + * @return + */ +bool SMDS_Down2D::isInFace(int cellId, int *pts, int npts) +{ + int nbFound = 0; + int *nodes = &_tempNodes[_nbNodes * cellId]; + for (int j = 0; j < npts; j++) + { + int point = pts[j]; + for (int i = 0; i < _nbNodes; i++) + { + if (nodes[i] == point) + { + nbFound++; + break; + } + } + } + return (nbFound == npts); +} + +/*! Resize the downward connectivity storage vector if needed. + * + * @param nbElems total number of elements of the same type required + */ +void SMDS_Down2D::allocate(int nbElems) +{ + if (nbElems >= _vtkCellIds.size()) + { + _cellIds.resize(_nbDownCells * (nbElems + SMDS_Mesh::chunkSize), -1); + _vtkCellIds.resize(nbElems + SMDS_Mesh::chunkSize, -1); + _upCellIds.resize(2 * (nbElems + SMDS_Mesh::chunkSize), -1); + _upCellTypes.resize(2 * (nbElems + SMDS_Mesh::chunkSize), -1); + _tempNodes.resize(_nbNodes * (nbElems + SMDS_Mesh::chunkSize), -1); + } +} + +void SMDS_Down2D::compactStorage() +{ + _cellIds.resize(_nbDownCells * _maxId); + _upCellIds.resize(2 * _maxId); + _upCellTypes.resize(2 * _maxId); + _vtkCellIds.resize(_maxId); + _tempNodes.clear(); +} + +void SMDS_Down2D::addUpCell(int cellId, int upCellId, unsigned char aType) +{ + //ASSERT((cellId >=0)&& (cellId < _maxId)); + int *vols = &_upCellIds[2 * cellId]; + unsigned char *types = &_upCellTypes[2 * cellId]; + for (int i = 0; i < 2; i++) + { + if (vols[i] < 0) + { + vols[i] = upCellId; // use non affected volume + types[i] = aType; + return; + } + if ((vols[i] == upCellId) && (types[i] == aType)) // already done + return; + } + ASSERT(0); +} + +int SMDS_Down2D::getNodeSet(int cellId, int* nodeSet) +{ + for (int i = 0; i < _nbNodes; i++) + nodeSet[i] = _tempNodes[_nbNodes * cellId + i]; + return _nbNodes; +} + +int SMDS_Down2D::FindEdgeByNodes(int cellId, ElemByNodesType& edgeByNodes) +{ + int *edges = &_cellIds[_nbDownCells * cellId]; + for (int i = 0; i < _nbDownCells; i++) + { + if ((edges[i] >= 0) && (edgeByNodes.vtkType == _cellTypes[i])) + { + int nodeSet[3]; + int npts = this->_grid->getDownArray(edgeByNodes.vtkType)->getNodeSet(edges[i], nodeSet); + bool found = false; + for (int j = 0; j < npts; j++) + { + int point = edgeByNodes.nodeIds[j]; + found = false; + for (int k = 0; k < npts; k++) + { + if (nodeSet[k] == point) + { + found = true; + break; + } + } + if (!found) + break; + } + if (found) + return edges[i]; + } + } + return -1; +} + +// --------------------------------------------------------------------------- + +SMDS_Down3D::SMDS_Down3D(SMDS_UnstructuredGrid *grid, int nbDownCells) : + SMDS_Downward(grid, nbDownCells) +{ +} + +SMDS_Down3D::~SMDS_Down3D() +{ +} + +void SMDS_Down3D::allocate(int nbElems) +{ + if (nbElems >= _vtkCellIds.size()) + { + _cellIds.resize(_nbDownCells * (nbElems + SMDS_Mesh::chunkSize), -1); + _vtkCellIds.resize(nbElems + SMDS_Mesh::chunkSize, -1); + } +} + +void SMDS_Down3D::compactStorage() +{ + // nothing to do, size was known before +} + +int SMDS_Down3D::getNumberOfUpCells(int cellId) +{ + return 0; +} + +const int* SMDS_Down3D::getUpCells(int cellId) +{ + return 0; +} + +const unsigned char* SMDS_Down3D::getUpTypes(int cellId) +{ + return 0; +} + +void SMDS_Down3D::getNodeIds(int cellId, std::set& nodeSet) +{ + int vtkId = this->_vtkCellIds[cellId]; + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(vtkId, npts, nodes); + for (int i = 0; i < npts; i++) + nodeSet.insert(nodes[i]); +} + +int SMDS_Down3D::FindFaceByNodes(int cellId, ElemByNodesType& faceByNodes) +{ + int *faces = &_cellIds[_nbDownCells * cellId]; + int npoints = 0; + + for (int i = 0; i < _nbDownCells; i++) + { + if ((faces[i] >= 0) && (faceByNodes.vtkType == _cellTypes[i])) + { + if (npoints == 0) + npoints = faceByNodes.nbNodes; + + int nodeSet[10]; + int npts = this->_grid->getDownArray(faceByNodes.vtkType)->getNodeSet(faces[i], nodeSet); + if (npts != npoints) + continue; // skip this face + bool found = false; + for (int j = 0; j < npts; j++) + { + int point = faceByNodes.nodeIds[j]; + found = false; + for (int k = 0; k < npts; k++) + { + if (nodeSet[k] == point) + { + found = true; + break; // point j is in the 2 faces, skip remaining k values + } + } + if (!found) + break; // point j is not in the 2 faces, skip the remaining tests + } + if (found) + return faces[i]; + } + } + return -1; +} + +// --------------------------------------------------------------------------- + +SMDS_DownEdge::SMDS_DownEdge(SMDS_UnstructuredGrid *grid) : + SMDS_Down1D(grid, 2) +{ + _cellTypes.push_back(VTK_VERTEX); + _cellTypes.push_back(VTK_VERTEX); +} + +SMDS_DownEdge::~SMDS_DownEdge() +{ +} + +// --------------------------------------------------------------------------- + +SMDS_DownQuadEdge::SMDS_DownQuadEdge(SMDS_UnstructuredGrid *grid) : + SMDS_Down1D(grid, 3) +{ + _cellTypes.push_back(VTK_VERTEX); + _cellTypes.push_back(VTK_VERTEX); + _cellTypes.push_back(VTK_VERTEX); +} + +SMDS_DownQuadEdge::~SMDS_DownQuadEdge() +{ +} + +// --------------------------------------------------------------------------- + +SMDS_DownTriangle::SMDS_DownTriangle(SMDS_UnstructuredGrid *grid) : + SMDS_Down2D(grid, 3) +{ + _cellTypes.push_back(VTK_LINE); + _cellTypes.push_back(VTK_LINE); + _cellTypes.push_back(VTK_LINE); + _nbNodes = 3; +} + +SMDS_DownTriangle::~SMDS_DownTriangle() +{ +} + +void SMDS_DownTriangle::computeEdgesWithNodes(int cellId, ListElemByNodesType& edgesWithNodes) +{ + int *nodes = &_tempNodes[_nbNodes * cellId]; + edgesWithNodes.nbElems = 3; + + edgesWithNodes.elems[0].nodeIds[0] = nodes[0]; + edgesWithNodes.elems[0].nodeIds[1] = nodes[1]; + edgesWithNodes.elems[0].nbNodes = 2; + edgesWithNodes.elems[0].vtkType = VTK_LINE; + + edgesWithNodes.elems[1].nodeIds[0] = nodes[1]; + edgesWithNodes.elems[1].nodeIds[1] = nodes[2]; + edgesWithNodes.elems[1].nbNodes = 2; + edgesWithNodes.elems[1].vtkType = VTK_LINE; + + edgesWithNodes.elems[2].nodeIds[0] = nodes[2]; + edgesWithNodes.elems[2].nodeIds[1] = nodes[0]; + edgesWithNodes.elems[2].nbNodes = 2; + edgesWithNodes.elems[2].vtkType = VTK_LINE; +} + +void SMDS_DownTriangle::addDownCell(int cellId, int lowCellId, unsigned char aType) +{ + //ASSERT((cellId >=0)&& (cellId < _maxId)); + //ASSERT(aType == VTK_LINE); + int *faces = &_cellIds[_nbDownCells * cellId]; + for (int i = 0; i < _nbDownCells; i++) + { + if (faces[i] < 0) + { + faces[i] = lowCellId; + return; + } + if (faces[i] == lowCellId) + return; + } + ASSERT(0); +} + +// --------------------------------------------------------------------------- + +SMDS_DownQuadTriangle::SMDS_DownQuadTriangle(SMDS_UnstructuredGrid *grid) : + SMDS_Down2D(grid, 3) +{ + _cellTypes.push_back(VTK_QUADRATIC_EDGE); + _cellTypes.push_back(VTK_QUADRATIC_EDGE); + _cellTypes.push_back(VTK_QUADRATIC_EDGE); + _nbNodes = 6; +} + +SMDS_DownQuadTriangle::~SMDS_DownQuadTriangle() +{ +} + +void SMDS_DownQuadTriangle::computeEdgesWithNodes(int cellId, ListElemByNodesType& edgesWithNodes) +{ + int *nodes = &_tempNodes[_nbNodes * cellId]; + edgesWithNodes.nbElems = 3; + + edgesWithNodes.elems[0].nodeIds[0] = nodes[0]; + edgesWithNodes.elems[0].nodeIds[1] = nodes[1]; + edgesWithNodes.elems[0].nodeIds[2] = nodes[3]; + edgesWithNodes.elems[0].nbNodes = 3; + edgesWithNodes.elems[0].vtkType = VTK_QUADRATIC_EDGE; + + edgesWithNodes.elems[1].nodeIds[0] = nodes[1]; + edgesWithNodes.elems[1].nodeIds[1] = nodes[2]; + edgesWithNodes.elems[1].nodeIds[2] = nodes[4]; + edgesWithNodes.elems[1].nbNodes = 3; + edgesWithNodes.elems[1].vtkType = VTK_QUADRATIC_EDGE; + + edgesWithNodes.elems[2].nodeIds[0] = nodes[2]; + edgesWithNodes.elems[2].nodeIds[1] = nodes[0]; + edgesWithNodes.elems[2].nodeIds[2] = nodes[5]; + edgesWithNodes.elems[2].nbNodes = 3; + edgesWithNodes.elems[2].vtkType = VTK_QUADRATIC_EDGE; +} + +void SMDS_DownQuadTriangle::addDownCell(int cellId, int lowCellId, unsigned char aType) +{ + //ASSERT((cellId >=0)&& (cellId < _maxId)); + //ASSERT(aType == VTK_QUADRATIC_EDGE); + int *edges = &_cellIds[_nbDownCells * cellId]; + for (int i = 0; i < _nbDownCells; i++) + { + if (edges[i] < 0) + { + edges[i] = lowCellId; + return; + } + if (edges[i] == lowCellId) + return; + } + ASSERT(0); +} + +// --------------------------------------------------------------------------- + +SMDS_DownQuadrangle::SMDS_DownQuadrangle(SMDS_UnstructuredGrid *grid) : + SMDS_Down2D(grid, 4) +{ + _cellTypes.push_back(VTK_LINE); + _cellTypes.push_back(VTK_LINE); + _cellTypes.push_back(VTK_LINE); + _cellTypes.push_back(VTK_LINE); + _nbNodes = 4; +} + +SMDS_DownQuadrangle::~SMDS_DownQuadrangle() +{ +} + +void SMDS_DownQuadrangle::computeEdgesWithNodes(int cellId, ListElemByNodesType& edgesWithNodes) +{ + int *nodes = &_tempNodes[_nbNodes * cellId]; + edgesWithNodes.nbElems = 4; + + edgesWithNodes.elems[0].nodeIds[0] = nodes[0]; + edgesWithNodes.elems[0].nodeIds[1] = nodes[1]; + edgesWithNodes.elems[0].nbNodes = 2; + edgesWithNodes.elems[0].vtkType = VTK_LINE; + + edgesWithNodes.elems[1].nodeIds[0] = nodes[1]; + edgesWithNodes.elems[1].nodeIds[1] = nodes[2]; + edgesWithNodes.elems[1].nbNodes = 2; + edgesWithNodes.elems[1].vtkType = VTK_LINE; + + edgesWithNodes.elems[2].nodeIds[0] = nodes[2]; + edgesWithNodes.elems[2].nodeIds[1] = nodes[3]; + edgesWithNodes.elems[2].nbNodes = 2; + edgesWithNodes.elems[2].vtkType = VTK_LINE; + + edgesWithNodes.elems[3].nodeIds[0] = nodes[3]; + edgesWithNodes.elems[3].nodeIds[1] = nodes[0]; + edgesWithNodes.elems[3].nbNodes = 2; + edgesWithNodes.elems[3].vtkType = VTK_LINE; +} + +void SMDS_DownQuadrangle::addDownCell(int cellId, int lowCellId, unsigned char aType) +{ + //ASSERT((cellId >=0)&& (cellId < _maxId)); + //ASSERT(aType == VTK_LINE); + int *faces = &_cellIds[_nbDownCells * cellId]; + for (int i = 0; i < _nbDownCells; i++) + { + if (faces[i] < 0) + { + faces[i] = lowCellId; + return; + } + if (faces[i] == lowCellId) + return; + } + ASSERT(0); +} + +// --------------------------------------------------------------------------- + +SMDS_DownQuadQuadrangle::SMDS_DownQuadQuadrangle(SMDS_UnstructuredGrid *grid) : + SMDS_Down2D(grid, 4) +{ + _cellTypes.push_back(VTK_QUADRATIC_EDGE); + _cellTypes.push_back(VTK_QUADRATIC_EDGE); + _cellTypes.push_back(VTK_QUADRATIC_EDGE); + _cellTypes.push_back(VTK_QUADRATIC_EDGE); + _nbNodes = 8; +} + +SMDS_DownQuadQuadrangle::~SMDS_DownQuadQuadrangle() +{ +} + +void SMDS_DownQuadQuadrangle::computeEdgesWithNodes(int cellId, ListElemByNodesType& edgesWithNodes) +{ + int *nodes = &_tempNodes[_nbNodes * cellId]; + edgesWithNodes.nbElems = 4; + + edgesWithNodes.elems[0].nodeIds[0] = nodes[0]; + edgesWithNodes.elems[0].nodeIds[1] = nodes[1]; + edgesWithNodes.elems[0].nodeIds[2] = nodes[4]; + edgesWithNodes.elems[0].nbNodes = 3; + edgesWithNodes.elems[0].vtkType = VTK_QUADRATIC_EDGE; + + edgesWithNodes.elems[1].nodeIds[0] = nodes[1]; + edgesWithNodes.elems[1].nodeIds[1] = nodes[2]; + edgesWithNodes.elems[1].nodeIds[2] = nodes[5]; + edgesWithNodes.elems[1].nbNodes = 3; + edgesWithNodes.elems[1].vtkType = VTK_QUADRATIC_EDGE; + + edgesWithNodes.elems[2].nodeIds[0] = nodes[2]; + edgesWithNodes.elems[2].nodeIds[1] = nodes[3]; + edgesWithNodes.elems[2].nodeIds[2] = nodes[6]; + edgesWithNodes.elems[2].nbNodes = 3; + edgesWithNodes.elems[2].vtkType = VTK_QUADRATIC_EDGE; + + edgesWithNodes.elems[3].nodeIds[0] = nodes[3]; + edgesWithNodes.elems[3].nodeIds[1] = nodes[0]; + edgesWithNodes.elems[3].nodeIds[2] = nodes[7]; + edgesWithNodes.elems[3].nbNodes = 3; + edgesWithNodes.elems[3].vtkType = VTK_QUADRATIC_EDGE; +} + +void SMDS_DownQuadQuadrangle::addDownCell(int cellId, int lowCellId, unsigned char aType) +{ + //ASSERT((cellId >=0)&& (cellId < _maxId)); + //ASSERT(aType == VTK_QUADRATIC_EDGE); + int *faces = &_cellIds[_nbDownCells * cellId]; + for (int i = 0; i < _nbDownCells; i++) + { + if (faces[i] < 0) + { + faces[i] = lowCellId; + return; + } + if (faces[i] == lowCellId) + return; + } + ASSERT(0); +} + +// --------------------------------------------------------------------------- + +SMDS_DownTetra::SMDS_DownTetra(SMDS_UnstructuredGrid *grid) : + SMDS_Down3D(grid, 4) +{ + _cellTypes.push_back(VTK_TRIANGLE); + _cellTypes.push_back(VTK_TRIANGLE); + _cellTypes.push_back(VTK_TRIANGLE); + _cellTypes.push_back(VTK_TRIANGLE); +} + +SMDS_DownTetra::~SMDS_DownTetra() +{ +} + +void SMDS_DownTetra::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + set setNodes; + setNodes.clear(); + for (int i = 0; i < orderedNodes.size(); i++) + setNodes.insert(orderedNodes[i]); + //MESSAGE("cellId = " << cellId); + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(this->_vtkCellIds[cellId], npts, nodes); + + set tofind; + int ids[12] = { 0, 1, 2, 0, 3, 1, 2, 3, 0, 1, 3, 2 }; +//int ids[12] = { 2, 1, 0, 1, 3, 0, 0, 3, 2, 2, 3, 1 }; + for (int k = 0; k < 4; k++) + { + tofind.clear(); + for (int i = 0; i < 3; i++) + tofind.insert(nodes[ids[3 * k + i]]); + if (setNodes == tofind) + { + for (int i = 0; i < 3; i++) + orderedNodes[i] = nodes[ids[3 * k + i]]; + return; + } + } + MESSAGE("=== Problem volume " << _vtkCellIds[cellId] << " " << _grid->_mesh->fromVtkToSmds(_vtkCellIds[cellId])); + MESSAGE(orderedNodes[0] << " " << orderedNodes[1] << " " << orderedNodes[2]); + MESSAGE(nodes[0] << " " << nodes[1] << " " << nodes[2] << " " << nodes[3]); +} + +void SMDS_DownTetra::addDownCell(int cellId, int lowCellId, unsigned char aType) +{ + //ASSERT((cellId >=0)&& (cellId < _maxId)); + //ASSERT(aType == VTK_TRIANGLE); + int *faces = &_cellIds[_nbDownCells * cellId]; + for (int i = 0; i < _nbDownCells; i++) + { + if (faces[i] < 0) + { + faces[i] = lowCellId; + return; + } + if (faces[i] == lowCellId) + return; + } + ASSERT(0); +} + +/*! Create a list of faces described by a vtk Type and an ordered set of Node Id's + * The linear tetrahedron is defined by four points. + * @see vtkTetra.h in Filtering. + * @param cellId volumeId in vtkUnstructuredGrid + * @param facesWithNodes vector of face descriptors to be filled + */ +void SMDS_DownTetra::computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes) +{ + // --- find point id's of the volume + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(cellId, npts, nodes); + + // --- create all the ordered list of node id's for each face + + facesWithNodes.nbElems = 4; + + facesWithNodes.elems[0].nodeIds[0] = nodes[0]; + facesWithNodes.elems[0].nodeIds[1] = nodes[1]; + facesWithNodes.elems[0].nodeIds[2] = nodes[2]; + facesWithNodes.elems[0].nbNodes = 3; + facesWithNodes.elems[0].vtkType = VTK_TRIANGLE; + + facesWithNodes.elems[1].nodeIds[0] = nodes[0]; + facesWithNodes.elems[1].nodeIds[1] = nodes[1]; + facesWithNodes.elems[1].nodeIds[2] = nodes[3]; + facesWithNodes.elems[1].nbNodes = 3; + facesWithNodes.elems[1].vtkType = VTK_TRIANGLE; + + facesWithNodes.elems[2].nodeIds[0] = nodes[0]; + facesWithNodes.elems[2].nodeIds[1] = nodes[2]; + facesWithNodes.elems[2].nodeIds[2] = nodes[3]; + facesWithNodes.elems[2].nbNodes = 3; + facesWithNodes.elems[2].vtkType = VTK_TRIANGLE; + + facesWithNodes.elems[3].nodeIds[0] = nodes[1]; + facesWithNodes.elems[3].nodeIds[1] = nodes[2]; + facesWithNodes.elems[3].nodeIds[2] = nodes[3]; + facesWithNodes.elems[3].nbNodes = 3; + facesWithNodes.elems[3].vtkType = VTK_TRIANGLE; +} + +// --------------------------------------------------------------------------- + +SMDS_DownQuadTetra::SMDS_DownQuadTetra(SMDS_UnstructuredGrid *grid) : + SMDS_Down3D(grid, 4) +{ + _cellTypes.push_back(VTK_QUADRATIC_TRIANGLE); + _cellTypes.push_back(VTK_QUADRATIC_TRIANGLE); + _cellTypes.push_back(VTK_QUADRATIC_TRIANGLE); + _cellTypes.push_back(VTK_QUADRATIC_TRIANGLE); +} + +SMDS_DownQuadTetra::~SMDS_DownQuadTetra() +{ +} + +void SMDS_DownQuadTetra::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + set setNodes; + setNodes.clear(); + for (int i = 0; i < orderedNodes.size(); i++) + setNodes.insert(orderedNodes[i]); + //MESSAGE("cellId = " << cellId); + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(this->_vtkCellIds[cellId], npts, nodes); + + set tofind; + int ids[24] = { 0, 1, 2, 4, 5, 6, 0, 3, 1, 7, 8, 4, 2, 3, 0, 9, 7, 6, 1, 3, 2, 8, 9, 5 }; +//int ids[24] = { 2, 1, 0, 5, 4, 6, 1, 3, 0, 8, 7, 4, 0, 3, 2, 7, 9, 6, 2, 3, 1, 9, 8, 5 }; + for (int k = 0; k < 4; k++) + { + tofind.clear(); + for (int i = 0; i < 6; i++) + tofind.insert(nodes[ids[6 * k + i]]); + if (setNodes == tofind) + { + for (int i = 0; i < 6; i++) + orderedNodes[i] = nodes[ids[6 * k + i]]; + return; + } + } + MESSAGE("=== Problem volume " << _vtkCellIds[cellId] << " " << _grid->_mesh->fromVtkToSmds(_vtkCellIds[cellId])); + MESSAGE(orderedNodes[0] << " " << orderedNodes[1] << " " << orderedNodes[2]); + MESSAGE(nodes[0] << " " << nodes[1] << " " << nodes[2] << " " << nodes[3]); +} + +void SMDS_DownQuadTetra::addDownCell(int cellId, int lowCellId, unsigned char aType) +{ + //ASSERT((cellId >=0)&& (cellId < _maxId)); + //ASSERT(aType == VTK_QUADRATIC_TRIANGLE); + int *faces = &_cellIds[_nbDownCells * cellId]; + for (int i = 0; i < _nbDownCells; i++) + { + if (faces[i] < 0) + { + faces[i] = lowCellId; + return; + } + if (faces[i] == lowCellId) + return; + } + ASSERT(0); +} + +/*! Create a list of faces described by a vtk Type and an ordered set of Node Id's + * The ordering of the ten points defining the quadratic tetrahedron cell is point id's (0-3,4-9) + * where id's 0-3 are the four tetrahedron vertices; + * and point id's 4-9 are the mid-edge nodes between (0,1), (1,2), (2,0), (0,3), (1,3), and (2,3). + * @see vtkQuadraticTetra.h in Filtering. + * @param cellId volumeId in vtkUnstructuredGrid + * @param facesWithNodes vector of face descriptors to be filled + */ +void SMDS_DownQuadTetra::computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes) +{ + // --- find point id's of the volume + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(cellId, npts, nodes); + + // --- create all the ordered list of node id's for each face + + facesWithNodes.nbElems = 4; + + facesWithNodes.elems[0].nodeIds[0] = nodes[0]; + facesWithNodes.elems[0].nodeIds[1] = nodes[1]; + facesWithNodes.elems[0].nodeIds[2] = nodes[2]; + facesWithNodes.elems[0].nodeIds[3] = nodes[4]; + facesWithNodes.elems[0].nodeIds[4] = nodes[5]; + facesWithNodes.elems[0].nodeIds[5] = nodes[6]; + facesWithNodes.elems[0].nbNodes = 6; + facesWithNodes.elems[0].vtkType = VTK_QUADRATIC_TRIANGLE; + + facesWithNodes.elems[1].nodeIds[0] = nodes[0]; + facesWithNodes.elems[1].nodeIds[1] = nodes[1]; + facesWithNodes.elems[1].nodeIds[2] = nodes[3]; + facesWithNodes.elems[1].nodeIds[3] = nodes[4]; + facesWithNodes.elems[1].nodeIds[4] = nodes[8]; + facesWithNodes.elems[1].nodeIds[5] = nodes[7]; + facesWithNodes.elems[1].nbNodes = 6; + facesWithNodes.elems[1].vtkType = VTK_QUADRATIC_TRIANGLE; + + facesWithNodes.elems[2].nodeIds[0] = nodes[0]; + facesWithNodes.elems[2].nodeIds[1] = nodes[2]; + facesWithNodes.elems[2].nodeIds[2] = nodes[3]; + facesWithNodes.elems[2].nodeIds[3] = nodes[6]; + facesWithNodes.elems[2].nodeIds[4] = nodes[9]; + facesWithNodes.elems[2].nodeIds[5] = nodes[7]; + facesWithNodes.elems[2].nbNodes = 6; + facesWithNodes.elems[2].vtkType = VTK_QUADRATIC_TRIANGLE; + + facesWithNodes.elems[3].nodeIds[0] = nodes[1]; + facesWithNodes.elems[3].nodeIds[1] = nodes[2]; + facesWithNodes.elems[3].nodeIds[2] = nodes[3]; + facesWithNodes.elems[3].nodeIds[3] = nodes[5]; + facesWithNodes.elems[3].nodeIds[4] = nodes[9]; + facesWithNodes.elems[3].nodeIds[5] = nodes[8]; + facesWithNodes.elems[3].nbNodes = 6; + facesWithNodes.elems[3].vtkType = VTK_QUADRATIC_TRIANGLE; +} + +// --------------------------------------------------------------------------- + +SMDS_DownPyramid::SMDS_DownPyramid(SMDS_UnstructuredGrid *grid) : + SMDS_Down3D(grid, 5) +{ + _cellTypes.push_back(VTK_QUAD); + _cellTypes.push_back(VTK_TRIANGLE); + _cellTypes.push_back(VTK_TRIANGLE); + _cellTypes.push_back(VTK_TRIANGLE); + _cellTypes.push_back(VTK_TRIANGLE); +} + +SMDS_DownPyramid::~SMDS_DownPyramid() +{ +} + +void SMDS_DownPyramid::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + set setNodes; + setNodes.clear(); + for (int i = 0; i < orderedNodes.size(); i++) + setNodes.insert(orderedNodes[i]); + //MESSAGE("cellId = " << cellId); + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(this->_vtkCellIds[cellId], npts, nodes); + + set tofind; + int ids[16] = { 0, 1, 2, 3, 0, 3, 4, 3, 2, 4, 2, 1, 4, 1, 0, 4 }; + + // Quadrangular face + tofind.clear(); + for (int i = 0; i < 4; i++) + tofind.insert(nodes[ids[i]]); + if (setNodes == tofind) + { + for (int i = 0; i < 4; i++) + orderedNodes[i] = nodes[ids[i]]; + return; + } + // Triangular faces + for (int k = 0; k < 4; k++) + { + tofind.clear(); + for (int i = 0; i < 3; i++) + tofind.insert(nodes[ids[4 + 3 * k + i]]); + if (setNodes == tofind) + { + for (int i = 0; i < 3; i++) + orderedNodes[i] = nodes[ids[4 + 3 * k + i]]; + return; + } + } + MESSAGE("=== Problem volume " << _vtkCellIds[cellId] << " " << _grid->_mesh->fromVtkToSmds(_vtkCellIds[cellId])); + MESSAGE(orderedNodes[0] << " " << orderedNodes[1] << " " << orderedNodes[2]); + MESSAGE(nodes[0] << " " << nodes[1] << " " << nodes[2] << " " << nodes[3]); +} + +void SMDS_DownPyramid::addDownCell(int cellId, int lowCellId, unsigned char aType) +{ + //ASSERT((cellId >=0) && (cellId < _maxId)); + int *faces = &_cellIds[_nbDownCells * cellId]; + if (aType == VTK_QUAD) + { + if (faces[0] < 0) + { + faces[0] = lowCellId; + return; + } + if (faces[0] == lowCellId) + return; + } + else + { + //ASSERT(aType == VTK_TRIANGLE); + for (int i = 1; i < _nbDownCells; i++) + { + if (faces[i] < 0) + { + faces[i] = lowCellId; + return; + } + if (faces[i] == lowCellId) + return; + } + } + ASSERT(0); +} + +/*! Create a list of faces described by a vtk Type and an ordered set of Node Id's + * The pyramid is defined by the five points (0-4) where (0,1,2,3) is the base of the pyramid which, + * using the right hand rule, forms a quadrilateral whose normal points in the direction of the + * pyramid apex at vertex #4. + * @see vtkPyramid.h in Filtering. + * @param cellId volumeId in vtkUnstructuredGrid + * @param facesWithNodes vector of face descriptors to be filled + */ +void SMDS_DownPyramid::computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes) +{ + // --- find point id's of the volume + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(cellId, npts, nodes); + + // --- create all the ordered list of node id's for each face + + facesWithNodes.nbElems = 5; + + facesWithNodes.elems[0].nodeIds[0] = nodes[0]; + facesWithNodes.elems[0].nodeIds[1] = nodes[1]; + facesWithNodes.elems[0].nodeIds[2] = nodes[2]; + facesWithNodes.elems[0].nodeIds[3] = nodes[3]; + facesWithNodes.elems[0].nbNodes = 4; + facesWithNodes.elems[0].vtkType = VTK_QUAD; + + facesWithNodes.elems[1].nodeIds[0] = nodes[0]; + facesWithNodes.elems[1].nodeIds[1] = nodes[1]; + facesWithNodes.elems[1].nodeIds[2] = nodes[4]; + facesWithNodes.elems[1].nbNodes = 3; + facesWithNodes.elems[1].vtkType = VTK_TRIANGLE; + + facesWithNodes.elems[2].nodeIds[0] = nodes[1]; + facesWithNodes.elems[2].nodeIds[1] = nodes[2]; + facesWithNodes.elems[2].nodeIds[2] = nodes[4]; + facesWithNodes.elems[2].nbNodes = 3; + facesWithNodes.elems[2].vtkType = VTK_TRIANGLE; + + facesWithNodes.elems[3].nodeIds[0] = nodes[2]; + facesWithNodes.elems[3].nodeIds[1] = nodes[3]; + facesWithNodes.elems[3].nodeIds[2] = nodes[4]; + facesWithNodes.elems[3].nbNodes = 3; + facesWithNodes.elems[3].vtkType = VTK_TRIANGLE; + + facesWithNodes.elems[4].nodeIds[0] = nodes[3]; + facesWithNodes.elems[4].nodeIds[1] = nodes[0]; + facesWithNodes.elems[4].nodeIds[2] = nodes[4]; + facesWithNodes.elems[4].nbNodes = 3; + facesWithNodes.elems[4].vtkType = VTK_TRIANGLE; +} + +// --------------------------------------------------------------------------- + +SMDS_DownQuadPyramid::SMDS_DownQuadPyramid(SMDS_UnstructuredGrid *grid) : + SMDS_Down3D(grid, 5) +{ + _cellTypes.push_back(VTK_QUADRATIC_QUAD); + _cellTypes.push_back(VTK_QUADRATIC_TRIANGLE); + _cellTypes.push_back(VTK_QUADRATIC_TRIANGLE); + _cellTypes.push_back(VTK_QUADRATIC_TRIANGLE); + _cellTypes.push_back(VTK_QUADRATIC_TRIANGLE); +} + +SMDS_DownQuadPyramid::~SMDS_DownQuadPyramid() +{ +} + +void SMDS_DownQuadPyramid::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ +// MESSAGE("SMDS_DownQuadPyramid::getOrderedNodesOfFace cellId = " << cellId); + set setNodes; + setNodes.clear(); + for (int i = 0; i < orderedNodes.size(); i++) + setNodes.insert(orderedNodes[i]); + //MESSAGE("cellId = " << cellId); + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(this->_vtkCellIds[cellId], npts, nodes); + + set tofind; + int ids[32] = { 0, 1, 2, 3, 5, 6, 7, 8, + 0, 3, 4, 8, 12, 9, 3, 2, 4, 7 , 11, 12, 2, 1, 4, 6, 10, 11, 1, 0, 4, 5, 9, 10 }; + + // Quadrangular face + tofind.clear(); + for (int i = 0; i < 8; i++) + tofind.insert(nodes[ids[i]]); + if (setNodes == tofind) + { + for (int i = 0; i < 8; i++) + orderedNodes[i] = nodes[ids[i]]; + return; + } + // Triangular faces + for (int k = 0; k < 4; k++) + { + tofind.clear(); + for (int i = 0; i < 6; i++) + tofind.insert(nodes[ids[8 + 6 * k + i]]); + if (setNodes == tofind) + { + for (int i = 0; i < 6; i++) + orderedNodes[i] = nodes[ids[8 + 6 * k + i]]; + return; + } + } + MESSAGE("=== Problem volume " << _vtkCellIds[cellId] << " " << _grid->_mesh->fromVtkToSmds(_vtkCellIds[cellId])); + MESSAGE(orderedNodes[0] << " " << orderedNodes[1] << " " << orderedNodes[2] << " " << orderedNodes[3]); + MESSAGE(nodes[0] << " " << nodes[1] << " " << nodes[2] << " " << nodes[3]); +} + +void SMDS_DownQuadPyramid::addDownCell(int cellId, int lowCellId, unsigned char aType) +{ + //ASSERT((cellId >=0) && (cellId < _maxId)); + int *faces = &_cellIds[_nbDownCells * cellId]; + if (aType == VTK_QUADRATIC_QUAD) + { + if (faces[0] < 0) + { + faces[0] = lowCellId; + return; + } + if (faces[0] == lowCellId) + return; + } + else + { + //ASSERT(aType == VTK_QUADRATIC_TRIANGLE); + for (int i = 1; i < _nbDownCells; i++) + { + if (faces[i] < 0) + { + faces[i] = lowCellId; + return; + } + if (faces[i] == lowCellId) + return; + } + } + ASSERT(0); +} + +/*! Create a list of faces described by a vtk Type and an ordered set of Node Id's + * The ordering of the thirteen points defining the quadratic pyramid cell is point id's (0-4,5-12) + * where point id's 0-4 are the five corner vertices of the pyramid; followed + * by eight mid-edge nodes (5-12). Note that these mid-edge nodes lie on the edges defined by + * 5(0,1), 6(1,2), 7(2,3), 8(3,0), 9(0,4), 10(1,4), 11(2,4), 12(3,4). + * @see vtkQuadraticPyramid.h in Filtering. + * @param cellId volumeId in vtkUnstructuredGrid + * @param facesWithNodes vector of face descriptors to be filled + */ +void SMDS_DownQuadPyramid::computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes) +{ + // --- find point id's of the volume + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(cellId, npts, nodes); + + // --- create all the ordered list of node id's for each face + + facesWithNodes.nbElems = 5; + + facesWithNodes.elems[0].nodeIds[0] = nodes[0]; + facesWithNodes.elems[0].nodeIds[1] = nodes[1]; + facesWithNodes.elems[0].nodeIds[2] = nodes[2]; + facesWithNodes.elems[0].nodeIds[3] = nodes[3]; + facesWithNodes.elems[0].nodeIds[4] = nodes[5]; + facesWithNodes.elems[0].nodeIds[5] = nodes[6]; + facesWithNodes.elems[0].nodeIds[6] = nodes[7]; + facesWithNodes.elems[0].nodeIds[7] = nodes[8]; + facesWithNodes.elems[0].nbNodes = 8; + facesWithNodes.elems[0].vtkType = VTK_QUADRATIC_QUAD; + + facesWithNodes.elems[1].nodeIds[0] = nodes[0]; + facesWithNodes.elems[1].nodeIds[1] = nodes[1]; + facesWithNodes.elems[1].nodeIds[2] = nodes[4]; + facesWithNodes.elems[1].nodeIds[3] = nodes[5]; + facesWithNodes.elems[1].nodeIds[4] = nodes[10]; + facesWithNodes.elems[1].nodeIds[5] = nodes[9]; + facesWithNodes.elems[1].nbNodes = 6; + facesWithNodes.elems[1].vtkType = VTK_QUADRATIC_TRIANGLE; + + facesWithNodes.elems[2].nodeIds[0] = nodes[1]; + facesWithNodes.elems[2].nodeIds[1] = nodes[2]; + facesWithNodes.elems[2].nodeIds[2] = nodes[4]; + facesWithNodes.elems[2].nodeIds[3] = nodes[6]; + facesWithNodes.elems[2].nodeIds[4] = nodes[11]; + facesWithNodes.elems[2].nodeIds[5] = nodes[10]; + facesWithNodes.elems[2].nbNodes = 6; + facesWithNodes.elems[2].vtkType = VTK_QUADRATIC_TRIANGLE; + + facesWithNodes.elems[3].nodeIds[0] = nodes[2]; + facesWithNodes.elems[3].nodeIds[1] = nodes[3]; + facesWithNodes.elems[3].nodeIds[2] = nodes[4]; + facesWithNodes.elems[3].nodeIds[3] = nodes[7]; + facesWithNodes.elems[3].nodeIds[4] = nodes[12]; + facesWithNodes.elems[3].nodeIds[5] = nodes[11]; + facesWithNodes.elems[3].nbNodes = 6; + facesWithNodes.elems[3].vtkType = VTK_QUADRATIC_TRIANGLE; + + facesWithNodes.elems[4].nodeIds[0] = nodes[3]; + facesWithNodes.elems[4].nodeIds[1] = nodes[0]; + facesWithNodes.elems[4].nodeIds[2] = nodes[4]; + facesWithNodes.elems[4].nodeIds[3] = nodes[8]; + facesWithNodes.elems[4].nodeIds[4] = nodes[9]; + facesWithNodes.elems[4].nodeIds[5] = nodes[12]; + facesWithNodes.elems[4].nbNodes = 6; + facesWithNodes.elems[4].vtkType = VTK_QUADRATIC_TRIANGLE; +} + +// --------------------------------------------------------------------------- + +SMDS_DownPenta::SMDS_DownPenta(SMDS_UnstructuredGrid *grid) : + SMDS_Down3D(grid, 5) +{ + _cellTypes.push_back(VTK_QUAD); + _cellTypes.push_back(VTK_QUAD); + _cellTypes.push_back(VTK_QUAD); + _cellTypes.push_back(VTK_TRIANGLE); + _cellTypes.push_back(VTK_TRIANGLE); +} + +SMDS_DownPenta::~SMDS_DownPenta() +{ +} + +void SMDS_DownPenta::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + set setNodes; + setNodes.clear(); + for (int i = 0; i < orderedNodes.size(); i++) + setNodes.insert(orderedNodes[i]); + //MESSAGE("cellId = " << cellId); + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(this->_vtkCellIds[cellId], npts, nodes); + + set tofind; +//int ids[18] = { 0, 2, 1, 3, 4, 5, 0, 1, 4, 3, 1, 2, 5, 4, 2, 0, 3, 5 }; + int ids[18] = { 0, 1, 2, 3, 5, 4, 0, 3, 4, 1, 1, 4, 5, 2, 2, 5, 3, 0 }; + + // Triangular faces + for (int k = 0; k < 2; k++) + { + tofind.clear(); + for (int i = 0; i < 3; i++) + tofind.insert(nodes[ids[3 * k + i]]); + if (setNodes == tofind) + { + for (int i = 0; i < 3; i++) + orderedNodes[i] = nodes[ids[3 * k + i]]; + return; + } + } + // Quadrangular faces + for (int k = 0; k < 3; k++) + { + tofind.clear(); + for (int i = 0; i < 4; i++) + tofind.insert(nodes[ids[6 + 4 * k + i]]); + if (setNodes == tofind) + { + for (int i = 0; i < 4; i++) + orderedNodes[i] = nodes[ids[6 + 4 * k + i]]; + return; + } + } + MESSAGE("=== Problem volume " << _vtkCellIds[cellId] << " " << _grid->_mesh->fromVtkToSmds(_vtkCellIds[cellId])); + MESSAGE(orderedNodes[0] << " " << orderedNodes[1] << " " << orderedNodes[2]); + MESSAGE(nodes[0] << " " << nodes[1] << " " << nodes[2] << " " << nodes[3]); +} + +void SMDS_DownPenta::addDownCell(int cellId, int lowCellId, unsigned char aType) +{ + //ASSERT((cellId >=0) && (cellId < _maxId)); + int *faces = &_cellIds[_nbDownCells * cellId]; + if (aType == VTK_QUAD) + for (int i = 0; i < 3; i++) + { + if (faces[i] < 0) + { + faces[i] = lowCellId; + return; + } + if (faces[i] == lowCellId) + return; + } + else + { + //ASSERT(aType == VTK_TRIANGLE); + for (int i = 3; i < _nbDownCells; i++) + { + if (faces[i] < 0) + { + faces[i] = lowCellId; + return; + } + if (faces[i] == lowCellId) + return; + } + } + ASSERT(0); +} + +/*! Create a list of faces described by a vtk Type and an ordered set of Node Id's. + * A wedge or pentahedron consists of two triangular and three quadrilateral faces + * and is defined by the six points (0-5) where (0,1,2) is the base of the wedge which, + * using the right hand rule, forms a triangle whose normal points outward + * (away from the triangular face (3,4,5)). + * @see vtkWedge.h in Filtering + * @param cellId volumeId in vtkUnstructuredGrid + * @param facesWithNodes vector of face descriptors to be filled + */ +void SMDS_DownPenta::computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes) +{ + // --- find point id's of the volume + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(cellId, npts, nodes); + + // --- create all the ordered list of node id's for each face + + facesWithNodes.nbElems = 5; + + facesWithNodes.elems[0].nodeIds[0] = nodes[0]; + facesWithNodes.elems[0].nodeIds[1] = nodes[2]; + facesWithNodes.elems[0].nodeIds[2] = nodes[5]; + facesWithNodes.elems[0].nodeIds[3] = nodes[3]; + facesWithNodes.elems[0].nbNodes = 4; + facesWithNodes.elems[0].vtkType = VTK_QUAD; + + facesWithNodes.elems[1].nodeIds[0] = nodes[1]; + facesWithNodes.elems[1].nodeIds[1] = nodes[2]; + facesWithNodes.elems[1].nodeIds[2] = nodes[5]; + facesWithNodes.elems[1].nodeIds[3] = nodes[4]; + facesWithNodes.elems[1].nbNodes = 4; + facesWithNodes.elems[1].vtkType = VTK_QUAD; + + facesWithNodes.elems[2].nodeIds[0] = nodes[0]; + facesWithNodes.elems[2].nodeIds[1] = nodes[1]; + facesWithNodes.elems[2].nodeIds[2] = nodes[4]; + facesWithNodes.elems[2].nodeIds[3] = nodes[3]; + facesWithNodes.elems[2].nbNodes = 4; + facesWithNodes.elems[2].vtkType = VTK_QUAD; + + facesWithNodes.elems[3].nodeIds[0] = nodes[0]; + facesWithNodes.elems[3].nodeIds[1] = nodes[1]; + facesWithNodes.elems[3].nodeIds[2] = nodes[2]; + facesWithNodes.elems[3].nbNodes = 3; + facesWithNodes.elems[3].vtkType = VTK_TRIANGLE; + + facesWithNodes.elems[4].nodeIds[0] = nodes[3]; + facesWithNodes.elems[4].nodeIds[1] = nodes[4]; + facesWithNodes.elems[4].nodeIds[2] = nodes[5]; + facesWithNodes.elems[4].nbNodes = 3; + facesWithNodes.elems[4].vtkType = VTK_TRIANGLE; +} + +// --------------------------------------------------------------------------- + +SMDS_DownQuadPenta::SMDS_DownQuadPenta(SMDS_UnstructuredGrid *grid) : + SMDS_Down3D(grid, 5) +{ + _cellTypes.push_back(VTK_QUADRATIC_QUAD); + _cellTypes.push_back(VTK_QUADRATIC_QUAD); + _cellTypes.push_back(VTK_QUADRATIC_QUAD); + _cellTypes.push_back(VTK_QUADRATIC_TRIANGLE); + _cellTypes.push_back(VTK_QUADRATIC_TRIANGLE); +} + +SMDS_DownQuadPenta::~SMDS_DownQuadPenta() +{ +} + +void SMDS_DownQuadPenta::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + set setNodes; + setNodes.clear(); + for (int i = 0; i < orderedNodes.size(); i++) + setNodes.insert(orderedNodes[i]); + //MESSAGE("cellId = " << cellId); + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(this->_vtkCellIds[cellId], npts, nodes); + + set tofind; +//int ids[18] = { 0, 2, 1, 3, 4, 5, 0, 1, 4, 3, 1, 2, 5, 4, 2, 0, 3, 5 }; + int ids[36] = { 0, 1, 2, 6, 7, 8, 3, 5, 4, 11, 10, 9, + 0, 3, 4, 1, 12, 9, 13, 6, 1, 4, 5, 2, 13, 10, 14, 7, 2, 5, 3, 0, 14, 11, 12, 8 }; + + // Triangular faces + for (int k = 0; k < 2; k++) + { + tofind.clear(); + for (int i = 0; i < 6; i++) + tofind.insert(nodes[ids[6 * k + i]]); + if (setNodes == tofind) + { + for (int i = 0; i < 6; i++) + orderedNodes[i] = nodes[ids[6 * k + i]]; + return; + } + } + // Quadrangular faces + for (int k = 0; k < 3; k++) + { + tofind.clear(); + for (int i = 0; i < 8; i++) + tofind.insert(nodes[ids[12 + 8 * k + i]]); + if (setNodes == tofind) + { + for (int i = 0; i < 8; i++) + orderedNodes[i] = nodes[ids[12 + 8 * k + i]]; + return; + } + } + MESSAGE("=== Problem volume " << _vtkCellIds[cellId] << " " << _grid->_mesh->fromVtkToSmds(_vtkCellIds[cellId])); + MESSAGE(orderedNodes[0] << " " << orderedNodes[1] << " " << orderedNodes[2]); + MESSAGE(nodes[0] << " " << nodes[1] << " " << nodes[2] << " " << nodes[3]); +} + +void SMDS_DownQuadPenta::addDownCell(int cellId, int lowCellId, unsigned char aType) +{ + //ASSERT((cellId >=0) && (cellId < _maxId)); + int *faces = &_cellIds[_nbDownCells * cellId]; + if (aType == VTK_QUADRATIC_QUAD) + for (int i = 0; i < 3; i++) + { + if (faces[i] < 0) + { + faces[i] = lowCellId; + return; + } + if (faces[i] == lowCellId) + return; + } + else + { + //ASSERT(aType == VTK_QUADRATIC_TRIANGLE); + for (int i = 3; i < _nbDownCells; i++) + { + if (faces[i] < 0) + { + faces[i] = lowCellId; + return; + } + if (faces[i] == lowCellId) + return; + } + } + ASSERT(0); +} + +/*! Create a list of faces described by a vtk Type and an ordered set of Node Id's + * The quadratic wedge (or pentahedron) is defined by fifteen points. + * The ordering of the fifteen points defining the cell is point id's (0-5,6-14) + * where point id's 0-5 are the six corner vertices of the wedge, followed by + * nine mid-edge nodes (6-14). Note that these mid-edge nodes lie on the edges defined by + * (0,1), (1,2), (2,0), (3,4), (4,5), (5,3), (0,3), (1,4), (2,5). + * @see vtkQuadraticWedge.h in Filtering + * @param cellId volumeId in vtkUnstructuredGrid + * @param facesWithNodes vector of face descriptors to be filled + */ +void SMDS_DownQuadPenta::computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes) +{ + // --- find point id's of the volume + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(cellId, npts, nodes); + + // --- create all the ordered list of node id's for each face + + facesWithNodes.nbElems = 5; + + facesWithNodes.elems[0].nodeIds[0] = nodes[0]; + facesWithNodes.elems[0].nodeIds[1] = nodes[2]; + facesWithNodes.elems[0].nodeIds[2] = nodes[5]; + facesWithNodes.elems[0].nodeIds[3] = nodes[3]; + facesWithNodes.elems[0].nodeIds[4] = nodes[8]; + facesWithNodes.elems[0].nodeIds[5] = nodes[14]; + facesWithNodes.elems[0].nodeIds[6] = nodes[11]; + facesWithNodes.elems[0].nodeIds[7] = nodes[12]; + facesWithNodes.elems[0].nbNodes = 8; + facesWithNodes.elems[0].vtkType = VTK_QUADRATIC_QUAD; + + facesWithNodes.elems[1].nodeIds[0] = nodes[1]; + facesWithNodes.elems[1].nodeIds[1] = nodes[2]; + facesWithNodes.elems[1].nodeIds[2] = nodes[5]; + facesWithNodes.elems[1].nodeIds[3] = nodes[4]; + facesWithNodes.elems[1].nodeIds[4] = nodes[7]; + facesWithNodes.elems[1].nodeIds[5] = nodes[14]; + facesWithNodes.elems[1].nodeIds[6] = nodes[10]; + facesWithNodes.elems[1].nodeIds[7] = nodes[13]; + facesWithNodes.elems[1].nbNodes = 8; + facesWithNodes.elems[1].vtkType = VTK_QUADRATIC_QUAD; + + facesWithNodes.elems[2].nodeIds[0] = nodes[0]; + facesWithNodes.elems[2].nodeIds[1] = nodes[1]; + facesWithNodes.elems[2].nodeIds[2] = nodes[4]; + facesWithNodes.elems[2].nodeIds[3] = nodes[3]; + facesWithNodes.elems[2].nodeIds[4] = nodes[6]; + facesWithNodes.elems[2].nodeIds[5] = nodes[13]; + facesWithNodes.elems[2].nodeIds[6] = nodes[9]; + facesWithNodes.elems[2].nodeIds[7] = nodes[12]; + facesWithNodes.elems[2].nbNodes = 8; + facesWithNodes.elems[2].vtkType = VTK_QUADRATIC_QUAD; + + facesWithNodes.elems[3].nodeIds[0] = nodes[0]; + facesWithNodes.elems[3].nodeIds[1] = nodes[1]; + facesWithNodes.elems[3].nodeIds[2] = nodes[2]; + facesWithNodes.elems[3].nodeIds[3] = nodes[6]; + facesWithNodes.elems[3].nodeIds[4] = nodes[7]; + facesWithNodes.elems[3].nodeIds[5] = nodes[8]; + facesWithNodes.elems[3].nbNodes = 6; + facesWithNodes.elems[3].vtkType = VTK_QUADRATIC_TRIANGLE; + + facesWithNodes.elems[4].nodeIds[0] = nodes[3]; + facesWithNodes.elems[4].nodeIds[1] = nodes[4]; + facesWithNodes.elems[4].nodeIds[2] = nodes[5]; + facesWithNodes.elems[4].nodeIds[3] = nodes[9]; + facesWithNodes.elems[4].nodeIds[4] = nodes[10]; + facesWithNodes.elems[4].nodeIds[5] = nodes[11]; + facesWithNodes.elems[4].nbNodes = 6; + facesWithNodes.elems[4].vtkType = VTK_QUADRATIC_TRIANGLE; +} + +// --------------------------------------------------------------------------- + +SMDS_DownHexa::SMDS_DownHexa(SMDS_UnstructuredGrid *grid) : + SMDS_Down3D(grid, 6) +{ + _cellTypes.push_back(VTK_QUAD); + _cellTypes.push_back(VTK_QUAD); + _cellTypes.push_back(VTK_QUAD); + _cellTypes.push_back(VTK_QUAD); + _cellTypes.push_back(VTK_QUAD); + _cellTypes.push_back(VTK_QUAD); +} + +SMDS_DownHexa::~SMDS_DownHexa() +{ +} + +void SMDS_DownHexa::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + set setNodes; + setNodes.clear(); + for (int i = 0; i < orderedNodes.size(); i++) + setNodes.insert(orderedNodes[i]); + //MESSAGE("cellId = " << cellId); + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(this->_vtkCellIds[cellId], npts, nodes); + + set tofind; +//int ids[24] = { 0, 1, 2, 3, 7, 6, 5, 4, 4, 0, 3, 7, 5, 1, 0, 4, 6, 2, 1, 5, 7, 3, 2, 6}; + int ids[24] = { 3, 2, 1, 0, 4, 5, 6, 7, 7, 3, 0, 4, 4, 0, 1, 5, 5, 1, 2, 6, 6, 2, 3, 7}; + for (int k = 0; k < 6; k++) // loop on the 6 faces + { + tofind.clear(); + for (int i = 0; i < 4; i++) + tofind.insert(nodes[ids[4 * k + i]]); // node ids of the face i + if (setNodes == tofind) + { + for (int i = 0; i < 4; i++) + orderedNodes[i] = nodes[ids[4 * k + i]]; + return; + } + } + MESSAGE("=== Problem volume " << _vtkCellIds[cellId] << " " << _grid->_mesh->fromVtkToSmds(_vtkCellIds[cellId])); + MESSAGE(orderedNodes[0] << " " << orderedNodes[1] << " " << orderedNodes[2] << " " << orderedNodes[3]); + MESSAGE(nodes[0] << " " << nodes[1] << " " << nodes[2] << " " << nodes[3]); + MESSAGE(nodes[4] << " " << nodes[5] << " " << nodes[6] << " " << nodes[7]); +} + +void SMDS_DownHexa::addDownCell(int cellId, int lowCellId, unsigned char aType) +{ + //ASSERT((cellId >=0)&& (cellId < _maxId)); + int *faces = &_cellIds[_nbDownCells * cellId]; + for (int i = 0; i < _nbDownCells; i++) + { + if (faces[i] < 0) + { + faces[i] = lowCellId; + return; + } + if (faces[i] == lowCellId) + return; + } + ASSERT(0); + // MESSAGE("-------------------------------------> trop de faces ! " << cellId << " " << lowCellId); +} + +/*! Create a list of faces described by a vtk Type and an ordered set of Node Id's + * The hexahedron is defined by the eight points (0-7), where (0,1,2,3) is the base + * of the hexahedron which, using the right hand rule, forms a quadrilateral whose normal + * points in the direction of the opposite face (4,5,6,7). + * @see vtkHexahedron.h in Filtering + * @param cellId volumeId in vtkUnstructuredGrid + * @param facesWithNodes vector of face descriptors to be filled + */ +void SMDS_DownHexa::computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes) +{ + // --- find point id's of the volume + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(cellId, npts, nodes); + + // --- create all the ordered list of node id's for each face + + facesWithNodes.nbElems = 6; + + facesWithNodes.elems[0].nodeIds[0] = nodes[0]; + facesWithNodes.elems[0].nodeIds[1] = nodes[1]; + facesWithNodes.elems[0].nodeIds[2] = nodes[2]; + facesWithNodes.elems[0].nodeIds[3] = nodes[3]; + facesWithNodes.elems[0].nbNodes = 4; + facesWithNodes.elems[0].vtkType = VTK_QUAD; + + facesWithNodes.elems[1].nodeIds[0] = nodes[4]; + facesWithNodes.elems[1].nodeIds[1] = nodes[5]; + facesWithNodes.elems[1].nodeIds[2] = nodes[6]; + facesWithNodes.elems[1].nodeIds[3] = nodes[7]; + facesWithNodes.elems[1].nbNodes = 4; + facesWithNodes.elems[1].vtkType = VTK_QUAD; + + facesWithNodes.elems[2].nodeIds[0] = nodes[0]; + facesWithNodes.elems[2].nodeIds[1] = nodes[1]; + facesWithNodes.elems[2].nodeIds[2] = nodes[5]; + facesWithNodes.elems[2].nodeIds[3] = nodes[4]; + facesWithNodes.elems[2].nbNodes = 4; + facesWithNodes.elems[2].vtkType = VTK_QUAD; + + facesWithNodes.elems[3].nodeIds[0] = nodes[1]; + facesWithNodes.elems[3].nodeIds[1] = nodes[2]; + facesWithNodes.elems[3].nodeIds[2] = nodes[6]; + facesWithNodes.elems[3].nodeIds[3] = nodes[5]; + facesWithNodes.elems[3].nbNodes = 4; + facesWithNodes.elems[3].vtkType = VTK_QUAD; + + facesWithNodes.elems[4].nodeIds[0] = nodes[2]; + facesWithNodes.elems[4].nodeIds[1] = nodes[6]; + facesWithNodes.elems[4].nodeIds[2] = nodes[7]; + facesWithNodes.elems[4].nodeIds[3] = nodes[3]; + facesWithNodes.elems[4].nbNodes = 4; + facesWithNodes.elems[4].vtkType = VTK_QUAD; + + facesWithNodes.elems[5].nodeIds[0] = nodes[3]; + facesWithNodes.elems[5].nodeIds[1] = nodes[7]; + facesWithNodes.elems[5].nodeIds[2] = nodes[4]; + facesWithNodes.elems[5].nodeIds[3] = nodes[0]; + facesWithNodes.elems[5].nbNodes = 4; + facesWithNodes.elems[5].vtkType = VTK_QUAD; +} + +// --------------------------------------------------------------------------- + +SMDS_DownQuadHexa::SMDS_DownQuadHexa(SMDS_UnstructuredGrid *grid) : + SMDS_Down3D(grid, 6) +{ + _cellTypes.push_back(VTK_QUADRATIC_QUAD); + _cellTypes.push_back(VTK_QUADRATIC_QUAD); + _cellTypes.push_back(VTK_QUADRATIC_QUAD); + _cellTypes.push_back(VTK_QUADRATIC_QUAD); + _cellTypes.push_back(VTK_QUADRATIC_QUAD); + _cellTypes.push_back(VTK_QUADRATIC_QUAD); +} + +SMDS_DownQuadHexa::~SMDS_DownQuadHexa() +{ +} + +void SMDS_DownQuadHexa::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + set setNodes; + setNodes.clear(); + for (int i = 0; i < orderedNodes.size(); i++) + setNodes.insert(orderedNodes[i]); + //MESSAGE("cellId = " << cellId); + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(this->_vtkCellIds[cellId], npts, nodes); + + set tofind; + //int ids[24] = { 3, 2, 1, 0, 4, 5, 6, 7, 7, 3, 0, 4, 4, 0, 1, 5, 5, 1, 2, 6, 6, 2, 3, 7}; + int ids[48] = { 3, 2, 1, 0,10, 9, 8,11, 4, 5, 6, 7,12,13,14,15, 7, 3, 0, 4,19,11,16,15, + 4, 0, 1, 5,16, 8,17,12, 5, 1, 2, 6,17, 9,18,13, 6, 2, 3, 7,18,10,19,14}; + for (int k = 0; k < 6; k++) + { + tofind.clear(); + for (int i = 0; i < 8; i++) + tofind.insert(nodes[ids[8 * k + i]]); + if (setNodes == tofind) + { + for (int i = 0; i < 8; i++) + orderedNodes[i] = nodes[ids[8 * k + i]]; + return; + } + } + MESSAGE("=== Problem volume " << _vtkCellIds[cellId] << " " << _grid->_mesh->fromVtkToSmds(_vtkCellIds[cellId])); + MESSAGE(orderedNodes[0] << " " << orderedNodes[1] << " " << orderedNodes[2] << " " << orderedNodes[3]); + MESSAGE(nodes[0] << " " << nodes[1] << " " << nodes[2] << " " << nodes[3]); +} + +void SMDS_DownQuadHexa::addDownCell(int cellId, int lowCellId, unsigned char aType) +{ + //ASSERT((cellId >=0)&& (cellId < _maxId)); + int *faces = &_cellIds[_nbDownCells * cellId]; + for (int i = 0; i < _nbDownCells; i++) + { + if (faces[i] < 0) + { + faces[i] = lowCellId; + return; + } + if (faces[i] == lowCellId) + return; + } + ASSERT(0); +} + +/*! Create a list of faces described by a vtk Type and an ordered set of Node Id's + * The ordering of the twenty points defining the quadratic hexahedron cell is point id's (0-7,8-19) + * where point id's 0-7 are the eight corner vertices of the cube, followed by twelve mid-edge nodes (8-19). + * Note that these mid-edge nodes lie on the edges defined by + * (0,1), (1,2), (2,3), (3,0), (4,5), (5,6), (6,7), (7,4), (0,4), (1,5), (2,6), (3,7). + * @see vtkQuadraticHexahedron.h in Filtering + * @param cellId volumeId in vtkUnstructuredGrid + * @param facesWithNodes vector of face descriptors to be filled + */ +void SMDS_DownQuadHexa::computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes) +{ + // --- find point id's of the volume + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(cellId, npts, nodes); + + // --- create all the ordered list of node id's for each face + + facesWithNodes.nbElems = 6; + + facesWithNodes.elems[0].nodeIds[0] = nodes[0]; + facesWithNodes.elems[0].nodeIds[1] = nodes[1]; + facesWithNodes.elems[0].nodeIds[2] = nodes[2]; + facesWithNodes.elems[0].nodeIds[3] = nodes[3]; + facesWithNodes.elems[0].nodeIds[4] = nodes[8]; + facesWithNodes.elems[0].nodeIds[5] = nodes[9]; + facesWithNodes.elems[0].nodeIds[6] = nodes[10]; + facesWithNodes.elems[0].nodeIds[7] = nodes[11]; + facesWithNodes.elems[0].nbNodes = 8; + facesWithNodes.elems[0].vtkType = VTK_QUADRATIC_QUAD; + + facesWithNodes.elems[1].nodeIds[0] = nodes[4]; + facesWithNodes.elems[1].nodeIds[1] = nodes[5]; + facesWithNodes.elems[1].nodeIds[2] = nodes[6]; + facesWithNodes.elems[1].nodeIds[3] = nodes[7]; + facesWithNodes.elems[1].nodeIds[4] = nodes[12]; + facesWithNodes.elems[1].nodeIds[5] = nodes[13]; + facesWithNodes.elems[1].nodeIds[6] = nodes[14]; + facesWithNodes.elems[1].nodeIds[7] = nodes[15]; + facesWithNodes.elems[1].nbNodes = 8; + facesWithNodes.elems[1].vtkType = VTK_QUADRATIC_QUAD; + + facesWithNodes.elems[2].nodeIds[0] = nodes[0]; + facesWithNodes.elems[2].nodeIds[1] = nodes[1]; + facesWithNodes.elems[2].nodeIds[2] = nodes[5]; + facesWithNodes.elems[2].nodeIds[3] = nodes[4]; + facesWithNodes.elems[2].nodeIds[4] = nodes[8]; + facesWithNodes.elems[2].nodeIds[5] = nodes[17]; + facesWithNodes.elems[2].nodeIds[6] = nodes[12]; + facesWithNodes.elems[2].nodeIds[7] = nodes[16]; + facesWithNodes.elems[2].nbNodes = 8; + facesWithNodes.elems[2].vtkType = VTK_QUADRATIC_QUAD; + + facesWithNodes.elems[3].nodeIds[0] = nodes[1]; + facesWithNodes.elems[3].nodeIds[1] = nodes[2]; + facesWithNodes.elems[3].nodeIds[2] = nodes[6]; + facesWithNodes.elems[3].nodeIds[3] = nodes[5]; + facesWithNodes.elems[3].nodeIds[4] = nodes[9]; + facesWithNodes.elems[3].nodeIds[5] = nodes[18]; + facesWithNodes.elems[3].nodeIds[6] = nodes[13]; + facesWithNodes.elems[3].nodeIds[7] = nodes[17]; + facesWithNodes.elems[3].nbNodes = 8; + facesWithNodes.elems[3].vtkType = VTK_QUADRATIC_QUAD; + + facesWithNodes.elems[4].nodeIds[0] = nodes[2]; + facesWithNodes.elems[4].nodeIds[1] = nodes[6]; + facesWithNodes.elems[4].nodeIds[2] = nodes[7]; + facesWithNodes.elems[4].nodeIds[3] = nodes[3]; + facesWithNodes.elems[4].nodeIds[4] = nodes[18]; + facesWithNodes.elems[4].nodeIds[5] = nodes[14]; + facesWithNodes.elems[4].nodeIds[6] = nodes[19]; + facesWithNodes.elems[4].nodeIds[7] = nodes[10]; + facesWithNodes.elems[4].nbNodes = 8; + facesWithNodes.elems[4].vtkType = VTK_QUADRATIC_QUAD; + + facesWithNodes.elems[5].nodeIds[0] = nodes[3]; + facesWithNodes.elems[5].nodeIds[1] = nodes[7]; + facesWithNodes.elems[5].nodeIds[2] = nodes[4]; + facesWithNodes.elems[5].nodeIds[3] = nodes[0]; + facesWithNodes.elems[5].nodeIds[4] = nodes[19]; + facesWithNodes.elems[5].nodeIds[5] = nodes[15]; + facesWithNodes.elems[5].nodeIds[6] = nodes[16]; + facesWithNodes.elems[5].nodeIds[7] = nodes[11]; + facesWithNodes.elems[5].nbNodes = 8; + facesWithNodes.elems[5].vtkType = VTK_QUADRATIC_QUAD; +} + +// --------------------------------------------------------------------------- + diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_EdgePosition.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_EdgePosition.cpp index 1317d2b75e89..7c847044fb27 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_EdgePosition.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_EdgePosition.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_EdgePosition.cxx // Author : Jean-Michel BOULCOURT @@ -35,33 +36,23 @@ using namespace std; //purpose : //======================================================================= -SMDS_EdgePosition::SMDS_EdgePosition(const int aEdgeId, - const double aUParam):SMDS_Position(aEdgeId), myUParameter(aUParam) -{ -} - -//======================================================================= -//function : Coords -//purpose : -//======================================================================= - -const double *SMDS_EdgePosition::Coords() const +SMDS_EdgePosition::SMDS_EdgePosition(const double aUParam): myUParameter(aUParam) { - static double origin[]={0,0,0}; - MESSAGE("SMDS_EdgePosition::Coords not implemented"); - return origin; + //MESSAGE("********************************* SMDS_EdgePosition " << myUParameter); } /** */ SMDS_TypeOfPosition SMDS_EdgePosition::GetTypeOfPosition() const { - return SMDS_TOP_EDGE; + //MESSAGE("###################################### SMDS_EdgePosition::GetTypeOfPosition"); + return SMDS_TOP_EDGE; } void SMDS_EdgePosition::SetUParameter(double aUparam) { - myUParameter = aUparam; + //MESSAGE("############################### SMDS_EdgePosition::SetUParameter " << aUparam); + myUParameter = aUparam; } //======================================================================= @@ -71,5 +62,6 @@ void SMDS_EdgePosition::SetUParameter(double aUparam) double SMDS_EdgePosition::GetUParameter() const { - return myUParameter; + //MESSAGE("########################## SMDS_EdgePosition::GetUParameter " << myUParameter); + return myUParameter; } diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_FaceOfEdges.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_FaceOfEdges.cpp index 926b6a446583..5f80713bf283 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_FaceOfEdges.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_FaceOfEdges.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // #ifdef _MSC_VER @@ -28,6 +29,7 @@ #include "SMDS_FaceOfEdges.hxx" #include "SMDS_IteratorOfElements.hxx" #include "SMDS_MeshNode.hxx" +#include "utilities.h" using namespace std; @@ -38,12 +40,12 @@ using namespace std; int SMDS_FaceOfEdges::NbEdges() const { - return myNbEdges; + return myNbEdges; } int SMDS_FaceOfEdges::NbFaces() const { - return 1; + return 1; } //======================================================================= //function : Print @@ -52,15 +54,15 @@ int SMDS_FaceOfEdges::NbFaces() const void SMDS_FaceOfEdges::Print(ostream & OS) const { - OS << "face <" << GetID() << " > : "; - int i; - for (i = 0; i < NbEdges() - 1; i++) OS << myEdges[i] << ","; - OS << myEdges[i] << ") " << endl; + OS << "face <" << GetID() << " > : "; + int i; + for (i = 0; i < NbEdges() - 1; i++) OS << myEdges[i] << ","; + OS << myEdges[i] << ") " << endl; } SMDSAbs_ElementType SMDS_FaceOfEdges::GetType() const { - return SMDSAbs_Face; + return SMDSAbs_Face; } //======================================================================= @@ -86,7 +88,7 @@ class SMDS_FaceOfEdges_MyIterator:public SMDS_ElemIterator { index++; return mySet[index-1]; - } + } }; SMDS_ElemIteratorPtr SMDS_FaceOfEdges::elementsIterator @@ -110,11 +112,12 @@ SMDS_FaceOfEdges::SMDS_FaceOfEdges(const SMDS_MeshEdge* edge1, const SMDS_MeshEdge* edge2, const SMDS_MeshEdge* edge3) { - myNbEdges = 3; - myEdges[0]=edge1; - myEdges[1]=edge2; - myEdges[2]=edge3; - myEdges[3]=0; + //MESSAGE("****************************************************** SMDS_FaceOfEdges"); + myNbEdges = 3; + myEdges[0]=edge1; + myEdges[1]=edge2; + myEdges[2]=edge3; + myEdges[3]=0; } SMDS_FaceOfEdges::SMDS_FaceOfEdges(const SMDS_MeshEdge* edge1, @@ -122,38 +125,39 @@ SMDS_FaceOfEdges::SMDS_FaceOfEdges(const SMDS_MeshEdge* edge1, const SMDS_MeshEdge* edge3, const SMDS_MeshEdge* edge4) { - myNbEdges = 4; - myEdges[0]=edge1; - myEdges[1]=edge2; - myEdges[2]=edge3; - myEdges[3]=edge4; + //MESSAGE("****************************************************** SMDS_FaceOfEdges"); + myNbEdges = 4; + myEdges[0]=edge1; + myEdges[1]=edge2; + myEdges[2]=edge3; + myEdges[3]=edge4; } /*bool operator<(const SMDS_FaceOfEdges& f1, const SMDS_FaceOfEdges& f2) { - set set1,set2; - SMDS_ElemIteratorPtr it; - const SMDS_MeshNode * n; - - it=f1.nodesIterator(); - - while(it->more()) - { - n=static_cast(it->next()); - set1.insert(*n); - } - - delete it; - it=f2.nodesIterator(); - - while(it->more()) - { - n=static_cast(it->next()); - set2.insert(*n); - } - - delete it; - return set1 set1,set2; + SMDS_ElemIteratorPtr it; + const SMDS_MeshNode * n; + + it=f1.nodesIterator(); + + while(it->more()) + { + n=static_cast(it->next()); + set1.insert(*n); + } + + delete it; + it=f2.nodesIterator(); + + while(it->more()) + { + n=static_cast(it->next()); + set2.insert(*n); + } + + delete it; + return set1 : "; - int i; - for (i = 0; i < NbNodes() - 1; i++) OS << myNodes[i] << ","; - OS << myNodes[i] << ") " << endl; + OS << "face <" << GetID() << " > : "; + int i; + for (i = 0; i < NbNodes() - 1; i++) OS << myNodes[i] << ","; + OS << myNodes[i] << ") " << endl; } //======================================================================= @@ -132,11 +133,12 @@ SMDS_FaceOfNodes::SMDS_FaceOfNodes(const SMDS_MeshNode* node1, const SMDS_MeshNode* node2, const SMDS_MeshNode* node3) { - myNbNodes = 3; - myNodes[0]=node1; - myNodes[1]=node2; - myNodes[2]=node3; - myNodes[3]=0; + //MESSAGE("******************************************************* SMDS_FaceOfNodes"); + myNbNodes = 3; + myNodes[0]=node1; + myNodes[1]=node2; + myNodes[2]=node3; + myNodes[3]=0; } SMDS_FaceOfNodes::SMDS_FaceOfNodes(const SMDS_MeshNode* node1, @@ -144,11 +146,12 @@ SMDS_FaceOfNodes::SMDS_FaceOfNodes(const SMDS_MeshNode* node1, const SMDS_MeshNode* node3, const SMDS_MeshNode* node4) { - myNbNodes = 4; - myNodes[0]=node1; - myNodes[1]=node2; - myNodes[2]=node3; - myNodes[3]=node4; + //MESSAGE("******************************************************* SMDS_FaceOfNodes"); + myNbNodes = 4; + myNodes[0]=node1; + myNodes[1]=node2; + myNodes[2]=node3; + myNodes[3]=node4; } bool SMDS_FaceOfNodes::ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) @@ -174,3 +177,12 @@ const SMDS_MeshNode* SMDS_FaceOfNodes::GetNode(const int ind) const { return myNodes[ ind ]; } + +SMDSAbs_EntityType SMDS_FaceOfNodes::GetEntityType() const +{ + return NbNodes() == 3 ? SMDSEntity_Triangle : SMDSEntity_Quadrangle; +} +SMDSAbs_GeometryType SMDS_FaceOfNodes::GetGeomType() const +{ + return NbNodes() == 3 ? SMDSGeom_TRIANGLE : SMDSGeom_QUADRANGLE; +} diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_FacePosition.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_FacePosition.cpp index 20498554e04d..5097c6b57628 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_FacePosition.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_FacePosition.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_FacePosition.cxx // Author : Jean-Michel BOULCOURT @@ -35,35 +36,23 @@ using namespace std; //purpose : //======================================================================= -SMDS_FacePosition::SMDS_FacePosition(const int aEdgeId, - const double aUParam, - const double aVParam) - :SMDS_Position(aEdgeId), - myUParameter(aUParam),myVParameter(aVParam) -{ -} - -//======================================================================= -//function : Coords -//purpose : -//======================================================================= -const double *SMDS_FacePosition::Coords() const +SMDS_FacePosition::SMDS_FacePosition(const double aUParam, + const double aVParam) + : myUParameter(aUParam),myVParameter(aVParam) { - static double origin[]={0,0,0}; - MESSAGE("SMDS_EdgePosition::Coords not implemented"); - return origin; + //MESSAGE("******************************************************** SMDS_FacePosition"); } /** */ SMDS_TypeOfPosition SMDS_FacePosition::GetTypeOfPosition() const { - return SMDS_TOP_FACE; + return SMDS_TOP_FACE; } void SMDS_FacePosition::SetUParameter(double aUparam) { - myUParameter = aUparam; + myUParameter = aUparam; } //======================================================================= @@ -73,7 +62,7 @@ void SMDS_FacePosition::SetUParameter(double aUparam) void SMDS_FacePosition::SetVParameter(double aVparam) { - myVParameter = aVparam; + myVParameter = aVparam; } //======================================================================= @@ -83,7 +72,7 @@ void SMDS_FacePosition::SetVParameter(double aVparam) double SMDS_FacePosition::GetUParameter() const { - return myUParameter; + return myUParameter; } //======================================================================= @@ -93,5 +82,16 @@ double SMDS_FacePosition::GetUParameter() const double SMDS_FacePosition::GetVParameter() const { - return myVParameter; + return myVParameter; +} + +//======================================================================= +//function : SetParameters +//purpose : +//======================================================================= + +void SMDS_FacePosition::SetParameters(double aUparam, double aVparam) +{ + myUParameter = aUparam; + myVParameter = aVparam; } diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_IteratorOfElements.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_IteratorOfElements.cpp index 220e67ac9cdb..3719c6b56ee1 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_IteratorOfElements.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_IteratorOfElements.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // #ifdef _MSC_VER @@ -29,24 +30,24 @@ bool SMDS_IteratorOfElements::subMore() { - if((t2Iterator.get()==NULL)||(!t2Iterator->more())) - { - if(t1Iterator->more()) - { - t2Iterator=t1Iterator->next()->elementsIterator(myType); - return subMore(); - } - else return false; - } - else return true; + if((t2Iterator.get()==NULL)||(!t2Iterator->more())) + { + if(t1Iterator->more()) + { + t2Iterator=t1Iterator->next()->elementsIterator(myType); + return subMore(); + } + else return false; + } + else return true; } const SMDS_MeshElement * SMDS_IteratorOfElements::subNext() { - if((t2Iterator.get()==NULL)||(!t2Iterator->more())) - if(t1Iterator->more()) - t2Iterator=t1Iterator->next()->elementsIterator(myType); - return t2Iterator->next(); + if((t2Iterator.get()==NULL)||(!t2Iterator->more())) + if(t1Iterator->more()) + t2Iterator=t1Iterator->next()->elementsIterator(myType); + return t2Iterator->next(); } ///////////////////////////////////////////////////////////////////////////// @@ -61,48 +62,48 @@ SMDS_IteratorOfElements::SMDS_IteratorOfElements(const SMDS_MeshElement * elemen myType(type), myElement(element), myProxyElement(NULL) { - while(subMore()) - alreadyReturnedElements.insert(subNext()); - itAlreadyReturned= alreadyReturnedElements.begin(); - switch(myElement->GetType()) - { - case SMDSAbs_Node: - case SMDSAbs_Edge: myReverseIteration=true; break; - case SMDSAbs_Face: myReverseIteration=(type==SMDSAbs_Volume); break; - default: myReverseIteration=false; - } + while(subMore()) + alreadyReturnedElements.insert(subNext()); + itAlreadyReturned= alreadyReturnedElements.begin(); + switch(myElement->GetType()) + { + case SMDSAbs_Node: + case SMDSAbs_Edge: myReverseIteration=true; break; + case SMDSAbs_Face: myReverseIteration=(type==SMDSAbs_Volume); break; + default: myReverseIteration=false; + } } bool SMDS_IteratorOfElements::more() { - if(myProxyElement==NULL) - { - while(itAlreadyReturned!=alreadyReturnedElements.end()) - { - myProxyElement=*itAlreadyReturned; - itAlreadyReturned++; + if(myProxyElement==NULL) + { + while(itAlreadyReturned!=alreadyReturnedElements.end()) + { + myProxyElement=*itAlreadyReturned; + itAlreadyReturned++; - if(myReverseIteration) - { - SMDS_ElemIteratorPtr it= - myProxyElement->elementsIterator(myElement->GetType()); - while(it->more()) - { - if(it->next()==myElement) return true; - } - } - else return true; - } - myProxyElement=NULL; - return false; - } - else return true; + if(myReverseIteration) + { + SMDS_ElemIteratorPtr it= + myProxyElement->elementsIterator(myElement->GetType()); + while(it->more()) + { + if(it->next()==myElement) return true; + } + } + else return true; + } + myProxyElement=NULL; + return false; + } + else return true; } const SMDS_MeshElement * SMDS_IteratorOfElements::next() { - more(); - const SMDS_MeshElement *e=myProxyElement; - myProxyElement=NULL; - return e; + more(); + const SMDS_MeshElement *e=myProxyElement; + myProxyElement=NULL; + return e; } diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_LinearEdge.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_LinearEdge.cpp new file mode 100644 index 000000000000..37a3cc3e709d --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_LinearEdge.cpp @@ -0,0 +1,160 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SMDS_LinearEdge.cxx +// Author : Jean-Michel BOULCOURT +// Module : SMESH +// +#ifdef _MSC_VER +#pragma warning(disable:4786) +#endif + +#include "SMDS_LinearEdge.hxx" +#include "SMDS_IteratorOfElements.hxx" +#include "SMDS_MeshNode.hxx" +#include "utilities.h" + +using namespace std; + +//======================================================================= +//function : SMDS_LinearEdge +//purpose : +//======================================================================= + +SMDS_LinearEdge::SMDS_LinearEdge(const SMDS_MeshNode * node1, + const SMDS_MeshNode * node2) +{ + //MESSAGE("SMDS_LinearEdge " << GetID()); + myNodes[0] = node1; + myNodes[1] = node2; +} + +//======================================================================= +//function : Print +//purpose : +//======================================================================= + +void SMDS_LinearEdge::Print(ostream & OS) const +{ + OS << "edge <" << GetID() << "> : (" << myNodes[0] << " , " << myNodes[1] + << ") " << endl; +} + +int SMDS_LinearEdge::NbNodes() const +{ + return 2; +} + +int SMDS_LinearEdge::NbEdges() const +{ + return 1; +} + +class SMDS_LinearEdge_MyNodeIterator: public SMDS_ElemIterator +{ + const SMDS_MeshNode * const * myNodes; + int myIndex; +public: + SMDS_LinearEdge_MyNodeIterator(const SMDS_MeshNode * const * nodes) : + myNodes(nodes), myIndex(0) + { + } + + bool more() + { + return myIndex < 2; + } + + const SMDS_MeshElement* next() + { + myIndex++; + return myNodes[myIndex - 1]; + } +}; + +SMDS_ElemIteratorPtr SMDS_LinearEdge::elementsIterator(SMDSAbs_ElementType type) const +{ + switch (type) + { + case SMDSAbs_Edge: + return SMDS_MeshElement::elementsIterator(SMDSAbs_Edge); + case SMDSAbs_Node: + return SMDS_ElemIteratorPtr(new SMDS_LinearEdge_MyNodeIterator(myNodes)); + default: + return SMDS_ElemIteratorPtr + (new SMDS_IteratorOfElements(this, + type, + SMDS_ElemIteratorPtr + (new SMDS_LinearEdge_MyNodeIterator(myNodes)))); + } +} + +bool operator<(const SMDS_LinearEdge & e1, const SMDS_LinearEdge & e2) +{ + int id11 = e1.myNodes[0]->getVtkId(); + int id21 = e2.myNodes[0]->getVtkId(); + int id12 = e1.myNodes[1]->getVtkId(); + int id22 = e2.myNodes[1]->getVtkId(); + int tmp; + + if (id11 >= id12) + { + tmp = id11; + id11 = id12; + id12 = tmp; + } + if (id21 >= id22) + { + tmp = id21; + id21 = id22; + id22 = tmp; + } + + if (id11 < id21) + return true; + else if (id11 == id21) + return (id21 < id22); + else + return false; +} + +/*! + * \brief Return node by its index + * \param ind - node index + * \retval const SMDS_MeshNode* - the node + */ +const SMDS_MeshNode* SMDS_LinearEdge::GetNode(const int ind) const +{ + return myNodes[ind]; +} + +//======================================================================= +//function : ChangeNodes +//purpose : +//======================================================================= + +bool SMDS_LinearEdge::ChangeNodes(const SMDS_MeshNode * node1, + const SMDS_MeshNode * node2) +{ + myNodes[0] = node1; + myNodes[1] = node2; + return true; +} diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MemoryLimit.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MemoryLimit.cpp deleted file mode 100644 index e46360f49947..000000000000 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MemoryLimit.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE -// -// Copyright (C) 2003-2007 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 : SMDS_MemoryLimit.cxx -// Created : Fri Sep 21 17:16:42 2007 -// Author : Edward AGAPOV (eap) -// Executable to find out a lower RAM limit (MB), i.e. at what size of freeRAM -// reported by sysinfo, no more memory can be allocated. -// This is not done inside a function of SALOME because allocated memory is not returned -// to the system. (PAL16631) -// -#ifndef WIN32 -#if !(defined(__MACH__) && defined(__APPLE__)) -#include -#endif -#endif - -#ifdef _DEBUG_ -#include -#endif - -int main (int argc, char ** argv) -{ -#if (defined(__MACH__) && defined(__APPLE__)) - //do nothing -#else - // To better understand what is going on here, consult bug [SALOME platform 0019911] -#ifndef WIN32 - struct sysinfo si; - int err = sysinfo( &si ); - if ( err ) - return -1; - unsigned long freeRamKb = ( si.freeram * si.mem_unit ) / 1024; - - // totat RAM size in Gb, float is in order not to have 1 instead of 1.9 - float totalramGb = float( si.totalram * si.mem_unit ) / 1024 / 1024 / 1024; - - // nb Kbites to allocate at one step. Small nb leads to hung up - const int stepKb = int( 5 * totalramGb ); - - unsigned long nbSteps = freeRamKb / stepKb * 2; - try { - while ( nbSteps-- ) { - new char[stepKb*1024]; - err = sysinfo( &si ); - if ( !err ) - freeRamKb = ( si.freeram * si.mem_unit ) / 1024; - } - } catch (...) {} - -// #ifdef _DEBUG_ -// std::cout << freeRamKb / 1024 << std::endl; -// #endif - return freeRamKb / 1024; -#endif -#endif - - return -1; -} diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_Mesh.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_Mesh.cpp index d31934890961..411268d80384 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_Mesh.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_Mesh.cpp @@ -1,44 +1,58 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMDS : implementaion of Salome mesh data structure + +// SMESH SMDS : implementation of Salome mesh data structure // #ifdef _MSC_VER #pragma warning(disable:4786) #endif -#include "utilities.h" -#include "SMDS_Mesh.hxx" -#include "SMDS_VolumeOfNodes.hxx" -#include "SMDS_VolumeOfFaces.hxx" -#include "SMDS_FaceOfNodes.hxx" #include "SMDS_FaceOfEdges.hxx" -#include "SMDS_PolyhedralVolumeOfNodes.hxx" +#include "SMDS_FaceOfNodes.hxx" +#include "SMDS_Mesh.hxx" #include "SMDS_PolygonalFaceOfNodes.hxx" +#include "SMDS_PolyhedralVolumeOfNodes.hxx" #include "SMDS_QuadraticEdge.hxx" #include "SMDS_QuadraticFaceOfNodes.hxx" #include "SMDS_QuadraticVolumeOfNodes.hxx" +#include "SMDS_SetIterator.hxx" +#include "SMDS_SpacePosition.hxx" +#include "SMDS_UnstructuredGrid.hxx" +#include "SMDS_VolumeOfFaces.hxx" +#include "SMDS_VolumeOfNodes.hxx" + +#include "utilities.h" + +#include +#include +#include +#include +#include +#include #include #include +#include +#include #include using namespace std; @@ -49,8 +63,12 @@ using namespace std; #include #endif -// number of added entitis to check memory after -#define CHECKMEMORY_INTERVAL 1000 +// number of added entities to check memory after +#define CHECKMEMORY_INTERVAL 100000 + +vector SMDS_Mesh::_meshList = vector(); +int SMDS_Mesh::chunkSize = 1024; + //================================================================================ /*! @@ -63,43 +81,46 @@ using namespace std; int SMDS_Mesh::CheckMemory(const bool doNotRaise) throw (std::bad_alloc) { #if (defined(__MACH__) && defined(__APPLE__)) - return 1000; -#else + return 1000; +#else #ifndef WIN32 struct sysinfo si; int err = sysinfo( &si ); if ( err ) return -1; + const unsigned long Mbyte = 1024 * 1024; + static int limit = -1; if ( limit < 0 ) { int status = system("SMDS_MemoryLimit"); // it returns lower limit of free RAM if (status >= 0 ) { limit = WEXITSTATUS(status); } + else { + double factor = ( si.totalswap == 0 ) ? 0.1 : 0.2; + limit = int(( factor * si.totalram * si.mem_unit ) / Mbyte ); + } if ( limit < 20 ) limit = 20; else - limit = int( limit * 1.5 ); -#ifdef _DEBUG_ + limit = int ( limit * 1.5 ); MESSAGE ( "SMDS_Mesh::CheckMemory() memory limit = " << limit << " MB" ); -#endif } - const unsigned long Mbyte = 1024 * 1024; // compute separately to avoid overflow int freeMb = ( si.freeram * si.mem_unit ) / Mbyte + ( si.freeswap * si.mem_unit ) / Mbyte; + //cout << "freeMb = " << freeMb << " limit = " << limit << endl; if ( freeMb > limit ) return freeMb - limit; if ( doNotRaise ) return 0; -#ifdef _DEBUG_ + MESSAGE ("SMDS_Mesh::CheckMemory() throws as free memory too low: " << freeMb <<" MB" ); -#endif throw std::bad_alloc(); #else return -1; @@ -111,12 +132,43 @@ int SMDS_Mesh::CheckMemory(const bool doNotRaise) throw (std::bad_alloc) /// Create a new mesh object /////////////////////////////////////////////////////////////////////////////// SMDS_Mesh::SMDS_Mesh() - :myParent(NULL), - myNodeIDFactory(new SMDS_MeshElementIDFactory()), - myElementIDFactory(new SMDS_MeshElementIDFactory()), - myHasConstructionEdges(false), myHasConstructionFaces(false), - myHasInverseElements(true) -{ + :myParent(NULL), + myNodeIDFactory(new SMDS_MeshNodeIDFactory()), + myElementIDFactory(new SMDS_MeshElementIDFactory()), + myHasConstructionEdges(false), myHasConstructionFaces(false), + myHasInverseElements(true), + myNodeMin(0), myNodeMax(0), + myNodePool(0), myEdgePool(0), myFacePool(0), myVolumePool(0),myBallPool(0), + myModified(false), myModifTime(0), myCompactTime(0), + xmin(0), xmax(0), ymin(0), ymax(0), zmin(0), zmax(0) +{ + myMeshId = _meshList.size(); // --- index of the mesh to push back in the vector + myNodeIDFactory->SetMesh(this); + myElementIDFactory->SetMesh(this); + _meshList.push_back(this); + myNodePool = new ObjectPool(SMDS_Mesh::chunkSize); + myEdgePool = new ObjectPool(SMDS_Mesh::chunkSize); + myFacePool = new ObjectPool(SMDS_Mesh::chunkSize); + myVolumePool = new ObjectPool(SMDS_Mesh::chunkSize); + myBallPool = new ObjectPool(SMDS_Mesh::chunkSize); + + myNodes.clear(); + myCells.clear(); + //myCellIdSmdsToVtk.clear(); + myCellIdVtkToSmds.clear(); + myGrid = SMDS_UnstructuredGrid::New(); + myGrid->setSMDS_mesh(this); + myGrid->Initialize(); + myGrid->Allocate(); + vtkPoints* points = vtkPoints::New(); + // bug "21125: EDF 1233 SMESH: Degrardation of precision in a test case for quadratic conversion" + // Use double type for storing coordinates of nodes instead of float. + points->SetDataType(VTK_DOUBLE); + points->SetNumberOfPoints(0 /*SMDS_Mesh::chunkSize*/); + myGrid->SetPoints( points ); + points->Delete(); + myGrid->BuildLinks(); + this->Modified(); } /////////////////////////////////////////////////////////////////////////////// @@ -125,10 +177,15 @@ SMDS_Mesh::SMDS_Mesh() /// (2003-09-08) of SMESH /////////////////////////////////////////////////////////////////////////////// SMDS_Mesh::SMDS_Mesh(SMDS_Mesh * parent) - :myParent(parent), myNodeIDFactory(parent->myNodeIDFactory), - myElementIDFactory(parent->myElementIDFactory), - myHasConstructionEdges(false), myHasConstructionFaces(false), - myHasInverseElements(true) + :myParent(parent), myNodeIDFactory(parent->myNodeIDFactory), + myElementIDFactory(parent->myElementIDFactory), + myHasConstructionEdges(false), myHasConstructionFaces(false), + myHasInverseElements(true), + myNodePool(parent->myNodePool), + myEdgePool(parent->myEdgePool), + myFacePool(parent->myFacePool), + myVolumePool(parent->myVolumePool), + myBallPool(parent->myBallPool) { } @@ -138,9 +195,9 @@ SMDS_Mesh::SMDS_Mesh(SMDS_Mesh * parent) SMDS_Mesh *SMDS_Mesh::AddSubMesh() { - SMDS_Mesh *submesh = new SMDS_Mesh(this); - myChildren.insert(myChildren.end(), submesh); - return submesh; + SMDS_Mesh *submesh = new SMDS_Mesh(this); + myChildren.insert(myChildren.end(), submesh); + return submesh; } /////////////////////////////////////////////////////////////////////////////// @@ -164,22 +221,131 @@ SMDS_MeshNode * SMDS_Mesh::AddNodeWithID(double x, double y, double z, int ID) // find the MeshNode corresponding to ID const SMDS_MeshElement *node = myNodeIDFactory->MeshElement(ID); if(!node){ - if ( myNodes.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); - SMDS_MeshNode * node=new SMDS_MeshNode(x, y, z); - myNodes.Add(node); + if (ID < 1) + { + MESSAGE("=============> Bad Node Id: " << ID); + ID = myNodeIDFactory->GetFreeID(); + } + myNodeIDFactory->adjustMaxId(ID); + SMDS_MeshNode * node = myNodePool->getNew(); + node->init(ID, myMeshId, 0, x, y, z); + + if (ID >= myNodes.size()) + { + myNodes.resize(ID+SMDS_Mesh::chunkSize, 0); +// MESSAGE(" ------------------ myNodes resize " << ID << " --> " << ID+SMDS_Mesh::chunkSize); + } + myNodes[ID] = node; myNodeIDFactory->BindID(ID,node); myInfo.myNbNodes++; + myModified = true; + this->adjustBoundingBox(x, y, z); return node; }else return NULL; } +/////////////////////////////////////////////////////////////////////////////// +/// create a Mesh0DElement and add it to the current Mesh +/// @return : The created Mesh0DElement +/////////////////////////////////////////////////////////////////////////////// +SMDS_Mesh0DElement* SMDS_Mesh::Add0DElementWithID(int idnode, int ID) +{ + SMDS_MeshNode * node = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode); + if (!node) return NULL; + return SMDS_Mesh::Add0DElementWithID(node, ID); +} + +/////////////////////////////////////////////////////////////////////////////// +/// create a Mesh0DElement and add it to the current Mesh +/// @return : The created Mesh0DElement +/////////////////////////////////////////////////////////////////////////////// +SMDS_Mesh0DElement* SMDS_Mesh::Add0DElement(const SMDS_MeshNode * node) +{ + return SMDS_Mesh::Add0DElementWithID(node, myElementIDFactory->GetFreeID()); +} + +/////////////////////////////////////////////////////////////////////////////// +/// Create a new Mesh0DElement and at it to the mesh +/// @param idnode ID of the node +/// @param ID ID of the 0D element to create +/// @return The created 0D element or NULL if an element with this +/// ID already exists or if input node is not found. +/////////////////////////////////////////////////////////////////////////////// +SMDS_Mesh0DElement* SMDS_Mesh::Add0DElementWithID(const SMDS_MeshNode * n, int ID) +{ + if (!n) return 0; + + if (Nb0DElements() % CHECKMEMORY_INTERVAL == 0) CheckMemory(); + //MESSAGE("Add0DElementWithID" << ID) + SMDS_Mesh0DElement * el0d = new SMDS_Mesh0DElement(n); + if (myElementIDFactory->BindID(ID, el0d)) { + //SMDS_MeshNode *node = const_cast(n); + //node->AddInverseElement(el0d);// --- fait avec BindID + adjustmyCellsCapacity(ID); + myCells[ID] = el0d; + myInfo.myNb0DElements++; + return el0d; + } + + delete el0d; + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +/// create a Ball and add it to the current Mesh +/// @return : The created Ball +/////////////////////////////////////////////////////////////////////////////// +SMDS_BallElement* SMDS_Mesh::AddBallWithID(int idnode, double diameter, int ID) +{ + SMDS_MeshNode * node = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode); + if (!node) return NULL; + return SMDS_Mesh::AddBallWithID(node, diameter, ID); +} + +/////////////////////////////////////////////////////////////////////////////// +/// create a Ball and add it to the current Mesh +/// @return : The created Ball +/////////////////////////////////////////////////////////////////////////////// +SMDS_BallElement* SMDS_Mesh::AddBall(const SMDS_MeshNode * node, double diameter) +{ + return SMDS_Mesh::AddBallWithID(node, diameter, myElementIDFactory->GetFreeID()); +} + +/////////////////////////////////////////////////////////////////////////////// +/// Create a new Ball and at it to the mesh +/// @param idnode ID of the node +// @param diameter ball diameter +/// @param ID ID of the 0D element to create +/// @return The created 0D element or NULL if an element with this +/// ID already exists or if input node is not found. +/////////////////////////////////////////////////////////////////////////////// +SMDS_BallElement* SMDS_Mesh::AddBallWithID(const SMDS_MeshNode * n, double diameter, int ID) +{ + if (!n) return 0; + + if (NbBalls() % CHECKMEMORY_INTERVAL == 0) CheckMemory(); + + SMDS_BallElement *ball = myBallPool->getNew(); + ball->init(n->getVtkId(), diameter, this); + if (!this->registerElement(ID,ball)) + { + this->myGrid->GetCellTypesArray()->SetValue(ball->getVtkId(), VTK_EMPTY_CELL); + myBallPool->destroy(ball); + return 0; + } + adjustmyCellsCapacity(ID); + myCells[ID] = ball; + myInfo.myNbBalls++; + return ball; +} + /////////////////////////////////////////////////////////////////////////////// /// create a MeshEdge and add it to the current Mesh /// @return : The created MeshEdge /////////////////////////////////////////////////////////////////////////////// -SMDS_MeshEdge* SMDS_Mesh::AddEdgeWithID(int idnode1, int idnode2, int ID) +SMDS_MeshEdge* SMDS_Mesh::AddEdgeWithID(int idnode1, int idnode2, int ID) { SMDS_MeshNode * node1 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode1); SMDS_MeshNode * node2 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode2); @@ -193,7 +359,7 @@ SMDS_MeshEdge* SMDS_Mesh::AddEdgeWithID(int idnode1, int idnode2, int ID) /////////////////////////////////////////////////////////////////////////////// SMDS_MeshEdge* SMDS_Mesh::AddEdge(const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2) + const SMDS_MeshNode * node2) { return SMDS_Mesh::AddEdgeWithID(node1, node2, myElementIDFactory->GetFreeID()); } @@ -208,28 +374,37 @@ SMDS_MeshEdge* SMDS_Mesh::AddEdge(const SMDS_MeshNode * node1, /////////////////////////////////////////////////////////////////////////////// SMDS_MeshEdge* SMDS_Mesh::AddEdgeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - int ID) + const SMDS_MeshNode * n2, + int ID) { if ( !n1 || !n2 ) return 0; + SMDS_MeshEdge * edge = 0; - if ( myEdges.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + // --- retreive nodes ID + vector nodeIds; + nodeIds.clear(); + nodeIds.push_back(n1->getVtkId()); + nodeIds.push_back(n2->getVtkId()); - SMDS_MeshEdge * edge=new SMDS_MeshEdge(n1,n2); - if(myElementIDFactory->BindID(ID, edge)) { - SMDS_MeshNode *node1,*node2; - node1=const_cast(n1); - node2=const_cast(n2); - node1->AddInverseElement(edge); - node2->AddInverseElement(edge); - myEdges.Add(edge); - myInfo.myNbEdges++; - return edge; - } - else { - delete edge; - return NULL; - } + SMDS_VtkEdge *edgevtk = myEdgePool->getNew(); + edgevtk->init(nodeIds, this); + if (!this->registerElement(ID,edgevtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(edgevtk->getVtkId(), VTK_EMPTY_CELL); + myEdgePool->destroy(edgevtk); + return 0; + } + edge = edgevtk; + adjustmyCellsCapacity(ID); + myCells[ID] = edge; + myInfo.myNbEdges++; + +// if (edge && !registerElement(ID, edge)) +// { +// RemoveElement(edge, false); +// edge = NULL; +// } + return edge; } /////////////////////////////////////////////////////////////////////////////// @@ -238,8 +413,8 @@ SMDS_MeshEdge* SMDS_Mesh::AddEdgeWithID(const SMDS_MeshNode * n1, /////////////////////////////////////////////////////////////////////////////// SMDS_MeshFace* SMDS_Mesh::AddFace(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3) { return SMDS_Mesh::AddFaceWithID(n1,n2,n3, myElementIDFactory->GetFreeID()); } @@ -254,7 +429,7 @@ SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(int idnode1, int idnode2, int idnode3, i SMDS_MeshNode * node2 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode2); SMDS_MeshNode * node3 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode3); if(!node1 || !node2 || !node3) return NULL; - return SMDS_Mesh::AddFaceWithID(node1, node2, node3, ID); + return SMDS_Mesh::AddFaceWithID(node1, node2, node3, ID); } /////////////////////////////////////////////////////////////////////////////// @@ -266,12 +441,13 @@ SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n3, int ID) { - SMDS_MeshFace * face=createTriangle(n1, n2, n3); + //MESSAGE("AddFaceWithID " << ID) + SMDS_MeshFace * face=createTriangle(n1, n2, n3, ID); - if (face && !registerElement(ID, face)) { - RemoveElement(face, false); - face = NULL; - } +// if (face && !registerElement(ID, face)) { +// RemoveElement(face, false); +// face = NULL; +// } return face; } @@ -281,9 +457,9 @@ SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, /////////////////////////////////////////////////////////////////////////////// SMDS_MeshFace* SMDS_Mesh::AddFace(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4) { return SMDS_Mesh::AddFaceWithID(n1,n2,n3, n4, myElementIDFactory->GetFreeID()); } @@ -292,11 +468,11 @@ SMDS_MeshFace* SMDS_Mesh::AddFace(const SMDS_MeshNode * n1, /// Add a quadrangle defined by its nodes IDs /////////////////////////////////////////////////////////////////////////////// -SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(int idnode1, - int idnode2, - int idnode3, - int idnode4, - int ID) +SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(int idnode1, + int idnode2, + int idnode3, + int idnode4, + int ID) { SMDS_MeshNode *node1, *node2, *node3, *node4; node1 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode1); @@ -304,7 +480,7 @@ SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(int idnode1, node3 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode3); node4 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode4); if(!node1 || !node2 || !node3 || !node4) return NULL; - return SMDS_Mesh::AddFaceWithID(node1, node2, node3, node4, ID); + return SMDS_Mesh::AddFaceWithID(node1, node2, node3, node4, ID); } /////////////////////////////////////////////////////////////////////////////// @@ -317,12 +493,13 @@ SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n4, int ID) { - SMDS_MeshFace * face=createQuadrangle(n1, n2, n3, n4); + //MESSAGE("AddFaceWithID " << ID); + SMDS_MeshFace * face=createQuadrangle(n1, n2, n3, n4, ID); - if (face && !registerElement(ID, face)) { - RemoveElement(face, false); - face = NULL; - } +// if (face && !registerElement(ID, face)) { +// RemoveElement(face, false); +// face = NULL; +// } return face; } @@ -337,7 +514,8 @@ SMDS_MeshFace* SMDS_Mesh::AddFace(const SMDS_MeshEdge * e1, { if (!hasConstructionEdges()) return NULL; - return AddFaceWithID(e1,e2,e3, myElementIDFactory->GetFreeID()); + //MESSAGE("AddFaceWithID"); + return AddFaceWithID(e1,e2,e3, myElementIDFactory->GetFreeID()); } /////////////////////////////////////////////////////////////////////////////// @@ -353,15 +531,18 @@ SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(const SMDS_MeshEdge * e1, return NULL; if ( !e1 || !e2 || !e3 ) return 0; - if ( myFaces.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if ( NbFaces() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + MESSAGE("AddFaceWithID" << ID); SMDS_MeshFace * face = new SMDS_FaceOfEdges(e1,e2,e3); - myFaces.Add(face); + adjustmyCellsCapacity(ID); + myCells[ID] = face; myInfo.myNbTriangles++; if (!registerElement(ID, face)) { - RemoveElement(face, false); - face = NULL; + registerElement(myElementIDFactory->GetFreeID(), face); + //RemoveElement(face, false); + //face = NULL; } return face; } @@ -378,7 +559,8 @@ SMDS_MeshFace* SMDS_Mesh::AddFace(const SMDS_MeshEdge * e1, { if (!hasConstructionEdges()) return NULL; - return AddFaceWithID(e1,e2,e3,e4, myElementIDFactory->GetFreeID()); + //MESSAGE("AddFaceWithID" ); + return AddFaceWithID(e1,e2,e3,e4, myElementIDFactory->GetFreeID()); } /////////////////////////////////////////////////////////////////////////////// @@ -393,49 +575,54 @@ SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(const SMDS_MeshEdge * e1, { if (!hasConstructionEdges()) return NULL; + MESSAGE("AddFaceWithID" << ID); if ( !e1 || !e2 || !e3 || !e4 ) return 0; - if ( myFaces.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if ( NbFaces() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); SMDS_MeshFace * face = new SMDS_FaceOfEdges(e1,e2,e3,e4); - myFaces.Add(face); + adjustmyCellsCapacity(ID); + myCells[ID] = face; myInfo.myNbQuadrangles++; if (!registerElement(ID, face)) { - RemoveElement(face, false); - face = NULL; + registerElement(myElementIDFactory->GetFreeID(), face); + //RemoveElement(face, false); + //face = NULL; } return face; } /////////////////////////////////////////////////////////////////////////////// -///Create a new tetrahedron and add it to the mesh. -///@return The created tetrahedron +///Create a new tetrahedron and add it to the mesh. +///@return The created tetrahedron /////////////////////////////////////////////////////////////////////////////// SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4) { int ID = myElementIDFactory->GetFreeID(); + //MESSAGE("AddVolumeWithID " << ID); SMDS_MeshVolume * v = SMDS_Mesh::AddVolumeWithID(n1, n2, n3, n4, ID); if(v==NULL) myElementIDFactory->ReleaseID(ID); return v; } /////////////////////////////////////////////////////////////////////////////// -///Create a new tetrahedron and add it to the mesh. +///Create a new tetrahedron and add it to the mesh. ///@param ID The ID of the new volume ///@return The created tetrahedron or NULL if an element with this ID already exists ///or if input nodes are not found. /////////////////////////////////////////////////////////////////////////////// -SMDS_MeshVolume * SMDS_Mesh::AddVolumeWithID(int idnode1, - int idnode2, - int idnode3, - int idnode4, - int ID) +SMDS_MeshVolume * SMDS_Mesh::AddVolumeWithID(int idnode1, + int idnode2, + int idnode3, + int idnode4, + int ID) { + //MESSAGE("AddVolumeWithID" << ID); SMDS_MeshNode *node1, *node2, *node3, *node4; node1 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode1); node2 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode2); @@ -444,11 +631,11 @@ SMDS_MeshVolume * SMDS_Mesh::AddVolumeWithID(int idnode1, if(!node1 || !node2 || !node3 || !node4) return NULL; return SMDS_Mesh::AddVolumeWithID(node1, node2, node3, node4, ID); } - + /////////////////////////////////////////////////////////////////////////////// -///Create a new tetrahedron and add it to the mesh. +///Create a new tetrahedron and add it to the mesh. ///@param ID The ID of the new volume -///@return The created tetrahedron +///@return The created tetrahedron /////////////////////////////////////////////////////////////////////////////// SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, @@ -457,16 +644,18 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n4, int ID) { + //MESSAGE("AddVolumeWithID " << ID); SMDS_MeshVolume* volume = 0; if ( !n1 || !n2 || !n3 || !n4) return volume; - if ( myVolumes.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if ( NbVolumes() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); if(hasConstructionFaces()) { SMDS_MeshFace * f1=FindFaceOrCreate(n1,n2,n3); SMDS_MeshFace * f2=FindFaceOrCreate(n1,n2,n4); SMDS_MeshFace * f3=FindFaceOrCreate(n1,n3,n4); SMDS_MeshFace * f4=FindFaceOrCreate(n2,n3,n4); volume=new SMDS_VolumeOfFaces(f1,f2,f3,f4); - myVolumes.Add(volume); + adjustmyCellsCapacity(ID); + myCells[ID] = volume; myInfo.myNbTetras++; } else if(hasConstructionEdges()) { @@ -474,51 +663,69 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, return NULL; } else { - volume=new SMDS_VolumeOfNodes(n1,n2,n3,n4); - myVolumes.Add(volume); + // --- retrieve nodes ID + myNodeIds.resize(4); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n3->getVtkId(); // order SMDS-->VTK + myNodeIds[2] = n2->getVtkId(); + myNodeIds[3] = n4->getVtkId(); + + SMDS_VtkVolume *volvtk = myVolumePool->getNew(); + volvtk->init(myNodeIds, this); + if (!this->registerElement(ID,volvtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(volvtk->getVtkId(), VTK_EMPTY_CELL); + myVolumePool->destroy(volvtk); + return 0; + } + volume = volvtk; + adjustmyCellsCapacity(ID); + myCells[ID] = volume; myInfo.myNbTetras++; } - if (!registerElement(ID, volume)) { - RemoveElement(volume, false); - volume = NULL; - } + // if (!registerElement(ID, volume)) { + // RemoveElement(volume, false); + // volume = NULL; + // } return volume; } /////////////////////////////////////////////////////////////////////////////// -///Create a new pyramid and add it to the mesh. +///Create a new pyramid and add it to the mesh. ///Nodes 1,2,3 and 4 define the base of the pyramid -///@return The created pyramid +///@return The created pyramid /////////////////////////////////////////////////////////////////////////////// SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5) { int ID = myElementIDFactory->GetFreeID(); + //MESSAGE("AddVolumeWithID " << ID); SMDS_MeshVolume * v = SMDS_Mesh::AddVolumeWithID(n1, n2, n3, n4, n5, ID); if(v==NULL) myElementIDFactory->ReleaseID(ID); return v; } /////////////////////////////////////////////////////////////////////////////// -///Create a new pyramid and add it to the mesh. +///Create a new pyramid and add it to the mesh. ///Nodes 1,2,3 and 4 define the base of the pyramid ///@param ID The ID of the new volume ///@return The created pyramid or NULL if an element with this ID already exists ///or if input nodes are not found. /////////////////////////////////////////////////////////////////////////////// -SMDS_MeshVolume * SMDS_Mesh::AddVolumeWithID(int idnode1, - int idnode2, - int idnode3, - int idnode4, - int idnode5, - int ID) +SMDS_MeshVolume * SMDS_Mesh::AddVolumeWithID(int idnode1, + int idnode2, + int idnode3, + int idnode4, + int idnode5, + int ID) { + //MESSAGE("AddVolumeWithID " << ID); SMDS_MeshNode *node1, *node2, *node3, *node4, *node5; node1 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode1); node2 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode2); @@ -528,7 +735,7 @@ SMDS_MeshVolume * SMDS_Mesh::AddVolumeWithID(int idnode1, if(!node1 || !node2 || !node3 || !node4 || !node5) return NULL; return SMDS_Mesh::AddVolumeWithID(node1, node2, node3, node4, node5, ID); } - + /////////////////////////////////////////////////////////////////////////////// ///Create a new pyramid and add it to the mesh. ///Nodes 1,2,3 and 4 define the base of the pyramid @@ -543,16 +750,18 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n5, int ID) { + //MESSAGE("AddVolumeWithID " << ID); SMDS_MeshVolume* volume = 0; if ( !n1 || !n2 || !n3 || !n4 || !n5) return volume; - if ( myVolumes.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if ( NbVolumes() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); if(hasConstructionFaces()) { SMDS_MeshFace * f1=FindFaceOrCreate(n1,n2,n3,n4); SMDS_MeshFace * f2=FindFaceOrCreate(n1,n2,n5); SMDS_MeshFace * f3=FindFaceOrCreate(n2,n3,n5); SMDS_MeshFace * f4=FindFaceOrCreate(n3,n4,n5); volume=new SMDS_VolumeOfFaces(f1,f2,f3,f4); - myVolumes.Add(volume); + adjustmyCellsCapacity(ID); + myCells[ID] = volume; myInfo.myNbPyramids++; } else if(hasConstructionEdges()) { @@ -560,53 +769,72 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, return NULL; } else { - volume=new SMDS_VolumeOfNodes(n1,n2,n3,n4,n5); - myVolumes.Add(volume); + // --- retrieve nodes ID + myNodeIds.resize(5); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n4->getVtkId(); + myNodeIds[2] = n3->getVtkId(); + myNodeIds[3] = n2->getVtkId(); + myNodeIds[4] = n5->getVtkId(); + + SMDS_VtkVolume *volvtk = myVolumePool->getNew(); + volvtk->init(myNodeIds, this); + if (!this->registerElement(ID,volvtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(volvtk->getVtkId(), VTK_EMPTY_CELL); + myVolumePool->destroy(volvtk); + return 0; + } + volume = volvtk; + adjustmyCellsCapacity(ID); + myCells[ID] = volume; myInfo.myNbPyramids++; } - if (!registerElement(ID, volume)) { - RemoveElement(volume, false); - volume = NULL; - } + // if (!registerElement(ID, volume)) { + // RemoveElement(volume, false); + // volume = NULL; + // } return volume; } /////////////////////////////////////////////////////////////////////////////// -///Create a new prism and add it to the mesh. +///Create a new prism and add it to the mesh. ///Nodes 1,2,3 is a triangle and 1,2,5,4 a quadrangle. -///@return The created prism +///@return The created prism /////////////////////////////////////////////////////////////////////////////// SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6) { int ID = myElementIDFactory->GetFreeID(); + //MESSAGE("AddVolumeWithID " << ID); SMDS_MeshVolume * v = SMDS_Mesh::AddVolumeWithID(n1, n2, n3, n4, n5, n6, ID); if(v==NULL) myElementIDFactory->ReleaseID(ID); return v; } /////////////////////////////////////////////////////////////////////////////// -///Create a new prism and add it to the mesh. +///Create a new prism and add it to the mesh. ///Nodes 1,2,3 is a triangle and 1,2,5,4 a quadrangle. ///@param ID The ID of the new volume ///@return The created prism or NULL if an element with this ID already exists ///or if input nodes are not found. /////////////////////////////////////////////////////////////////////////////// -SMDS_MeshVolume * SMDS_Mesh::AddVolumeWithID(int idnode1, - int idnode2, - int idnode3, - int idnode4, - int idnode5, - int idnode6, - int ID) +SMDS_MeshVolume * SMDS_Mesh::AddVolumeWithID(int idnode1, + int idnode2, + int idnode3, + int idnode4, + int idnode5, + int idnode6, + int ID) { + //MESSAGE("AddVolumeWithID " << ID); SMDS_MeshNode *node1, *node2, *node3, *node4, *node5, *node6; node1 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode1); node2 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode2); @@ -617,7 +845,7 @@ SMDS_MeshVolume * SMDS_Mesh::AddVolumeWithID(int idnode1, if(!node1 || !node2 || !node3 || !node4 || !node5 || !node6) return NULL; return SMDS_Mesh::AddVolumeWithID(node1, node2, node3, node4, node5, node6, ID); } - + /////////////////////////////////////////////////////////////////////////////// ///Create a new prism and add it to the mesh. ///Nodes 1,2,3 is a triangle and 1,2,5,4 a quadrangle. @@ -633,9 +861,10 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n6, int ID) { + //MESSAGE("AddVolumeWithID " << ID); SMDS_MeshVolume* volume = 0; if ( !n1 || !n2 || !n3 || !n4 || !n5 || !n6) return volume; - if ( myVolumes.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if ( NbVolumes() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); if(hasConstructionFaces()) { SMDS_MeshFace * f1=FindFaceOrCreate(n1,n2,n3); SMDS_MeshFace * f2=FindFaceOrCreate(n4,n5,n6); @@ -643,7 +872,8 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, SMDS_MeshFace * f4=FindFaceOrCreate(n2,n5,n6,n3); SMDS_MeshFace * f5=FindFaceOrCreate(n3,n6,n4,n1); volume=new SMDS_VolumeOfFaces(f1,f2,f3,f4,f5); - myVolumes.Add(volume); + adjustmyCellsCapacity(ID); + myCells[ID] = volume; myInfo.myNbPrisms++; } else if(hasConstructionEdges()) { @@ -651,57 +881,207 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, return NULL; } else { - volume=new SMDS_VolumeOfNodes(n1,n2,n3,n4,n5,n6); - myVolumes.Add(volume); + // --- retrieve nodes ID + myNodeIds.resize(6); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n2->getVtkId(); + myNodeIds[2] = n3->getVtkId(); + myNodeIds[3] = n4->getVtkId(); + myNodeIds[4] = n5->getVtkId(); + myNodeIds[5] = n6->getVtkId(); + + SMDS_VtkVolume *volvtk = myVolumePool->getNew(); + volvtk->init(myNodeIds, this); + if (!this->registerElement(ID,volvtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(volvtk->getVtkId(), VTK_EMPTY_CELL); + myVolumePool->destroy(volvtk); + return 0; + } + volume = volvtk; + adjustmyCellsCapacity(ID); + myCells[ID] = volume; myInfo.myNbPrisms++; } - if (!registerElement(ID, volume)) { - RemoveElement(volume, false); - volume = NULL; + // if (!registerElement(ID, volume)) { + // RemoveElement(volume, false); + // volume = NULL; + // } + return volume; +} + +/////////////////////////////////////////////////////////////////////////////// +///Create a new hexagonal prism and add it to the mesh. +///@return The created prism +/////////////////////////////////////////////////////////////////////////////// + +SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n9, + const SMDS_MeshNode * n10, + const SMDS_MeshNode * n11, + const SMDS_MeshNode * n12) +{ + int ID = myElementIDFactory->GetFreeID(); + SMDS_MeshVolume * v = SMDS_Mesh::AddVolumeWithID(n1, n2, n3, n4, n5, n6, + n7, n8, n9, n10, n11, n12, + ID); + if(v==NULL) myElementIDFactory->ReleaseID(ID); + return v; +} + +/////////////////////////////////////////////////////////////////////////////// +///Create a new hexagonal prism and add it to the mesh. +///@param ID The ID of the new volume +///@return The created prism or NULL if an element with this ID already exists +///or if input nodes are not found. +/////////////////////////////////////////////////////////////////////////////// + +SMDS_MeshVolume * SMDS_Mesh::AddVolumeWithID(int idnode1, + int idnode2, + int idnode3, + int idnode4, + int idnode5, + int idnode6, + int idnode7, + int idnode8, + int idnode9, + int idnode10, + int idnode11, + int idnode12, + int ID) +{ + SMDS_MeshNode *node1 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode1); + SMDS_MeshNode *node2 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode2); + SMDS_MeshNode *node3 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode3); + SMDS_MeshNode *node4 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode4); + SMDS_MeshNode *node5 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode5); + SMDS_MeshNode *node6 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode6); + SMDS_MeshNode *node7 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode7); + SMDS_MeshNode *node8 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode8); + SMDS_MeshNode *node9 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode9); + SMDS_MeshNode *node10 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode10); + SMDS_MeshNode *node11 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode11); + SMDS_MeshNode *node12 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode12); + return SMDS_Mesh::AddVolumeWithID(node1, node2, node3, node4, node5, node6, + node7, node8, node9, node10, node11, node12, + ID); +} + +/////////////////////////////////////////////////////////////////////////////// +///Create a new hexagonal prism and add it to the mesh. +///@param ID The ID of the new volume +///@return The created prism +/////////////////////////////////////////////////////////////////////////////// + +SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n9, + const SMDS_MeshNode * n10, + const SMDS_MeshNode * n11, + const SMDS_MeshNode * n12, + int ID) +{ + SMDS_MeshVolume* volume = 0; + if(!n1 || !n2 || !n3 || !n4 || !n5 || !n6 || + !n7 || !n8 || !n9 || !n10 || !n11 || !n12 ) + return volume; + if ( NbVolumes() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if(hasConstructionFaces()) { + MESSAGE("Error : Not implemented"); + return NULL; + } + else if(hasConstructionEdges()) { + MESSAGE("Error : Not implemented"); + return NULL; + } + else { + // --- retrieve nodes ID + myNodeIds.resize(12); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n6->getVtkId(); + myNodeIds[2] = n5->getVtkId(); + myNodeIds[3] = n4->getVtkId(); + myNodeIds[4] = n3->getVtkId(); + myNodeIds[5] = n2->getVtkId(); + + myNodeIds[6] = n7->getVtkId(); + myNodeIds[7] = n12->getVtkId(); + myNodeIds[8] = n11->getVtkId(); + myNodeIds[9] = n10->getVtkId(); + myNodeIds[10] = n9->getVtkId(); + myNodeIds[11] = n8->getVtkId(); + + SMDS_VtkVolume *volvtk = myVolumePool->getNew(); + volvtk->init(myNodeIds, this); + if (!this->registerElement(ID,volvtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(volvtk->getVtkId(), VTK_EMPTY_CELL); + myVolumePool->destroy(volvtk); + return 0; + } + volume = volvtk; + adjustmyCellsCapacity(ID); + myCells[ID] = volume; + myInfo.myNbHexPrism++; } + return volume; } /////////////////////////////////////////////////////////////////////////////// -///Create a new hexahedron and add it to the mesh. +///Create a new hexahedron and add it to the mesh. ///Nodes 1,2,3,4 and 5,6,7,8 are quadrangle and 5,1 and 7,3 are an edges. -///@return The created hexahedron +///@return The created hexahedron /////////////////////////////////////////////////////////////////////////////// SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8) { int ID = myElementIDFactory->GetFreeID(); - SMDS_MeshVolume * v = SMDS_Mesh::AddVolumeWithID(n1, n2, n3, n4, n5, n6, n7, n8, ID); + SMDS_MeshVolume * v = SMDS_Mesh::AddVolumeWithID(n1, n2, n3, n4, n5, n6, n7, n8, ID); if(v==NULL) myElementIDFactory->ReleaseID(ID); return v; } /////////////////////////////////////////////////////////////////////////////// -///Create a new hexahedron and add it to the mesh. +///Create a new hexahedron and add it to the mesh. ///Nodes 1,2,3,4 and 5,6,7,8 are quadrangle and 5,1 and 7,3 are an edges. ///@param ID The ID of the new volume ///@return The created hexahedron or NULL if an element with this ID already ///exists or if input nodes are not found. /////////////////////////////////////////////////////////////////////////////// -SMDS_MeshVolume * SMDS_Mesh::AddVolumeWithID(int idnode1, - int idnode2, - int idnode3, - int idnode4, - int idnode5, - int idnode6, - int idnode7, - int idnode8, - int ID) +SMDS_MeshVolume * SMDS_Mesh::AddVolumeWithID(int idnode1, + int idnode2, + int idnode3, + int idnode4, + int idnode5, + int idnode6, + int idnode7, + int idnode8, + int ID) { + //MESSAGE("AddVolumeWithID " << ID); SMDS_MeshNode *node1, *node2, *node3, *node4, *node5, *node6, *node7, *node8; node1 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode1); node2 = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(idnode2); @@ -716,7 +1096,7 @@ SMDS_MeshVolume * SMDS_Mesh::AddVolumeWithID(int idnode1, return SMDS_Mesh::AddVolumeWithID(node1, node2, node3, node4, node5, node6, node7, node8, ID); } - + /////////////////////////////////////////////////////////////////////////////// ///Create a new hexahedron and add it to the mesh. ///Nodes 1,2,3,4 and 5,6,7,8 are quadrangle and 5,1 and 7,3 are an edges. @@ -735,9 +1115,10 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n8, int ID) { + //MESSAGE("AddVolumeWithID " << ID); SMDS_MeshVolume* volume = 0; if ( !n1 || !n2 || !n3 || !n4 || !n5 || !n6 || !n7 || !n8) return volume; - if ( myVolumes.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if ( NbVolumes() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); if(hasConstructionFaces()) { SMDS_MeshFace * f1=FindFaceOrCreate(n1,n2,n3,n4); SMDS_MeshFace * f2=FindFaceOrCreate(n5,n6,n7,n8); @@ -746,7 +1127,8 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, SMDS_MeshFace * f5=FindFaceOrCreate(n2,n3,n7,n6); SMDS_MeshFace * f6=FindFaceOrCreate(n3,n4,n8,n7); volume=new SMDS_VolumeOfFaces(f1,f2,f3,f4,f5,f6); - myVolumes.Add(volume); + adjustmyCellsCapacity(ID); + myCells[ID] = volume; myInfo.myNbHexas++; } else if(hasConstructionEdges()) { @@ -754,16 +1136,35 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, return NULL; } else { -// volume=new SMDS_HexahedronOfNodes(n1,n2,n3,n4,n5,n6,n7,n8); - volume=new SMDS_VolumeOfNodes(n1,n2,n3,n4,n5,n6,n7,n8); - myVolumes.Add(volume); + // --- retrieve nodes ID + myNodeIds.resize(8); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n4->getVtkId(); + myNodeIds[2] = n3->getVtkId(); + myNodeIds[3] = n2->getVtkId(); + myNodeIds[4] = n5->getVtkId(); + myNodeIds[5] = n8->getVtkId(); + myNodeIds[6] = n7->getVtkId(); + myNodeIds[7] = n6->getVtkId(); + + SMDS_VtkVolume *volvtk = myVolumePool->getNew(); + volvtk->init(myNodeIds, this); + if (!this->registerElement(ID,volvtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(volvtk->getVtkId(), VTK_EMPTY_CELL); + myVolumePool->destroy(volvtk); + return 0; + } + volume = volvtk; + adjustmyCellsCapacity(ID); + myCells[ID] = volume; myInfo.myNbHexas++; } - if (!registerElement(ID, volume)) { - RemoveElement(volume, false); - volume = NULL; - } + // if (!registerElement(ID, volume)) { + // RemoveElement(volume, false); + // volume = NULL; + // } return volume; } @@ -777,6 +1178,7 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshFace * f1, const SMDS_MeshFace * f3, const SMDS_MeshFace * f4) { + //MESSAGE("AddVolumeWithID"); if (!hasConstructionFaces()) return NULL; return AddVolumeWithID(f1,f2,f3,f4, myElementIDFactory->GetFreeID()); @@ -785,7 +1187,7 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshFace * f1, /////////////////////////////////////////////////////////////////////////////// ///Create a new tetrahedron defined by its faces and add it to the mesh. ///@param ID The ID of the new volume -///@return The created tetrahedron +///@return The created tetrahedron /////////////////////////////////////////////////////////////////////////////// SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshFace * f1, @@ -794,17 +1196,20 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshFace * f1, const SMDS_MeshFace * f4, int ID) { + MESSAGE("AddVolumeWithID" << ID); if (!hasConstructionFaces()) return NULL; if ( !f1 || !f2 || !f3 || !f4) return 0; - if ( myVolumes.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if ( NbVolumes() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); SMDS_MeshVolume * volume = new SMDS_VolumeOfFaces(f1,f2,f3,f4); - myVolumes.Add(volume); + adjustmyCellsCapacity(ID); + myCells[ID] = volume; myInfo.myNbTetras++; if (!registerElement(ID, volume)) { - RemoveElement(volume, false); - volume = NULL; + registerElement(myElementIDFactory->GetFreeID(), volume); + //RemoveElement(volume, false); + //volume = NULL; } return volume; } @@ -820,7 +1225,8 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshFace * f1, const SMDS_MeshFace * f4, const SMDS_MeshFace * f5) { - if (!hasConstructionFaces()) + //MESSAGE("AddVolumeWithID"); + if (!hasConstructionFaces()) return NULL; return AddVolumeWithID(f1,f2,f3,f4,f5, myElementIDFactory->GetFreeID()); } @@ -828,7 +1234,7 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshFace * f1, /////////////////////////////////////////////////////////////////////////////// ///Create a new pyramid defined by its faces and add it to the mesh. ///@param ID The ID of the new volume -///@return The created pyramid +///@return The created pyramid /////////////////////////////////////////////////////////////////////////////// SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshFace * f1, @@ -838,17 +1244,20 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshFace * f1, const SMDS_MeshFace * f5, int ID) { + MESSAGE("AddVolumeWithID" << ID); if (!hasConstructionFaces()) return NULL; if ( !f1 || !f2 || !f3 || !f4 || !f5) return 0; - if ( myVolumes.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if ( NbVolumes() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); SMDS_MeshVolume * volume = new SMDS_VolumeOfFaces(f1,f2,f3,f4,f5); - myVolumes.Add(volume); + adjustmyCellsCapacity(ID); + myCells[ID] = volume; myInfo.myNbPyramids++; if (!registerElement(ID, volume)) { - RemoveElement(volume, false); - volume = NULL; + registerElement(myElementIDFactory->GetFreeID(), volume); + //RemoveElement(volume, false); + //volume = NULL; } return volume; } @@ -865,7 +1274,8 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshFace * f1, const SMDS_MeshFace * f5, const SMDS_MeshFace * f6) { - if (!hasConstructionFaces()) + //MESSAGE("AddVolumeWithID" ); + if (!hasConstructionFaces()) return NULL; return AddVolumeWithID(f1,f2,f3,f4,f5,f6, myElementIDFactory->GetFreeID()); } @@ -873,7 +1283,7 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshFace * f1, /////////////////////////////////////////////////////////////////////////////// ///Create a new prism defined by its faces and add it to the mesh. ///@param ID The ID of the new volume -///@return The created prism +///@return The created prism /////////////////////////////////////////////////////////////////////////////// SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshFace * f1, @@ -884,17 +1294,20 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshFace * f1, const SMDS_MeshFace * f6, int ID) { + MESSAGE("AddVolumeWithID" << ID); if (!hasConstructionFaces()) return NULL; if ( !f1 || !f2 || !f3 || !f4 || !f5 || !f6) return 0; - if ( myVolumes.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if ( NbVolumes() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); SMDS_MeshVolume * volume = new SMDS_VolumeOfFaces(f1,f2,f3,f4,f5,f6); - myVolumes.Add(volume); + adjustmyCellsCapacity(ID); + myCells[ID] = volume; myInfo.myNbPrisms++; if (!registerElement(ID, volume)) { - RemoveElement(volume, false); - volume = NULL; + registerElement(myElementIDFactory->GetFreeID(), volume); + //RemoveElement(volume, false); + //volume = NULL; } return volume; } @@ -903,29 +1316,29 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshFace * f1, /// Add a polygon defined by its nodes IDs /////////////////////////////////////////////////////////////////////////////// -SMDS_MeshFace* SMDS_Mesh::AddPolygonalFaceWithID (std::vector nodes_ids, - const int ID) +SMDS_MeshFace* SMDS_Mesh::AddPolygonalFaceWithID (const vector & nodes_ids, + const int ID) { int nbNodes = nodes_ids.size(); - std::vector nodes (nbNodes); + vector nodes (nbNodes); for (int i = 0; i < nbNodes; i++) { nodes[i] = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(nodes_ids[i]); if (!nodes[i]) return NULL; } - return SMDS_Mesh::AddPolygonalFaceWithID(nodes, ID); + return SMDS_Mesh::AddPolygonalFaceWithID(nodes, ID); } /////////////////////////////////////////////////////////////////////////////// /// Add a polygon defined by its nodes /////////////////////////////////////////////////////////////////////////////// -SMDS_MeshFace* SMDS_Mesh::AddPolygonalFaceWithID - (std::vector nodes, - const int ID) +SMDS_MeshFace* +SMDS_Mesh::AddPolygonalFaceWithID (const vector & nodes, + const int ID) { SMDS_MeshFace * face; - if ( myFaces.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if ( NbFaces() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); if (hasConstructionEdges()) { MESSAGE("Error : Not implemented"); @@ -933,17 +1346,25 @@ SMDS_MeshFace* SMDS_Mesh::AddPolygonalFaceWithID } else { - for ( int i = 0; i < nodes.size(); ++i ) - if ( !nodes[ i ] ) return 0; - face = new SMDS_PolygonalFaceOfNodes(nodes); - myFaces.Add(face); + myNodeIds.resize( nodes.size() ); + for ( size_t i = 0; i < nodes.size(); ++i ) + myNodeIds[i] = nodes[i]->getVtkId(); + + SMDS_VtkFace *facevtk = myFacePool->getNew(); + facevtk->initPoly(myNodeIds, this); + if (!this->registerElement(ID,facevtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(facevtk->getVtkId(), VTK_EMPTY_CELL); + myFacePool->destroy(facevtk); + return 0; + } + face = facevtk; + + adjustmyCellsCapacity(ID); + myCells[ID] = face; myInfo.myNbPolygons++; } - if (!registerElement(ID, face)) { - RemoveElement(face, false); - face = NULL; - } return face; } @@ -952,25 +1373,88 @@ SMDS_MeshFace* SMDS_Mesh::AddPolygonalFaceWithID /// An ID is automatically affected to the created face. /////////////////////////////////////////////////////////////////////////////// -SMDS_MeshFace* SMDS_Mesh::AddPolygonalFace (std::vector nodes) +SMDS_MeshFace* SMDS_Mesh::AddPolygonalFace (const vector & nodes) { return SMDS_Mesh::AddPolygonalFaceWithID(nodes, myElementIDFactory->GetFreeID()); } /////////////////////////////////////////////////////////////////////////////// -/// Create a new polyhedral volume and add it to the mesh. +/// Add a quadratic polygon defined by its nodes IDs +/////////////////////////////////////////////////////////////////////////////// + +SMDS_MeshFace* SMDS_Mesh::AddQuadPolygonalFaceWithID (const vector & nodes_ids, + const int ID) +{ + vector nodes( nodes_ids.size() ); + for ( size_t i = 0; i < nodes.size(); i++) { + nodes[i] = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(nodes_ids[i]); + if (!nodes[i]) return NULL; + } + return SMDS_Mesh::AddQuadPolygonalFaceWithID(nodes, ID); +} + +/////////////////////////////////////////////////////////////////////////////// +/// Add a quadratic polygon defined by its nodes +/////////////////////////////////////////////////////////////////////////////// + +SMDS_MeshFace* +SMDS_Mesh::AddQuadPolygonalFaceWithID (const vector & nodes, + const int ID) +{ + SMDS_MeshFace * face; + + if ( NbFaces() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if (hasConstructionEdges()) + { + MESSAGE("Error : Not implemented"); + return NULL; + } + else + { + myNodeIds.resize( nodes.size() ); + for ( size_t i = 0; i < nodes.size(); ++i ) + myNodeIds[i] = nodes[i]->getVtkId(); + + SMDS_VtkFace *facevtk = myFacePool->getNew(); + facevtk->initQuadPoly(myNodeIds, this); + if (!this->registerElement(ID,facevtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(facevtk->getVtkId(), VTK_EMPTY_CELL); + myFacePool->destroy(facevtk); + return 0; + } + face = facevtk; + adjustmyCellsCapacity(ID); + myCells[ID] = face; + myInfo.myNbQuadPolygons++; + } + return face; +} + +/////////////////////////////////////////////////////////////////////////////// +/// Add a quadratic polygon defined by its nodes. +/// An ID is automatically affected to the created face. +/////////////////////////////////////////////////////////////////////////////// + +SMDS_MeshFace* SMDS_Mesh::AddQuadPolygonalFace (const vector & nodes) +{ + return SMDS_Mesh::AddQuadPolygonalFaceWithID(nodes, myElementIDFactory->GetFreeID()); +} + +/////////////////////////////////////////////////////////////////////////////// +/// Create a new polyhedral volume and add it to the mesh. /// @param ID The ID of the new volume /// @return The created volume or NULL if an element with this ID already exists /// or if input nodes are not found. /////////////////////////////////////////////////////////////////////////////// SMDS_MeshVolume * SMDS_Mesh::AddPolyhedralVolumeWithID - (std::vector nodes_ids, - std::vector quantities, - const int ID) + (const vector & nodes_ids, + const vector & quantities, + const int ID) { int nbNodes = nodes_ids.size(); - std::vector nodes (nbNodes); + vector nodes (nbNodes); for (int i = 0; i < nbNodes; i++) { nodes[i] = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(nodes_ids[i]); if (!nodes[i]) return NULL; @@ -979,47 +1463,77 @@ SMDS_MeshVolume * SMDS_Mesh::AddPolyhedralVolumeWithID } /////////////////////////////////////////////////////////////////////////////// -/// Create a new polyhedral volume and add it to the mesh. +/// Create a new polyhedral volume and add it to the mesh. /// @param ID The ID of the new volume /// @return The created volume /////////////////////////////////////////////////////////////////////////////// -SMDS_MeshVolume* SMDS_Mesh::AddPolyhedralVolumeWithID - (std::vector nodes, - std::vector quantities, - const int ID) +SMDS_MeshVolume* +SMDS_Mesh::AddPolyhedralVolumeWithID (const vector& nodes, + const vector & quantities, + const int ID) { - SMDS_MeshVolume* volume; - if ( myVolumes.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); - if (hasConstructionFaces()) { + SMDS_MeshVolume* volume = 0; + if ( nodes.empty() || quantities.empty() ) + return NULL; + if ( NbVolumes() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if (hasConstructionFaces()) + { MESSAGE("Error : Not implemented"); return NULL; - } else if (hasConstructionEdges()) { + } + else if (hasConstructionEdges()) + { MESSAGE("Error : Not implemented"); return NULL; - } else { - for ( int i = 0; i < nodes.size(); ++i ) - if ( !nodes[ i ] ) return 0; - volume = new SMDS_PolyhedralVolumeOfNodes(nodes, quantities); - myVolumes.Add(volume); + } + else + { + //#ifdef VTK_HAVE_POLYHEDRON + //MESSAGE("AddPolyhedralVolumeWithID vtk " << ID); + myNodeIds.resize( nodes.size() ); + for ( size_t i = 0; i < nodes.size(); ++i ) + myNodeIds[i] = nodes[i]->getVtkId(); + + SMDS_VtkVolume *volvtk = myVolumePool->getNew(); + volvtk->initPoly(myNodeIds, quantities, this); + if (!this->registerElement(ID, volvtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(volvtk->getVtkId(), VTK_EMPTY_CELL); + myVolumePool->destroy(volvtk); + return 0; + } + volume = volvtk; + //#else + // MESSAGE("AddPolyhedralVolumeWithID smds " << ID); + // for ( int i = 0; i < nodes.size(); ++i ) + // if ( !nodes[ i ] ) return 0; + // volume = new SMDS_PolyhedralVolumeOfNodes(nodes, quantities); + //#endif + adjustmyCellsCapacity(ID); + myCells[ID] = volume; myInfo.myNbPolyhedrons++; } - if (!registerElement(ID, volume)) { - RemoveElement(volume, false); - volume = NULL; - } + //#ifndef VTK_HAVE_POLYHEDRON + // if (!registerElement(ID, volume)) + // { + // registerElement(myElementIDFactory->GetFreeID(), volume); + // //RemoveElement(volume, false); + // //volume = NULL; + // } + //#endif return volume; } /////////////////////////////////////////////////////////////////////////////// -/// Create a new polyhedral volume and add it to the mesh. +/// Create a new polyhedral volume and add it to the mesh. /// @return The created volume /////////////////////////////////////////////////////////////////////////////// SMDS_MeshVolume* SMDS_Mesh::AddPolyhedralVolume - (std::vector nodes, - std::vector quantities) + (const vector & nodes, + const vector & quantities) { int ID = myElementIDFactory->GetFreeID(); SMDS_MeshVolume * v = SMDS_Mesh::AddPolyhedralVolumeWithID(nodes, quantities, ID); @@ -1027,41 +1541,200 @@ SMDS_MeshVolume* SMDS_Mesh::AddPolyhedralVolume return v; } -/////////////////////////////////////////////////////////////////////////////// -/// Registers element with the given ID, maintains inverse connections -/////////////////////////////////////////////////////////////////////////////// -bool SMDS_Mesh::registerElement(int ID, SMDS_MeshElement * element) +SMDS_MeshVolume* SMDS_Mesh::AddVolumeFromVtkIds(const std::vector& vtkNodeIds) +{ + int ID = myElementIDFactory->GetFreeID(); + SMDS_MeshVolume * v = SMDS_Mesh::AddVolumeFromVtkIdsWithID(vtkNodeIds, ID); + if (v == NULL) myElementIDFactory->ReleaseID(ID); + return v; +} + +SMDS_MeshVolume* SMDS_Mesh::AddVolumeFromVtkIdsWithID(const std::vector& vtkNodeIds, const int ID) { - if (myElementIDFactory->BindID(ID, element)) { - SMDS_ElemIteratorPtr it = element->nodesIterator(); - while (it->more()) { - SMDS_MeshNode *node = static_cast - (const_cast(it->next())); - node->AddInverseElement(element); + SMDS_VtkVolume *volvtk = myVolumePool->getNew(); + volvtk->init(vtkNodeIds, this); + if (!this->registerElement(ID,volvtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(volvtk->getVtkId(), VTK_EMPTY_CELL); + myVolumePool->destroy(volvtk); + return 0; } - return true; + adjustmyCellsCapacity(ID); + myCells[ID] = volvtk; + vtkIdType aVtkType = volvtk->GetVtkType(); + switch (aVtkType) + { + case VTK_TETRA: + myInfo.myNbTetras++; + break; + case VTK_PYRAMID: + myInfo.myNbPyramids++; + break; + case VTK_WEDGE: + myInfo.myNbPrisms++; + break; + case VTK_HEXAHEDRON: + myInfo.myNbHexas++; + break; + case VTK_QUADRATIC_TETRA: + myInfo.myNbQuadTetras++; + break; + case VTK_QUADRATIC_PYRAMID: + myInfo.myNbQuadPyramids++; + break; + case VTK_QUADRATIC_WEDGE: + myInfo.myNbQuadPrisms++; + break; + case VTK_QUADRATIC_HEXAHEDRON: + myInfo.myNbQuadHexas++; + break; +//#ifdef VTK_HAVE_POLYHEDRON + case VTK_POLYHEDRON: + myInfo.myNbPolyhedrons++; + break; +//#endif + default: + myInfo.myNbPolyhedrons++; + break; } - return false; + return volvtk; } -/////////////////////////////////////////////////////////////////////////////// -/// Return the node whose ID is 'ID'. -/////////////////////////////////////////////////////////////////////////////// -const SMDS_MeshNode * SMDS_Mesh::FindNode(int ID) const +SMDS_MeshFace* SMDS_Mesh::AddFaceFromVtkIds(const std::vector& vtkNodeIds) { - return (const SMDS_MeshNode *)myNodeIDFactory->MeshElement(ID); + int ID = myElementIDFactory->GetFreeID(); + SMDS_MeshFace * f = SMDS_Mesh::AddFaceFromVtkIdsWithID(vtkNodeIds, ID); + if (f == NULL) myElementIDFactory->ReleaseID(ID); + return f; } -/////////////////////////////////////////////////////////////////////////////// -///Create a triangle and add it to the current mesh. This methode do not bind a -///ID to the create triangle. -/////////////////////////////////////////////////////////////////////////////// -SMDS_MeshFace * SMDS_Mesh::createTriangle(const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2, - const SMDS_MeshNode * node3) +SMDS_MeshFace* SMDS_Mesh::AddFaceFromVtkIdsWithID(const std::vector& vtkNodeIds, const int ID) +{ + SMDS_VtkFace *facevtk = myFacePool->getNew(); + facevtk->init(vtkNodeIds, this); + if (!this->registerElement(ID,facevtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(facevtk->getVtkId(), VTK_EMPTY_CELL); + myFacePool->destroy(facevtk); + return 0; + } + adjustmyCellsCapacity(ID); + myCells[ID] = facevtk; + vtkIdType aVtkType = facevtk->GetVtkType(); + switch (aVtkType) + { + case VTK_TRIANGLE: + myInfo.myNbTriangles++; + break; + case VTK_QUAD: + myInfo.myNbQuadrangles++; + break; + case VTK_QUADRATIC_TRIANGLE: + myInfo.myNbQuadTriangles++; + break; + case VTK_QUADRATIC_QUAD: + myInfo.myNbQuadQuadrangles++; + break; + case VTK_BIQUADRATIC_QUAD: + myInfo.myNbBiQuadQuadrangles++; + break; + case VTK_BIQUADRATIC_TRIANGLE: + myInfo.myNbBiQuadTriangles++; + break; + case VTK_POLYGON: + myInfo.myNbPolygons++; + break; + default: + myInfo.myNbPolygons++; + } + return facevtk; +} + +/////////////////////////////////////////////////////////////////////////////// +/// Registers element with the given ID, maintains inverse connections +/////////////////////////////////////////////////////////////////////////////// +bool SMDS_Mesh::registerElement(int ID, SMDS_MeshElement* element) +{ + //MESSAGE("registerElement " << ID); + if ((ID >=0) && (ID < myCells.size()) && myCells[ID]) // --- already bound + { + MESSAGE(" ------------------ already bound "<< ID << " " << myCells[ID]->getVtkId()); + return false; + } + + element->myID = ID; + element->myMeshId = myMeshId; + + SMDS_MeshCell *cell = dynamic_cast(element); + MYASSERT(cell); + int vtkId = cell->getVtkId(); + if (vtkId == -1) + vtkId = myElementIDFactory->SetInVtkGrid(element); + + if (vtkId >= myCellIdVtkToSmds.size()) // --- resize local vector + { +// MESSAGE(" --------------------- resize myCellIdVtkToSmds " << vtkId << " --> " << vtkId + SMDS_Mesh::chunkSize); + myCellIdVtkToSmds.resize(vtkId + SMDS_Mesh::chunkSize, -1); + } + myCellIdVtkToSmds[vtkId] = ID; + + myElementIDFactory->updateMinMax(ID); + return true; +} + +//======================================================================= +//function : MoveNode +//purpose : +//======================================================================= + +void SMDS_Mesh::MoveNode(const SMDS_MeshNode *n, double x, double y, double z) +{ + SMDS_MeshNode * node=const_cast(n); + node->setXYZ(x,y,z); +} + +/////////////////////////////////////////////////////////////////////////////// +/// Return the node whose SMDS ID is 'ID'. +/////////////////////////////////////////////////////////////////////////////// +const SMDS_MeshNode * SMDS_Mesh::FindNode(int ID) const +{ + if (ID < 1 || ID >= myNodes.size()) + { +// MESSAGE("------------------------------------------------------------------------- "); +// MESSAGE("----------------------------------- bad ID " << ID << " " << myNodes.size()); +// MESSAGE("------------------------------------------------------------------------- "); + return 0; + } + return (const SMDS_MeshNode *)myNodes[ID]; +} + +/////////////////////////////////////////////////////////////////////////////// +/// Return the node whose VTK ID is 'vtkId'. +/////////////////////////////////////////////////////////////////////////////// +const SMDS_MeshNode * SMDS_Mesh::FindNodeVtk(int vtkId) const +{ + // TODO if needed use mesh->nodeIdFromVtkToSmds + if (vtkId < 0 || vtkId >= (myNodes.size() -1)) + { + MESSAGE("------------------------------------------------------------------------- "); + MESSAGE("---------------------------- bad VTK ID " << vtkId << " " << myNodes.size()); + MESSAGE("------------------------------------------------------------------------- "); + return 0; + } + return (const SMDS_MeshNode *)myNodes[vtkId+1]; +} + +/////////////////////////////////////////////////////////////////////////////// +///Create a triangle and add it to the current mesh. This method do not bind an +///ID to the create triangle. +/////////////////////////////////////////////////////////////////////////////// +SMDS_MeshFace * SMDS_Mesh::createTriangle(const SMDS_MeshNode * node1, + const SMDS_MeshNode * node2, + const SMDS_MeshNode * node3, + int ID) { if ( !node1 || !node2 || !node3) return 0; - if ( myFaces.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if ( NbFaces() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); if(hasConstructionEdges()) { SMDS_MeshEdge *edge1, *edge2, *edge3; @@ -1069,15 +1742,34 @@ SMDS_MeshFace * SMDS_Mesh::createTriangle(const SMDS_MeshNode * node1, edge2=FindEdgeOrCreate(node2,node3); edge3=FindEdgeOrCreate(node3,node1); + //int ID = myElementIDFactory->GetFreeID(); // -PR- voir si on range cet element SMDS_MeshFace * face = new SMDS_FaceOfEdges(edge1,edge2,edge3); - myFaces.Add(face); + adjustmyCellsCapacity(ID); + myCells[ID] = face; myInfo.myNbTriangles++; return face; } else { - SMDS_MeshFace * face = new SMDS_FaceOfNodes(node1,node2,node3); - myFaces.Add(face); + // --- retrieve nodes ID + myNodeIds.resize(3); + myNodeIds[0] = node1->getVtkId(); + myNodeIds[1] = node2->getVtkId(); + myNodeIds[2] = node3->getVtkId(); + + SMDS_MeshFace * face = 0; + SMDS_VtkFace *facevtk = myFacePool->getNew(); + facevtk->init(myNodeIds, this); // put in vtkUnstructuredGrid + if (!this->registerElement(ID,facevtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(facevtk->getVtkId(), VTK_EMPTY_CELL); + myFacePool->destroy(facevtk); + return 0; + } + face = facevtk; + adjustmyCellsCapacity(ID); + myCells[ID] = face; + //MESSAGE("createTriangle " << ID << " " << face); myInfo.myNbTriangles++; return face; } @@ -1088,14 +1780,16 @@ SMDS_MeshFace * SMDS_Mesh::createTriangle(const SMDS_MeshNode * node1, ///a ID to the create triangle. /////////////////////////////////////////////////////////////////////////////// SMDS_MeshFace * SMDS_Mesh::createQuadrangle(const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2, - const SMDS_MeshNode * node3, - const SMDS_MeshNode * node4) + const SMDS_MeshNode * node2, + const SMDS_MeshNode * node3, + const SMDS_MeshNode * node4, + int ID) { if ( !node1 || !node2 || !node3 || !node4 ) return 0; - if ( myFaces.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if ( NbFaces() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); if(hasConstructionEdges()) { + //MESSAGE("createQuadrangle hasConstructionEdges "<< ID); SMDS_MeshEdge *edge1, *edge2, *edge3, *edge4; edge1=FindEdgeOrCreate(node1,node2); edge2=FindEdgeOrCreate(node2,node3); @@ -1103,14 +1797,32 @@ SMDS_MeshFace * SMDS_Mesh::createQuadrangle(const SMDS_MeshNode * node1, edge4=FindEdgeOrCreate(node4,node1); SMDS_MeshFace * face = new SMDS_FaceOfEdges(edge1,edge2,edge3,edge4); - myFaces.Add(face); + adjustmyCellsCapacity(ID); + myCells[ID] = face; myInfo.myNbQuadrangles++; return face; } else { - SMDS_MeshFace * face = new SMDS_FaceOfNodes(node1,node2,node3,node4); - myFaces.Add(face); + // --- retrieve nodes ID + myNodeIds.resize(4); + myNodeIds[0] = node1->getVtkId(); + myNodeIds[1] = node2->getVtkId(); + myNodeIds[2] = node3->getVtkId(); + myNodeIds[3] = node4->getVtkId(); + + SMDS_MeshFace * face = 0; + SMDS_VtkFace *facevtk = myFacePool->getNew(); + facevtk->init(myNodeIds, this); + if (!this->registerElement(ID,facevtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(facevtk->getVtkId(), VTK_EMPTY_CELL); + myFacePool->destroy(facevtk); + return 0; + } + face = facevtk; + adjustmyCellsCapacity(ID); + myCells[ID] = face; myInfo.myNbQuadrangles++; return face; } @@ -1122,7 +1834,18 @@ SMDS_MeshFace * SMDS_Mesh::createQuadrangle(const SMDS_MeshNode * node1, void SMDS_Mesh::RemoveNode(const SMDS_MeshNode * node) { - RemoveElement(node, true); + MESSAGE("RemoveNode"); + RemoveElement(node, true); +} + +/////////////////////////////////////////////////////////////////////////////// +/// Remove an edge and all the elements which own this edge +/////////////////////////////////////////////////////////////////////////////// + +void SMDS_Mesh::Remove0DElement(const SMDS_Mesh0DElement * elem0d) +{ + MESSAGE("Remove0DElement"); + RemoveElement(elem0d,true); } /////////////////////////////////////////////////////////////////////////////// @@ -1131,7 +1854,8 @@ void SMDS_Mesh::RemoveNode(const SMDS_MeshNode * node) void SMDS_Mesh::RemoveEdge(const SMDS_MeshEdge * edge) { - RemoveElement(edge,true); + MESSAGE("RemoveEdge"); + RemoveElement(edge,true); } /////////////////////////////////////////////////////////////////////////////// @@ -1140,7 +1864,8 @@ void SMDS_Mesh::RemoveEdge(const SMDS_MeshEdge * edge) void SMDS_Mesh::RemoveFace(const SMDS_MeshFace * face) { - RemoveElement(face, true); + MESSAGE("RemoveFace"); + RemoveElement(face, true); } /////////////////////////////////////////////////////////////////////////////// @@ -1149,7 +1874,8 @@ void SMDS_Mesh::RemoveFace(const SMDS_MeshFace * face) void SMDS_Mesh::RemoveVolume(const SMDS_MeshVolume * volume) { - RemoveElement(volume, true); + MESSAGE("RemoveVolume"); + RemoveElement(volume, true); } //======================================================================= @@ -1159,8 +1885,8 @@ void SMDS_Mesh::RemoveVolume(const SMDS_MeshVolume * volume) bool SMDS_Mesh::RemoveFromParent() { - if (myParent==NULL) return false; - else return (myParent->RemoveSubMesh(this)); + if (myParent==NULL) return false; + else return (myParent->RemoveSubMesh(this)); } //======================================================================= @@ -1170,89 +1896,54 @@ bool SMDS_Mesh::RemoveFromParent() bool SMDS_Mesh::RemoveSubMesh(const SMDS_Mesh * aMesh) { - bool found = false; + bool found = false; - list::iterator itmsh=myChildren.begin(); - for (; itmsh!=myChildren.end() && !found; itmsh++) - { - SMDS_Mesh * submesh = *itmsh; - if (submesh == aMesh) - { - found = true; - myChildren.erase(itmsh); - } - } + list::iterator itmsh=myChildren.begin(); + for (; itmsh!=myChildren.end() && !found; itmsh++) + { + SMDS_Mesh * submesh = *itmsh; + if (submesh == aMesh) + { + found = true; + myChildren.erase(itmsh); + } + } - return found; + return found; } //======================================================================= //function : ChangeElementNodes -//purpose : +//purpose : //======================================================================= bool SMDS_Mesh::ChangeElementNodes(const SMDS_MeshElement * element, const SMDS_MeshNode * nodes[], const int nbnodes) { + MESSAGE("SMDS_Mesh::ChangeElementNodes"); // keep current nodes of elem - set oldNodes; - SMDS_ElemIteratorPtr itn = element->nodesIterator(); - while(itn->more()) - oldNodes.insert( itn->next() ); - - if ( !element->IsPoly() ) - myInfo.remove( element ); // element may change type + set oldNodes( element->begin_nodes(), element->end_nodes() ); // change nodes bool Ok = false; - SMDS_MeshElement* elem = const_cast(element); - switch ( elem->GetType() ) + SMDS_MeshCell* cell = dynamic_cast((SMDS_MeshElement*) element); + if (cell) { - case SMDSAbs_Edge: { - if ( nbnodes == 2 ) { - if ( SMDS_MeshEdge* edge = dynamic_cast( elem )) - Ok = edge->ChangeNodes( nodes[0], nodes[1] ); - } - else if ( nbnodes == 3 ) { - if ( SMDS_QuadraticEdge* edge = dynamic_cast( elem )) - Ok = edge->ChangeNodes( nodes[0], nodes[1], nodes[2] ); - } - break; - } - case SMDSAbs_Face: { - if ( SMDS_FaceOfNodes* face = dynamic_cast( elem )) - Ok = face->ChangeNodes( nodes, nbnodes ); - else - if ( SMDS_QuadraticFaceOfNodes* QF = dynamic_cast( elem )) - Ok = QF->ChangeNodes( nodes, nbnodes ); - else - if (SMDS_PolygonalFaceOfNodes* face = dynamic_cast(elem)) - Ok = face->ChangeNodes(nodes, nbnodes); - break; - } - case SMDSAbs_Volume: { - if ( SMDS_VolumeOfNodes* vol = dynamic_cast( elem )) - Ok = vol->ChangeNodes( nodes, nbnodes ); - else - if ( SMDS_QuadraticVolumeOfNodes* QV = dynamic_cast( elem )) - Ok = QV->ChangeNodes( nodes, nbnodes ); - break; - } - default: - MESSAGE ( "WRONG ELEM TYPE"); + Ok = cell->vtkOrder(nodes, nbnodes); + Ok = cell->ChangeNodes(nodes, nbnodes); } if ( Ok ) { // update InverseElements - set::iterator it; + set::iterator it; // AddInverseElement to new nodes for ( int i = 0; i < nbnodes; i++ ) { it = oldNodes.find( nodes[i] ); if ( it == oldNodes.end() ) // new node - const_cast( nodes[i] )->AddInverseElement( elem ); + const_cast( nodes[i] )->AddInverseElement( cell ); else // remove from oldNodes a node that remains in elem oldNodes.erase( it ); @@ -1260,15 +1951,11 @@ bool SMDS_Mesh::ChangeElementNodes(const SMDS_MeshElement * element, // RemoveInverseElement from the nodes removed from elem for ( it = oldNodes.begin(); it != oldNodes.end(); it++ ) { - SMDS_MeshNode * n = static_cast - (const_cast( *it )); - n->RemoveInverseElement( elem ); + SMDS_MeshNode * n = const_cast( *it ); + n->RemoveInverseElement( cell ); } } - if ( !element->IsPoly() ) - myInfo.add( element ); // element may change type - return Ok; } @@ -1285,7 +1972,7 @@ bool SMDS_Mesh::ChangePolyhedronNodes (const SMDS_MeshElement * elem, return false; } - const SMDS_PolyhedralVolumeOfNodes* vol = dynamic_cast(elem); + const SMDS_VtkVolume* vol = dynamic_cast(elem); if (!vol) { return false; } @@ -1298,7 +1985,9 @@ bool SMDS_Mesh::ChangePolyhedronNodes (const SMDS_MeshElement * elem, } // change nodes - bool Ok = const_cast(vol)->ChangeNodes(nodes, quantities); + // TODO remove this function + //bool Ok = const_cast(vol)->ChangeNodes(nodes, quantities); + bool Ok = false; if (!Ok) { return false; } @@ -1330,6 +2019,75 @@ bool SMDS_Mesh::ChangePolyhedronNodes (const SMDS_MeshElement * elem, } +//======================================================================= +//function : Find0DElement +//purpose : +//======================================================================= +const SMDS_Mesh0DElement* SMDS_Mesh::Find0DElement(int idnode) const +{ + const SMDS_MeshNode * node = FindNode(idnode); + if(node == NULL) return NULL; + return Find0DElement(node); +} + +const SMDS_Mesh0DElement* SMDS_Mesh::Find0DElement(const SMDS_MeshNode * node) +{ + if (!node) return 0; + const SMDS_Mesh0DElement* toReturn = NULL; + SMDS_ElemIteratorPtr it1 = node->GetInverseElementIterator(SMDSAbs_0DElement); + while (it1->more() && (toReturn == NULL)) { + const SMDS_MeshElement* e = it1->next(); + if (e->NbNodes() == 1) { + toReturn = static_cast(e); + } + } + return toReturn; +} + +//======================================================================= +//function : FindBall +//purpose : +//======================================================================= + +const SMDS_BallElement* SMDS_Mesh::FindBall(int idnode) const +{ + const SMDS_MeshNode * node = FindNode(idnode); + if(node == NULL) return NULL; + return FindBall(node); +} + +const SMDS_BallElement* SMDS_Mesh::FindBall(const SMDS_MeshNode * node) +{ + if (!node) return 0; + const SMDS_BallElement* toReturn = NULL; + SMDS_ElemIteratorPtr it1 = node->GetInverseElementIterator(SMDSAbs_Ball); + while (it1->more() && (toReturn == NULL)) { + const SMDS_MeshElement* e = it1->next(); + if (e->GetGeomType() == SMDSGeom_BALL) + toReturn = static_cast(e); + } + return toReturn; +} + +//======================================================================= +//function : Find0DElementOrCreate +//purpose : +//======================================================================= +//SMDS_Mesh0DElement* SMDS_Mesh::Find0DElementOrCreate(const SMDS_MeshNode * node) +//{ +// if (!node) return 0; +// SMDS_Mesh0DElement * toReturn = NULL; +// toReturn = const_cast(Find0DElement(node)); +// if (toReturn == NULL) { +// //if (my0DElements.Extent() % CHECKMEMORY_INTERVAL == 0) CheckMemory(); +// toReturn = new SMDS_Mesh0DElement(node); +// my0DElements.Add(toReturn); +// myInfo.myNb0DElements++; +// } +// return toReturn; +//} + + //======================================================================= //function : FindEdge //purpose : @@ -1372,15 +2130,29 @@ const SMDS_MeshEdge* SMDS_Mesh::FindEdge(const SMDS_MeshNode * node1, //======================================================================= SMDS_MeshEdge* SMDS_Mesh::FindEdgeOrCreate(const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2) + const SMDS_MeshNode * node2) { if ( !node1 || !node2) return 0; SMDS_MeshEdge * toReturn=NULL; toReturn=const_cast(FindEdge(node1,node2)); if(toReturn==NULL) { - if ( myEdges.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); - toReturn=new SMDS_MeshEdge(node1,node2); - myEdges.Add(toReturn); + if ( NbEdges() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + int ID = myElementIDFactory->GetFreeID(); // -PR- voir si on range cet element + adjustmyCellsCapacity(ID); + myNodeIds.resize(2); + myNodeIds[0] = node1->getVtkId(); + myNodeIds[1] = node2->getVtkId(); + + SMDS_VtkEdge *edgevtk = myEdgePool->getNew(); + edgevtk->init(myNodeIds, this); + if (!this->registerElement(ID,edgevtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(edgevtk->getVtkId(), VTK_EMPTY_CELL); + myEdgePool->destroy(edgevtk); + return 0; + } + toReturn = edgevtk; + myCells[ID] = toReturn; myInfo.myNbEdges++; } return toReturn; @@ -1435,7 +2207,7 @@ const SMDS_MeshEdge* SMDS_Mesh::FindEdge(const SMDS_MeshNode * node1, //======================================================================= const SMDS_MeshFace* SMDS_Mesh::FindFace(int idnode1, int idnode2, - int idnode3) const + int idnode3) const { const SMDS_MeshNode * node1=FindNode(idnode1); const SMDS_MeshNode * node2=FindNode(idnode2); @@ -1477,7 +2249,8 @@ SMDS_MeshFace* SMDS_Mesh::FindFaceOrCreate(const SMDS_MeshNode *node1, SMDS_MeshFace * toReturn=NULL; toReturn = const_cast(FindFace(node1,node2,node3)); if(toReturn==NULL) { - toReturn = createTriangle(node1,node2,node3); + int ID = myElementIDFactory->GetFreeID(); + toReturn = createTriangle(node1,node2,node3, ID); } return toReturn; } @@ -1535,7 +2308,8 @@ SMDS_MeshFace* SMDS_Mesh::FindFaceOrCreate(const SMDS_MeshNode *node1, SMDS_MeshFace * toReturn=NULL; toReturn=const_cast(FindFace(node1,node2,node3,node4)); if(toReturn==NULL) { - toReturn=createQuadrangle(node1,node2,node3,node4); + int ID = myElementIDFactory->GetFreeID(); + toReturn=createQuadrangle(node1,node2,node3,node4,ID); } return toReturn; } @@ -1659,7 +2433,16 @@ const SMDS_MeshFace* SMDS_Mesh::FindFace(const SMDS_MeshNode *node1, const SMDS_MeshElement* SMDS_Mesh::FindElement(int IDelem) const { - return myElementIDFactory->MeshElement(IDelem); + if ((IDelem <= 0) || IDelem >= myCells.size()) + { + MESSAGE("--------------------------------------------------------------------------------- "); + MESSAGE("----------------------------------- bad IDelem " << IDelem << " " << myCells.size()); + MESSAGE("--------------------------------------------------------------------------------- "); + // TODO raise an exception + //assert(0); + return 0; + } + return myCells[IDelem]; } //======================================================================= @@ -1667,33 +2450,55 @@ const SMDS_MeshElement* SMDS_Mesh::FindElement(int IDelem) const //purpose : find polygon //======================================================================= -const SMDS_MeshFace* SMDS_Mesh::FindFace (std::vector nodes_ids) const +const SMDS_MeshFace* SMDS_Mesh::FindFace (const vector& nodes_ids) const { int nbnodes = nodes_ids.size(); - std::vector poly_nodes (nbnodes); + vector poly_nodes (nbnodes); for (int inode = 0; inode < nbnodes; inode++) { const SMDS_MeshNode * node = FindNode(nodes_ids[inode]); if (node == NULL) return NULL; + poly_nodes[inode] = node; } return FindFace(poly_nodes); } -const SMDS_MeshFace* SMDS_Mesh::FindFace (std::vector nodes) +const SMDS_MeshFace* SMDS_Mesh::FindFace (const vector& nodes) { - if ( nodes.size() > 2 && nodes[0] ) { - SMDS_ElemIteratorPtr itF = nodes[0]->GetInverseElementIterator(SMDSAbs_Face); - while (itF->more()) { - const SMDS_MeshElement* f = itF->next(); - if ( f->NbNodes() == nodes.size() ) { - SMDS_ElemIteratorPtr it2 = f->nodesIterator(); - while(it2->more()) { - if ( find( nodes.begin(), nodes.end(), it2->next() ) == nodes.end() ) { - f = 0; - break; - } + return (const SMDS_MeshFace*) FindElement( nodes, SMDSAbs_Face ); +} + + +//================================================================================ +/*! + * \brief Return element based on all given nodes + * \param nodes - node of element + * \param type - type of element + * \param noMedium - true if medium nodes of quadratic element are not included in + * \retval const SMDS_MeshElement* - found element or NULL + */ +//================================================================================ + +const SMDS_MeshElement* SMDS_Mesh::FindElement (const vector& nodes, + const SMDSAbs_ElementType type, + const bool noMedium) +{ + if ( nodes.size() > 0 && nodes[0] ) + { + SMDS_ElemIteratorPtr itF = nodes[0]->GetInverseElementIterator(type); + while (itF->more()) + { + const SMDS_MeshElement* e = itF->next(); + int nbNodesToCheck = noMedium ? e->NbCornerNodes() : e->NbNodes(); + if ( nbNodesToCheck == nodes.size() ) + { + for ( size_t i = 1; e && i < nodes.size(); ++i ) + { + int nodeIndex = e->GetNodeIndex( nodes[ i ]); + if ( nodeIndex < 0 || nodeIndex >= nbNodesToCheck ) + e = 0; } - if ( f ) - return static_cast (f); + if ( e ) + return e; } } } @@ -1702,100 +2507,111 @@ const SMDS_MeshFace* SMDS_Mesh::FindFace (std::vector nod //======================================================================= //function : DumpNodes -//purpose : +//purpose : //======================================================================= void SMDS_Mesh::DumpNodes() const { - MESSAGE("dump nodes of mesh : "); - SMDS_NodeIteratorPtr itnode=nodesIterator(); - while(itnode->more()) MESSAGE(itnode->next()); + MESSAGE("dump nodes of mesh : "); + SMDS_NodeIteratorPtr itnode=nodesIterator(); + while(itnode->more()) ; //MESSAGE(itnode->next()); +} + +//======================================================================= +//function : Dump0DElements +//purpose : +//======================================================================= +void SMDS_Mesh::Dump0DElements() const +{ + MESSAGE("dump 0D elements of mesh : "); + SMDS_ElemIteratorPtr it0d = elementsIterator(SMDSAbs_0DElement); + while(it0d->more()) ; //MESSAGE(it0d->next()); } //======================================================================= //function : DumpEdges -//purpose : +//purpose : //======================================================================= void SMDS_Mesh::DumpEdges() const { - MESSAGE("dump edges of mesh : "); - SMDS_EdgeIteratorPtr itedge=edgesIterator(); - while(itedge->more()) MESSAGE(itedge->next()); + MESSAGE("dump edges of mesh : "); + SMDS_EdgeIteratorPtr itedge=edgesIterator(); + while(itedge->more()) ; //MESSAGE(itedge->next()); } //======================================================================= //function : DumpFaces -//purpose : +//purpose : //======================================================================= void SMDS_Mesh::DumpFaces() const { - MESSAGE("dump faces of mesh : "); - SMDS_FaceIteratorPtr itface=facesIterator(); - while(itface->more()) MESSAGE(itface->next()); + MESSAGE("dump faces of mesh : "); + SMDS_FaceIteratorPtr itface=facesIterator(); + while(itface->more()) ; //MESSAGE(itface->next()); } //======================================================================= //function : DumpVolumes -//purpose : +//purpose : //======================================================================= void SMDS_Mesh::DumpVolumes() const { - MESSAGE("dump volumes of mesh : "); - SMDS_VolumeIteratorPtr itvol=volumesIterator(); - while(itvol->more()) MESSAGE(itvol->next()); + MESSAGE("dump volumes of mesh : "); + SMDS_VolumeIteratorPtr itvol=volumesIterator(); + while(itvol->more()) ; //MESSAGE(itvol->next()); } //======================================================================= //function : DebugStats -//purpose : +//purpose : //======================================================================= void SMDS_Mesh::DebugStats() const { - MESSAGE("Debug stats of mesh : "); + MESSAGE("Debug stats of mesh : "); + + MESSAGE("===== NODES ====="<more()) - { - const SMDS_MeshNode *node = itnode->next(); + while(itnode->more()) + { + const SMDS_MeshNode *node = itnode->next(); - sizeofnodes += sizeof(*node); - - SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); - while(it->more()) - { - const SMDS_MeshElement *me = it->next(); - sizeofnodes += sizeof(me); - } + sizeofnodes += sizeof(*node); - } + SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); + while(it->more()) + { + const SMDS_MeshElement *me = it->next(); + sizeofnodes += sizeof(me); + } + } - SMDS_FaceIteratorPtr itface=facesIterator(); - while(itface->more()) - { - const SMDS_MeshElement *face = itface->next(); - sizeoffaces += sizeof(*face); + SMDS_FaceIteratorPtr itface=facesIterator(); + while(itface->more()) + { + const SMDS_MeshElement *face = itface->next(); + sizeoffaces += sizeof(*face); + } - } - MESSAGE("total size of node elements = " << sizeofnodes);; - MESSAGE("total size of face elements = " << sizeoffaces);; + MESSAGE("total size of node elements = " << sizeofnodes);; + MESSAGE("total size of face elements = " << sizeoffaces);; - //#endif + //#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1803,7 +2619,26 @@ void SMDS_Mesh::DebugStats() const /////////////////////////////////////////////////////////////////////////////// int SMDS_Mesh::NbNodes() const { - return myNodes.Size(); + //MESSAGE(myGrid->GetNumberOfPoints()); + //MESSAGE(myInfo.NbNodes()); + //MESSAGE(myNodeMax); + return myInfo.NbNodes(); +} + +/////////////////////////////////////////////////////////////////////////////// +/// Return the number of 0D elements +/////////////////////////////////////////////////////////////////////////////// +int SMDS_Mesh::Nb0DElements() const +{ + return myInfo.Nb0DElements(); +} + +/////////////////////////////////////////////////////////////////////////////// +/// Return the number of 0D elements +/////////////////////////////////////////////////////////////////////////////// +int SMDS_Mesh::NbBalls() const +{ + return myInfo.NbBalls(); } /////////////////////////////////////////////////////////////////////////////// @@ -1811,7 +2646,7 @@ int SMDS_Mesh::NbNodes() const /////////////////////////////////////////////////////////////////////////////// int SMDS_Mesh::NbEdges() const { - return myEdges.Size(); + return myInfo.NbEdges(); } /////////////////////////////////////////////////////////////////////////////// @@ -1819,7 +2654,7 @@ int SMDS_Mesh::NbEdges() const /////////////////////////////////////////////////////////////////////////////// int SMDS_Mesh::NbFaces() const { - return myFaces.Size(); + return myInfo.NbFaces(); } /////////////////////////////////////////////////////////////////////////////// @@ -1827,17 +2662,16 @@ int SMDS_Mesh::NbFaces() const /////////////////////////////////////////////////////////////////////////////// int SMDS_Mesh::NbVolumes() const { - return myVolumes.Size(); + return myInfo.NbVolumes(); } /////////////////////////////////////////////////////////////////////////////// /// Return the number of child mesh of this mesh. -/// Note that the tree structure of SMDS_Mesh seems to be unused in this version -/// (2003-09-08) of SMESH +/// Note that the tree structure of SMDS_Mesh is unused in SMESH /////////////////////////////////////////////////////////////////////////////// int SMDS_Mesh::NbSubMesh() const { - return myChildren.size(); + return myChildren.size(); } /////////////////////////////////////////////////////////////////////////////// @@ -1862,36 +2696,25 @@ SMDS_Mesh::~SMDS_Mesh() { SMDS_ElemIteratorPtr eIt = elementsIterator(); while ( eIt->more() ) - myElementIDFactory->ReleaseID(eIt->next()->GetID()); + { + const SMDS_MeshElement *elem = eIt->next(); + myElementIDFactory->ReleaseID(elem->GetID(), elem->getVtkId()); + } SMDS_NodeIteratorPtr itn = nodesIterator(); while (itn->more()) - myNodeIDFactory->ReleaseID(itn->next()->GetID()); - } - SetOfNodes::Iterator itn(myNodes); - for (; itn.More(); itn.Next()) - delete itn.Value(); - - SetOfEdges::Iterator ite(myEdges); - for (; ite.More(); ite.Next()) - { - SMDS_MeshElement* elem = ite.Value(); - delete elem; - } - - SetOfFaces::Iterator itf(myFaces); - for (; itf.More(); itf.Next()) - { - SMDS_MeshElement* elem = itf.Value(); - delete elem; - } - - SetOfVolumes::Iterator itv(myVolumes); - for (; itv.More(); itv.Next()) - { - SMDS_MeshElement* elem = itv.Value(); - delete elem; + { + const SMDS_MeshNode *node = itn->next(); + ((SMDS_MeshNode*)node)->SetPosition(SMDS_SpacePosition::originSpacePosition()); + myNodeIDFactory->ReleaseID(node->GetID(), node->getVtkId()); + } } + myGrid->Delete(); + delete myNodePool; + delete myVolumePool; + delete myFacePool; + delete myEdgePool; + delete myBallPool; } //================================================================================ @@ -1902,43 +2725,94 @@ SMDS_Mesh::~SMDS_Mesh() void SMDS_Mesh::Clear() { - if (myParent!=NULL) { + MESSAGE("SMDS_Mesh::Clear"); + if (myParent!=NULL) + { SMDS_ElemIteratorPtr eIt = elementsIterator(); while ( eIt->more() ) - myElementIDFactory->ReleaseID(eIt->next()->GetID()); + { + const SMDS_MeshElement *elem = eIt->next(); + myElementIDFactory->ReleaseID(elem->GetID(), elem->getVtkId()); + } SMDS_NodeIteratorPtr itn = nodesIterator(); while (itn->more()) - myNodeIDFactory->ReleaseID(itn->next()->GetID()); - } - else { + { + const SMDS_MeshNode *node = itn->next(); + myNodeIDFactory->ReleaseID(node->GetID(), node->getVtkId()); + } + } + else + { myNodeIDFactory->Clear(); myElementIDFactory->Clear(); - } - SMDS_VolumeIteratorPtr itv = volumesIterator(); - while (itv->more()) - delete itv->next(); - myVolumes.Clear(); - - SMDS_FaceIteratorPtr itf = facesIterator(); - while (itf->more()) - delete itf->next(); - myFaces.Clear(); - - SMDS_EdgeIteratorPtr ite = edgesIterator(); - while (ite->more()) - delete ite->next(); - myEdges.Clear(); + } + + // SMDS_ElemIteratorPtr itv = elementsIterator(); + // while (itv->more()) + // { + // SMDS_MeshElement* elem = (SMDS_MeshElement*)(itv->next()); + // SMDSAbs_ElementType aType = elem->GetType(); + // switch (aType) + // { + // case SMDSAbs_0DElement: + // delete elem; + // break; + // case SMDSAbs_Edge: + // myEdgePool->destroy(static_cast(elem)); + // break; + // case SMDSAbs_Face: + // myFacePool->destroy(static_cast(elem)); + // break; + // case SMDSAbs_Volume: + // myVolumePool->destroy(static_cast(elem)); + // break; + // case SMDSAbs_Ball: + // myBallPool->destroy(static_cast(elem)); + // break; + // default: + // break; + // } + // } + myVolumePool->clear(); + myFacePool->clear(); + myEdgePool->clear(); + myBallPool->clear(); + + clearVector( myCells ); + clearVector( myCellIdVtkToSmds ); SMDS_NodeIteratorPtr itn = nodesIterator(); while (itn->more()) - delete itn->next(); - myNodes.Clear(); + { + SMDS_MeshNode *node = (SMDS_MeshNode*)(itn->next()); + node->SetPosition(SMDS_SpacePosition::originSpacePosition()); + //myNodePool->destroy(node); + } + myNodePool->clear(); + clearVector( myNodes ); list::iterator itc=myChildren.begin(); while(itc!=myChildren.end()) (*itc)->Clear(); + myModified = false; + myModifTime++; + xmin = 0; xmax = 0; + ymin = 0; ymax = 0; + zmin = 0; zmax = 0; + myInfo.Clear(); + + myGrid->Initialize(); + myGrid->Allocate(); + vtkPoints* points = vtkPoints::New(); + // rnv: to fix bug "21125: EDF 1233 SMESH: Degrardation of precision in a test case for quadratic conversion" + // using double type for storing coordinates of nodes instead float. + points->SetDataType(VTK_DOUBLE); + points->SetNumberOfPoints(0 /*SMDS_Mesh::chunkSize*/); + myGrid->SetPoints( points ); + points->Delete(); + myGrid->BuildLinks(); } /////////////////////////////////////////////////////////////////////////////// @@ -1948,7 +2822,7 @@ void SMDS_Mesh::Clear() /////////////////////////////////////////////////////////////////////////////// bool SMDS_Mesh::hasConstructionEdges() { - return myHasConstructionEdges; + return myHasConstructionEdges; } /////////////////////////////////////////////////////////////////////////////// @@ -1960,7 +2834,7 @@ bool SMDS_Mesh::hasConstructionEdges() /////////////////////////////////////////////////////////////////////////////// bool SMDS_Mesh::hasConstructionFaces() { - return myHasConstructionFaces; + return myHasConstructionFaces; } /////////////////////////////////////////////////////////////////////////////// @@ -1969,7 +2843,7 @@ bool SMDS_Mesh::hasConstructionFaces() /////////////////////////////////////////////////////////////////////////////// bool SMDS_Mesh::hasInverseElements() { - return myHasInverseElements; + return myHasInverseElements; } /////////////////////////////////////////////////////////////////////////////// @@ -1978,7 +2852,7 @@ bool SMDS_Mesh::hasInverseElements() /////////////////////////////////////////////////////////////////////////////// void SMDS_Mesh::setConstructionEdges(bool b) { - myHasConstructionEdges=b; + myHasConstructionEdges=b; } /////////////////////////////////////////////////////////////////////////////// @@ -1987,7 +2861,7 @@ void SMDS_Mesh::setConstructionEdges(bool b) /////////////////////////////////////////////////////////////////////////////// void SMDS_Mesh::setConstructionFaces(bool b) { - myHasConstructionFaces=b; + myHasConstructionFaces=b; } /////////////////////////////////////////////////////////////////////////////// @@ -1996,283 +2870,344 @@ void SMDS_Mesh::setConstructionFaces(bool b) /////////////////////////////////////////////////////////////////////////////// void SMDS_Mesh::setInverseElements(bool b) { - if(!b) MESSAGE("Error : inverseElement=false not implemented"); - myHasInverseElements=b; + if(!b) MESSAGE("Error : inverseElement=false not implemented"); + myHasInverseElements=b; +} + +namespace { + + //================================================================================ + /*! + * \brief Iterator on elements in id increasing order + */ + //================================================================================ + + template + class IdSortedIterator : public SMDS_Iterator + { + SMDS_MeshElementIDFactory& myIDFact; + int myID, myMaxID, myNbFound, myTotalNb; + SMDSAbs_ElementType myType; + ELEM myElem; + + public: + IdSortedIterator(SMDS_MeshElementIDFactory& fact, + const SMDSAbs_ElementType type, // SMDSAbs_All NOT allowed!!! + const int totalNb) + :myIDFact( fact ), + myID(1), myMaxID( myIDFact.GetMaxID() ),myNbFound(0), myTotalNb( totalNb ), + myType( type ), + myElem(0) + { + next(); + } + bool more() + { + return myElem; + } + ELEM next() + { + ELEM current = myElem; + + for ( myElem = 0; !myElem && myNbFound < myTotalNb && myID <= myMaxID; ++myID ) + if ((myElem = (ELEM) myIDFact.MeshElement( myID )) + && myElem->GetType() != myType ) + myElem = 0; + + myNbFound += bool(myElem); + + return current; + } + }; + + //================================================================================ + /*! + * \brief Iterator on vector of elements, possibly being resized while iteration + */ + //================================================================================ + + template > + class ElemVecIterator: public SMDS_Iterator + { + const std::vector& _vector; + size_t _index; + bool _more; + VALUE_FILTER _filter; + public: + ElemVecIterator(const std::vector& vec, + const VALUE_FILTER& filter=VALUE_FILTER() ) + :_vector( vec ), _index(0), _more( !vec.empty() ), _filter( filter ) + { + if ( _more && !_filter( _vector[ _index ])) + next(); + } + virtual bool more() + { + return _more; + } + virtual RETURN_VALUE next() + { + if ( !_more ) return NULL; + VECTOR_VALUE current = _vector[ _index ]; + _more = 0; + while ( !_more && ++_index < _vector.size() ) + _more = _filter( _vector[ _index ]); + return (RETURN_VALUE) current; + } + }; } /////////////////////////////////////////////////////////////////////////////// /// Return an iterator on nodes of the current mesh factory /////////////////////////////////////////////////////////////////////////////// -class SMDS_Mesh_MyNodeIterator:public SMDS_NodeIterator + +SMDS_NodeIteratorPtr SMDS_Mesh::nodesIterator(bool idInceasingOrder) const { - SMDS_ElemIteratorPtr myIterator; - public: - SMDS_Mesh_MyNodeIterator(const SMDS_ElemIteratorPtr& it):myIterator(it) - {} + // naturally always sorted by ID + typedef ElemVecIterator TIterator; + return SMDS_NodeIteratorPtr( new TIterator(myNodes)); +} - bool more() - { - return myIterator->more(); - } +SMDS_ElemIteratorPtr SMDS_Mesh::elementGeomIterator(SMDSAbs_GeometryType type) const +{ + // naturally always sorted by ID + typedef ElemVecIterator + < const SMDS_MeshElement*, SMDS_MeshCell*, SMDS_MeshElement::GeomFilter > TIterator; + return SMDS_ElemIteratorPtr + (new TIterator(myCells, SMDS_MeshElement::GeomFilter( type ))); +} - const SMDS_MeshNode* next() +SMDS_ElemIteratorPtr SMDS_Mesh::elementEntityIterator(SMDSAbs_EntityType type) const +{ + if ( type == SMDSEntity_Node ) { - return static_cast(myIterator->next()); + typedef ElemVecIterator TIterator; + return SMDS_ElemIteratorPtr( new TIterator(myNodes)); } -}; - -SMDS_NodeIteratorPtr SMDS_Mesh::nodesIterator() const -{ - return SMDS_NodeIteratorPtr - (new SMDS_Mesh_MyNodeIterator(myNodeIDFactory->elementsIterator())); + // naturally always sorted by ID + typedef ElemVecIterator + < const SMDS_MeshElement*, SMDS_MeshCell*, SMDS_MeshElement::EntityFilter > TIterator; + return SMDS_ElemIteratorPtr + (new TIterator(myCells, SMDS_MeshElement::EntityFilter( type ))); } /////////////////////////////////////////////////////////////////////////////// /// Return an iterator on elements of the current mesh factory /////////////////////////////////////////////////////////////////////////////// -SMDS_ElemIteratorPtr SMDS_Mesh::elementsIterator() const +SMDS_ElemIteratorPtr SMDS_Mesh::elementsIterator(SMDSAbs_ElementType type) const { - return myElementIDFactory->elementsIterator(); + // naturally always sorted by ID + switch ( type ) { + + case SMDSAbs_All: + return SMDS_ElemIteratorPtr (new ElemVecIterator(myCells)); + + case SMDSAbs_Node: + return SMDS_ElemIteratorPtr + ( new ElemVecIterator( myNodes )); + + default: + typedef ElemVecIterator + < const SMDS_MeshElement*, SMDS_MeshCell*, SMDS_MeshElement::TypeFilter > TIterator; + return SMDS_ElemIteratorPtr (new TIterator(myCells, SMDS_MeshElement::TypeFilter( type ))); + } + return SMDS_ElemIteratorPtr(); } /////////////////////////////////////////////////////////////////////////////// ///Return an iterator on edges of the current mesh. /////////////////////////////////////////////////////////////////////////////// -class SMDS_Mesh_MyEdgeIterator:public SMDS_EdgeIterator -{ - typedef SMDS_Mesh::SetOfEdges SetOfEdges; - SetOfEdges::Iterator myIterator; - public: - SMDS_Mesh_MyEdgeIterator(const SetOfEdges& s):myIterator(s) - {} - - bool more() - { - while(myIterator.More()) - { - if(myIterator.Value()->GetID()!=-1) - return true; - myIterator.Next(); - } - return false; - } - - const SMDS_MeshEdge* next() - { - const SMDS_MeshEdge* current = myIterator.Value(); - myIterator.Next(); - return current; - } -}; -SMDS_EdgeIteratorPtr SMDS_Mesh::edgesIterator() const +SMDS_EdgeIteratorPtr SMDS_Mesh::edgesIterator(bool idInceasingOrder) const { - return SMDS_EdgeIteratorPtr(new SMDS_Mesh_MyEdgeIterator(myEdges)); + // naturally always sorted by ID + typedef ElemVecIterator + < const SMDS_MeshEdge*, SMDS_MeshCell*, SMDS_MeshElement::TypeFilter > TIterator; + return SMDS_EdgeIteratorPtr + (new TIterator(myCells, SMDS_MeshElement::TypeFilter( SMDSAbs_Edge ))); } /////////////////////////////////////////////////////////////////////////////// ///Return an iterator on faces of the current mesh. /////////////////////////////////////////////////////////////////////////////// -class SMDS_Mesh_MyFaceIterator:public SMDS_FaceIterator -{ - typedef SMDS_Mesh::SetOfFaces SetOfFaces; - SetOfFaces::Iterator myIterator; - public: - SMDS_Mesh_MyFaceIterator(const SetOfFaces& s):myIterator(s) - {} - - bool more() - { - while(myIterator.More()) - { - if(myIterator.Value()->GetID()!=-1) - return true; - myIterator.Next(); - } - return false; - } - - const SMDS_MeshFace* next() - { - const SMDS_MeshFace* current = myIterator.Value(); - myIterator.Next(); - return current; - } -}; -SMDS_FaceIteratorPtr SMDS_Mesh::facesIterator() const +SMDS_FaceIteratorPtr SMDS_Mesh::facesIterator(bool idInceasingOrder) const { - return SMDS_FaceIteratorPtr(new SMDS_Mesh_MyFaceIterator(myFaces)); + // naturally always sorted by ID + typedef ElemVecIterator + < const SMDS_MeshFace*, SMDS_MeshCell*, SMDS_MeshElement::TypeFilter > TIterator; + return SMDS_FaceIteratorPtr + (new TIterator(myCells, SMDS_MeshElement::TypeFilter( SMDSAbs_Face ))); } /////////////////////////////////////////////////////////////////////////////// ///Return an iterator on volumes of the current mesh. /////////////////////////////////////////////////////////////////////////////// -class SMDS_Mesh_MyVolumeIterator:public SMDS_VolumeIterator + +SMDS_VolumeIteratorPtr SMDS_Mesh::volumesIterator(bool idInceasingOrder) const { - typedef SMDS_Mesh::SetOfVolumes SetOfVolumes; - SetOfVolumes::Iterator myIterator; - public: - SMDS_Mesh_MyVolumeIterator(const SetOfVolumes& s):myIterator(s) - {} - - bool more() - { - return myIterator.More() != Standard_False; - } - - const SMDS_MeshVolume* next() - { - const SMDS_MeshVolume* current = myIterator.Value(); - myIterator.Next(); - return current; - } -}; - -SMDS_VolumeIteratorPtr SMDS_Mesh::volumesIterator() const -{ - return SMDS_VolumeIteratorPtr(new SMDS_Mesh_MyVolumeIterator(myVolumes)); -} + // naturally always sorted by ID + typedef ElemVecIterator + < const SMDS_MeshVolume*, SMDS_MeshCell*, SMDS_MeshElement::TypeFilter > TIterator; + return SMDS_VolumeIteratorPtr + (new TIterator(myCells, SMDS_MeshElement::TypeFilter( SMDSAbs_Volume ))); +} /////////////////////////////////////////////////////////////////////////////// /// Do intersection of sets (more than 2) /////////////////////////////////////////////////////////////////////////////// static set * intersectionOfSets( - set vs[], int numberOfSets) + set vs[], int numberOfSets) { - set* rsetA=new set(vs[0]); - set* rsetB; + set* rsetA=new set(vs[0]); + set* rsetB; - for(int i=0; i(); - set_intersection( - rsetA->begin(), rsetA->end(), - vs[i+1].begin(), vs[i+1].end(), - std::inserter(*rsetB, rsetB->begin())); - delete rsetA; - rsetA=rsetB; - } - return rsetA; + for(int i=0; i(); + set_intersection( + rsetA->begin(), rsetA->end(), + vs[i+1].begin(), vs[i+1].end(), + inserter(*rsetB, rsetB->begin())); + delete rsetA; + rsetA=rsetB; + } + return rsetA; } /////////////////////////////////////////////////////////////////////////////// -/// Return the list of finit elements owning the given element +/// Return the list of finite elements owning the given element: elements +/// containing all the nodes of the given element, for instance faces and +/// volumes containing a given edge. /////////////////////////////////////////////////////////////////////////////// static set * getFinitElements(const SMDS_MeshElement * element) { - int numberOfSets=element->NbNodes(); - set *initSet = new set[numberOfSets]; + int numberOfSets=element->NbNodes(); + set *initSet = new set[numberOfSets]; - SMDS_ElemIteratorPtr itNodes=element->nodesIterator(); + SMDS_ElemIteratorPtr itNodes=element->nodesIterator(); + + int i=0; + while(itNodes->more()) + { + const SMDS_MeshElement* node = itNodes->next(); + MYASSERT(node); + const SMDS_MeshNode * n=static_cast(node); + SMDS_ElemIteratorPtr itFe = n->GetInverseElementIterator(); - int i=0; - while(itNodes->more()) - { - const SMDS_MeshNode * n=static_cast(itNodes->next()); - SMDS_ElemIteratorPtr itFe = n->GetInverseElementIterator(); + //initSet[i]=set(); + while(itFe->more()) + { + const SMDS_MeshElement* elem = itFe->next(); + MYASSERT(elem); + initSet[i].insert(elem); - //initSet[i]=set(); - while(itFe->more()) - initSet[i].insert(itFe->next()); + } - i++; - } - set *retSet=intersectionOfSets(initSet, numberOfSets); + i++; + } + set *retSet=intersectionOfSets(initSet, numberOfSets); +// MESSAGE("nb elems " << i << " intersection " << retSet->size()); delete [] initSet; - return retSet; + return retSet; } /////////////////////////////////////////////////////////////////////////////// /// Return the list of nodes used only by the given elements /////////////////////////////////////////////////////////////////////////////// static set * getExclusiveNodes( - set& elements) -{ - set * toReturn=new set(); - set::iterator itElements=elements.begin(); - - while(itElements!=elements.end()) - { - SMDS_ElemIteratorPtr itNodes = (*itElements)->nodesIterator(); - itElements++; - - while(itNodes->more()) - { - const SMDS_MeshNode * n=static_cast(itNodes->next()); - SMDS_ElemIteratorPtr itFe = n->GetInverseElementIterator(); - set s; - while(itFe->more()) + set& elements) +{ + set * toReturn=new set(); + set::iterator itElements=elements.begin(); + + while(itElements!=elements.end()) + { + SMDS_ElemIteratorPtr itNodes = (*itElements)->nodesIterator(); + itElements++; + + while(itNodes->more()) + { + const SMDS_MeshNode * n=static_cast(itNodes->next()); + SMDS_ElemIteratorPtr itFe = n->GetInverseElementIterator(); + set s; + while(itFe->more()) s.insert(itFe->next()); - if(s==elements) toReturn->insert(n); - } - } - return toReturn; + if(s==elements) toReturn->insert(n); + } + } + return toReturn; } /////////////////////////////////////////////////////////////////////////////// -///Find the children of an element that are made of given nodes +///Find the children of an element that are made of given nodes ///@param setOfChildren The set in which matching children will be inserted ///@param element The element were to search matching children ///@param nodes The nodes that the children must have to be selected /////////////////////////////////////////////////////////////////////////////// -void SMDS_Mesh::addChildrenWithNodes(set& setOfChildren, - const SMDS_MeshElement * element, set& nodes) -{ - - switch(element->GetType()) - { - case SMDSAbs_Node: - MESSAGE("Internal Error: This should not append"); - break; - case SMDSAbs_Edge: - { - SMDS_ElemIteratorPtr itn=element->nodesIterator(); - while(itn->more()) - { - const SMDS_MeshElement * e=itn->next(); - if(nodes.find(e)!=nodes.end()) +void SMDS_Mesh::addChildrenWithNodes(set& setOfChildren, + const SMDS_MeshElement * element, + set& nodes) +{ + switch(element->GetType()) + { + case SMDSAbs_Node: + MESSAGE("Internal Error: This should not happen"); + break; + case SMDSAbs_0DElement: + { + } + break; + case SMDSAbs_Edge: + { + SMDS_ElemIteratorPtr itn=element->nodesIterator(); + while(itn->more()) + { + const SMDS_MeshElement * e=itn->next(); + if(nodes.find(e)!=nodes.end()) { setOfChildren.insert(element); break; } - } - } break; - case SMDSAbs_Face: - { - SMDS_ElemIteratorPtr itn=element->nodesIterator(); - while(itn->more()) - { - const SMDS_MeshElement * e=itn->next(); - if(nodes.find(e)!=nodes.end()) + } + } break; + case SMDSAbs_Face: + { + SMDS_ElemIteratorPtr itn=element->nodesIterator(); + while(itn->more()) + { + const SMDS_MeshElement * e=itn->next(); + if(nodes.find(e)!=nodes.end()) { setOfChildren.insert(element); break; } - } - if(hasConstructionEdges()) - { - SMDS_ElemIteratorPtr ite=element->edgesIterator(); - while(ite->more()) - addChildrenWithNodes(setOfChildren, ite->next(), nodes); - } - } break; - case SMDSAbs_Volume: - { - if(hasConstructionFaces()) - { - SMDS_ElemIteratorPtr ite=element->facesIterator(); - while(ite->more()) - addChildrenWithNodes(setOfChildren, ite->next(), nodes); - } - else if(hasConstructionEdges()) - { - SMDS_ElemIteratorPtr ite=element->edgesIterator(); - while(ite->more()) - addChildrenWithNodes(setOfChildren, ite->next(), nodes); - } - } - } + } + if(hasConstructionEdges()) + { + SMDS_ElemIteratorPtr ite=element->edgesIterator(); + while(ite->more()) + addChildrenWithNodes(setOfChildren, ite->next(), nodes); + } + } break; + case SMDSAbs_Volume: + { + if(hasConstructionFaces()) + { + SMDS_ElemIteratorPtr ite=element->facesIterator(); + while(ite->more()) + addChildrenWithNodes(setOfChildren, ite->next(), nodes); + } + else if(hasConstructionEdges()) + { + SMDS_ElemIteratorPtr ite=element->edgesIterator(); + while(ite->more()) + addChildrenWithNodes(setOfChildren, ite->next(), nodes); + } + } + } } /////////////////////////////////////////////////////////////////////////////// @@ -2280,17 +3215,17 @@ void SMDS_Mesh::addChildrenWithNodes(set& setOfChildren ///@param removenodes if true remaining nodes will be removed /////////////////////////////////////////////////////////////////////////////// void SMDS_Mesh::RemoveElement(const SMDS_MeshElement * elem, - const bool removenodes) + const bool removenodes) { list removedElems; list removedNodes; RemoveElement( elem, removedElems, removedNodes, removenodes ); } - + /////////////////////////////////////////////////////////////////////////////// ///@param elem The element to delete -///@param removedElems contains all removed elements -///@param removedNodes contains all removed nodes +///@param removedElems to be filled with all removed elements +///@param removedNodes to be filled with all removed nodes ///@param removenodes if true remaining nodes will be removed /////////////////////////////////////////////////////////////////////////////// void SMDS_Mesh::RemoveElement(const SMDS_MeshElement * elem, @@ -2298,125 +3233,196 @@ void SMDS_Mesh::RemoveElement(const SMDS_MeshElement * elem, list& removedNodes, bool removenodes) { + //MESSAGE("SMDS_Mesh::RemoveElement " << elem->getVtkId() << " " << removenodes); // get finite elements built on elem set * s1; - if ((!hasConstructionEdges() && elem->GetType() == SMDSAbs_Edge) || - (!hasConstructionFaces() && elem->GetType() == SMDSAbs_Face) || - elem->GetType() == SMDSAbs_Volume) - { - s1 = new set(); - s1->insert(elem); - } + if ( (elem->GetType() == SMDSAbs_0DElement) + || ((elem->GetType() == SMDSAbs_Edge) && !hasConstructionEdges()) + || ((elem->GetType() == SMDSAbs_Face) && !hasConstructionFaces()) + || (elem->GetType() == SMDSAbs_Volume) ) + { + s1 = new set (); + s1->insert(elem); + } else s1 = getFinitElements(elem); // get exclusive nodes (which would become free afterwards) set * s2; if (elem->GetType() == SMDSAbs_Node) // a node is removed - { - // do not remove nodes except elem - s2 = new set(); - s2->insert(elem); - removenodes = true; - } + { + // do not remove nodes except elem + s2 = new set (); + s2->insert(elem); + removenodes = true; + } else s2 = getExclusiveNodes(*s1); // form the set of finite and construction elements to remove set s3; - set::iterator it=s1->begin(); - while(it!=s1->end()) - { - addChildrenWithNodes(s3, *it ,*s2); - s3.insert(*it); - it++; - } - if(elem->GetType()!=SMDSAbs_Node) s3.insert(elem); - - // remove finite and construction elements - it=s3.begin(); - while(it!=s3.end()) - { - // Remove element from of its nodes - SMDS_ElemIteratorPtr itn=(*it)->nodesIterator(); - while(itn->more()) + set::iterator it = s1->begin(); + while (it != s1->end()) { - SMDS_MeshNode * n = static_cast - (const_cast(itn->next())); - n->RemoveInverseElement( (*it) ); + addChildrenWithNodes(s3, *it, *s2); + s3.insert(*it); + it++; } + if (elem->GetType() != SMDSAbs_Node) + s3.insert(elem); - switch((*it)->GetType()) + // remove finite and construction elements + it = s3.begin(); + while (it != s3.end()) { - case SMDSAbs_Node: - MESSAGE("Internal Error: This should not happen"); - break; - case SMDSAbs_Edge: - myEdges.Remove(static_cast - (const_cast(*it))); - myInfo.RemoveEdge(*it); - break; - case SMDSAbs_Face: - myFaces.Remove(static_cast - (const_cast(*it))); - myInfo.RemoveFace(*it); - break; - case SMDSAbs_Volume: - myVolumes.Remove(static_cast - (const_cast(*it))); - myInfo.RemoveVolume(*it); - break; + // Remove element from of its nodes + SMDS_ElemIteratorPtr itn = (*it)->nodesIterator(); + while (itn->more()) + { + SMDS_MeshNode * n = static_cast (const_cast (itn->next())); + n->RemoveInverseElement((*it)); + } + int IdToRemove = (*it)->GetID(); + int vtkid = (*it)->getVtkId(); + //MESSAGE("elem Id to remove " << IdToRemove << " vtkid " << vtkid << + // " vtktype " << (*it)->GetVtkType() << " type " << (*it)->GetType()); + switch ((*it)->GetType()) + { + case SMDSAbs_Node: + MYASSERT("Internal Error: This should not happen") + ; + break; + case SMDSAbs_0DElement: + if (IdToRemove >= 0) + { + myCells[IdToRemove] = 0; // -PR- ici ou dans myElementIDFactory->ReleaseID ? + myInfo.remove(*it); + } + removedElems.push_back((*it)); + myElementIDFactory->ReleaseID(IdToRemove, vtkid); + delete (*it); + break; + case SMDSAbs_Edge: + if (IdToRemove >= 0) + { + myCells[IdToRemove] = 0; + myInfo.RemoveEdge(*it); + } + removedElems.push_back((*it)); + myElementIDFactory->ReleaseID(IdToRemove, vtkid); + if (const SMDS_VtkEdge* vtkElem = dynamic_cast(*it)) + myEdgePool->destroy((SMDS_VtkEdge*) vtkElem); + else + delete (*it); + break; + case SMDSAbs_Face: + if (IdToRemove >= 0) + { + myCells[IdToRemove] = 0; + myInfo.RemoveFace(*it); + } + removedElems.push_back((*it)); + myElementIDFactory->ReleaseID(IdToRemove, vtkid); + if (const SMDS_VtkFace* vtkElem = dynamic_cast(*it)) + myFacePool->destroy((SMDS_VtkFace*) vtkElem); + else + delete (*it); + break; + case SMDSAbs_Volume: + if (IdToRemove >= 0) + { + myCells[IdToRemove] = 0; + myInfo.RemoveVolume(*it); + } + removedElems.push_back((*it)); + myElementIDFactory->ReleaseID(IdToRemove, vtkid); + if (const SMDS_VtkVolume* vtkElem = dynamic_cast(*it)) + myVolumePool->destroy((SMDS_VtkVolume*) vtkElem); + else + delete (*it); + break; + case SMDSAbs_Ball: + if (IdToRemove >= 0) + { + myCells[IdToRemove] = 0; + myInfo.remove(*it); + } + removedElems.push_back((*it)); + myElementIDFactory->ReleaseID(IdToRemove, vtkid); + if (const SMDS_BallElement* vtkElem = dynamic_cast(*it)) + myBallPool->destroy(const_cast( vtkElem )); + else + delete (*it); + break; + } + if (vtkid >= 0) + { + //MESSAGE("VTK_EMPTY_CELL in " << vtkid); + this->myGrid->GetCellTypesArray()->SetValue(vtkid, VTK_EMPTY_CELL); + } + it++; } - //MESSAGE( "SMDS: RM elem " << (*it)->GetID() ); - removedElems.push_back( (*it) ); - myElementIDFactory->ReleaseID((*it)->GetID()); - delete (*it); - it++; - } // remove exclusive (free) nodes - if(removenodes) - { - it=s2->begin(); - while(it!=s2->end()) + if (removenodes) { - //MESSAGE( "SMDS: RM node " << (*it)->GetID() ); - myNodes.Remove(static_cast - (const_cast(*it))); - myInfo.myNbNodes--; - myNodeIDFactory->ReleaseID((*it)->GetID()); - removedNodes.push_back( (*it) ); - delete *it; - it++; + it = s2->begin(); + while (it != s2->end()) + { + int IdToRemove = (*it)->GetID(); + //MESSAGE( "SMDS: RM node " << IdToRemove); + if (IdToRemove >= 0) + { + myNodes[IdToRemove] = 0; + myInfo.myNbNodes--; + } + myNodeIDFactory->ReleaseID((*it)->GetID(), (*it)->getVtkId()); + removedNodes.push_back((*it)); + if (const SMDS_MeshNode* vtkElem = dynamic_cast(*it)) + { + ((SMDS_MeshNode*)vtkElem)->SetPosition(SMDS_SpacePosition::originSpacePosition()); + myNodePool->destroy((SMDS_MeshNode*) vtkElem); + } + else + delete (*it); + it++; + } } - } delete s2; delete s1; } - + /////////////////////////////////////////////////////////////////////////////// ///@param elem The element to delete /////////////////////////////////////////////////////////////////////////////// void SMDS_Mesh::RemoveFreeElement(const SMDS_MeshElement * elem) { + int elemId = elem->GetID(); + int vtkId = elem->getVtkId(); + //MESSAGE("RemoveFreeElement " << elemId); SMDSAbs_ElementType aType = elem->GetType(); + SMDS_MeshElement* todest = (SMDS_MeshElement*)(elem); if (aType == SMDSAbs_Node) { + //MESSAGE("Remove free node " << elemId); // only free node can be removed by this method - const SMDS_MeshNode* n = static_cast(elem); + const SMDS_MeshNode* n = static_cast(todest); SMDS_ElemIteratorPtr itFe = n->GetInverseElementIterator(); if (!itFe->more()) { // free node - myNodes.Remove(const_cast(n)); + myNodes[elemId] = 0; myInfo.myNbNodes--; - myNodeIDFactory->ReleaseID(elem->GetID()); - delete elem; + ((SMDS_MeshNode*) n)->SetPosition(SMDS_SpacePosition::originSpacePosition()); + ((SMDS_MeshNode*) n)->SMDS_MeshElement::init( -1, -1, -1 ); // avoid reuse + myNodePool->destroy(static_cast(todest)); + myNodeIDFactory->ReleaseID(elemId, vtkId); } } else { if (hasConstructionEdges() || hasConstructionFaces()) // this methods is only for meshes without descendants return; + //MESSAGE("Remove free element " << elemId); // Remove element from of its nodes SMDS_ElemIteratorPtr itn = elem->nodesIterator(); while (itn->more()) { @@ -2426,27 +3432,39 @@ void SMDS_Mesh::RemoveFreeElement(const SMDS_MeshElement * elem) } // in meshes without descendants elements are always free - switch (aType) { + switch (aType) { + case SMDSAbs_0DElement: + myCells[elemId] = 0; + myInfo.remove(elem); + delete elem; + break; case SMDSAbs_Edge: - myEdges.Remove(static_cast - (const_cast(elem))); + myCells[elemId] = 0; myInfo.RemoveEdge(elem); + myEdgePool->destroy(static_cast(todest)); break; case SMDSAbs_Face: - myFaces.Remove(static_cast - (const_cast(elem))); + myCells[elemId] = 0; myInfo.RemoveFace(elem); + myFacePool->destroy(static_cast(todest)); break; case SMDSAbs_Volume: - myVolumes.Remove(static_cast - (const_cast(elem))); + myCells[elemId] = 0; myInfo.RemoveVolume(elem); + myVolumePool->destroy(static_cast(todest)); + break; + case SMDSAbs_Ball: + myCells[elemId] = 0; + myInfo.remove(elem); + myBallPool->destroy(static_cast(todest)); break; default: break; } - myElementIDFactory->ReleaseID(elem->GetID()); - delete elem; + myElementIDFactory->ReleaseID(elemId, vtkId); + + this->myGrid->GetCellTypesArray()->SetValue(vtkId, VTK_EMPTY_CELL); + // --- to do: keep vtkid in a list of reusable cells } } @@ -2462,44 +3480,36 @@ bool SMDS_Mesh::Contains (const SMDS_MeshElement* elem) const while (itn->more()) if (elem == itn->next()) return true; - SMDS_EdgeIteratorPtr ite = edgesIterator(); + SMDS_ElemIteratorPtr ite = elementsIterator(); while (ite->more()) if (elem == ite->next()) return true; - SMDS_FaceIteratorPtr itf = facesIterator(); - while (itf->more()) - if (elem == itf->next()) - return true; - SMDS_VolumeIteratorPtr itv = volumesIterator(); - while (itv->more()) - if (elem == itv->next()) - return true; return false; } //======================================================================= //function : MaxNodeID -//purpose : +//purpose : //======================================================================= int SMDS_Mesh::MaxNodeID() const { - return myNodeIDFactory->GetMaxID(); + return myNodeMax; } //======================================================================= //function : MinNodeID -//purpose : +//purpose : //======================================================================= int SMDS_Mesh::MinNodeID() const { - return myNodeIDFactory->GetMinID(); + return myNodeMin; } //======================================================================= //function : MaxElementID -//purpose : +//purpose : //======================================================================= int SMDS_Mesh::MaxElementID() const @@ -2509,7 +3519,7 @@ int SMDS_Mesh::MaxElementID() const //======================================================================= //function : MinElementID -//purpose : +//purpose : //======================================================================= int SMDS_Mesh::MinElementID() const @@ -2524,10 +3534,11 @@ int SMDS_Mesh::MinElementID() const void SMDS_Mesh::Renumber (const bool isNodes, const int startID, const int deltaID) { + MESSAGE("Renumber"); if ( deltaID == 0 ) return; - SMDS_MeshElementIDFactory * idFactory = + SMDS_MeshNodeIDFactory * idFactory = isNodes ? myNodeIDFactory : myElementIDFactory; // get existing elements in the order of ID increasing @@ -2571,7 +3582,7 @@ SMDSAbs_ElementType SMDS_Mesh::GetElementType( const int id, const bool iselem ) if( !elem ) { - //throw SMESH_Exception(LOCALIZED ("this element isn't exist")); + //throw SALOME_Exception(LOCALIZED ("this element isn't exist")); return SMDSAbs_All; } else @@ -2590,9 +3601,9 @@ SMDSAbs_ElementType SMDS_Mesh::GetElementType( const int id, const bool iselem ) //======================================================================= //function : AddEdgeWithID -//purpose : +//purpose : //======================================================================= -SMDS_MeshEdge* SMDS_Mesh::AddEdgeWithID(int n1, int n2, int n12, int ID) +SMDS_MeshEdge* SMDS_Mesh::AddEdgeWithID(int n1, int n2, int n12, int ID) { return SMDS_Mesh::AddEdgeWithID ((SMDS_MeshNode*) myNodeIDFactory->MeshElement(n1), @@ -2603,10 +3614,10 @@ SMDS_MeshEdge* SMDS_Mesh::AddEdgeWithID(int n1, int n2, int n12, int ID) //======================================================================= //function : AddEdge -//purpose : +//purpose : //======================================================================= SMDS_MeshEdge* SMDS_Mesh::AddEdge(const SMDS_MeshNode* n1, - const SMDS_MeshNode* n2, + const SMDS_MeshNode* n2, const SMDS_MeshNode* n12) { return SMDS_Mesh::AddEdgeWithID(n1, n2, n12, myElementIDFactory->GetFreeID()); @@ -2614,41 +3625,51 @@ SMDS_MeshEdge* SMDS_Mesh::AddEdge(const SMDS_MeshNode* n1, //======================================================================= //function : AddEdgeWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshEdge* SMDS_Mesh::AddEdgeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n12, - int ID) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n12, + int ID) { if ( !n1 || !n2 || !n12 ) return 0; - SMDS_QuadraticEdge* edge = new SMDS_QuadraticEdge(n1,n2,n12); - if(myElementIDFactory->BindID(ID, edge)) { - SMDS_MeshNode *node1,*node2, *node12; - node1 = const_cast(n1); - node2 = const_cast(n2); - node12 = const_cast(n12); - node1->AddInverseElement(edge); - node2->AddInverseElement(edge); - node12->AddInverseElement(edge); - myEdges.Add(edge); - myInfo.myNbQuadEdges++; - return edge; - } - else { - delete edge; - return NULL; + + // --- retrieve nodes ID + myNodeIds.resize(3); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n2->getVtkId(); + myNodeIds[2] = n12->getVtkId(); + + SMDS_MeshEdge * edge = 0; + SMDS_VtkEdge *edgevtk = myEdgePool->getNew(); + edgevtk->init(myNodeIds, this); + if (!this->registerElement(ID,edgevtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(edgevtk->getVtkId(), VTK_EMPTY_CELL); + myEdgePool->destroy(edgevtk); + return 0; } + edge = edgevtk; + adjustmyCellsCapacity(ID); + myCells[ID] = edge; + myInfo.myNbQuadEdges++; + + // if (!registerElement(ID, edge)) { + // RemoveElement(edge, false); + // edge = NULL; + // } + return edge; + } //======================================================================= //function : AddFace -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMDS_Mesh::AddFace(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n31) @@ -2659,7 +3680,7 @@ SMDS_MeshFace* SMDS_Mesh::AddFace(const SMDS_MeshNode * n1, //======================================================================= //function : AddFaceWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(int n1, int n2, int n3, int n12,int n23,int n31, int ID) @@ -2676,14 +3697,14 @@ SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(int n1, int n2, int n3, //======================================================================= //function : AddFaceWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31, + const SMDS_MeshNode * n31, int ID) { if ( !n1 || !n2 || !n3 || !n12 || !n23 || !n31) return 0; @@ -2691,27 +3712,135 @@ SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, // creation quadratic edges - not implemented return 0; } - SMDS_QuadraticFaceOfNodes* face = - new SMDS_QuadraticFaceOfNodes(n1,n2,n3,n12,n23,n31); - myFaces.Add(face); - myInfo.myNbQuadTriangles++; + else + { + // --- retrieve nodes ID + myNodeIds.resize(6); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n2->getVtkId(); + myNodeIds[2] = n3->getVtkId(); + myNodeIds[3] = n12->getVtkId(); + myNodeIds[4] = n23->getVtkId(); + myNodeIds[5] = n31->getVtkId(); + + SMDS_MeshFace * face = 0; + SMDS_VtkFace *facevtk = myFacePool->getNew(); + facevtk->init(myNodeIds, this); + if (!this->registerElement(ID,facevtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(facevtk->getVtkId(), VTK_EMPTY_CELL); + myFacePool->destroy(facevtk); + return 0; + } + face = facevtk; + adjustmyCellsCapacity(ID); + myCells[ID] = face; + myInfo.myNbQuadTriangles++; + + // if (!registerElement(ID, face)) { + // RemoveElement(face, false); + // face = NULL; + // } + return face; + } +} - if (!registerElement(ID, face)) { - RemoveElement(face, false); - face = NULL; + +//======================================================================= +//function : AddFace +//purpose : +//======================================================================= +SMDS_MeshFace* SMDS_Mesh::AddFace(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31, + const SMDS_MeshNode * nCenter) +{ + return SMDS_Mesh::AddFaceWithID(n1,n2,n3,n12,n23,n31,nCenter, + myElementIDFactory->GetFreeID()); +} + +//======================================================================= +//function : AddFaceWithID +//purpose : +//======================================================================= +SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(int n1, int n2, int n3, + int n12,int n23,int n31, int nCenter, int ID) +{ + return SMDS_Mesh::AddFaceWithID + ((SMDS_MeshNode *)myNodeIDFactory->MeshElement(n1) , + (SMDS_MeshNode *)myNodeIDFactory->MeshElement(n2) , + (SMDS_MeshNode *)myNodeIDFactory->MeshElement(n3) , + (SMDS_MeshNode *)myNodeIDFactory->MeshElement(n12), + (SMDS_MeshNode *)myNodeIDFactory->MeshElement(n23), + (SMDS_MeshNode *)myNodeIDFactory->MeshElement(n31), + (SMDS_MeshNode *)myNodeIDFactory->MeshElement(nCenter), + ID); +} + +//======================================================================= +//function : AddFaceWithID +//purpose : +//======================================================================= +SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31, + const SMDS_MeshNode * nCenter, + int ID) +{ + if ( !n1 || !n2 || !n3 || !n12 || !n23 || !n31 || !nCenter) return 0; + if(hasConstructionEdges()) { + // creation quadratic edges - not implemented + return 0; + } + else + { + // --- retrieve nodes ID + myNodeIds.resize(7); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n2->getVtkId(); + myNodeIds[2] = n3->getVtkId(); + myNodeIds[3] = n12->getVtkId(); + myNodeIds[4] = n23->getVtkId(); + myNodeIds[5] = n31->getVtkId(); + myNodeIds[6] = nCenter->getVtkId(); + + SMDS_MeshFace * face = 0; + SMDS_VtkFace *facevtk = myFacePool->getNew(); + facevtk->init(myNodeIds, this); + if (!this->registerElement(ID,facevtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(facevtk->getVtkId(), VTK_EMPTY_CELL); + myFacePool->destroy(facevtk); + return 0; + } + face = facevtk; + adjustmyCellsCapacity(ID); + myCells[ID] = face; + myInfo.myNbBiQuadTriangles++; + + // if (!registerElement(ID, face)) { + // RemoveElement(face, false); + // face = NULL; + // } + return face; } - return face; } //======================================================================= //function : AddFace -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMDS_Mesh::AddFace(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, @@ -2723,7 +3852,7 @@ SMDS_MeshFace* SMDS_Mesh::AddFace(const SMDS_MeshNode * n1, //======================================================================= //function : AddFaceWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(int n1, int n2, int n3, int n4, int n12,int n23,int n34,int n41, int ID) @@ -2742,7 +3871,7 @@ SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(int n1, int n2, int n3, int n4, //======================================================================= //function : AddFaceWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, @@ -2750,39 +3879,157 @@ SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n4, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, - const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, int ID) { if ( !n1 || !n2 || !n3 || !n4 || !n12 || !n23 || !n34 || !n41) return 0; if(hasConstructionEdges()) { // creation quadratic edges - not implemented + return 0; } - SMDS_QuadraticFaceOfNodes* face = - new SMDS_QuadraticFaceOfNodes(n1,n2,n3,n4,n12,n23,n34,n41); - myFaces.Add(face); - myInfo.myNbQuadQuadrangles++; + else + { + // --- retrieve nodes ID + myNodeIds.resize(8); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n2->getVtkId(); + myNodeIds[2] = n3->getVtkId(); + myNodeIds[3] = n4->getVtkId(); + myNodeIds[4] = n12->getVtkId(); + myNodeIds[5] = n23->getVtkId(); + myNodeIds[6] = n34->getVtkId(); + myNodeIds[7] = n41->getVtkId(); + + SMDS_MeshFace * face = 0; + SMDS_VtkFace *facevtk = myFacePool->getNew(); + facevtk->init(myNodeIds, this); + if (!this->registerElement(ID,facevtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(facevtk->getVtkId(), VTK_EMPTY_CELL); + myFacePool->destroy(facevtk); + return 0; + } + face = facevtk; + adjustmyCellsCapacity(ID); + myCells[ID] = face; + myInfo.myNbQuadQuadrangles++; + + // if (!registerElement(ID, face)) { + // RemoveElement(face, false); + // face = NULL; + // } + return face; + } +} - if (!registerElement(ID, face)) { - RemoveElement(face, false); - face = NULL; +//======================================================================= +//function : AddFace +//purpose : +//======================================================================= +SMDS_MeshFace* SMDS_Mesh::AddFace(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * nCenter) +{ + return SMDS_Mesh::AddFaceWithID(n1,n2,n3,n4,n12,n23,n34,n41,nCenter, + myElementIDFactory->GetFreeID()); +} + +//======================================================================= +//function : AddFaceWithID +//purpose : +//======================================================================= +SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(int n1, int n2, int n3, int n4, + int n12,int n23,int n34,int n41, int nCenter, int ID) +{ + return SMDS_Mesh::AddFaceWithID + ((SMDS_MeshNode *)myNodeIDFactory->MeshElement(n1) , + (SMDS_MeshNode *)myNodeIDFactory->MeshElement(n2) , + (SMDS_MeshNode *)myNodeIDFactory->MeshElement(n3) , + (SMDS_MeshNode *)myNodeIDFactory->MeshElement(n4) , + (SMDS_MeshNode *)myNodeIDFactory->MeshElement(n12), + (SMDS_MeshNode *)myNodeIDFactory->MeshElement(n23), + (SMDS_MeshNode *)myNodeIDFactory->MeshElement(n34), + (SMDS_MeshNode *)myNodeIDFactory->MeshElement(n41), + (SMDS_MeshNode *)myNodeIDFactory->MeshElement(nCenter), + ID); +} + +//======================================================================= +//function : AddFaceWithID +//purpose : +//======================================================================= +SMDS_MeshFace* SMDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * nCenter, + int ID) +{ + if ( !n1 || !n2 || !n3 || !n4 || !n12 || !n23 || !n34 || !n41 || !nCenter) return 0; + if(hasConstructionEdges()) { + // creation quadratic edges - not implemented + return 0; + } + else + { + // --- retrieve nodes ID + myNodeIds.resize(9); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n2->getVtkId(); + myNodeIds[2] = n3->getVtkId(); + myNodeIds[3] = n4->getVtkId(); + myNodeIds[4] = n12->getVtkId(); + myNodeIds[5] = n23->getVtkId(); + myNodeIds[6] = n34->getVtkId(); + myNodeIds[7] = n41->getVtkId(); + myNodeIds[8] = nCenter->getVtkId(); + + SMDS_MeshFace * face = 0; + SMDS_VtkFace *facevtk = myFacePool->getNew(); + facevtk->init(myNodeIds, this); + if (!this->registerElement(ID,facevtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(facevtk->getVtkId(), VTK_EMPTY_CELL); + myFacePool->destroy(facevtk); + return 0; + } + face = facevtk; + adjustmyCellsCapacity(ID); + myCells[ID] = face; + myInfo.myNbBiQuadQuadrangles++; + + // if (!registerElement(ID, face)) { + // RemoveElement(face, false); + // face = NULL; + // } + return face; } - return face; } //======================================================================= //function : AddVolume -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n31, - const SMDS_MeshNode * n14, + const SMDS_MeshNode * n14, const SMDS_MeshNode * n24, const SMDS_MeshNode * n34) { @@ -2795,7 +4042,7 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshNode * n1, //======================================================================= //function : AddVolumeWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, int n4, int n12,int n23,int n31, @@ -2826,7 +4073,7 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n31, - const SMDS_MeshNode * n14, + const SMDS_MeshNode * n14, const SMDS_MeshNode * n24, const SMDS_MeshNode * n34, int ID) @@ -2837,33 +4084,55 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, // creation quadratic faces - not implemented return 0; } - SMDS_QuadraticVolumeOfNodes * volume = - new SMDS_QuadraticVolumeOfNodes(n1,n2,n3,n4,n12,n23,n31,n14,n24,n34); - myVolumes.Add(volume); + // --- retrieve nodes ID + myNodeIds.resize(10); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n3->getVtkId(); + myNodeIds[2] = n2->getVtkId(); + myNodeIds[3] = n4->getVtkId(); + + myNodeIds[4] = n31->getVtkId(); + myNodeIds[5] = n23->getVtkId(); + myNodeIds[6] = n12->getVtkId(); + + myNodeIds[7] = n14->getVtkId(); + myNodeIds[8] = n34->getVtkId(); + myNodeIds[9] = n24->getVtkId(); + + SMDS_VtkVolume *volvtk = myVolumePool->getNew(); + volvtk->init(myNodeIds, this); + if (!this->registerElement(ID,volvtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(volvtk->getVtkId(), VTK_EMPTY_CELL); + myVolumePool->destroy(volvtk); + return 0; + } + adjustmyCellsCapacity(ID); + myCells[ID] = volvtk; myInfo.myNbQuadTetras++; - if (!registerElement(ID, volume)) { - RemoveElement(volume, false); - volume = NULL; - } - return volume; + // if (!registerElement(ID, volvtk)) { + // RemoveElement(volvtk, false); + // volvtk = NULL; + // } + return volvtk; } //======================================================================= //function : AddVolume -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, const SMDS_MeshNode * n41, - const SMDS_MeshNode * n15, + const SMDS_MeshNode * n15, const SMDS_MeshNode * n25, const SMDS_MeshNode * n35, const SMDS_MeshNode * n45) @@ -2878,7 +4147,7 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshNode * n1, //======================================================================= //function : AddVolumeWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n12,int n23,int n34,int n41, @@ -2909,12 +4178,12 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, + const SMDS_MeshNode * n5, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, const SMDS_MeshNode * n41, - const SMDS_MeshNode * n15, + const SMDS_MeshNode * n15, const SMDS_MeshNode * n25, const SMDS_MeshNode * n35, const SMDS_MeshNode * n45, @@ -2927,36 +4196,60 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, // creation quadratic faces - not implemented return 0; } - SMDS_QuadraticVolumeOfNodes * volume = - new SMDS_QuadraticVolumeOfNodes(n1,n2,n3,n4,n5,n12,n23, - n34,n41,n15,n25,n35,n45); - myVolumes.Add(volume); + // --- retrieve nodes ID + myNodeIds.resize(13); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n4->getVtkId(); + myNodeIds[2] = n3->getVtkId(); + myNodeIds[3] = n2->getVtkId(); + myNodeIds[4] = n5->getVtkId(); + + myNodeIds[5] = n41->getVtkId(); + myNodeIds[6] = n34->getVtkId(); + myNodeIds[7] = n23->getVtkId(); + myNodeIds[8] = n12->getVtkId(); + + myNodeIds[9] = n15->getVtkId(); + myNodeIds[10] = n45->getVtkId(); + myNodeIds[11] = n35->getVtkId(); + myNodeIds[12] = n25->getVtkId(); + + SMDS_VtkVolume *volvtk = myVolumePool->getNew(); + volvtk->init(myNodeIds, this); + if (!this->registerElement(ID,volvtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(volvtk->getVtkId(), VTK_EMPTY_CELL); + myVolumePool->destroy(volvtk); + return 0; + } + adjustmyCellsCapacity(ID); + myCells[ID] = volvtk; myInfo.myNbQuadPyramids++; - if (!registerElement(ID, volume)) { - RemoveElement(volume, false); - volume = NULL; - } - return volume; + // if (!registerElement(ID, volvtk)) { + // RemoveElement(volvtk, false); + // volvtk = NULL; + // } + return volvtk; } //======================================================================= //function : AddVolume -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31, + const SMDS_MeshNode * n31, const SMDS_MeshNode * n45, const SMDS_MeshNode * n56, - const SMDS_MeshNode * n64, + const SMDS_MeshNode * n64, const SMDS_MeshNode * n14, const SMDS_MeshNode * n25, const SMDS_MeshNode * n36) @@ -2971,7 +4264,7 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshNode * n1, //======================================================================= //function : AddVolumeWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6, @@ -3006,14 +4299,14 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31, + const SMDS_MeshNode * n31, const SMDS_MeshNode * n45, const SMDS_MeshNode * n56, - const SMDS_MeshNode * n64, + const SMDS_MeshNode * n64, const SMDS_MeshNode * n14, const SMDS_MeshNode * n25, const SMDS_MeshNode * n36, @@ -3026,40 +4319,68 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, // creation quadratic faces - not implemented return 0; } - SMDS_QuadraticVolumeOfNodes * volume = - new SMDS_QuadraticVolumeOfNodes(n1,n2,n3,n4,n5,n6,n12,n23,n31, - n45,n56,n64,n14,n25,n36); - myVolumes.Add(volume); + // --- retrieve nodes ID + myNodeIds.resize(15); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n2->getVtkId(); + myNodeIds[2] = n3->getVtkId(); + + myNodeIds[3] = n4->getVtkId(); + myNodeIds[4] = n5->getVtkId(); + myNodeIds[5] = n6->getVtkId(); + + myNodeIds[6] = n12->getVtkId(); + myNodeIds[7] = n23->getVtkId(); + myNodeIds[8] = n31->getVtkId(); + + myNodeIds[9] = n45->getVtkId(); + myNodeIds[10] = n56->getVtkId(); + myNodeIds[11] = n64->getVtkId(); + + myNodeIds[12] = n14->getVtkId(); + myNodeIds[13] = n25->getVtkId(); + myNodeIds[14] = n36->getVtkId(); + + SMDS_VtkVolume *volvtk = myVolumePool->getNew(); + volvtk->init(myNodeIds, this); + if (!this->registerElement(ID,volvtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(volvtk->getVtkId(), VTK_EMPTY_CELL); + myVolumePool->destroy(volvtk); + return 0; + } + adjustmyCellsCapacity(ID); + myCells[ID] = volvtk; myInfo.myNbQuadPrisms++; - if (!registerElement(ID, volume)) { - RemoveElement(volume, false); - volume = NULL; - } - return volume; + // if (!registerElement(ID, volvtk)) { + // RemoveElement(volvtk, false); + // volvtk = NULL; + // } + return volvtk; } //======================================================================= //function : AddVolume -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, + const SMDS_MeshNode * n8, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, + const SMDS_MeshNode * n41, const SMDS_MeshNode * n56, const SMDS_MeshNode * n67, const SMDS_MeshNode * n78, - const SMDS_MeshNode * n85, + const SMDS_MeshNode * n85, const SMDS_MeshNode * n15, const SMDS_MeshNode * n26, const SMDS_MeshNode * n37, @@ -3075,7 +4396,7 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshNode * n1, //======================================================================= //function : AddVolumeWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6, int n7, int n8, @@ -3115,18 +4436,18 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, + const SMDS_MeshNode * n8, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, + const SMDS_MeshNode * n41, const SMDS_MeshNode * n56, const SMDS_MeshNode * n67, const SMDS_MeshNode * n78, - const SMDS_MeshNode * n85, + const SMDS_MeshNode * n85, const SMDS_MeshNode * n15, const SMDS_MeshNode * n26, const SMDS_MeshNode * n37, @@ -3140,15 +4461,389 @@ SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, return 0; // creation quadratic faces - not implemented } - SMDS_QuadraticVolumeOfNodes * volume = - new SMDS_QuadraticVolumeOfNodes(n1,n2,n3,n4,n5,n6,n7,n8,n12,n23,n34,n41, - n56,n67,n78,n85,n15,n26,n37,n48); - myVolumes.Add(volume); + // --- retrieve nodes ID + myNodeIds.resize(20); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n4->getVtkId(); + myNodeIds[2] = n3->getVtkId(); + myNodeIds[3] = n2->getVtkId(); + + myNodeIds[4] = n5->getVtkId(); + myNodeIds[5] = n8->getVtkId(); + myNodeIds[6] = n7->getVtkId(); + myNodeIds[7] = n6->getVtkId(); + + myNodeIds[8] = n41->getVtkId(); + myNodeIds[9] = n34->getVtkId(); + myNodeIds[10] = n23->getVtkId(); + myNodeIds[11] = n12->getVtkId(); + + myNodeIds[12] = n85->getVtkId(); + myNodeIds[13] = n78->getVtkId(); + myNodeIds[14] = n67->getVtkId(); + myNodeIds[15] = n56->getVtkId(); + + myNodeIds[16] = n15->getVtkId(); + myNodeIds[17] = n48->getVtkId(); + myNodeIds[18] = n37->getVtkId(); + myNodeIds[19] = n26->getVtkId(); + + SMDS_VtkVolume *volvtk = myVolumePool->getNew(); + volvtk->init(myNodeIds, this); + if (!this->registerElement(ID,volvtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(volvtk->getVtkId(), VTK_EMPTY_CELL); + myVolumePool->destroy(volvtk); + return 0; + } + adjustmyCellsCapacity(ID); + myCells[ID] = volvtk; myInfo.myNbQuadHexas++; - if (!registerElement(ID, volume)) { - RemoveElement(volume, false); - volume = NULL; + // if (!registerElement(ID, volvtk)) { + // RemoveElement(volvtk, false); + // volvtk = NULL; + // } + return volvtk; +} + +//======================================================================= +//function : AddVolume +//purpose : +//======================================================================= +SMDS_MeshVolume* SMDS_Mesh::AddVolume(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * n56, + const SMDS_MeshNode * n67, + const SMDS_MeshNode * n78, + const SMDS_MeshNode * n85, + const SMDS_MeshNode * n15, + const SMDS_MeshNode * n26, + const SMDS_MeshNode * n37, + const SMDS_MeshNode * n48, + const SMDS_MeshNode * n1234, + const SMDS_MeshNode * n1256, + const SMDS_MeshNode * n2367, + const SMDS_MeshNode * n3478, + const SMDS_MeshNode * n1458, + const SMDS_MeshNode * n5678, + const SMDS_MeshNode * nCenter) +{ + int ID = myElementIDFactory->GetFreeID(); + SMDS_MeshVolume * v = + SMDS_Mesh::AddVolumeWithID(n1, n2, n3, n4, n5, n6, n7, n8, n12, n23, n34, n41, + n56, n67, n78, n85, n15, n26, n37, n48, + n1234, n1256, n2367, n3478, n1458, n5678, nCenter, + ID); + if(v==NULL) myElementIDFactory->ReleaseID(ID); + return v; +} + +//======================================================================= +//function : AddVolumeWithID +//purpose : +//======================================================================= +SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, int n4, + int n5, int n6, int n7, int n8, + int n12,int n23,int n34,int n41, + int n56,int n67,int n78,int n85, + int n15,int n26,int n37,int n48, + int n1234,int n1256,int n2367,int n3478, + int n1458,int n5678,int nCenter, int ID) +{ + return SMDS_Mesh::AddVolumeWithID + ((SMDS_MeshNode*) myNodeIDFactory->MeshElement(n1), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n2), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n3), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n4), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n5), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n6), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n7), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n8), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n12), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n23), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n34), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n41), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n56), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n67), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n78), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n85), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n15), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n26), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n37), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n48), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n1234), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n1256), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n2367), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n3478), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n1458), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(n5678), + (SMDS_MeshNode*) myNodeIDFactory->MeshElement(nCenter), + ID); +} + +//======================================================================= +//function : AddVolumeWithID +//purpose : 2d order Hexahedrons with 20 nodes +//======================================================================= +SMDS_MeshVolume* SMDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * n56, + const SMDS_MeshNode * n67, + const SMDS_MeshNode * n78, + const SMDS_MeshNode * n85, + const SMDS_MeshNode * n15, + const SMDS_MeshNode * n26, + const SMDS_MeshNode * n37, + const SMDS_MeshNode * n48, + const SMDS_MeshNode * n1234, + const SMDS_MeshNode * n1256, + const SMDS_MeshNode * n2367, + const SMDS_MeshNode * n3478, + const SMDS_MeshNode * n1458, + const SMDS_MeshNode * n5678, + const SMDS_MeshNode * nCenter, + int ID) +{ + if (!n1 || !n2 || !n3 || !n4 || !n5 || !n6 || !n7 || !n8 || !n12 || !n23 || + !n34 || !n41 || !n56 || !n67 || !n78 || !n85 || !n15 || !n26 || !n37 || !n48 || + !n1234 || !n1256 || !n2367 || !n3478 || !n1458 || !n5678 || !nCenter ) + return 0; + if(hasConstructionFaces()) { + return 0; + // creation quadratic faces - not implemented } - return volume; + // --- retrieve nodes ID + myNodeIds.resize(27); + myNodeIds[0] = n1->getVtkId(); + myNodeIds[1] = n4->getVtkId(); + myNodeIds[2] = n3->getVtkId(); + myNodeIds[3] = n2->getVtkId(); + + myNodeIds[4] = n5->getVtkId(); + myNodeIds[5] = n8->getVtkId(); + myNodeIds[6] = n7->getVtkId(); + myNodeIds[7] = n6->getVtkId(); + + myNodeIds[8] = n41->getVtkId(); + myNodeIds[9] = n34->getVtkId(); + myNodeIds[10] = n23->getVtkId(); + myNodeIds[11] = n12->getVtkId(); + + myNodeIds[12] = n85->getVtkId(); + myNodeIds[13] = n78->getVtkId(); + myNodeIds[14] = n67->getVtkId(); + myNodeIds[15] = n56->getVtkId(); + + myNodeIds[16] = n15->getVtkId(); + myNodeIds[17] = n48->getVtkId(); + myNodeIds[18] = n37->getVtkId(); + myNodeIds[19] = n26->getVtkId(); + + myNodeIds[20] = n1256->getVtkId(); + myNodeIds[21] = n3478->getVtkId(); + myNodeIds[22] = n1458->getVtkId(); + myNodeIds[23] = n2367->getVtkId(); + myNodeIds[24] = n1234->getVtkId(); + myNodeIds[25] = n5678->getVtkId(); + myNodeIds[26] = nCenter->getVtkId(); + + SMDS_VtkVolume *volvtk = myVolumePool->getNew(); + volvtk->init(myNodeIds, this); + if (!this->registerElement(ID,volvtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(volvtk->getVtkId(), VTK_EMPTY_CELL); + myVolumePool->destroy(volvtk); + return 0; + } + adjustmyCellsCapacity(ID); + myCells[ID] = volvtk; + myInfo.myNbTriQuadHexas++; + + return volvtk; +} + + +void SMDS_Mesh::updateNodeMinMax() +{ + myNodeMin = 0; + if (myNodes.size() == 0) + { + myNodeMax=0; + return; + } + while (!myNodes[myNodeMin] && (myNodeMin=0)) + myNodeMin--; +} + +void SMDS_Mesh::incrementNodesCapacity(int nbNodes) +{ +// int val = myCellIdSmdsToVtk.size(); +// MESSAGE(" ------------------- resize myCellIdSmdsToVtk " << val << " --> " << val + nbNodes); +// myCellIdSmdsToVtk.resize(val + nbNodes, -1); // fill new elements with -1 + int val = myNodes.size(); + MESSAGE(" ------------------- resize myNodes " << val << " --> " << val + nbNodes); + myNodes.resize(val +nbNodes, 0); +} + +void SMDS_Mesh::incrementCellsCapacity(int nbCells) +{ + int val = myCellIdVtkToSmds.size(); + MESSAGE(" ------------------- resize myCellIdVtkToSmds " << val << " --> " << val + nbCells); + myCellIdVtkToSmds.resize(val + nbCells, -1); // fill new elements with -1 + val = myCells.size(); + MESSAGE(" ------------------- resize myCells " << val << " --> " << val + nbCells); + myNodes.resize(val +nbCells, 0); +} + +void SMDS_Mesh::adjustStructure() +{ + myGrid->GetPoints()->GetData()->SetNumberOfTuples(myNodeIDFactory->GetMaxID()); +} + +void SMDS_Mesh::dumpGrid(string ficdump) +{ + MESSAGE("SMDS_Mesh::dumpGrid " << ficdump); +// vtkUnstructuredGridWriter* aWriter = vtkUnstructuredGridWriter::New(); +// aWriter->SetFileName(ficdump.c_str()); +// aWriter->SetInput(myGrid); +// if(myGrid->GetNumberOfCells()) +// { +// aWriter->Write(); +// } +// aWriter->Delete(); + ficdump = ficdump + "_connectivity"; + ofstream ficcon(ficdump.c_str(), ios::out); + int nbPoints = myGrid->GetNumberOfPoints(); + ficcon << "-------------------------------- points " << nbPoints << endl; + for (int i=0; iGetPoint(i)) << " " << *(myGrid->GetPoint(i)+1) << " " << " " << *(myGrid->GetPoint(i)+2) << endl; + } + int nbCells = myGrid->GetNumberOfCells(); + ficcon << "-------------------------------- cells " << nbCells << endl; + for (int i=0; iGetCell(i)); +// MESSAGE(" " << myGrid->GetCell(i)->GetCellType()); + ficcon << i << " - " << myGrid->GetCell(i)->GetCellType() << " -"; + int nbptcell = myGrid->GetCell(i)->GetNumberOfPoints(); + vtkIdList *listid = myGrid->GetCell(i)->GetPointIds(); + for (int j=0; jGetId(j); + } + ficcon << endl; + } + ficcon << "-------------------------------- connectivity " << nbPoints << endl; + vtkCellLinks *links = myGrid->GetCellLinks(); + for (int i=0; iGetNcells(i); + vtkIdType *cells = links->GetCells(i); + ficcon << i << " - " << ncells << " -"; + for (int j=0; j= 0 && vtkid < myCellIdVtkToSmds.size()) + return myCellIdVtkToSmds[vtkid]; + throw SALOME_Exception(LOCALIZED ("vtk id out of bounds")); +} + +void SMDS_Mesh::updateBoundingBox() +{ + xmin = 0; xmax = 0; + ymin = 0; ymax = 0; + zmin = 0; zmax = 0; + vtkPoints *points = myGrid->GetPoints(); + int myNodesSize = this->myNodes.size(); + for (int i = 0; i < myNodesSize; i++) + { + if (SMDS_MeshNode *n = myNodes[i]) + { + double coords[3]; + points->GetPoint(n->myVtkID, coords); + if (coords[0] < xmin) xmin = coords[0]; + else if (coords[0] > xmax) xmax = coords[0]; + if (coords[1] < ymin) ymin = coords[1]; + else if (coords[1] > ymax) ymax = coords[1]; + if (coords[2] < zmin) zmin = coords[2]; + else if (coords[2] > zmax) zmax = coords[2]; + } + } +} + +double SMDS_Mesh::getMaxDim() +{ + double dmax = 1.e-3; + if ((xmax - xmin) > dmax) dmax = xmax -xmin; + if ((ymax - ymin) > dmax) dmax = ymax -ymin; + if ((zmax - zmin) > dmax) dmax = zmax -zmin; + MESSAGE("getMaxDim " << dmax); + return dmax; +} + +//! modification that needs compact structure and redraw +void SMDS_Mesh::Modified() +{ + if (this->myModified) + { + this->myModifTime++; + MESSAGE("modified"); + myModified = false; + } +} + +//! get last modification timeStamp +unsigned long SMDS_Mesh::GetMTime() const +{ + return this->myModifTime; +} + +bool SMDS_Mesh::isCompacted() +{ + if (this->myModifTime > this->myCompactTime) + { + MESSAGE(" *** isCompacted " << myCompactTime << " < " << myModifTime); + this->myCompactTime = this->myModifTime; + return false; + } + return true; } diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_Mesh0DElement.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_Mesh0DElement.cpp new file mode 100644 index 000000000000..95438eab0648 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_Mesh0DElement.cpp @@ -0,0 +1,164 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMDS : implementaion of Salome mesh data structure +// File : SMDS_Mesh0DElement.cxx +// Module : SMESH +// +#ifdef _MSC_VER +#pragma warning(disable:4786) +#endif + +#include "SMDS_Mesh0DElement.hxx" +#include "SMDS_IteratorOfElements.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMDS_Mesh.hxx" + +#include "utilities.h" + +using namespace std; + +//======================================================================= +//function : SMDS_Mesh0DElement +//purpose : +//======================================================================= +SMDS_Mesh0DElement::SMDS_Mesh0DElement (const SMDS_MeshNode * node) +{ + myNode = node; +} + +//======================================================================= +//function : Print +//purpose : +//======================================================================= +void SMDS_Mesh0DElement::Print (ostream & OS) const +{ + OS << "0D Element <" << GetID() << "> : (" << myNode << ") " << endl; +} + +//======================================================================= +//function : NbNodes +//purpose : +//======================================================================= +int SMDS_Mesh0DElement::NbNodes() const +{ + return 1; +} + +//======================================================================= +//function : NbEdges +//purpose : +//======================================================================= +int SMDS_Mesh0DElement::NbEdges() const +{ + return 0; +} + +//======================================================================= +//function : GetType +//purpose : +//======================================================================= +SMDSAbs_ElementType SMDS_Mesh0DElement::GetType() const +{ + return SMDSAbs_0DElement; +} + +vtkIdType SMDS_Mesh0DElement::GetVtkType() const +{ + return VTK_VERTEX; +} + +//======================================================================= +//function : elementsIterator +//purpose : +//======================================================================= +class SMDS_Mesh0DElement_MyNodeIterator: public SMDS_ElemIterator +{ + const SMDS_MeshNode * myNode; + int myIndex; + public: + SMDS_Mesh0DElement_MyNodeIterator(const SMDS_MeshNode * node): + myNode(node),myIndex(0) {} + + bool more() + { + return myIndex < 1; + } + + const SMDS_MeshElement* next() + { + myIndex++; + if (myIndex == 1) + return myNode; + return NULL; + } +}; + +SMDS_ElemIteratorPtr SMDS_Mesh0DElement::elementsIterator (SMDSAbs_ElementType type) const +{ + switch(type) + { + case SMDSAbs_0DElement: + return SMDS_MeshElement::elementsIterator(SMDSAbs_0DElement); + case SMDSAbs_Node: + return SMDS_ElemIteratorPtr(new SMDS_Mesh0DElement_MyNodeIterator(myNode)); + default: + return SMDS_ElemIteratorPtr + (new SMDS_IteratorOfElements + (this,type, SMDS_ElemIteratorPtr(new SMDS_Mesh0DElement_MyNodeIterator(myNode)))); + } +} + +/*! + * \brief Return node by its index + * \param ind - node index + * \retval const SMDS_MeshNode* - the node + */ +const SMDS_MeshNode* SMDS_Mesh0DElement::GetNode(const int ind) const +{ + if (ind == 0) + return myNode; + return NULL; +} + +//======================================================================= +//function : ChangeNode +//purpose : +//======================================================================= +bool SMDS_Mesh0DElement::ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) +{ + if ( nbNodes == 1 ) + { + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(myVtkID, npts, pts); + if (nbNodes != npts) + { + MESSAGE("ChangeNodes problem: not the same number of nodes " << npts << " -> " << nbNodes); + return false; + } + myNode = nodes[0]; + pts[0] = myNode->getVtkId(); + + SMDS_Mesh::_meshList[myMeshId]->setMyModified(); + return true; + } + return false; +} diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshCell.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshCell.cpp new file mode 100644 index 000000000000..e629a2f5b7a0 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshCell.cpp @@ -0,0 +1,476 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +#include "SMDS_MeshCell.hxx" +#include "utilities.h" + +int SMDS_MeshCell::nbCells = 0; + +SMDS_MeshCell::SMDS_MeshCell() : + SMDS_MeshElement(-1) +{ + nbCells++; + myVtkID = -1; +} + +SMDS_MeshCell::~SMDS_MeshCell() +{ + nbCells--; +} +//================================================================================ +/*! + * \brief Return VTKCellType corresponding to SMDSAbs_EntityType + */ +//================================================================================ + +VTKCellType SMDS_MeshCell::toVtkType (SMDSAbs_EntityType smdsType) +{ + static std::vector< VTKCellType > vtkTypes; + if ( vtkTypes.empty() ) + { + vtkTypes.resize( SMDSEntity_Last+1, VTK_EMPTY_CELL ); + vtkTypes[ SMDSEntity_Node ] = VTK_VERTEX; + vtkTypes[ SMDSEntity_0D ] = VTK_VERTEX; + vtkTypes[ SMDSEntity_Edge ] = VTK_LINE; + vtkTypes[ SMDSEntity_Quad_Edge ] = VTK_QUADRATIC_EDGE; + vtkTypes[ SMDSEntity_Triangle ] = VTK_TRIANGLE; + vtkTypes[ SMDSEntity_Quad_Triangle ] = VTK_QUADRATIC_TRIANGLE; + vtkTypes[ SMDSEntity_BiQuad_Triangle ] = VTK_BIQUADRATIC_TRIANGLE; + vtkTypes[ SMDSEntity_Quadrangle ] = VTK_QUAD; + vtkTypes[ SMDSEntity_Quad_Quadrangle ] = VTK_QUADRATIC_QUAD; + vtkTypes[ SMDSEntity_BiQuad_Quadrangle ] = VTK_BIQUADRATIC_QUAD; + vtkTypes[ SMDSEntity_Polygon ] = VTK_POLYGON; + vtkTypes[ SMDSEntity_Quad_Polygon ] = VTK_QUADRATIC_POLYGON; + vtkTypes[ SMDSEntity_Tetra ] = VTK_TETRA; + vtkTypes[ SMDSEntity_Quad_Tetra ] = VTK_QUADRATIC_TETRA; + vtkTypes[ SMDSEntity_Pyramid ] = VTK_PYRAMID; + vtkTypes[ SMDSEntity_Quad_Pyramid ] = VTK_QUADRATIC_PYRAMID; + vtkTypes[ SMDSEntity_Hexa ] = VTK_HEXAHEDRON; + vtkTypes[ SMDSEntity_Quad_Hexa ] = VTK_QUADRATIC_HEXAHEDRON; + vtkTypes[ SMDSEntity_TriQuad_Hexa ] = VTK_TRIQUADRATIC_HEXAHEDRON; + vtkTypes[ SMDSEntity_Penta ] = VTK_WEDGE; + vtkTypes[ SMDSEntity_Quad_Penta ] = VTK_QUADRATIC_WEDGE; + vtkTypes[ SMDSEntity_Hexagonal_Prism ] = VTK_HEXAGONAL_PRISM; + vtkTypes[ SMDSEntity_Polyhedra ] = VTK_POLYHEDRON; + //vtkTypes[ SMDSEntity_Quad_Polyhedra ] = ; + vtkTypes[ SMDSEntity_Ball ] = VTK_POLY_VERTEX; + } + return vtkTypes[ smdsType ]; +} + +//================================================================================ +/*! + * \brief Return indices to transform cell connectivity from SMDS to VTK + * Usage: vtkIDs[i] = smdsIDs[ indices[ i ]] + */ +//================================================================================ + +const std::vector< int >& SMDS_MeshCell::toVtkOrder(SMDSAbs_EntityType smdsType) +{ + static std::vector< std::vector< int > > toVtkInterlaces; + if ( toVtkInterlaces.empty() ) + { + toVtkInterlaces.resize( SMDSEntity_Last+1 ); + // { + // const int ids[] = {0}; + // toVtkInterlaces[SMDSEntity_0D].assign( &ids[0], &ids[0]+1 ); + // toVtkInterlaces[SMDSEntity_Node].assign( &ids[0], &ids[0]+1 ); + // } + // { + // const int ids[] = {0,1}; + // toVtkInterlaces[SMDSEntity_Edge].assign( &ids[0], &ids[0]+2 ); + // } + // { + // const int ids[] = {0,1,2}; + // toVtkInterlaces[SMDSEntity_Quad_Edge].assign( &ids[0], &ids[0]+3 ); + // } + // { + // const int ids[] = {0,1,2}; + // toVtkInterlaces[SMDSEntity_Triangle].assign( &ids[0], &ids[0]+3 ); + // } + // { + // const int ids[] = {0,1,2,3,4,5}; + // toVtkInterlaces[SMDSEntity_Quad_Triangle].assign( &ids[0], &ids[0]+6 ); + // } + // { + // const int ids[] = {0,1,2,3}; + // toVtkInterlaces[SMDSEntity_Quadrangle].assign( &ids[0], &ids[0]+4 ); + // } + // { + // const int ids[] = {0,1,2,3,4,5,6,7}; + // toVtkInterlaces[SMDSEntity_Quad_Quadrangle].assign( &ids[0], &ids[0]+8 ); + // } + // { + // const int ids[] = {0,1,2,3,4,5,6,7,8}; + // toVtkInterlaces[SMDSEntity_BiQuad_Quadrangle].assign( &ids[0], &ids[0]+9 ); + // } + { + const int ids[] = {0,2,1,3}; + toVtkInterlaces[SMDSEntity_Tetra].assign( &ids[0], &ids[0]+4 ); + } + { + const int ids[] = {0,2,1,3,6,5,4,7,9,8}; + toVtkInterlaces[SMDSEntity_Quad_Tetra].assign( &ids[0], &ids[0]+10 ); + } + { + const int ids[] = {0,3,2,1,4}; + toVtkInterlaces[SMDSEntity_Pyramid].assign( &ids[0], &ids[0]+5 ); + } + { + const int ids[] = {0,3,2,1,4,8,7,6,5,9,12,11,10}; + toVtkInterlaces[SMDSEntity_Quad_Pyramid].assign( &ids[0], &ids[0]+13 ); + } + { + const int ids[] = {0,3,2,1,4,7,6,5}; + toVtkInterlaces[SMDSEntity_Hexa].assign( &ids[0], &ids[0]+8 ); + } + { + const int ids[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17}; + toVtkInterlaces[SMDSEntity_Quad_Hexa].assign( &ids[0], &ids[0]+20 ); + } + { + const int ids[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17, 21,23,24,22,20,25,26}; + toVtkInterlaces[SMDSEntity_TriQuad_Hexa].assign( &ids[0], &ids[0]+27 ); + } + { + const int ids[] = {0,1,2,3,4,5}; + toVtkInterlaces[SMDSEntity_Penta].assign( &ids[0], &ids[0]+6 ); + } + { + const int ids[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14}; + toVtkInterlaces[SMDSEntity_Quad_Penta].assign( &ids[0], &ids[0]+15 ); + } + { + const int ids[] = {0,5,4,3,2,1,6,11,10,9,8,7}; + toVtkInterlaces[SMDSEntity_Hexagonal_Prism].assign( &ids[0], &ids[0]+12 ); + } + } + return toVtkInterlaces[smdsType]; +} + +//================================================================================ +/*! + * \brief Return indices to reverse an SMDS cell of given type. + * nbNodes is useful for polygons + * Usage: reverseIDs[i] = forwardIDs[ indices[ i ]] + */ +//================================================================================ + +const std::vector& SMDS_MeshCell::reverseSmdsOrder(SMDSAbs_EntityType smdsType, + const size_t nbNodes) +{ + static std::vector< std::vector< int > > reverseInterlaces; + if ( reverseInterlaces.empty() ) + { + reverseInterlaces.resize( SMDSEntity_Last+1 ); + { + const int ids[] = {0}; + reverseInterlaces[SMDSEntity_0D].assign( &ids[0], &ids[0]+1 ); + reverseInterlaces[SMDSEntity_Node].assign( &ids[0], &ids[0]+1 ); + reverseInterlaces[SMDSEntity_Ball].assign( &ids[0], &ids[0]+1 ); + } + { + const int ids[] = {1,0}; + reverseInterlaces[SMDSEntity_Edge].assign( &ids[0], &ids[0]+2 ); + } + { + const int ids[] = {1,0,2}; + reverseInterlaces[SMDSEntity_Quad_Edge].assign( &ids[0], &ids[0]+3 ); + } + { + const int ids[] = {0,2,1}; + reverseInterlaces[SMDSEntity_Triangle].assign( &ids[0], &ids[0]+3 ); + } + { + const int ids[] = {0,2,1,5,4,3}; + reverseInterlaces[SMDSEntity_Quad_Triangle].assign( &ids[0], &ids[0]+6 ); + } + { + const int ids[] = {0,2,1,5,4,3,6}; + reverseInterlaces[SMDSEntity_BiQuad_Triangle].assign( &ids[0], &ids[0]+7 ); + } + { + const int ids[] = {0,3,2,1}; + reverseInterlaces[SMDSEntity_Quadrangle].assign( &ids[0], &ids[0]+4 ); + } + { + const int ids[] = {0,3,2,1,7,6,5,4}; + reverseInterlaces[SMDSEntity_Quad_Quadrangle].assign( &ids[0], &ids[0]+8 ); + } + { + const int ids[] = {0,3,2,1,7,6,5,4,8}; + reverseInterlaces[SMDSEntity_BiQuad_Quadrangle].assign( &ids[0], &ids[0]+9 ); + } + { + const int ids[] = {0,2,1,3}; + reverseInterlaces[SMDSEntity_Tetra].assign( &ids[0], &ids[0]+4 ); + } + { + const int ids[] = {0,2,1,3,6,5,4,7,9,8}; + reverseInterlaces[SMDSEntity_Quad_Tetra].assign( &ids[0], &ids[0]+10 ); + } + { + const int ids[] = {0,3,2,1,4}; + reverseInterlaces[SMDSEntity_Pyramid].assign( &ids[0], &ids[0]+5 ); + } + { + const int ids[] = {0,3,2,1,4,8,7,6,5,9,12,11,10}; + reverseInterlaces[SMDSEntity_Quad_Pyramid].assign( &ids[0], &ids[0]+13 ); + } + { + const int ids[] = {0,3,2,1,4,7,6,5}; + reverseInterlaces[SMDSEntity_Hexa].assign( &ids[0], &ids[0]+8 ); + } + { + const int ids[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17}; + reverseInterlaces[SMDSEntity_Quad_Hexa].assign( &ids[0], &ids[0]+20 ); + } + { + const int ids[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17, 20,24,23,22,21,25,26}; + reverseInterlaces[SMDSEntity_TriQuad_Hexa].assign( &ids[0], &ids[0]+27 ); + } + { + const int ids[] = {0,2,1,3,5,4}; + reverseInterlaces[SMDSEntity_Penta].assign( &ids[0], &ids[0]+6 ); + } + { + const int ids[] = {0,2,1,3,5,4, 8,7,6,11,10,9,12,14,13}; + reverseInterlaces[SMDSEntity_Quad_Penta].assign( &ids[0], &ids[0]+15 ); + } + { + const int ids[] = {0,5,4,3,2,1,6,11,10,9,8,7}; + reverseInterlaces[SMDSEntity_Hexagonal_Prism].assign( &ids[0], &ids[0]+12 ); + } + } + + if ( smdsType == SMDSEntity_Polygon ) + { + if ( reverseInterlaces[ smdsType ].size() != nbNodes ) + { + reverseInterlaces[ smdsType ].resize( nbNodes ); + for ( size_t i = 0; i < nbNodes; ++i ) + reverseInterlaces[ smdsType ][i] = nbNodes - i - 1; + } + } + else if ( smdsType == SMDSEntity_Quad_Polygon ) + { + if ( reverseInterlaces[ smdsType ].size() != nbNodes ) + { + // e.g. for 8 nodes: [ 0, 3,2,1, 7,6,5,4 ] + reverseInterlaces[ smdsType ].resize( nbNodes ); + size_t pos = 0; + reverseInterlaces[ smdsType ][pos++] = 0; + for ( int i = nbNodes / 2 - 1; i > 0 ; --i ) // 3,2,1 + reverseInterlaces[ smdsType ][pos++] = i; + for ( int i = nbNodes - 1; i >= nbNodes / 2; --i ) // 7,6,5,4 + reverseInterlaces[ smdsType ][pos++] = i; + } + } + + return reverseInterlaces[smdsType]; +} + +//================================================================================ +/*! + * \brief Return indices to set nodes of a quadratic 1D or 2D element in interlaced order + * Usage: interlacedIDs[i] = smdsIDs[ indices[ i ]] + */ +//================================================================================ + +const std::vector& SMDS_MeshCell::interlacedSmdsOrder(SMDSAbs_EntityType smdsType, + const size_t nbNodes) +{ + static std::vector< std::vector< int > > interlace; + if ( interlace.empty() ) + { + interlace.resize( SMDSEntity_Last+1 ); + { + const int ids[] = {0,2,1}; + interlace[SMDSEntity_Quad_Edge].assign( &ids[0], &ids[0]+3 ); + } + { + const int ids[] = {0,3,1,4,2,5,6}; + interlace[SMDSEntity_Quad_Triangle ].assign( &ids[0], &ids[0]+6 ); + interlace[SMDSEntity_BiQuad_Triangle].assign( &ids[0], &ids[0]+7 ); + } + { + const int ids[] = {0,4,1,5,2,6,3,7,8}; + interlace[SMDSEntity_Quad_Quadrangle ].assign( &ids[0], &ids[0]+8 ); + interlace[SMDSEntity_BiQuad_Quadrangle].assign( &ids[0], &ids[0]+9 ); + } + } + + if ( smdsType == SMDSEntity_Quad_Polygon ) + { + if ( interlace[smdsType].size() != nbNodes ) + { + interlace[smdsType].resize( nbNodes ); + for ( size_t i = 0; i < nbNodes / 2; ++i ) + { + interlace[smdsType][i*2+0] = i; + interlace[smdsType][i*2+1] = i + nbNodes / 2; + } + } + } + return interlace[smdsType]; +} + +//================================================================================ +/*! + * \brief Return SMDSAbs_EntityType corresponding to VTKCellType + */ +//================================================================================ + +SMDSAbs_EntityType SMDS_MeshCell::toSmdsType(VTKCellType vtkType) +{ + static std::vector< SMDSAbs_EntityType > smdsTypes; + if ( smdsTypes.empty() ) + { + smdsTypes.resize( VTK_NUMBER_OF_CELL_TYPES, SMDSEntity_Last ); + for ( int iSMDS = 0; iSMDS < SMDSEntity_Last; ++iSMDS ) + smdsTypes[ toVtkType( SMDSAbs_EntityType( iSMDS ))] = SMDSAbs_EntityType( iSMDS ); + } + return smdsTypes[ vtkType ]; +} + +//================================================================================ +/*! + * \brief Return SMDSAbs_ElementType by SMDSAbs_GeometryType + */ +//================================================================================ + +SMDSAbs_ElementType SMDS_MeshCell::toSmdsType(SMDSAbs_GeometryType geomType) +{ + switch ( geomType ) { + case SMDSGeom_POINT: return SMDSAbs_0DElement; + + case SMDSGeom_EDGE: return SMDSAbs_Edge; + + case SMDSGeom_TRIANGLE: + case SMDSGeom_QUADRANGLE: + case SMDSGeom_POLYGON: return SMDSAbs_Face; + + case SMDSGeom_TETRA: + case SMDSGeom_PYRAMID: + case SMDSGeom_HEXA: + case SMDSGeom_PENTA: + case SMDSGeom_HEXAGONAL_PRISM: + case SMDSGeom_POLYHEDRA: return SMDSAbs_Volume; + + case SMDSGeom_BALL: return SMDSAbs_Ball; + + case SMDSGeom_NONE: ; + } + return SMDSAbs_All; +} + +//================================================================================ +/*! + * \brief Return SMDSAbs_ElementType by SMDSAbs_EntityType + */ +//================================================================================ + +SMDSAbs_ElementType SMDS_MeshCell::toSmdsType(SMDSAbs_EntityType entityType) +{ + switch ( entityType ) { + case SMDSEntity_Node: return SMDSAbs_Node; + + case SMDSEntity_0D: return SMDSAbs_0DElement; + + case SMDSEntity_Edge: + case SMDSEntity_Quad_Edge: return SMDSAbs_Edge; + + case SMDSEntity_Triangle: + case SMDSEntity_Quad_Triangle: + case SMDSEntity_BiQuad_Triangle: + case SMDSEntity_Quadrangle: + case SMDSEntity_Quad_Quadrangle: + case SMDSEntity_BiQuad_Quadrangle: + case SMDSEntity_Polygon: + case SMDSEntity_Quad_Polygon: return SMDSAbs_Face; + + case SMDSEntity_Tetra: + case SMDSEntity_Quad_Tetra: + case SMDSEntity_Pyramid: + case SMDSEntity_Quad_Pyramid: + case SMDSEntity_Hexa: + case SMDSEntity_Quad_Hexa: + case SMDSEntity_TriQuad_Hexa: + case SMDSEntity_Penta: + case SMDSEntity_Quad_Penta: + case SMDSEntity_Hexagonal_Prism: + case SMDSEntity_Polyhedra: + case SMDSEntity_Quad_Polyhedra: return SMDSAbs_Volume; + + case SMDSEntity_Ball: return SMDSAbs_Ball; + + case SMDSEntity_Last:; + } + return SMDSAbs_All; +} + + +//================================================================================ +/*! + * \brief Return indices to transform cell connectivity from VTK to SMDS + * Usage: smdsIDs[i] = vtkIDs[ indices[ i ]] + */ +//================================================================================ + +const std::vector& SMDS_MeshCell::fromVtkOrder(SMDSAbs_EntityType smdsType) +{ + static std::vector< std::vector > fromVtkInterlaces; + if ( fromVtkInterlaces.empty() ) + { + fromVtkInterlaces.resize( SMDSEntity_Last+1 ); + for ( int iSMDS = 0; iSMDS < SMDSEntity_Last; ++iSMDS ) + { + const std::vector & toVtk = toVtkOrder( SMDSAbs_EntityType( iSMDS )); + std::vector & toSmds = fromVtkInterlaces[ iSMDS ]; + toSmds.resize( toVtk.size() ); + for ( size_t i = 0; i < toVtk.size(); ++i ) + toSmds[ toVtk[i] ] = i; + } + } + return fromVtkInterlaces[ smdsType ]; +} + +//================================================================================ +/*! + * \brief Return indices to transform cell connectivity from SMDS to VTK + * Usage: vtkIDs[i] = smdsIDs[ indices[ i ]] + */ +//================================================================================ + +const std::vector& SMDS_MeshCell::toVtkOrder(VTKCellType vtkType) +{ + return toVtkOrder( toSmdsType( vtkType )); +} + +//================================================================================ +/*! + * \brief Return indices to transform cell connectivity from VTK to SMDS + * Usage: smdsIDs[i] = vtkIDs[ indices[ i ]] + */ +//================================================================================ + +const std::vector& SMDS_MeshCell::fromVtkOrder(VTKCellType vtkType) +{ + return fromVtkOrder( toSmdsType( vtkType )); +} diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshEdge.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshEdge.cpp index 924a6c2e714c..d381349414e5 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshEdge.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshEdge.cpp @@ -1,159 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 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, or (at your option) any later version. // -// 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. // -// 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 // -// 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 // -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// SMESH SMDS : implementaion of Salome mesh data structure -// File : SMDS_MeshEdge.cxx -// Author : Jean-Michel BOULCOURT -// Module : SMESH -// -#ifdef _MSC_VER -#pragma warning(disable:4786) -#endif #include "SMDS_MeshEdge.hxx" -#include "SMDS_IteratorOfElements.hxx" -#include "SMDS_MeshNode.hxx" - -using namespace std; - -//======================================================================= -//function : SMDS_MeshEdge -//purpose : -//======================================================================= - -SMDS_MeshEdge::SMDS_MeshEdge(const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2) -{ - myNodes[0]=node1; - myNodes[1]=node2; -} - -//======================================================================= -//function : Print -//purpose : -//======================================================================= - -void SMDS_MeshEdge::Print(ostream & OS) const -{ - OS << "edge <" << GetID() << "> : (" << myNodes[0] << " , " << myNodes[1] << - ") " << endl; -} - -int SMDS_MeshEdge::NbNodes() const -{ - return 2; -} - -int SMDS_MeshEdge::NbEdges() const -{ - return 1; -} SMDSAbs_ElementType SMDS_MeshEdge::GetType() const { - return SMDSAbs_Edge; + return SMDSAbs_Edge; } -class SMDS_MeshEdge_MyNodeIterator:public SMDS_ElemIterator +vtkIdType SMDS_MeshEdge::GetVtkType() const { - const SMDS_MeshNode *const* myNodes; - int myIndex; - public: - SMDS_MeshEdge_MyNodeIterator(const SMDS_MeshNode * const* nodes): - myNodes(nodes),myIndex(0) {} - - bool more() - { - return myIndex<2; - } - - const SMDS_MeshElement* next() - { - myIndex++; - return myNodes[myIndex-1]; - } -}; - -SMDS_ElemIteratorPtr SMDS_MeshEdge:: - elementsIterator(SMDSAbs_ElementType type) const -{ - switch(type) - { - case SMDSAbs_Edge: - return SMDS_MeshElement::elementsIterator(SMDSAbs_Edge); - case SMDSAbs_Node: - return SMDS_ElemIteratorPtr(new SMDS_MeshEdge_MyNodeIterator(myNodes)); - default: - return SMDS_ElemIteratorPtr - (new SMDS_IteratorOfElements - (this,type, SMDS_ElemIteratorPtr(new SMDS_MeshEdge_MyNodeIterator(myNodes)))); - } -} - -bool operator<(const SMDS_MeshEdge & e1, const SMDS_MeshEdge & e2) -{ - int id11=e1.myNodes[0]->GetID(); - int id21=e2.myNodes[0]->GetID(); - int id12=e1.myNodes[1]->GetID(); - int id22=e2.myNodes[1]->GetID(); - int tmp; - - if(id11>=id12) - { - tmp=id11; - id11=id12; - id12=tmp; - } - if(id21>=id22) - { - tmp=id21; - id21=id22; - id22=tmp; - } - - if(id11Print(OS); - return OS; + ME->Print(OS); + return OS; } /////////////////////////////////////////////////////////////////////////////// @@ -55,7 +70,7 @@ ostream & operator <<(ostream & OS, const SMDS_MeshElement * ME) /////////////////////////////////////////////////////////////////////////////// SMDS_ElemIteratorPtr SMDS_MeshElement::nodesIterator() const { - return elementsIterator(SMDSAbs_Node); + return elementsIterator(SMDSAbs_Node); } /////////////////////////////////////////////////////////////////////////////// @@ -64,7 +79,7 @@ SMDS_ElemIteratorPtr SMDS_MeshElement::nodesIterator() const /////////////////////////////////////////////////////////////////////////////// SMDS_ElemIteratorPtr SMDS_MeshElement::edgesIterator() const { - return elementsIterator(SMDSAbs_Edge); + return elementsIterator(SMDSAbs_Edge); } /////////////////////////////////////////////////////////////////////////////// @@ -73,7 +88,7 @@ SMDS_ElemIteratorPtr SMDS_MeshElement::edgesIterator() const /////////////////////////////////////////////////////////////////////////////// SMDS_ElemIteratorPtr SMDS_MeshElement::facesIterator() const { - return elementsIterator(SMDSAbs_Face); + return elementsIterator(SMDSAbs_Face); } /////////////////////////////////////////////////////////////////////////////// @@ -81,14 +96,14 @@ SMDS_ElemIteratorPtr SMDS_MeshElement::facesIterator() const /////////////////////////////////////////////////////////////////////////////// int SMDS_MeshElement::NbNodes() const { - int nbnodes=0; - SMDS_ElemIteratorPtr it=nodesIterator(); - while(it->more()) - { - it->next(); - nbnodes++; - } - return nbnodes; + int nbnodes=0; + SMDS_ElemIteratorPtr it=nodesIterator(); + while(it->more()) + { + it->next(); + nbnodes++; + } + return nbnodes; } /////////////////////////////////////////////////////////////////////////////// @@ -96,14 +111,14 @@ int SMDS_MeshElement::NbNodes() const /////////////////////////////////////////////////////////////////////////////// int SMDS_MeshElement::NbEdges() const { - int nbedges=0; - SMDS_ElemIteratorPtr it=edgesIterator(); - while(it->more()) - { - it->next(); - nbedges++; - } - return nbedges; + int nbedges=0; + SMDS_ElemIteratorPtr it=edgesIterator(); + while(it->more()) + { + it->next(); + nbedges++; + } + return nbedges; } /////////////////////////////////////////////////////////////////////////////// @@ -111,14 +126,14 @@ int SMDS_MeshElement::NbEdges() const /////////////////////////////////////////////////////////////////////////////// int SMDS_MeshElement::NbFaces() const { - int nbfaces=0; - SMDS_ElemIteratorPtr it=facesIterator(); - while(it->more()) - { - it->next(); - nbfaces++; - } - return nbfaces; + int nbfaces=0; + SMDS_ElemIteratorPtr it=facesIterator(); + while(it->more()) + { + it->next(); + nbfaces++; + } + return nbfaces; } /////////////////////////////////////////////////////////////////////////////// @@ -142,56 +157,98 @@ class SMDS_MeshElement_MyIterator:public SMDS_ElemIterator const SMDS_MeshElement* next() { myMore=false; - return myElement; - } + return myElement; + } }; -SMDS_ElemIteratorPtr SMDS_MeshElement:: - elementsIterator(SMDSAbs_ElementType type) const -{ - /** @todo Check that iterator in the child classes return elements - in the same order for each different implementation (i.e: SMDS_VolumeOfNodes - and SMDS_VolumeOfFaces */ - - if(type==GetType()) - return SMDS_ElemIteratorPtr(new SMDS_MeshElement_MyIterator(this)); - else - { - MESSAGE("Iterator not implemented"); - return SMDS_ElemIteratorPtr((SMDS_ElemIterator*)NULL); - } + +SMDS_ElemIteratorPtr +SMDS_MeshElement::elementsIterator(SMDSAbs_ElementType type) const +{ + /** @todo Check that iterator in the child classes return elements + in the same order for each different implementation (i.e: SMDS_VolumeOfNodes + and SMDS_VolumeOfFaces */ + if(type==GetType()) + return SMDS_ElemIteratorPtr(new SMDS_MeshElement_MyIterator(this)); + else + { + MESSAGE("Iterator not implemented"); + return SMDS_ElemIteratorPtr((SMDS_ElemIterator*)NULL); + } } -/////////////////////////////////////////////////////////////////////////////// -///Return the ID of the element -/////////////////////////////////////////////////////////////////////////////// -int SMDS_MeshElement::GetID() const +//! virtual, redefined in vtkEdge, vtkFace and vtkVolume classes +SMDS_NodeIteratorPtr SMDS_MeshElement::nodesIteratorToUNV() const { - return myID; + return nodeIterator(); +} + +//! virtual, redefined in vtkEdge, vtkFace and vtkVolume classes +SMDS_NodeIteratorPtr SMDS_MeshElement::interlacedNodesIterator() const +{ + return nodeIterator(); +} + +namespace +{ + //======================================================================= + //class : _MyNodeIteratorFromElemIterator + //======================================================================= + class _MyNodeIteratorFromElemIterator : public SMDS_NodeIterator + { + SMDS_ElemIteratorPtr myItr; + public: + _MyNodeIteratorFromElemIterator(SMDS_ElemIteratorPtr elemItr):myItr( elemItr ) {} + bool more() { return myItr->more(); } + const SMDS_MeshNode* next() { return static_cast< const SMDS_MeshNode*>( myItr->next() ); } + }; + //======================================================================= + //class : _MyElemIteratorFromNodeIterator + //======================================================================= + class _MyElemIteratorFromNodeIterator : public SMDS_ElemIterator + { + SMDS_NodeIteratorPtr myItr; + public: + _MyElemIteratorFromNodeIterator(SMDS_NodeIteratorPtr nodeItr): myItr( nodeItr ) {} + bool more() { return myItr->more(); } + const SMDS_MeshElement* next() { return myItr->next(); } + }; +} + +SMDS_ElemIteratorPtr SMDS_MeshElement::interlacedNodesElemIterator() const +{ + return SMDS_ElemIteratorPtr + ( new _MyElemIteratorFromNodeIterator( interlacedNodesIterator() )); +} + +SMDS_NodeIteratorPtr SMDS_MeshElement::nodeIterator() const +{ + return SMDS_NodeIteratorPtr + ( new _MyNodeIteratorFromElemIterator( nodesIterator() )); } bool operator<(const SMDS_MeshElement& e1, const SMDS_MeshElement& e2) { - if(e1.GetType()!=e2.GetType()) return false; - switch(e1.GetType()) - { - case SMDSAbs_Node: - return static_cast(e1) < - static_cast(e2); + if(e1.GetType()!=e2.GetType()) return false; + switch(e1.GetType()) + { + case SMDSAbs_Node: + return static_cast(e1) < + static_cast(e2); - case SMDSAbs_Edge: - return static_cast(e1) < - static_cast(e2); + case SMDSAbs_Edge: + return static_cast(e1) < + static_cast(e2); - case SMDSAbs_Face: - return static_cast(e1) < - static_cast(e2); + case SMDSAbs_Face: + return static_cast(e1) < + static_cast(e2); - case SMDSAbs_Volume: - return static_cast(e1) < - static_cast(e2); + case SMDSAbs_Volume: + return static_cast(e1) < + static_cast(e2); - default : MESSAGE("Internal Error"); - } + default : MESSAGE("Internal Error"); + } return false; } @@ -222,6 +279,17 @@ bool SMDS_MeshElement::IsMediumNode(const SMDS_MeshNode* node) const return false; } +//================================================================================ +/*! + * \brief Return number of nodes excluding medium ones + */ +//================================================================================ + +int SMDS_MeshElement::NbCornerNodes() const +{ + return IsQuadratic() ? NbNodes() - NbEdges() : NbNodes(); +} + //================================================================================ /*! * \brief Check if a node belongs to the element diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshElementIDFactory.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshElementIDFactory.cpp index 7ecfba5b025d..f8eb2ddefc89 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshElementIDFactory.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshElementIDFactory.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshElementIDFactory.cxx // Author : Jean-Michel BOULCOURT @@ -30,6 +31,14 @@ #include "SMDS_MeshElementIDFactory.hxx" #include "SMDS_MeshElement.hxx" +#include "SMDS_Mesh.hxx" + +#include "utilities.h" + +#include "SMDS_UnstructuredGrid.hxx" +#include + +#include using namespace std; @@ -38,23 +47,46 @@ using namespace std; //purpose : //======================================================================= SMDS_MeshElementIDFactory::SMDS_MeshElementIDFactory(): - SMDS_MeshIDFactory(), - myMin(0), myMax(0) + SMDS_MeshNodeIDFactory() +{ +} + +int SMDS_MeshElementIDFactory::SetInVtkGrid(SMDS_MeshElement * elem) { + // --- retrieve nodes ID + + SMDS_MeshCell *cell = dynamic_cast(elem); + assert(cell); + vector nodeIds; + SMDS_ElemIteratorPtr it = elem->nodesIterator(); + while(it->more()) + { + int nodeId = (static_cast(it->next()))->getVtkId(); + MESSAGE(" node in cell " << cell->getVtkId() << " : " << nodeId) + nodeIds.push_back(nodeId); + } + + // --- insert cell in vtkUnstructuredGrid + + vtkUnstructuredGrid * grid = myMesh->getGrid(); + //int locType = elem->GetType(); + int typ = VTK_VERTEX;//GetVtkCellType(locType); + int cellId = grid->InsertNextLinkedCell(typ, nodeIds.size(), &nodeIds[0]); + cell->setVtkId(cellId); + //MESSAGE("SMDS_MeshElementIDFactory::SetInVtkGrid " << cellId); + return cellId; } //======================================================================= //function : BindID //purpose : //======================================================================= + bool SMDS_MeshElementIDFactory::BindID(int ID, SMDS_MeshElement * elem) { - if (myIDElements.IsBound(ID)) - return false; - myIDElements.Bind(ID,elem); - elem->myID=ID; - updateMinMax (ID); - return true; + MESSAGE("SMDS_MeshElementIDFactory::BindID " << ID); + SetInVtkGrid(elem); + return myMesh->registerElement(ID, elem); } //======================================================================= @@ -63,22 +95,23 @@ bool SMDS_MeshElementIDFactory::BindID(int ID, SMDS_MeshElement * elem) //======================================================================= SMDS_MeshElement* SMDS_MeshElementIDFactory::MeshElement(int ID) { - if (!myIDElements.IsBound(ID)) + if ((ID<1) || (ID>=myMesh->myCells.size())) return NULL; - return myIDElements.Find(ID); + const SMDS_MeshElement* elem = GetMesh()->FindElement(ID); + return (SMDS_MeshElement*)(elem); } - //======================================================================= //function : GetFreeID //purpose : //======================================================================= + int SMDS_MeshElementIDFactory::GetFreeID() { int ID; do { ID = SMDS_MeshIDFactory::GetFreeID(); - } while (myIDElements.IsBound(ID)); + } while ( MeshElement( ID )); return ID; } @@ -86,38 +119,25 @@ int SMDS_MeshElementIDFactory::GetFreeID() //function : ReleaseID //purpose : //======================================================================= -void SMDS_MeshElementIDFactory::ReleaseID(const int ID) +void SMDS_MeshElementIDFactory::ReleaseID(int ID, int vtkId) { - myIDElements.UnBind(ID); + if (ID < 1) // TODO check case ID == O + { + MESSAGE("~~~~~~~~~~~~~~ SMDS_MeshElementIDFactory::ReleaseID ID = " << ID); + return; + } + //MESSAGE("~~~~~~~~~~~~~~ SMDS_MeshElementIDFactory::ReleaseID smdsId vtkId " << ID << " " << vtkId); + if (vtkId >= 0) + { + assert(vtkId < myMesh->myCellIdVtkToSmds.size()); + myMesh->myCellIdVtkToSmds[vtkId] = -1; + myMesh->setMyModified(); + } SMDS_MeshIDFactory::ReleaseID(ID); if (ID == myMax) myMax = 0; if (ID == myMin) - myMin = 0; -} - -//======================================================================= -//function : GetMaxID -//purpose : -//======================================================================= - -int SMDS_MeshElementIDFactory::GetMaxID() const -{ - if (myMax == 0) - updateMinMax(); - return myMax; -} - -//======================================================================= -//function : GetMinID -//purpose : -//======================================================================= - -int SMDS_MeshElementIDFactory::GetMinID() const -{ - if (myMin == 0) - updateMinMax(); - return myMin; + myMax = 0; } //======================================================================= @@ -127,12 +147,20 @@ int SMDS_MeshElementIDFactory::GetMinID() const void SMDS_MeshElementIDFactory::updateMinMax() const { - myMin = IntegerLast(); + myMin = INT_MAX; myMax = 0; - SMDS_IdElementMap::Iterator it(myIDElements); - for (; it.More(); it.Next()) - updateMinMax (it.Key()); - if (myMin == IntegerLast()) + for (int i = 0; i < myMesh->myCells.size(); i++) + { + if (myMesh->myCells[i]) + { + int id = myMesh->myCells[i]->GetID(); + if (id > myMax) + myMax = id; + if (id < myMin) + myMin = id; + } + } + if (myMin == INT_MAX) myMin = 0; } @@ -141,35 +169,15 @@ void SMDS_MeshElementIDFactory::updateMinMax() const //purpose : Return an iterator on elements of the factory //======================================================================= -class SMDS_Fact_MyElemIterator:public SMDS_ElemIterator -{ - SMDS_IdElementMap::Iterator myIterator; - public: - SMDS_Fact_MyElemIterator(const SMDS_IdElementMap& s):myIterator(s) - {} - - bool more() - { - return myIterator.More() != Standard_False; - } - - const SMDS_MeshElement* next() - { - const SMDS_MeshElement* current = myIterator.Value(); - myIterator.Next(); - return current; - } -}; - SMDS_ElemIteratorPtr SMDS_MeshElementIDFactory::elementsIterator() const { - return SMDS_ElemIteratorPtr - (new SMDS_Fact_MyElemIterator(myIDElements)); + return myMesh->elementsIterator(SMDSAbs_All); } void SMDS_MeshElementIDFactory::Clear() { - myIDElements.Clear(); + //myMesh->myCellIdSmdsToVtk.clear(); + myMesh->myCellIdVtkToSmds.clear(); myMin = myMax = 0; SMDS_MeshIDFactory::Clear(); } diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshFace.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshFace.cpp index a4a19f03f43d..53ce3166109b 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshFace.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshFace.cpp @@ -1,29 +1,35 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // #include "SMDS_MeshFace.hxx" SMDSAbs_ElementType SMDS_MeshFace::GetType() const { - return SMDSAbs_Face; + return SMDSAbs_Face; +} + +vtkIdType SMDS_MeshFace::GetVtkType() const +{ + return VTK_POLY_LINE; // --- must be reimplemented in derived classes } diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshGroup.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshGroup.cpp index 67c1df426165..14b71412da64 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshGroup.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshGroup.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshGroup.cxx // Author : Jean-Michel BOULCOURT @@ -40,7 +41,7 @@ using namespace std; SMDS_MeshGroup::SMDS_MeshGroup(const SMDS_Mesh * theMesh, const SMDSAbs_ElementType theType) - :myMesh(theMesh),myType(theType), myParent(NULL) + :myMesh(theMesh),myType(theType), myParent(NULL), myTic(0) { } @@ -51,7 +52,7 @@ SMDS_MeshGroup::SMDS_MeshGroup(const SMDS_Mesh * theMesh, SMDS_MeshGroup::SMDS_MeshGroup(SMDS_MeshGroup * theParent, const SMDSAbs_ElementType theType) - :myMesh(theParent->myMesh),myType(theType), myParent(theParent) + :myMesh(theParent->myMesh),myType(theType), myParent(theParent) { } @@ -63,9 +64,9 @@ SMDS_MeshGroup::SMDS_MeshGroup(SMDS_MeshGroup * theParent, const SMDS_MeshGroup *SMDS_MeshGroup::AddSubGroup (const SMDSAbs_ElementType theType) { - const SMDS_MeshGroup * subgroup = new SMDS_MeshGroup(this,theType); - myChildren.insert(myChildren.end(),subgroup); - return subgroup; + const SMDS_MeshGroup * subgroup = new SMDS_MeshGroup(this,theType); + myChildren.insert(myChildren.end(),subgroup); + return subgroup; } //======================================================================= @@ -75,19 +76,19 @@ const SMDS_MeshGroup *SMDS_MeshGroup::AddSubGroup bool SMDS_MeshGroup::RemoveSubGroup(const SMDS_MeshGroup * theGroup) { - bool found = false; - list::iterator itgroup; - for(itgroup=myChildren.begin(); itgroup!=myChildren.end(); itgroup++) - { - const SMDS_MeshGroup* subgroup=*itgroup; - if (subgroup == theGroup) - { - found = true; - myChildren.erase(itgroup); - } - } - - return found; + bool found = false; + list::iterator itgroup; + for(itgroup=myChildren.begin(); itgroup!=myChildren.end(); itgroup++) + { + const SMDS_MeshGroup* subgroup=*itgroup; + if (subgroup == theGroup) + { + found = true; + myChildren.erase(itgroup); + } + } + + return found; } //======================================================================= @@ -97,12 +98,12 @@ bool SMDS_MeshGroup::RemoveSubGroup(const SMDS_MeshGroup * theGroup) bool SMDS_MeshGroup::RemoveFromParent() { - - if (myParent==NULL) return false; - else - { - return (myParent->RemoveSubGroup(this)); - } + + if (myParent==NULL) return false; + else + { + return (myParent->RemoveSubGroup(this)); + } } //======================================================================= //function : Clear @@ -111,8 +112,9 @@ bool SMDS_MeshGroup::RemoveFromParent() void SMDS_MeshGroup::Clear() { - myElements.clear(); - myType = SMDSAbs_All; + myElements.clear(); + myType = SMDSAbs_All; + ++myTic; } //======================================================================= @@ -120,16 +122,21 @@ void SMDS_MeshGroup::Clear() //purpose : //======================================================================= -void SMDS_MeshGroup::Add(const SMDS_MeshElement * theElem) +bool SMDS_MeshGroup::Add(const SMDS_MeshElement * theElem) { - // the type of the group is determined by the first element added - if (myElements.empty()) myType = theElem->GetType(); - else if (theElem->GetType() != myType) { - MESSAGE("SMDS_MeshGroup::Add : Type Mismatch "<GetType()<<"!="<GetType(); + } + else if (theElem->GetType() != myType) { + MESSAGE("SMDS_MeshGroup::Add : Type Mismatch "<GetType()<<"!="<::iterator found - = myElements.find(theElem); + set::iterator found = myElements.find(theElem); if ( found != myElements.end() ) { myElements.erase(found); if (myElements.empty()) myType = SMDSAbs_All; + ++myTic; return true; } return false; @@ -156,7 +163,7 @@ bool SMDS_MeshGroup::Remove(const SMDS_MeshElement * theElem) bool SMDS_MeshGroup::Contains(const SMDS_MeshElement * theElem) const { - return myElements.find(theElem)!=myElements.end(); + return myElements.find(theElem)!=myElements.end(); } //======================================================================= diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshIDFactory.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshIDFactory.cpp index 88b9ce38d55e..1cd2a7b69aaf 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshIDFactory.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshIDFactory.cpp @@ -1,30 +1,33 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshIDFactory.cxx // Author : Jean-Michel BOULCOURT // Module : SMESH // #include "SMDS_MeshIDFactory.hxx" +#include "SMDS_Mesh.hxx" +#include "utilities.h" using namespace std; @@ -33,27 +36,33 @@ using namespace std; //purpose : //======================================================================= -SMDS_MeshIDFactory::SMDS_MeshIDFactory():myMaxID(0) +SMDS_MeshIDFactory::SMDS_MeshIDFactory():myMaxID(0), myMesh(0) { } int SMDS_MeshIDFactory::GetFreeID() { - if (myPoolOfID.empty()) return ++myMaxID; - else - { + int newid; + if (myPoolOfID.empty()) + { + newid = ++myMaxID; + //MESSAGE("GetFreeID new " << newid); + } + else + { set::iterator i = myPoolOfID.begin(); - int ID = *i;//myPoolOfID.top(); - myPoolOfID.erase( i );//myPoolOfID.pop(); - return ID; - } + newid = *i;//myPoolOfID.top(); + myPoolOfID.erase( i );//myPoolOfID.pop(); + //MESSAGE("GetFreeID pool " << newid); + } + return newid; } //======================================================================= //function : ReleaseID //purpose : //======================================================================= -void SMDS_MeshIDFactory::ReleaseID(const int ID) +void SMDS_MeshIDFactory::ReleaseID(int ID, int vtkId) { if ( ID > 0 ) { @@ -82,6 +91,24 @@ void SMDS_MeshIDFactory::ReleaseID(const int ID) void SMDS_MeshIDFactory::Clear() { - myMaxID = 0; - myPoolOfID.clear(); + myMaxID = 0; + myPoolOfID.clear(); +} + +void SMDS_MeshIDFactory::SetMesh(SMDS_Mesh *mesh) +{ + myMesh = mesh; } + +SMDS_Mesh* SMDS_MeshIDFactory::GetMesh() +{ + return myMesh; +} + +void SMDS_MeshIDFactory::emptyPool(int maxId) +{ + MESSAGE("SMDS_MeshIDFactory::emptyPool " << myMaxID << " --> " << maxId); + myMaxID = maxId; + myPoolOfID.clear(); +} + diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshNode.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshNode.cpp index d7c291b520ef..b852b2a64f3b 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshNode.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshNode.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // #ifdef _MSC_VER @@ -28,66 +29,104 @@ #include "SMDS_MeshNode.hxx" #include "SMDS_SpacePosition.hxx" #include "SMDS_IteratorOfElements.hxx" +#include "SMDS_Mesh.hxx" +#include + +#include "utilities.h" +#include "Utils_SALOME_Exception.hxx" +#include using namespace std; +int SMDS_MeshNode::nbNodes =0; + //======================================================================= //function : SMDS_MeshNode -//purpose : +//purpose : //======================================================================= +SMDS_MeshNode::SMDS_MeshNode() : + SMDS_MeshElement(-1, -1, 0), + myPosition(SMDS_SpacePosition::originSpacePosition()) +{ + nbNodes++; +} -SMDS_MeshNode::SMDS_MeshNode(double x, double y, double z): - myX(x), myY(y), myZ(z), - myPosition(SMDS_SpacePosition::originSpacePosition()) +SMDS_MeshNode::SMDS_MeshNode(int id, int meshId, int shapeId, double x, double y, double z): + SMDS_MeshElement(id, meshId, shapeId), + myPosition(SMDS_SpacePosition::originSpacePosition()) { + nbNodes++; + init(id, meshId, shapeId, x, y ,z); +} + +void SMDS_MeshNode::init(int id, int meshId, int shapeId, double x, double y, double z) +{ + SMDS_MeshElement::init(id, meshId, shapeId); + myVtkID = id -1; + assert(myVtkID >= 0); + //MESSAGE("Node " << myID << " " << myVtkID << " (" << x << ", " << y << ", " << z << ")"); + SMDS_Mesh* mesh = SMDS_Mesh::_meshList[myMeshId]; + SMDS_UnstructuredGrid * grid = mesh->getGrid(); + vtkPoints *points = grid->GetPoints(); + points->InsertPoint(myVtkID, x, y, z); + SMDS_CellLinks *cellLinks = dynamic_cast(grid->GetCellLinks()); + assert(cellLinks); + cellLinks->ResizeForPoint( myVtkID ); +} + +SMDS_MeshNode::~SMDS_MeshNode() +{ + nbNodes--; + if ( myPosition && myPosition != SMDS_SpacePosition::originSpacePosition() ) + delete myPosition, myPosition = 0; } //======================================================================= //function : RemoveInverseElement -//purpose : +//purpose : //======================================================================= void SMDS_MeshNode::RemoveInverseElement(const SMDS_MeshElement * parent) { - NCollection_List::Iterator it(myInverseElements); - while (it.More()) { - const SMDS_MeshElement* elem = it.Value(); - if (elem == parent) - myInverseElements.Remove(it); - else - it.Next(); - } + //MESSAGE("RemoveInverseElement " << myID << " " << parent->GetID()); + const SMDS_MeshCell* cell = dynamic_cast(parent); + MYASSERT(cell); + SMDS_Mesh::_meshList[myMeshId]->getGrid()->RemoveReferenceToCell(myVtkID, cell->getVtkId()); } //======================================================================= //function : Print -//purpose : +//purpose : //======================================================================= void SMDS_MeshNode::Print(ostream & OS) const { - OS << "Node <" << GetID() << "> : X = " << myX << " Y = " - << myY << " Z = " << myZ << endl; + OS << "Node <" << myID << "> : X = " << X() << " Y = " + << Y() << " Z = " << Z() << endl; } //======================================================================= //function : SetPosition -//purpose : +//purpose : //======================================================================= void SMDS_MeshNode::SetPosition(const SMDS_PositionPtr& aPos) { - myPosition = aPos; + if ( myPosition && + myPosition != SMDS_SpacePosition::originSpacePosition() && + myPosition != aPos ) + delete myPosition; + myPosition = aPos; } //======================================================================= //function : GetPosition -//purpose : +//purpose : //======================================================================= const SMDS_PositionPtr& SMDS_MeshNode::GetPosition() const { - return myPosition; + return myPosition; } //======================================================================= @@ -96,121 +135,203 @@ const SMDS_PositionPtr& SMDS_MeshNode::GetPosition() const */ //======================================================================= -class SMDS_MeshNode_MyInvIterator:public SMDS_ElemIterator +class SMDS_MeshNode_MyInvIterator: public SMDS_ElemIterator { - NCollection_List::Iterator myIterator; - SMDSAbs_ElementType myType; - public: - SMDS_MeshNode_MyInvIterator(const NCollection_List& s, - SMDSAbs_ElementType type): - myIterator(s), myType(type) - {} +private: + SMDS_Mesh* myMesh; + vtkIdType* myCells; + int myNcells; + SMDSAbs_ElementType myType; + int iter; + vector cellList; + +public: + SMDS_MeshNode_MyInvIterator(SMDS_Mesh *mesh, vtkIdType* cells, int ncells, SMDSAbs_ElementType type) : + myMesh(mesh), myCells(cells), myNcells(ncells), myType(type), iter(0) + { + cellList.reserve( ncells ); + if (type == SMDSAbs_All) + cellList.assign( cells, cells + ncells ); + else + for (int i = 0; i < ncells; i++) + { + int vtkId = cells[i]; + int smdsId = myMesh->fromVtkToSmds(vtkId); + const SMDS_MeshElement* elem = myMesh->FindElement(smdsId); + if (elem->GetType() == type) + { + cellList.push_back(vtkId); + } + } + myCells = cellList.empty() ? 0 : &cellList[0]; + myNcells = cellList.size(); + } bool more() { - if ( myType != SMDSAbs_All ) { - while ( myIterator.More() && myIterator.Value()->GetType() != myType) - myIterator.Next(); - } - return myIterator.More() != Standard_False; + return (iter < myNcells); } const SMDS_MeshElement* next() { - const SMDS_MeshElement* current=myIterator.Value(); - myIterator.Next(); - return current; - } + int vtkId = myCells[iter]; + int smdsId = myMesh->fromVtkToSmds(vtkId); + const SMDS_MeshElement* elem = myMesh->FindElement(smdsId); + if (!elem) + { + MESSAGE("SMDS_MeshNode_MyInvIterator problem Null element"); + throw SALOME_Exception("SMDS_MeshNode_MyInvIterator problem Null element"); + } + //MESSAGE("vtkId " << vtkId << " smdsId " << smdsId << " " << elem->GetType()); + iter++; + return elem; + } }; SMDS_ElemIteratorPtr SMDS_MeshNode:: - GetInverseElementIterator(SMDSAbs_ElementType type) const +GetInverseElementIterator(SMDSAbs_ElementType type) const { - return SMDS_ElemIteratorPtr(new SMDS_MeshNode_MyInvIterator(myInverseElements,type)); + vtkCellLinks::Link l = SMDS_Mesh::_meshList[myMeshId]->getGrid()->GetCellLinks()->GetLink(myVtkID); + //MESSAGE("myID " << myID << " ncells " << l.ncells); + return SMDS_ElemIteratorPtr(new SMDS_MeshNode_MyInvIterator(SMDS_Mesh::_meshList[myMeshId], l.cells, l.ncells, type)); } // Same as GetInverseElementIterator but the create iterator only return // wanted type elements. class SMDS_MeshNode_MyIterator:public SMDS_ElemIterator { - NCollection_List mySet; - NCollection_List::Iterator myIterator; - public: - SMDS_MeshNode_MyIterator(SMDSAbs_ElementType type, - const NCollection_List& s) +private: + SMDS_Mesh* myMesh; + vtkIdType* myCells; + int myNcells; + SMDSAbs_ElementType myType; + int iter; + vector myFiltCells; + +public: + SMDS_MeshNode_MyIterator(SMDS_Mesh *mesh, + vtkIdType* cells, + int ncells, + SMDSAbs_ElementType type): + myMesh(mesh), myCells(cells), myNcells(ncells), myType(type), iter(0) { - const SMDS_MeshElement * e; - bool toInsert; - NCollection_List::Iterator it(s); - for(; it.More(); it.Next()) + //MESSAGE("myNcells " << myNcells); + for (; iterGetType()!=SMDSAbs_Edge); break; - case SMDSAbs_Volume: toInsert=(e->GetType()==SMDSAbs_Volume); break; - } - if(toInsert) mySet.Append(e); + int vtkId = myCells[iter]; + int smdsId = myMesh->fromVtkToSmds(vtkId); + //MESSAGE("vtkId " << vtkId << " smdsId " << smdsId); + const SMDS_MeshElement* elem = myMesh->FindElement(smdsId); + if (elem->GetType() == type) + myFiltCells.push_back((SMDS_MeshElement*)elem); } - myIterator.Init(mySet); + myNcells = myFiltCells.size(); + //MESSAGE("myNcells " << myNcells); + iter = 0; + //MESSAGE("SMDS_MeshNode_MyIterator (filter) " << ncells << " " << myNcells); } bool more() { - return myIterator.More() != Standard_False; + return (iter< myNcells); } const SMDS_MeshElement* next() { - const SMDS_MeshElement* current=myIterator.Value(); - myIterator.Next(); - return current; + const SMDS_MeshElement* elem = myFiltCells[iter]; + iter++; + return elem; } }; SMDS_ElemIteratorPtr SMDS_MeshNode:: - elementsIterator(SMDSAbs_ElementType type) const +elementsIterator(SMDSAbs_ElementType type) const { if(type==SMDSAbs_Node) - return SMDS_MeshElement::elementsIterator(SMDSAbs_Node); + return SMDS_MeshElement::elementsIterator(SMDSAbs_Node); else - return SMDS_ElemIteratorPtr - (new SMDS_IteratorOfElements - (this,type, - SMDS_ElemIteratorPtr(new SMDS_MeshNode_MyIterator(type, myInverseElements)))); + { + vtkCellLinks::Link l = SMDS_Mesh::_meshList[myMeshId]->getGrid()->GetCellLinks()->GetLink(myVtkID); + return SMDS_ElemIteratorPtr(new SMDS_MeshNode_MyIterator(SMDS_Mesh::_meshList[myMeshId], l.cells, l.ncells, type)); + } } int SMDS_MeshNode::NbNodes() const { - return 1; + return 1; +} + +double* SMDS_MeshNode::getCoord() const +{ + double coord[3]; + double *coord2; + vtkUnstructuredGrid *grid; + coord2=(double *)malloc(3*sizeof(double)); + if ( SMDS_Mesh::_meshList[myMeshId] != NULL ) + if ( SMDS_Mesh::_meshList[myMeshId]->getGrid() != NULL ) + { + grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + grid->GetPoints()->GetPoint(myVtkID,coord); + coord2[0]=coord[0]; + coord2[1]=coord[1]; + coord2[2]=coord[2]; + return(coord2); +// return (double *)(SMDS_Mesh::_meshList[myMeshId]->getGrid()->GetPoints()->GetPoint(myVtkID,coord)); + } + else + { + coord2[0]=0.; + coord2[1]=0.; + coord2[2]=0.; + return coord2; + } } double SMDS_MeshNode::X() const { - return myX; + double *coord = getCoord(); + return coord[0]; } double SMDS_MeshNode::Y() const { - return myY; + double *coord = getCoord(); + return coord[1]; } double SMDS_MeshNode::Z() const { - return myZ; + double *coord = getCoord(); + return coord[2]; } +//================================================================================ +/*! + * \brief thread safe getting coords + */ +void SMDS_MeshNode::GetXYZ(double xyz[3]) const +{ + return SMDS_Mesh::_meshList[myMeshId]->getGrid()->GetPoint(myVtkID,xyz); +} + +//* resize the vtkPoints structure every SMDS_Mesh::chunkSize points void SMDS_MeshNode::setXYZ(double x, double y, double z) { - myX=x; - myY=y; - myZ=z; + SMDS_Mesh *mesh = SMDS_Mesh::_meshList[myMeshId]; + vtkPoints *points = mesh->getGrid()->GetPoints(); + points->InsertPoint(myVtkID, x, y, z); + mesh->adjustBoundingBox(x, y, z); + mesh->setMyModified(); } SMDSAbs_ElementType SMDS_MeshNode::GetType() const { - return SMDSAbs_Node; + return SMDSAbs_Node; +} + +vtkIdType SMDS_MeshNode::GetVtkType() const +{ + return VTK_VERTEX; } //======================================================================= @@ -219,13 +340,12 @@ SMDSAbs_ElementType SMDS_MeshNode::GetType() const //======================================================================= void SMDS_MeshNode::AddInverseElement(const SMDS_MeshElement* ME) { - NCollection_List::Iterator it(myInverseElements); - for (; it.More(); it.Next()) { - const SMDS_MeshElement* elem = it.Value(); - if (elem == ME) - return; - } - myInverseElements.Append(ME); + const SMDS_MeshCell *cell = dynamic_cast (ME); + assert(cell); + SMDS_UnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkCellLinks *Links = grid->GetCellLinks(); + Links->ResizeCellList(myVtkID, 1); + Links->AddCellReference(cell->getVtkId(), myVtkID); } //======================================================================= @@ -234,12 +354,13 @@ void SMDS_MeshNode::AddInverseElement(const SMDS_MeshElement* ME) //======================================================================= void SMDS_MeshNode::ClearInverseElements() { - myInverseElements.Clear(); + SMDS_Mesh::_meshList[myMeshId]->getGrid()->ResizeCellList(myVtkID, 0); } bool SMDS_MeshNode::emptyInverseElements() { - return myInverseElements.IsEmpty() != Standard_False; + vtkCellLinks::Link l = SMDS_Mesh::_meshList[myMeshId]->getGrid()->GetCellLinks()->GetLink(myVtkID); + return (l.ncells == 0); } //================================================================================ @@ -250,13 +371,19 @@ bool SMDS_MeshNode::emptyInverseElements() int SMDS_MeshNode::NbInverseElements(SMDSAbs_ElementType type) const { + vtkCellLinks::Link l = SMDS_Mesh::_meshList[myMeshId]->getGrid()->GetCellLinks()->GetLink(myVtkID); + if ( type == SMDSAbs_All ) - return myInverseElements.Extent(); + return l.ncells; + int nb = 0; - NCollection_List::Iterator it( myInverseElements ); - for ( ; it.More(); it.Next() ) - if ( it.Value()->GetType() == type ) + SMDS_Mesh *mesh = SMDS_Mesh::_meshList[myMeshId]; + for (int i=0; iFindElement(mesh->fromVtkToSmds(l.cells[i])); + if (elem->GetType() == type) nb++; + } return nb; } @@ -265,14 +392,14 @@ int SMDS_MeshNode::NbInverseElements(SMDSAbs_ElementType type) const /////////////////////////////////////////////////////////////////////////////// bool operator<(const SMDS_MeshNode& e1, const SMDS_MeshNode& e2) { - return e1.GetID() +#include + +using namespace std; + +//======================================================================= +//function : SMDS_MeshNodeIDFactory +//purpose : +//======================================================================= +SMDS_MeshNodeIDFactory::SMDS_MeshNodeIDFactory() : + SMDS_MeshIDFactory(), myMin(0), myMax(0) +{ +} + +//======================================================================= +//function : BindID +//purpose : +//======================================================================= +bool SMDS_MeshNodeIDFactory::BindID(int ID, SMDS_MeshElement * elem) +{ + updateMinMax(ID); + return true; +} + +//======================================================================= +//function : MeshElement +//purpose : +//======================================================================= +SMDS_MeshElement* SMDS_MeshNodeIDFactory::MeshElement(int ID) +{ + // commented since myMax can be 0 after ReleaseID() +// if ((ID < 1) || (ID > myMax)) +// return NULL; + const SMDS_MeshElement* elem = GetMesh()->FindNode(ID); + return (SMDS_MeshElement*) (elem); +} + +//======================================================================= +//function : GetFreeID +//purpose : +//======================================================================= +int SMDS_MeshNodeIDFactory::GetFreeID() +{ + int ID; + do { + ID = SMDS_MeshIDFactory::GetFreeID(); + } while ( MeshElement( ID )); + return ID; +} + +//======================================================================= +//function : ReleaseID +//purpose : +//======================================================================= +void SMDS_MeshNodeIDFactory::ReleaseID(const int ID, int vtkId) +{ + SMDS_MeshIDFactory::ReleaseID(ID); + myMesh->setMyModified(); + if (ID == myMax) + myMax = 0; // --- force updateMinMax + if (ID == myMin) + myMax = 0; // --- force updateMinMax +} + +//======================================================================= +//function : GetMaxID +//purpose : +//======================================================================= + +int SMDS_MeshNodeIDFactory::GetMaxID() const +{ + if (myMax == 0) + updateMinMax(); + return myMax; +} + +//======================================================================= +//function : GetMinID +//purpose : +//======================================================================= + +int SMDS_MeshNodeIDFactory::GetMinID() const +{ + if (myMax == 0) + updateMinMax(); + return myMin; +} + +//======================================================================= +//function : updateMinMax +//purpose : +//======================================================================= + +void SMDS_MeshNodeIDFactory::updateMinMax() const +{ + myMesh->updateNodeMinMax(); + myMin = myMesh->MinNodeID(); + myMax = myMesh->MaxNodeID(); +} + +SMDS_ElemIteratorPtr SMDS_MeshNodeIDFactory::elementsIterator() const +{ + return myMesh->elementsIterator(SMDSAbs_Node); +} + +void SMDS_MeshNodeIDFactory::Clear() +{ + myMin = myMax = 0; + SMDS_MeshIDFactory::Clear(); +} + +void SMDS_MeshNodeIDFactory::emptyPool(int maxId) +{ + SMDS_MeshIDFactory::emptyPool(maxId); + myMax = maxId; +} diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshObject.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshObject.cpp index b023c73e966e..50adf413fabc 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshObject.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshObject.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshObject.cxx // Author : Jean-Michel BOULCOURT diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshVolume.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshVolume.cpp index 574b5b0ffd51..1f7a6a001c9c 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshVolume.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_MeshVolume.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_MeshVolume.cxx // Author : Jean-Michel BOULCOURT @@ -32,6 +33,10 @@ SMDSAbs_ElementType SMDS_MeshVolume::GetType() const { - return SMDSAbs_Volume; + return SMDSAbs_Volume; } +vtkIdType SMDS_MeshVolume::GetVtkType() const +{ + return VTK_CONVEX_POINT_SET; // --- must be reimplemented in derived classes +} diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_PolygonalFaceOfNodes.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_PolygonalFaceOfNodes.cpp index 96b7e261c47f..f291b0bff1b1 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_PolygonalFaceOfNodes.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_PolygonalFaceOfNodes.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // #ifdef _MSC_VER @@ -40,8 +41,9 @@ using namespace std; //purpose : //======================================================================= SMDS_PolygonalFaceOfNodes::SMDS_PolygonalFaceOfNodes - (std::vector nodes) + (const std::vector& nodes) { + //MESSAGE("******************************************** SMDS_PolygonalFaceOfNodes"); myNodes = nodes; } @@ -196,4 +198,3 @@ const SMDS_MeshNode* SMDS_PolygonalFaceOfNodes::GetNode(const int ind) const { return myNodes[ WrappedIndex( ind )]; } - diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_PolyhedralVolumeOfNodes.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_PolyhedralVolumeOfNodes.cpp index ce8ace8300e9..2dfa337db3a4 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_PolyhedralVolumeOfNodes.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_PolyhedralVolumeOfNodes.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // #ifdef _MSC_VER @@ -44,6 +45,7 @@ SMDS_PolyhedralVolumeOfNodes::SMDS_PolyhedralVolumeOfNodes vector quantities) : SMDS_VolumeOfNodes(NULL, NULL, NULL, NULL) { + //MESSAGE("****************************************** SMDS_PolyhedralVolumeOfNodes"); ChangeNodes(nodes, quantities); } diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_Position.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_Position.cpp index 46b63e1f8ac4..2e3b6488d488 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_Position.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_Position.cpp @@ -1,58 +1,41 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_Position.cxx // Author : Jean-Michel BOULCOURT // Module : SMESH // #include "SMDS_Position.hxx" +#include "utilities.h" //======================================================================= //function : SMDS_Position //purpose : //======================================================================= -SMDS_Position::SMDS_Position(int aShapeId) :myShapeId(aShapeId) -{ -} - -//======================================================================= -//function : SetShapeId -//purpose : -//======================================================================= - -void SMDS_Position::SetShapeId(int aShapeId) -{ - myShapeId = aShapeId; -} - -//======================================================================= -//function : GetShapeId -//purpose : -//======================================================================= - -int SMDS_Position::GetShapeId() const +SMDS_Position::SMDS_Position() { - return myShapeId; + //MESSAGE("########################## SMDS_Position "); } //======================================================================= diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_QuadraticEdge.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_QuadraticEdge.cpp index d314cf281ec6..8475c62cd866 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_QuadraticEdge.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_QuadraticEdge.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File: SMDS_QuadraticEdge.cxx // Created: 16.01.06 16:25:42 @@ -29,6 +30,7 @@ #include "SMDS_SetIterator.hxx" #include "SMDS_IteratorOfElements.hxx" #include "SMDS_MeshNode.hxx" +#include "utilities.h" using namespace std; @@ -40,8 +42,9 @@ using namespace std; SMDS_QuadraticEdge::SMDS_QuadraticEdge(const SMDS_MeshNode * node1, const SMDS_MeshNode * node2, const SMDS_MeshNode * node12) - :SMDS_MeshEdge(node1,node2) -{ + :SMDS_LinearEdge(node1,node2) +{ + //MESSAGE("******************************************************* SMDS_QuadraticEdge"); myNodes[2]=node12; } @@ -113,21 +116,6 @@ namespace } }; - //======================================================================= - //class : _MyInterlacedNodeElemIterator - //purpose : - //======================================================================= - - class _MyInterlacedNodeElemIterator : public SMDS_ElemIterator - { - SMDS_NodeIteratorPtr myItr; - public: - _MyInterlacedNodeElemIterator(SMDS_NodeIteratorPtr interlacedNodeItr): - myItr( interlacedNodeItr ) {} - bool more() { return myItr->more(); } - const SMDS_MeshElement* next() { return myItr->next(); } - }; - //======================================================================= //class : _MyNodeIterator //purpose : @@ -151,18 +139,6 @@ SMDS_NodeIteratorPtr SMDS_QuadraticEdge::interlacedNodesIterator() const return SMDS_NodeIteratorPtr (new _MyInterlacedNodeIterator (myNodes)); } - -//======================================================================= -//function : interlacedNodesElemIterator -//purpose : -//======================================================================= - -SMDS_ElemIteratorPtr SMDS_QuadraticEdge::interlacedNodesElemIterator() const -{ - return SMDS_ElemIteratorPtr - (new _MyInterlacedNodeElemIterator ( interlacedNodesIterator() )); -} - //======================================================================= //function : elementsIterator //purpose : @@ -182,4 +158,3 @@ SMDS_ElemIteratorPtr SMDS_QuadraticEdge::elementsIterator(SMDSAbs_ElementType ty (this,type, SMDS_ElemIteratorPtr(new _MyNodeIterator(myNodes)))); } } - diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_QuadraticFaceOfNodes.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_QuadraticFaceOfNodes.cpp index 472759fb9579..f427dac9692b 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_QuadraticFaceOfNodes.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_QuadraticFaceOfNodes.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File: SMDS_QuadraticFaceOfNodes.cxx // Created: 16.01.06 17:12:58 @@ -48,6 +49,7 @@ SMDS_QuadraticFaceOfNodes::SMDS_QuadraticFaceOfNodes(const SMDS_MeshNode * n1, const SMDS_MeshNode * n23, const SMDS_MeshNode * n31) { + //MESSAGE("********************************************** SMDS_QuadraticFaceOfNodes 1"); myNodes.resize( 6 ); myNodes[ 0 ] = n1; myNodes[ 1 ] = n2; @@ -72,6 +74,7 @@ SMDS_QuadraticFaceOfNodes::SMDS_QuadraticFaceOfNodes(const SMDS_MeshNode * n1, const SMDS_MeshNode * n34, const SMDS_MeshNode * n41) { + //MESSAGE("********************************************* SMDS_QuadraticFaceOfNodes 2"); myNodes.resize( 8 ); myNodes[ 0 ] = n1; myNodes[ 1 ] = n2; @@ -189,21 +192,6 @@ namespace { } }; - //======================================================================= - //class : _MyInterlacedNodeElemIterator - //purpose : - //======================================================================= - - class _MyInterlacedNodeElemIterator : public SMDS_ElemIterator - { - SMDS_NodeIteratorPtr myItr; - public: - _MyInterlacedNodeElemIterator(SMDS_NodeIteratorPtr interlacedNodeItr): - myItr( interlacedNodeItr ) {} - bool more() { return myItr->more(); } - const SMDS_MeshElement* next() { return myItr->next(); } - }; - //======================================================================= //class : _MyNodeIterator //purpose : @@ -231,16 +219,6 @@ SMDS_NodeIteratorPtr SMDS_QuadraticFaceOfNodes::interlacedNodesIterator() const (new _MyInterlacedNodeIterator (myNodes, myNodes.size()==6 ? triaInterlace : quadInterlace)); } -//======================================================================= -//function : interlacedNodesElemIterator -//purpose : -//======================================================================= - -SMDS_ElemIteratorPtr SMDS_QuadraticFaceOfNodes::interlacedNodesElemIterator() const -{ - return SMDS_ElemIteratorPtr - (new _MyInterlacedNodeElemIterator ( interlacedNodesIterator() )); -} /// =================================================================== /*! * \brief Iterator on edges of face @@ -254,10 +232,10 @@ class _MyEdgeIterator : public SMDS_ElemIterator public: _MyEdgeIterator(const SMDS_QuadraticFaceOfNodes* face):myIndex(0) { myElems.reserve( face->NbNodes() ); - SMDS_ElemIteratorPtr nIt = face->interlacedNodesElemIterator(); + SMDS_NodeIteratorPtr nIt = face->interlacedNodesIterator(); const SMDS_MeshNode* n0 = face->GetNodeWrap( -1 ); while ( nIt->more() ) { - const SMDS_MeshNode* n1 = static_cast( nIt->next() ); + const SMDS_MeshNode* n1 = nIt->next(); const SMDS_MeshElement* edge = SMDS_Mesh::FindEdge( n0, n1 ); if ( edge ) myElems.push_back( edge ); @@ -306,3 +284,7 @@ const SMDS_MeshNode* SMDS_QuadraticFaceOfNodes::GetNode(const int ind) const return myNodes[ ind ]; } +SMDSAbs_EntityType SMDS_QuadraticFaceOfNodes::GetEntityType() const +{ + return NbNodes() == 6 ? SMDSEntity_Quad_Triangle : SMDSEntity_Quad_Quadrangle; +} diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_QuadraticVolumeOfNodes.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_QuadraticVolumeOfNodes.cpp index 2225bdcda846..2a356d581064 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_QuadraticVolumeOfNodes.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_QuadraticVolumeOfNodes.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File: SMDS_QuadraticVolumeOfNodes.cxx // Created: 17.01.06 09:46:11 @@ -53,6 +54,7 @@ SMDS_QuadraticVolumeOfNodes::SMDS_QuadraticVolumeOfNodes const SMDS_MeshNode * n24, const SMDS_MeshNode * n34) { + //MESSAGE("*********************************************** SMDS_QuadraticVolumeOfNodes"); myNodes.resize( 10 ); myNodes[ 0 ] = n1; myNodes[ 1 ] = n2; @@ -87,6 +89,7 @@ SMDS_QuadraticVolumeOfNodes::SMDS_QuadraticVolumeOfNodes const SMDS_MeshNode * n35, const SMDS_MeshNode * n45) { + //MESSAGE("*********************************************** SMDS_QuadraticVolumeOfNodes"); myNodes.resize( 13 ); myNodes[ 0 ] = n1; myNodes[ 1 ] = n2; @@ -126,6 +129,7 @@ SMDS_QuadraticVolumeOfNodes::SMDS_QuadraticVolumeOfNodes const SMDS_MeshNode * n25, const SMDS_MeshNode * n36) { + //MESSAGE("*********************************************** SMDS_QuadraticVolumeOfNodes"); myNodes.resize( 15 ); myNodes[ 0 ] = n1; myNodes[ 1 ] = n2; @@ -172,6 +176,7 @@ SMDS_QuadraticVolumeOfNodes::SMDS_QuadraticVolumeOfNodes const SMDS_MeshNode * n37, const SMDS_MeshNode * n48) { + //MESSAGE("*********************************************** SMDS_QuadraticVolumeOfNodes"); myNodes.resize( 20 ); myNodes[ 0 ] = n1; myNodes[ 1 ] = n2; @@ -368,3 +373,16 @@ const SMDS_MeshNode* SMDS_QuadraticVolumeOfNodes::GetNode(const int ind) const return myNodes[ ind ]; } +SMDSAbs_EntityType SMDS_QuadraticVolumeOfNodes::GetEntityType() const +{ + SMDSAbs_EntityType aType = SMDSEntity_Quad_Tetra; + switch(NbNodes()) + { + case 10: aType = SMDSEntity_Quad_Tetra; break; + case 13: aType = SMDSEntity_Quad_Pyramid; break; + case 15: aType = SMDSEntity_Quad_Penta; break; + case 20: + default: aType = SMDSEntity_Quad_Hexa; break; + } + return aType; +} diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_SpacePosition.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_SpacePosition.cpp index 09532f3476bc..413dacd8e8b7 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_SpacePosition.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_SpacePosition.cpp @@ -1,58 +1,45 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_SpacePosition.cxx // Author : Jean-Michel BOULCOURT // Module : SMESH // + #include "SMDS_SpacePosition.hxx" -//======================================================================= -//function : SMDS_SpacePosition -//purpose : -//======================================================================= +SMDS_SpacePosition* SMDS_SpacePosition::_originPosition = new SMDS_SpacePosition(); -SMDS_SpacePosition::SMDS_SpacePosition(double x, double y, double z): - SMDS_Position(0) +SMDS_SpacePosition::SMDS_SpacePosition(double x, double y, double z) { - myCoords[0]=x; - myCoords[1]=y; - myCoords[2]=z; } -/** -*/ SMDS_TypeOfPosition SMDS_SpacePosition::GetTypeOfPosition() const { - return SMDS_TOP_3DSPACE; -} - -const double * SMDS_SpacePosition::Coords() const -{ - return myCoords; + return SMDS_TOP_3DSPACE; } SMDS_PositionPtr SMDS_SpacePosition::originSpacePosition() { - static SMDS_PositionPtr staticpos (new SMDS_SpacePosition()); - return staticpos; + return _originPosition; } diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_UnstructuredGrid.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_UnstructuredGrid.cpp new file mode 100644 index 000000000000..5fe82a432a7c --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_UnstructuredGrid.cpp @@ -0,0 +1,1168 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +#include "SMDS_UnstructuredGrid.hxx" +#include "SMDS_Mesh.hxx" +#include "SMDS_MeshInfo.hxx" +#include "SMDS_Downward.hxx" +#include "SMDS_MeshVolume.hxx" + +#include "utilities.h" +#include "chrono.hxx" + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; + +SMDS_CellLinks* SMDS_CellLinks::New() +{ + MESSAGE("SMDS_CellLinks::New"); + return new SMDS_CellLinks(); +} + +void SMDS_CellLinks::ResizeForPoint(vtkIdType vtkID) +{ + if ( vtkID > this->MaxId ) + { + this->MaxId = vtkID; + if ( vtkID >= this->Size ) + vtkCellLinks::Resize( vtkID+SMDS_Mesh::chunkSize ); + } +} + +SMDS_CellLinks::SMDS_CellLinks() : + vtkCellLinks() +{ +} + +SMDS_CellLinks::~SMDS_CellLinks() +{ +} + +SMDS_UnstructuredGrid* SMDS_UnstructuredGrid::New() +{ + MESSAGE("SMDS_UnstructuredGrid::New"); + return new SMDS_UnstructuredGrid(); +} + +SMDS_UnstructuredGrid::SMDS_UnstructuredGrid() : + vtkUnstructuredGrid() +{ + _cellIdToDownId.clear(); + _downTypes.clear(); + _downArray.clear(); + _mesh = 0; +} + +SMDS_UnstructuredGrid::~SMDS_UnstructuredGrid() +{ +} + +unsigned long SMDS_UnstructuredGrid::GetMTime() +{ + unsigned long mtime = vtkUnstructuredGrid::GetMTime(); + MESSAGE("vtkUnstructuredGrid::GetMTime: " << mtime); + return mtime; +} +// OUV_PORTING_VTK6: seems to be useless +/* +void SMDS_UnstructuredGrid::Update() +{ + MESSAGE("SMDS_UnstructuredGrid::Update"); + return vtkUnstructuredGrid::Update(); +} + +void SMDS_UnstructuredGrid::UpdateInformation() +{ + MESSAGE("SMDS_UnstructuredGrid::UpdateInformation"); + return vtkUnstructuredGrid::UpdateInformation(); +} +*/ +vtkPoints* SMDS_UnstructuredGrid::GetPoints() +{ + // TODO erreur incomprehensible de la macro vtk GetPoints apparue avec la version paraview de fin aout 2010 + //MESSAGE("*********************** SMDS_UnstructuredGrid::GetPoints " << this->Points << " " << vtkUnstructuredGrid::GetPoints()); + return this->Points; +} + +//#ifdef VTK_HAVE_POLYHEDRON +int SMDS_UnstructuredGrid::InsertNextLinkedCell(int type, int npts, vtkIdType *pts) +{ + if (type != VTK_POLYHEDRON) + return vtkUnstructuredGrid::InsertNextLinkedCell(type, npts, pts); + + // --- type = VTK_POLYHEDRON + //MESSAGE("InsertNextLinkedCell VTK_POLYHEDRON"); + int cellid = this->InsertNextCell(type, npts, pts); + + set setOfNodes; + setOfNodes.clear(); + int nbfaces = npts; + int i = 0; + for (int nf = 0; nf < nbfaces; nf++) + { + int nbnodes = pts[i]; + i++; + for (int k = 0; k < nbnodes; k++) + { + //MESSAGE(" cell " << cellid << " face " << nf << " node " << pts[i]); + setOfNodes.insert(pts[i]); + i++; + } + } + + set::iterator it = setOfNodes.begin(); + for (; it != setOfNodes.end(); ++it) + { + //MESSAGE("reverse link for node " << *it << " cell " << cellid); + this->Links->ResizeCellList(*it, 1); + this->Links->AddCellReference(cellid, *it); + } + + return cellid; +} +//#endif + +void SMDS_UnstructuredGrid::setSMDS_mesh(SMDS_Mesh *mesh) +{ + _mesh = mesh; +} + +void SMDS_UnstructuredGrid::compactGrid(std::vector& idNodesOldToNew, int newNodeSize, + std::vector& idCellsOldToNew, int newCellSize) +{ + MESSAGE("------------------------- SMDS_UnstructuredGrid::compactGrid " << newNodeSize << " " << newCellSize);//CHRONO(1); + int alreadyCopied = 0; + + // --- if newNodeSize, create a new compacted vtkPoints + + vtkPoints *newPoints = vtkPoints::New(); + newPoints->SetDataType(VTK_DOUBLE); + newPoints->SetNumberOfPoints(newNodeSize); + if (newNodeSize) + { + MESSAGE("-------------- compactGrid, newNodeSize " << newNodeSize); + // rnv: to fix bug "21125: EDF 1233 SMESH: Degradation of precision in a test case for quadratic conversion" + // using double type for storing coordinates of nodes instead float. + int oldNodeSize = idNodesOldToNew.size(); + + int i = 0; + while ( i < oldNodeSize ) + { + // skip a hole if any + while ( i < oldNodeSize && idNodesOldToNew[i] < 0 ) + ++i; + int startBloc = i; + // look for a block end + while ( i < oldNodeSize && idNodesOldToNew[i] >= 0 ) + ++i; + int endBloc = i; + copyNodes(newPoints, idNodesOldToNew, alreadyCopied, startBloc, endBloc); + } + newPoints->Squeeze(); + } + + // --- create new compacted Connectivity, Locations and Types + + int oldCellSize = this->Types->GetNumberOfTuples(); + + vtkCellArray *newConnectivity = vtkCellArray::New(); + newConnectivity->Initialize(); + int oldCellDataSize = this->Connectivity->GetData()->GetSize(); + newConnectivity->Allocate(oldCellDataSize); + MESSAGE("oldCellSize="<< oldCellSize << " oldCellDataSize=" << oldCellDataSize); + + vtkUnsignedCharArray *newTypes = vtkUnsignedCharArray::New(); + newTypes->Initialize(); + newTypes->SetNumberOfValues(newCellSize); + + vtkIdTypeArray *newLocations = vtkIdTypeArray::New(); + newLocations->Initialize(); + newLocations->SetNumberOfValues(newCellSize); + + // TODO some polyhedron may be huge (only in some tests) + vtkIdType tmpid[NBMAXNODESINCELL]; + vtkIdType *pointsCell = &tmpid[0]; // --- points id to fill a new cell + + alreadyCopied = 0; + int i = 0; + while ( i < oldCellSize ) + { + // skip a hole if any + while ( i < oldCellSize && this->Types->GetValue(i) == VTK_EMPTY_CELL ) + ++i; + int startBloc = i; + // look for a block end + while ( i < oldCellSize && this->Types->GetValue(i) != VTK_EMPTY_CELL ) + ++i; + int endBloc = i; + if ( endBloc > startBloc ) + copyBloc(newTypes, + idCellsOldToNew, idNodesOldToNew, + newConnectivity, newLocations, + pointsCell, alreadyCopied, + startBloc, endBloc); + } + newConnectivity->Squeeze(); + + if (1/*newNodeSize*/) + { + MESSAGE("------- newNodeSize, setPoints"); + this->SetPoints(newPoints); + MESSAGE("NumberOfPoints: " << this->GetNumberOfPoints()); + } + + if (vtkDoubleArray* diameters = + vtkDoubleArray::SafeDownCast( vtkDataSet::CellData->GetScalars() )) // Balls + { + for (int oldCellID = 0; oldCellID < oldCellSize; oldCellID++) + { + if (this->Types->GetValue(oldCellID) == VTK_EMPTY_CELL) + continue; + int newCellId = idCellsOldToNew[ oldCellID ]; + if (newTypes->GetValue(newCellId) == VTK_POLY_VERTEX) + diameters->SetValue( newCellId, diameters->GetValue( oldCellID )); + } + } + + if (this->FaceLocations) + { + vtkIdTypeArray *newFaceLocations = vtkIdTypeArray::New(); + newFaceLocations->Initialize(); + newFaceLocations->Allocate(newTypes->GetSize()); + vtkIdTypeArray *newFaces = vtkIdTypeArray::New(); + newFaces->Initialize(); + newFaces->Allocate(this->Faces->GetSize()); + for (int i = 0; i < oldCellSize; i++) + { + if (this->Types->GetValue(i) == VTK_EMPTY_CELL) + continue; + int newCellId = idCellsOldToNew[i]; + if (newTypes->GetValue(newCellId) == VTK_POLYHEDRON) + { + newFaceLocations->InsertNextValue(newFaces->GetMaxId()+1); + int oldFaceLoc = this->FaceLocations->GetValue(i); + int nCellFaces = this->Faces->GetValue(oldFaceLoc++); + newFaces->InsertNextValue(nCellFaces); + for (int n=0; nFaces->GetValue(oldFaceLoc++); + newFaces->InsertNextValue(nptsInFace); + for (int k=0; kFaces->GetValue(oldFaceLoc++); + newFaces->InsertNextValue(idNodesOldToNew[oldpt]); + } + } + } + else + { + newFaceLocations->InsertNextValue(-1); + } + } + newFaceLocations->Squeeze(); + newFaces->Squeeze(); + this->SetCells(newTypes, newLocations, newConnectivity, newFaceLocations, newFaces); + newFaceLocations->Delete(); + newFaces->Delete(); + } + else + { + this->SetCells(newTypes, newLocations, newConnectivity, FaceLocations, Faces); + } + + newPoints->Delete(); + newTypes->Delete(); + newLocations->Delete(); + newConnectivity->Delete(); + this->BuildLinks(); +} + +void SMDS_UnstructuredGrid::copyNodes(vtkPoints *newPoints, std::vector& idNodesOldToNew, int& alreadyCopied, + int start, int end) +{ + MESSAGE("copyNodes " << alreadyCopied << " " << start << " " << end << " size: " << end - start << " total: " << alreadyCopied + end - start); + void *target = newPoints->GetVoidPointer(3 * alreadyCopied); + void *source = this->Points->GetVoidPointer(3 * start); + int nbPoints = end - start; + if (nbPoints > 0) + { + memcpy(target, source, 3 * sizeof(double) * nbPoints); + for (int j = start; j < end; j++) + idNodesOldToNew[j] = alreadyCopied++; // old vtkId --> new vtkId + } +} + +void SMDS_UnstructuredGrid::copyBloc(vtkUnsignedCharArray *newTypes, + std::vector& idCellsOldToNew, + std::vector& idNodesOldToNew, + vtkCellArray* newConnectivity, + vtkIdTypeArray* newLocations, + vtkIdType* pointsCell, + int& alreadyCopied, + int start, + int end) +{ + //MESSAGE("copyBloc " << alreadyCopied << " " << start << " " << end << " size: " << end - start << " total: " << alreadyCopied + end - start); + for (int j = start; j < end; j++) + { + newTypes->SetValue(alreadyCopied, this->Types->GetValue(j)); + idCellsOldToNew[j] = alreadyCopied; // old vtkId --> new vtkId + vtkIdType oldLoc = this->Locations->GetValue(j); + vtkIdType nbpts; + vtkIdType *oldPtsCell = 0; + this->Connectivity->GetCell(oldLoc, nbpts, oldPtsCell); + assert(nbpts < NBMAXNODESINCELL); + //MESSAGE(j << " " << alreadyCopied << " " << (int)this->Types->GetValue(j) << " " << oldLoc << " " << nbpts ); + for (int l = 0; l < nbpts; l++) + { + int oldval = oldPtsCell[l]; + pointsCell[l] = idNodesOldToNew[oldval]; + //MESSAGE(" " << oldval << " " << pointsCell[l]); + } + /*int newcnt = */newConnectivity->InsertNextCell(nbpts, pointsCell); + int newLoc = newConnectivity->GetInsertLocation(nbpts); + //MESSAGE(newcnt << " " << newLoc); + newLocations->SetValue(alreadyCopied, newLoc); + alreadyCopied++; + } +} + +int SMDS_UnstructuredGrid::CellIdToDownId(int vtkCellId) +{ + if((vtkCellId < 0) || (vtkCellId >= _cellIdToDownId.size())) + { + //MESSAGE("SMDS_UnstructuredGrid::CellIdToDownId structure not up to date: vtkCellId=" + // << vtkCellId << " max="<< _cellIdToDownId.size()); + return -1; + } + return _cellIdToDownId[vtkCellId]; +} + +void SMDS_UnstructuredGrid::setCellIdToDownId(int vtkCellId, int downId) +{ + // ASSERT((vtkCellId >= 0) && (vtkCellId < _cellIdToDownId.size())); + _cellIdToDownId[vtkCellId] = downId; +} + +void SMDS_UnstructuredGrid::CleanDownwardConnectivity() +{ + for (int i = 0; i < _downArray.size(); i++) + { + if (_downArray[i]) + delete _downArray[i]; + _downArray[i] = 0; + } + _cellIdToDownId.clear(); +} + +/*! Build downward connectivity: to do only when needed because heavy memory load. + * Downward connectivity is no more valid if vtkUnstructuredGrid is modified. + * + */ +void SMDS_UnstructuredGrid::BuildDownwardConnectivity(bool withEdges) +{ + MESSAGE("SMDS_UnstructuredGrid::BuildDownwardConnectivity");CHRONO(2); + // TODO calcul partiel sans edges + + // --- erase previous data if any + + this->CleanDownwardConnectivity(); + + // --- create SMDS_Downward structures (in _downArray vector[vtkCellType]) + + _downArray.resize(VTK_MAXTYPE + 1, 0); + + _downArray[VTK_LINE] = new SMDS_DownEdge(this); + _downArray[VTK_QUADRATIC_EDGE] = new SMDS_DownQuadEdge(this); + _downArray[VTK_TRIANGLE] = new SMDS_DownTriangle(this); + _downArray[VTK_QUADRATIC_TRIANGLE] = new SMDS_DownQuadTriangle(this); + _downArray[VTK_BIQUADRATIC_TRIANGLE] = new SMDS_DownQuadTriangle(this); + _downArray[VTK_QUAD] = new SMDS_DownQuadrangle(this); + _downArray[VTK_QUADRATIC_QUAD] = new SMDS_DownQuadQuadrangle(this); + _downArray[VTK_BIQUADRATIC_QUAD] = new SMDS_DownQuadQuadrangle(this); + _downArray[VTK_TETRA] = new SMDS_DownTetra(this); + _downArray[VTK_QUADRATIC_TETRA] = new SMDS_DownQuadTetra(this); + _downArray[VTK_PYRAMID] = new SMDS_DownPyramid(this); + _downArray[VTK_QUADRATIC_PYRAMID] = new SMDS_DownQuadPyramid(this); + _downArray[VTK_WEDGE] = new SMDS_DownPenta(this); + _downArray[VTK_QUADRATIC_WEDGE] = new SMDS_DownQuadPenta(this); + _downArray[VTK_HEXAHEDRON] = new SMDS_DownHexa(this); + _downArray[VTK_QUADRATIC_HEXAHEDRON] = new SMDS_DownQuadHexa(this); + _downArray[VTK_TRIQUADRATIC_HEXAHEDRON] = new SMDS_DownQuadHexa(this); + _downArray[VTK_HEXAGONAL_PRISM] = new SMDS_DownPenta(this); + + // --- get detailed info of number of cells of each type, allocate SMDS_downward structures + + const SMDS_MeshInfo &meshInfo = _mesh->GetMeshInfo(); + + int nbLinTetra = meshInfo.NbTetras (ORDER_LINEAR); + int nbQuadTetra = meshInfo.NbTetras (ORDER_QUADRATIC); + int nbLinPyra = meshInfo.NbPyramids(ORDER_LINEAR); + int nbQuadPyra = meshInfo.NbPyramids(ORDER_QUADRATIC); + int nbLinPrism = meshInfo.NbPrisms (ORDER_LINEAR); + int nbQuadPrism = meshInfo.NbPrisms (ORDER_QUADRATIC); + int nbLinHexa = meshInfo.NbHexas (ORDER_LINEAR); + int nbQuadHexa = meshInfo.NbHexas (ORDER_QUADRATIC); + int nbHexPrism = meshInfo.NbHexPrisms(); + + int nbLineGuess = int((4.0 / 3.0) * nbLinTetra + 2 * nbLinPrism + 2.5 * nbLinPyra + 3 * nbLinHexa); + int nbQuadEdgeGuess = int((4.0 / 3.0) * nbQuadTetra + 2 * nbQuadPrism + 2.5 * nbQuadPyra + 3 * nbQuadHexa); + int nbLinTriaGuess = 2 * nbLinTetra + nbLinPrism + 2 * nbLinPyra; + int nbQuadTriaGuess = 2 * nbQuadTetra + nbQuadPrism + 2 * nbQuadPyra; + int nbLinQuadGuess = int((2.0 / 3.0) * nbLinPrism + (1.0 / 2.0) * nbLinPyra + 3 * nbLinHexa); + int nbQuadQuadGuess = int((2.0 / 3.0) * nbQuadPrism + (1.0 / 2.0) * nbQuadPyra + 3 * nbQuadHexa); + + int GuessSize[VTK_MAXTYPE]; + GuessSize[VTK_LINE] = nbLineGuess; + GuessSize[VTK_QUADRATIC_EDGE] = nbQuadEdgeGuess; + GuessSize[VTK_TRIANGLE] = nbLinTriaGuess; + GuessSize[VTK_QUADRATIC_TRIANGLE] = nbQuadTriaGuess; + GuessSize[VTK_BIQUADRATIC_TRIANGLE] = nbQuadTriaGuess; + GuessSize[VTK_QUAD] = nbLinQuadGuess; + GuessSize[VTK_QUADRATIC_QUAD] = nbQuadQuadGuess; + GuessSize[VTK_BIQUADRATIC_QUAD] = nbQuadQuadGuess; + GuessSize[VTK_TETRA] = nbLinTetra; + GuessSize[VTK_QUADRATIC_TETRA] = nbQuadTetra; + GuessSize[VTK_PYRAMID] = nbLinPyra; + GuessSize[VTK_QUADRATIC_PYRAMID] = nbQuadPyra; + GuessSize[VTK_WEDGE] = nbLinPrism; + GuessSize[VTK_QUADRATIC_WEDGE] = nbQuadPrism; + GuessSize[VTK_HEXAHEDRON] = nbLinHexa; + GuessSize[VTK_QUADRATIC_HEXAHEDRON] = nbQuadHexa; + GuessSize[VTK_TRIQUADRATIC_HEXAHEDRON] = nbQuadHexa; + GuessSize[VTK_HEXAGONAL_PRISM] = nbHexPrism; + + _downArray[VTK_LINE] ->allocate(nbLineGuess); + _downArray[VTK_QUADRATIC_EDGE] ->allocate(nbQuadEdgeGuess); + _downArray[VTK_TRIANGLE] ->allocate(nbLinTriaGuess); + _downArray[VTK_QUADRATIC_TRIANGLE] ->allocate(nbQuadTriaGuess); + _downArray[VTK_BIQUADRATIC_TRIANGLE] ->allocate(nbQuadTriaGuess); + _downArray[VTK_QUAD] ->allocate(nbLinQuadGuess); + _downArray[VTK_QUADRATIC_QUAD] ->allocate(nbQuadQuadGuess); + _downArray[VTK_BIQUADRATIC_QUAD] ->allocate(nbQuadQuadGuess); + _downArray[VTK_TETRA] ->allocate(nbLinTetra); + _downArray[VTK_QUADRATIC_TETRA] ->allocate(nbQuadTetra); + _downArray[VTK_PYRAMID] ->allocate(nbLinPyra); + _downArray[VTK_QUADRATIC_PYRAMID] ->allocate(nbQuadPyra); + _downArray[VTK_WEDGE] ->allocate(nbLinPrism); + _downArray[VTK_QUADRATIC_WEDGE] ->allocate(nbQuadPrism); + _downArray[VTK_HEXAHEDRON] ->allocate(nbLinHexa); + _downArray[VTK_QUADRATIC_HEXAHEDRON] ->allocate(nbQuadHexa); + _downArray[VTK_TRIQUADRATIC_HEXAHEDRON]->allocate(nbQuadHexa); + _downArray[VTK_HEXAGONAL_PRISM] ->allocate(nbHexPrism); + + // --- iteration on vtkUnstructuredGrid cells, only faces + // for each vtk face: + // create a downward face entry with its downward id. + // compute vtk volumes, create downward volumes entry. + // mark face in downward volumes + // mark volumes in downward face + + MESSAGE("--- iteration on vtkUnstructuredGrid cells, only faces");CHRONO(20); + int cellSize = this->Types->GetNumberOfTuples(); + _cellIdToDownId.resize(cellSize, -1); + + for (int i = 0; i < cellSize; i++) + { + int vtkFaceType = this->GetCellType(i); + if (SMDS_Downward::getCellDimension(vtkFaceType) == 2) + { + int vtkFaceId = i; + //ASSERT(_downArray[vtkFaceType]); + int connFaceId = _downArray[vtkFaceType]->addCell(vtkFaceId); + SMDS_Down2D* downFace = static_cast (_downArray[vtkFaceType]); + downFace->setTempNodes(connFaceId, vtkFaceId); + int vols[2] = { -1, -1 }; + int nbVolumes = downFace->computeVolumeIds(vtkFaceId, vols); + //MESSAGE("nbVolumes="<< nbVolumes); + for (int ivol = 0; ivol < nbVolumes; ivol++) + { + int vtkVolId = vols[ivol]; + int vtkVolType = this->GetCellType(vtkVolId); + //ASSERT(_downArray[vtkVolType]); + int connVolId = _downArray[vtkVolType]->addCell(vtkVolId); + _downArray[vtkVolType]->addDownCell(connVolId, connFaceId, vtkFaceType); + _downArray[vtkFaceType]->addUpCell(connFaceId, connVolId, vtkVolType); + // MESSAGE("Face " << vtkFaceId << " belongs to volume " << vtkVolId); + } + } + } + + // --- iteration on vtkUnstructuredGrid cells, only volumes + // for each vtk volume: + // create downward volumes entry if not already done + // build a temporary list of faces described with their nodes + // for each face + // compute the vtk volumes containing this face + // check if the face is already listed in the volumes (comparison of ordered list of nodes) + // if not, create a downward face entry (resizing of structure required) + // (the downward faces store a temporary list of nodes to ease the comparison) + // create downward volumes entry if not already done + // mark volumes in downward face + // mark face in downward volumes + + CHRONOSTOP(20); + MESSAGE("--- iteration on vtkUnstructuredGrid cells, only volumes");CHRONO(21); + + for (int i = 0; i < cellSize; i++) + { + int vtkType = this->GetCellType(i); + if (SMDS_Downward::getCellDimension(vtkType) == 3) + { + //CHRONO(31); + int vtkVolId = i; + // MESSAGE("vtk volume " << vtkVolId); + //ASSERT(_downArray[vtkType]); + /*int connVolId = */_downArray[vtkType]->addCell(vtkVolId); + + // --- find all the faces of the volume, describe the faces by their nodes + + SMDS_Down3D* downVol = static_cast (_downArray[vtkType]); + ListElemByNodesType facesWithNodes; + downVol->computeFacesWithNodes(vtkVolId, facesWithNodes); + // MESSAGE("vtk volume " << vtkVolId << " contains " << facesWithNodes.nbElems << " faces"); + //CHRONOSTOP(31); + for (int iface = 0; iface < facesWithNodes.nbElems; iface++) + { + // --- find the volumes containing the face + + //CHRONO(32); + int vtkFaceType = facesWithNodes.elems[iface].vtkType; + SMDS_Down2D* downFace = static_cast (_downArray[vtkFaceType]); + int vols[2] = { -1, -1 }; + int *nodes = &facesWithNodes.elems[iface].nodeIds[0]; + int lg = facesWithNodes.elems[iface].nbNodes; + int nbVolumes = downFace->computeVolumeIdsFromNodesFace(nodes, lg, vols); + // MESSAGE("vtk volume " << vtkVolId << " face " << iface << " belongs to " << nbVolumes << " volumes"); + + // --- check if face is registered in the volumes + //CHRONOSTOP(32); + + //CHRONO(33); + int connFaceId = -1; + for (int ivol = 0; ivol < nbVolumes; ivol++) + { + int vtkVolId2 = vols[ivol]; + int vtkVolType = this->GetCellType(vtkVolId2); + //ASSERT(_downArray[vtkVolType]); + int connVolId2 = _downArray[vtkVolType]->addCell(vtkVolId2); + SMDS_Down3D* downVol2 = static_cast (_downArray[vtkVolType]); + connFaceId = downVol2->FindFaceByNodes(connVolId2, facesWithNodes.elems[iface]); + if (connFaceId >= 0) + break; // --- face already created + }//CHRONOSTOP(33); + + // --- if face is not registered in the volumes, create face + + //CHRONO(34); + if (connFaceId < 0) + { + connFaceId = _downArray[vtkFaceType]->addCell(); + downFace->setTempNodes(connFaceId, facesWithNodes.elems[iface]); + }//CHRONOSTOP(34); + + // --- mark volumes in downward face and mark face in downward volumes + + //CHRONO(35); + for (int ivol = 0; ivol < nbVolumes; ivol++) + { + int vtkVolId2 = vols[ivol]; + int vtkVolType = this->GetCellType(vtkVolId2); + //ASSERT(_downArray[vtkVolType]); + int connVolId2 = _downArray[vtkVolType]->addCell(vtkVolId2); + _downArray[vtkVolType]->addDownCell(connVolId2, connFaceId, vtkFaceType); + _downArray[vtkFaceType]->addUpCell(connFaceId, connVolId2, vtkVolType); + // MESSAGE(" From volume " << vtkVolId << " face " << connFaceId << " belongs to volume " << vtkVolId2); + }//CHRONOSTOP(35); + } + } + } + + // --- iteration on vtkUnstructuredGrid cells, only edges + // for each vtk edge: + // create downward edge entry + // store the nodes id's in downward edge (redundant with vtkUnstructuredGrid) + // find downward faces + // (from vtk faces or volumes, get downward faces, they have a temporary list of nodes) + // mark edge in downward faces + // mark faces in downward edge + + CHRONOSTOP(21); + MESSAGE("--- iteration on vtkUnstructuredGrid cells, only edges");CHRONO(22); + + for (int i = 0; i < cellSize; i++) + { + int vtkEdgeType = this->GetCellType(i); + if (SMDS_Downward::getCellDimension(vtkEdgeType) == 1) + { + int vtkEdgeId = i; + //ASSERT(_downArray[vtkEdgeType]); + int connEdgeId = _downArray[vtkEdgeType]->addCell(vtkEdgeId); + SMDS_Down1D* downEdge = static_cast (_downArray[vtkEdgeType]); + downEdge->setNodes(connEdgeId, vtkEdgeId); + vector vtkIds; + int nbVtkCells = downEdge->computeVtkCells(connEdgeId, vtkIds); + int downFaces[1000]; + unsigned char downTypes[1000]; + int nbDownFaces = downEdge->computeFaces(connEdgeId, &vtkIds[0], nbVtkCells, downFaces, downTypes); + for (int n = 0; n < nbDownFaces; n++) + { + _downArray[downTypes[n]]->addDownCell(downFaces[n], connEdgeId, vtkEdgeType); + _downArray[vtkEdgeType]->addUpCell(connEdgeId, downFaces[n], downTypes[n]); + } + } + } + + // --- iteration on downward faces (they are all listed now) + // for each downward face: + // build a temporary list of edges with their ordered list of nodes + // for each edge: + // find all the vtk cells containing this edge + // then identify all the downward faces containing the edge, from the vtk cells + // check if the edge is already listed in the faces (comparison of ordered list of nodes) + // if not, create a downward edge entry with the node id's + // mark edge in downward faces + // mark downward faces in edge (size of list unknown, to be allocated) + + CHRONOSTOP(22);CHRONO(23); + + for (int vtkFaceType = 0; vtkFaceType < VTK_QUADRATIC_PYRAMID; vtkFaceType++) + { + if (SMDS_Downward::getCellDimension(vtkFaceType) != 2) + continue; + + // --- find all the edges of the face, describe the edges by their nodes + + SMDS_Down2D* downFace = static_cast (_downArray[vtkFaceType]); + int maxId = downFace->getMaxId(); + for (int faceId = 0; faceId < maxId; faceId++) + { + //CHRONO(40); + ListElemByNodesType edgesWithNodes; + downFace->computeEdgesWithNodes(faceId, edgesWithNodes); + // MESSAGE("downward face type " << vtkFaceType << " num " << faceId << " contains " << edgesWithNodes.nbElems << " edges"); + + //CHRONOSTOP(40); + for (int iedge = 0; iedge < edgesWithNodes.nbElems; iedge++) + { + + // --- check if the edge is already registered by exploration of the faces + + //CHRONO(41); + vector vtkIds; + unsigned char vtkEdgeType = edgesWithNodes.elems[iedge].vtkType; + int *pts = &edgesWithNodes.elems[iedge].nodeIds[0]; + SMDS_Down1D* downEdge = static_cast (_downArray[vtkEdgeType]); + int nbVtkCells = downEdge->computeVtkCells(pts, vtkIds); + //CHRONOSTOP(41);CHRONO(42); + int downFaces[1000]; + unsigned char downTypes[1000]; + int nbDownFaces = downEdge->computeFaces(pts, &vtkIds[0], nbVtkCells, downFaces, downTypes); + //CHRONOSTOP(42); + + //CHRONO(43); + int connEdgeId = -1; + for (int idf = 0; idf < nbDownFaces; idf++) + { + int faceId2 = downFaces[idf]; + int faceType = downTypes[idf]; + //ASSERT(_downArray[faceType]); + SMDS_Down2D* downFace2 = static_cast (_downArray[faceType]); + connEdgeId = downFace2->FindEdgeByNodes(faceId2, edgesWithNodes.elems[iedge]); + if (connEdgeId >= 0) + break; // --- edge already created + }//CHRONOSTOP(43); + + // --- if edge is not registered in the faces, create edge + + if (connEdgeId < 0) + { + //CHRONO(44); + connEdgeId = _downArray[vtkEdgeType]->addCell(); + downEdge->setNodes(connEdgeId, edgesWithNodes.elems[iedge].nodeIds); + //CHRONOSTOP(44); + } + + // --- mark faces in downward edge and mark edge in downward faces + + //CHRONO(45); + for (int idf = 0; idf < nbDownFaces; idf++) + { + int faceId2 = downFaces[idf]; + int faceType = downTypes[idf]; + //ASSERT(_downArray[faceType]); + //SMDS_Down2D* downFace2 = static_cast (_downArray[faceType]); + _downArray[vtkEdgeType]->addUpCell(connEdgeId, faceId2, faceType); + _downArray[faceType]->addDownCell(faceId2, connEdgeId, vtkEdgeType); + // MESSAGE(" From face t:" << vtkFaceType << " " << faceId << + // " edge " << connEdgeId << " belongs to face t:" << faceType << " " << faceId2); + }//CHRONOSTOP(45); + } + } + } + + CHRONOSTOP(23);CHRONO(24); + + // compact downward connectivity structure: adjust downward arrays size, replace vector> by a single vector + // 3D first then 2D and last 1D to release memory before edge upCells reorganization, (temporary memory use) + + for (int vtkType = VTK_QUADRATIC_PYRAMID; vtkType >= 0; vtkType--) + { + if (SMDS_Downward *down = _downArray[vtkType]) + { + down->compactStorage(); + } + } + + // --- Statistics + + for (int vtkType = 0; vtkType <= VTK_QUADRATIC_PYRAMID; vtkType++) + { + if (SMDS_Downward *down = _downArray[vtkType]) + { + if (down->getMaxId()) + { + MESSAGE("Cells of Type " << vtkType << " : number of entities, est: " + << GuessSize[vtkType] << " real: " << down->getMaxId()); + } + } + }CHRONOSTOP(24);CHRONOSTOP(2); + counters::stats(); +} + +/*! Get the neighbors of a cell. + * Only the neighbors having the dimension of the cell are taken into account + * (neighbors of a volume are the volumes sharing a face with this volume, + * neighbors of a face are the faces sharing an edge with this face...). + * @param neighborsVtkIds vector of neighbors vtk id's to fill (reserve enough space). + * @param downIds downward id's of cells of dimension n-1, to fill (reserve enough space). + * @param downTypes vtk types of cells of dimension n-1, to fill (reserve enough space). + * @param vtkId the vtk id of the cell + * @return number of neighbors + */ +int SMDS_UnstructuredGrid::GetNeighbors(int* neighborsVtkIds, int* downIds, unsigned char* downTypes, int vtkId, bool getSkin) +{ + int vtkType = this->GetCellType(vtkId); + int cellDim = SMDS_Downward::getCellDimension(vtkType); + if (cellDim <2) + return 0; // TODO voisins des edges = edges connectees + int cellId = this->_cellIdToDownId[vtkId]; + + int nbCells = _downArray[vtkType]->getNumberOfDownCells(cellId); + const int *downCells = _downArray[vtkType]->getDownCells(cellId); + const unsigned char* downTyp = _downArray[vtkType]->getDownTypes(cellId); + + // --- iteration on faces of the 3D cell (or edges on the 2D cell). + + int nb = 0; + for (int i = 0; i < nbCells; i++) + { + int downId = downCells[i]; + int cellType = downTyp[i]; + int nbUp = _downArray[cellType]->getNumberOfUpCells(downId); + const int *upCells = _downArray[cellType]->getUpCells(downId); + const unsigned char* upTypes = _downArray[cellType]->getUpTypes(downId); + + // ---for a volume, max 2 upCells, one is this cell, the other is a neighbor + // for a face, number of neighbors (connected faces) not known + + for (int j = 0; j < nbUp; j++) + { + if ((upCells[j] == cellId) && (upTypes[j] == vtkType)) + continue; + int vtkNeighbor = _downArray[upTypes[j]]->getVtkCellId(upCells[j]); + neighborsVtkIds[nb] = vtkNeighbor; + downIds[nb] = downId; + downTypes[nb] = cellType; + nb++; + if (nb >= NBMAXNEIGHBORS) + { + INFOS("SMDS_UnstructuredGrid::GetNeighbors problem: NBMAXNEIGHBORS=" <getVtkCellId(downId); // OK if skin present + downIds[nb] = downId; + downTypes[nb] = cellType; + nb++; + if (nb >= NBMAXNEIGHBORS) + { + INFOS("SMDS_UnstructuredGrid::GetNeighbors problem: NBMAXNEIGHBORS=" <GetCellType(vtkId); + int dim = SMDS_Downward::getCellDimension(vtkType); + int nbFaces = 0; + unsigned char cellTypes[1000]; + int downCellId[1000]; + if (dim == 1) + { + int downId = this->CellIdToDownId(vtkId); + if (downId < 0) + { + MESSAGE("Downward structure not up to date: new edge not taken into account"); + return 0; + } + nbFaces = _downArray[vtkType]->getNumberOfUpCells(downId); + const int *upCells = _downArray[vtkType]->getUpCells(downId); + const unsigned char* upTypes = _downArray[vtkType]->getUpTypes(downId); + for (int i=0; i< nbFaces; i++) + { + cellTypes[i] = upTypes[i]; + downCellId[i] = upCells[i]; + } + } + else if (dim == 2) + { + nbFaces = 1; + cellTypes[0] = this->GetCellType(vtkId); + int downId = this->CellIdToDownId(vtkId); + if (downId < 0) + { + MESSAGE("Downward structure not up to date: new face not taken into account"); + return 0; + } + downCellId[0] = downId; + } + + int nbvol =0; + for (int i=0; igetNumberOfUpCells(downId); + const int *upCells = _downArray[vtkTypeFace]->getUpCells(downId); + const unsigned char* upTypes = _downArray[vtkTypeFace]->getUpTypes(downId); + for (int j=0; jgetVtkCellId(upCells[j]); + if (vtkVolId >= 0) + volVtkIds[nbvol++] = vtkVolId; + } + } + return nbvol; +} + +/*! get the volumes containing a face or an edge of the downward structure + * The edge or face does not necessary belong to the vtkUnstructuredGrid + * @param volVtkIds vector of parent volume ids to fill (reserve enough space!) + * @param downId id in the downward structure + * @param downType type of cell + */ +int SMDS_UnstructuredGrid::GetParentVolumes(int* volVtkIds, int downId, unsigned char downType) +{ + int vtkType = downType; + int dim = SMDS_Downward::getCellDimension(vtkType); + int nbFaces = 0; + unsigned char cellTypes[1000]; + int downCellId[1000]; + if (dim == 1) + { + nbFaces = _downArray[vtkType]->getNumberOfUpCells(downId); + const int *upCells = _downArray[vtkType]->getUpCells(downId); + const unsigned char* upTypes = _downArray[vtkType]->getUpTypes(downId); + for (int i=0; i< nbFaces; i++) + { + cellTypes[i] = upTypes[i]; + downCellId[i] = upCells[i]; + } + } + else if (dim == 2) + { + nbFaces = 1; + cellTypes[0] = vtkType; + downCellId[0] = downId; + } + + int nbvol =0; + for (int i=0; igetNumberOfUpCells(downId); + const int *upCells = _downArray[vtkTypeFace]->getUpCells(downId); + const unsigned char* upTypes = _downArray[vtkTypeFace]->getUpTypes(downId); + for (int j=0; jgetVtkCellId(upCells[j]); + if (vtkVolId >= 0) + volVtkIds[nbvol++] = vtkVolId; + } + } + return nbvol; +} + +/*! get the node id's of a cell. + * The cell is defined by it's downward connectivity id and type. + * @param nodeSet set of of vtk node id's to fill. + * @param downId downward connectivity id of the cell. + * @param downType type of cell. + */ +void SMDS_UnstructuredGrid::GetNodeIds(std::set& nodeSet, int downId, unsigned char downType) +{ + _downArray[downType]->getNodeIds(downId, nodeSet); +} + +/*! change some nodes in cell without modifying type or internal connectivity. + * Nodes inverse connectivity is maintained up to date. + * @param vtkVolId vtk id of the cell + * @param localClonedNodeIds map old node id to new node id. + */ +void SMDS_UnstructuredGrid::ModifyCellNodes(int vtkVolId, std::map localClonedNodeIds) +{ + vtkIdType npts = 0; + vtkIdType *pts; // will refer to the point id's of the face + this->GetCellPoints(vtkVolId, npts, pts); + for (int i = 0; i < npts; i++) + { + if (localClonedNodeIds.count(pts[i])) + { + vtkIdType oldpt = pts[i]; + pts[i] = localClonedNodeIds[oldpt]; + //MESSAGE(oldpt << " --> " << pts[i]); + //this->RemoveReferenceToCell(oldpt, vtkVolId); + //this->AddReferenceToCell(pts[i], vtkVolId); + } + } +} + +/*! reorder the nodes of a face + * @param vtkVolId vtk id of a volume containing the face, to get an orientation for the face. + * @param orderedNodes list of nodes to reorder (in out) + * @return size of the list + */ +int SMDS_UnstructuredGrid::getOrderedNodesOfFace(int vtkVolId, int& dim, std::vector& orderedNodes) +{ + int vtkType = this->GetCellType(vtkVolId); + dim = SMDS_Downward::getCellDimension(vtkType); + if (dim == 3) + { + SMDS_Down3D *downvol = static_cast (_downArray[vtkType]); + int downVolId = this->_cellIdToDownId[vtkVolId]; + downvol->getOrderedNodesOfFace(downVolId, orderedNodes); + } + // else nothing to do; + return orderedNodes.size(); +} + +void SMDS_UnstructuredGrid::BuildLinks() +{ + // Remove the old links if they are already built + if (this->Links) + { + this->Links->UnRegister(this); + } + + this->Links = SMDS_CellLinks::New(); + this->Links->Allocate(this->GetNumberOfPoints()); + this->Links->Register(this); + this->Links->BuildLinks(this, this->Connectivity); + this->Links->Delete(); +} + +/*! Create a volume (prism or hexahedron) by duplication of a face. + * Designed for use in creation of flat elements separating volume domains. + * A face separating two domains is shared by two volume cells. + * All the nodes are already created (for the two faces). + * Each original Node is associated to corresponding nodes in the domains. + * Some nodes may be duplicated for more than two domains, when domain separations intersect. + * In that case, even some of the nodes to use for the original face may be changed. + * @param vtkVolId: vtk id of a volume containing the face, to get an orientation for the face. + * @param domain1: domain of the original face + * @param domain2: domain of the duplicated face + * @param originalNodes: the vtk node ids of the original face + * @param nodeDomains: map(original id --> map(domain --> duplicated node id)) + * @return ok if success. + */ +SMDS_MeshCell* SMDS_UnstructuredGrid::extrudeVolumeFromFace(int vtkVolId, + int domain1, + int domain2, + std::set& originalNodes, + std::map >& nodeDomains, + std::map >& nodeQuadDomains) +{ + //MESSAGE("extrudeVolumeFromFace " << vtkVolId); + vector orderedOriginals; + orderedOriginals.clear(); + set::const_iterator it = originalNodes.begin(); + for (; it != originalNodes.end(); ++it) + orderedOriginals.push_back(*it); + + int dim = 0; + int nbNodes = this->getOrderedNodesOfFace(vtkVolId, dim, orderedOriginals); + vector orderedNodes; + + bool isQuadratic = false; + switch (orderedOriginals.size()) + { + case 3: + if (dim == 2) + isQuadratic = true; + break; + case 6: + case 8: + isQuadratic = true; + break; + default: + isQuadratic = false; + break; + } + + if (isQuadratic) + { + long dom1 = domain1; + long dom2 = domain2; + long dom1_2; // for nodeQuadDomains + if (domain1 < domain2) + dom1_2 = dom1 + INT_MAX * dom2; + else + dom1_2 = dom2 + INT_MAX * dom1; + //cerr << "dom1=" << dom1 << " dom2=" << dom2 << " dom1_2=" << dom1_2 << endl; + int ima = orderedOriginals.size(); + int mid = orderedOriginals.size() / 2; + //cerr << "ima=" << ima << " mid=" << mid << endl; + for (int i = 0; i < mid; i++) + orderedNodes.push_back(nodeDomains[orderedOriginals[i]][domain1]); + for (int i = 0; i < mid; i++) + orderedNodes.push_back(nodeDomains[orderedOriginals[i]][domain2]); + for (int i = mid; i < ima; i++) + orderedNodes.push_back(nodeDomains[orderedOriginals[i]][domain1]); + for (int i = mid; i < ima; i++) + orderedNodes.push_back(nodeDomains[orderedOriginals[i]][domain2]); + for (int i = 0; i < mid; i++) + { + int oldId = orderedOriginals[i]; + int newId; + if (nodeQuadDomains.count(oldId) && nodeQuadDomains[oldId].count(dom1_2)) + newId = nodeQuadDomains[oldId][dom1_2]; + else + { + double *coords = this->GetPoint(oldId); + SMDS_MeshNode *newNode = _mesh->AddNode(coords[0], coords[1], coords[2]); + newId = newNode->getVtkId(); + if (! nodeQuadDomains.count(oldId)) + { + std::map emptyMap; + nodeQuadDomains[oldId] = emptyMap; + } + nodeQuadDomains[oldId][dom1_2] = newId; + } + orderedNodes.push_back(newId); + } + } + else + { + for (int i = 0; i < nbNodes; i++) + orderedNodes.push_back(nodeDomains[orderedOriginals[i]][domain1]); + if (dim == 3) + for (int i = 0; i < nbNodes; i++) + orderedNodes.push_back(nodeDomains[orderedOriginals[i]][domain2]); + else + for (int i = nbNodes-1; i >= 0; i--) + orderedNodes.push_back(nodeDomains[orderedOriginals[i]][domain2]); + + } + + if (dim == 3) + { + SMDS_MeshVolume *vol = _mesh->AddVolumeFromVtkIds(orderedNodes); + return vol; + } + else if (dim == 2) + { + SMDS_MeshFace *face = _mesh->AddFaceFromVtkIds(orderedNodes); + return face; + } + + // TODO update sub-shape list of elements and nodes + return 0; +} + +//================================================================================ +/*! + * \brief Allocates data array for ball diameters + * \param MaxVtkID - max ID of a ball element + */ +//================================================================================ + +void SMDS_UnstructuredGrid::AllocateDiameters( vtkIdType MaxVtkID ) +{ + SetBallDiameter( MaxVtkID, 0 ); +} + +//================================================================================ +/*! + * \brief Sets diameter of a ball element + * \param vtkID - vtk id of the ball element + * \param diameter - diameter of the ball element + */ +//================================================================================ + +void SMDS_UnstructuredGrid::SetBallDiameter( vtkIdType vtkID, double diameter ) +{ + vtkDoubleArray* array = vtkDoubleArray::SafeDownCast( vtkDataSet::CellData->GetScalars() ); + if ( !array ) + { + array = vtkDoubleArray::New(); + array->SetNumberOfComponents(1); + vtkDataSet::CellData->SetScalars( array ); + } + array->InsertValue( vtkID, diameter ); +} + +//================================================================================ +/*! + * \brief Returns diameter of a ball element + * \param vtkID - vtk id of the ball element + */ +//================================================================================ + +double SMDS_UnstructuredGrid::GetBallDiameter( vtkIdType vtkID ) const +{ + if ( vtkDataSet::CellData ) + return vtkDoubleArray::SafeDownCast( vtkDataSet::CellData->GetScalars() )->GetValue( vtkID ); + return 0; +} + diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_VertexPosition.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VertexPosition.cpp index c3311b5a599f..6f05329daefd 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_VertexPosition.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VertexPosition.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_VertexPosition.cxx // Author : Jean-Michel BOULCOURT @@ -35,25 +36,13 @@ using namespace std; //purpose : //======================================================================= -SMDS_VertexPosition:: SMDS_VertexPosition(const int aVertexId) - :SMDS_Position(aVertexId) +SMDS_VertexPosition:: SMDS_VertexPosition() { + //MESSAGE("*********************************************** SMDS_VertexPosition " << aVertexId); } -//======================================================================= -//function : Coords -//purpose : -//======================================================================= - -const double *SMDS_VertexPosition::Coords() const -{ - const static double origin[]={0,0,0}; - MESSAGE("SMDS_VertexPosition::Coords not implemented"); - return origin; -} - - SMDS_TypeOfPosition SMDS_VertexPosition::GetTypeOfPosition() const { - return SMDS_TOP_VERTEX; + //MESSAGE("################################################# GetTypeOfPosition"); + return SMDS_TOP_VERTEX; } diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_VolumeOfFaces.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VolumeOfFaces.cpp index c993dcc66f56..09a16f785b57 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_VolumeOfFaces.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VolumeOfFaces.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // File : SMDS_VolumeOfFaces.cxx // Author : Jean-Michel BOULCOURT @@ -30,6 +31,7 @@ #include "SMDS_VolumeOfFaces.hxx" #include "SMDS_IteratorOfElements.hxx" +#include "utilities.h" using namespace std; @@ -40,16 +42,16 @@ using namespace std; void SMDS_VolumeOfFaces::Print(ostream & OS) const { - OS << "volume <" << GetID() << "> : "; - int i; - for (i = 0; i < NbFaces()-1; ++i) OS << myFaces[i] << ","; - OS << myFaces[i]<< ") " << endl; + OS << "volume <" << GetID() << "> : "; + int i; + for (i = 0; i < NbFaces()-1; ++i) OS << myFaces[i] << ","; + OS << myFaces[i]<< ") " << endl; } int SMDS_VolumeOfFaces::NbFaces() const { - return myNbFaces; + return myNbFaces; } class SMDS_VolumeOfFaces_MyIterator:public SMDS_ElemIterator @@ -74,7 +76,7 @@ class SMDS_VolumeOfFaces_MyIterator:public SMDS_ElemIterator }; SMDS_ElemIteratorPtr SMDS_VolumeOfFaces:: - elementsIterator(SMDSAbs_ElementType type) const + elementsIterator(SMDSAbs_ElementType type) const { switch(type) { @@ -95,13 +97,14 @@ SMDS_VolumeOfFaces::SMDS_VolumeOfFaces(const SMDS_MeshFace * face1, const SMDS_MeshFace * face3, const SMDS_MeshFace * face4) { - myNbFaces = 4; - myFaces[0]=face1; - myFaces[1]=face2; - myFaces[2]=face3; - myFaces[3]=face4; - myFaces[4]=0; - myFaces[5]=0; + //MESSAGE("****************************************************** SMDS_VolumeOfFaces"); + myNbFaces = 4; + myFaces[0]=face1; + myFaces[1]=face2; + myFaces[2]=face3; + myFaces[3]=face4; + myFaces[4]=0; + myFaces[5]=0; } SMDS_VolumeOfFaces::SMDS_VolumeOfFaces(const SMDS_MeshFace * face1, @@ -110,13 +113,14 @@ SMDS_VolumeOfFaces::SMDS_VolumeOfFaces(const SMDS_MeshFace * face1, const SMDS_MeshFace * face4, const SMDS_MeshFace * face5) { - myNbFaces = 5; - myFaces[0]=face1; - myFaces[1]=face2; - myFaces[2]=face3; - myFaces[3]=face4; - myFaces[4]=face5; - myFaces[5]=0; + //MESSAGE("****************************************************** SMDS_VolumeOfFaces"); + myNbFaces = 5; + myFaces[0]=face1; + myFaces[1]=face2; + myFaces[2]=face3; + myFaces[3]=face4; + myFaces[4]=face5; + myFaces[5]=0; } SMDS_VolumeOfFaces::SMDS_VolumeOfFaces(const SMDS_MeshFace * face1, @@ -126,12 +130,40 @@ SMDS_VolumeOfFaces::SMDS_VolumeOfFaces(const SMDS_MeshFace * face1, const SMDS_MeshFace * face5, const SMDS_MeshFace * face6) { - myNbFaces = 6; - myFaces[0]=face1; - myFaces[1]=face2; - myFaces[2]=face3; - myFaces[3]=face4; - myFaces[4]=face5; - myFaces[5]=face6; + //MESSAGE("****************************************************** SMDS_VolumeOfFaces"); + myNbFaces = 6; + myFaces[0]=face1; + myFaces[1]=face2; + myFaces[2]=face3; + myFaces[3]=face4; + myFaces[4]=face5; + myFaces[5]=face6; +} + +SMDSAbs_EntityType SMDS_VolumeOfFaces::GetEntityType() const +{ + SMDSAbs_EntityType aType = SMDSEntity_Tetra; + switch(myNbFaces) + { + case 4: aType = SMDSEntity_Tetra; break; + case 5: aType = SMDSEntity_Pyramid; break; + case 6: aType = SMDSEntity_Penta; break; + case 8: + default: aType = SMDSEntity_Hexa; break; + } + return aType; } +SMDSAbs_GeometryType SMDS_VolumeOfFaces::GetGeomType() const +{ + SMDSAbs_GeometryType aType = SMDSGeom_NONE; + switch(myNbFaces) + { + case 4: aType = SMDSGeom_TETRA; break; + case 5: aType = SMDSGeom_PYRAMID; break; + case 6: aType = SMDSGeom_PENTA; break; + case 8: + default: aType = SMDSGeom_HEXA; break; + } + return aType; +} diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_VolumeOfNodes.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VolumeOfNodes.cpp index eb5101e7a96c..80d41a2636fa 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_VolumeOfNodes.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VolumeOfNodes.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMDS : implementaion of Salome mesh data structure // #ifdef _MSC_VER @@ -29,10 +30,9 @@ #include "SMDS_MeshNode.hxx" #include "SMDS_SetIterator.hxx" #include "SMDS_VolumeTool.hxx" +#include "SMDS_Mesh.hxx" #include "utilities.h" -#include - using namespace std; /////////////////////////////////////////////////////////////////////////////// @@ -40,73 +40,77 @@ using namespace std; /// 5,1 and 7,3 are an edges. /////////////////////////////////////////////////////////////////////////////// SMDS_VolumeOfNodes::SMDS_VolumeOfNodes( - const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2, - const SMDS_MeshNode * node3, - const SMDS_MeshNode * node4, - const SMDS_MeshNode * node5, - const SMDS_MeshNode * node6, - const SMDS_MeshNode * node7, - const SMDS_MeshNode * node8) -{ - myNbNodes = 8; - myNodes = new const SMDS_MeshNode* [myNbNodes]; - myNodes[0]=node1; - myNodes[1]=node2; - myNodes[2]=node3; - myNodes[3]=node4; - myNodes[4]=node5; - myNodes[5]=node6; - myNodes[6]=node7; - myNodes[7]=node8; + const SMDS_MeshNode * node1, + const SMDS_MeshNode * node2, + const SMDS_MeshNode * node3, + const SMDS_MeshNode * node4, + const SMDS_MeshNode * node5, + const SMDS_MeshNode * node6, + const SMDS_MeshNode * node7, + const SMDS_MeshNode * node8) +{ + //MESSAGE("***************************************************** SMDS_VolumeOfNodes"); + myNbNodes = 8; + myNodes = new const SMDS_MeshNode* [myNbNodes]; + myNodes[0]=node1; + myNodes[1]=node2; + myNodes[2]=node3; + myNodes[3]=node4; + myNodes[4]=node5; + myNodes[5]=node6; + myNodes[6]=node7; + myNodes[7]=node8; } SMDS_VolumeOfNodes::SMDS_VolumeOfNodes( - const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2, - const SMDS_MeshNode * node3, - const SMDS_MeshNode * node4) -{ - myNbNodes = 4; - myNodes = new const SMDS_MeshNode* [myNbNodes]; - myNodes[0]=node1; - myNodes[1]=node2; - myNodes[2]=node3; - myNodes[3]=node4; + const SMDS_MeshNode * node1, + const SMDS_MeshNode * node2, + const SMDS_MeshNode * node3, + const SMDS_MeshNode * node4) +{ + //MESSAGE("***************************************************** SMDS_VolumeOfNodes"); + myNbNodes = 4; + myNodes = new const SMDS_MeshNode* [myNbNodes]; + myNodes[0]=node1; + myNodes[1]=node2; + myNodes[2]=node3; + myNodes[3]=node4; } SMDS_VolumeOfNodes::SMDS_VolumeOfNodes( - const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2, - const SMDS_MeshNode * node3, - const SMDS_MeshNode * node4, - const SMDS_MeshNode * node5) -{ - myNbNodes = 5; - myNodes = new const SMDS_MeshNode* [myNbNodes]; - myNodes[0]=node1; - myNodes[1]=node2; - myNodes[2]=node3; - myNodes[3]=node4; - myNodes[4]=node5; + const SMDS_MeshNode * node1, + const SMDS_MeshNode * node2, + const SMDS_MeshNode * node3, + const SMDS_MeshNode * node4, + const SMDS_MeshNode * node5) +{ + //MESSAGE("***************************************************** SMDS_VolumeOfNodes"); + myNbNodes = 5; + myNodes = new const SMDS_MeshNode* [myNbNodes]; + myNodes[0]=node1; + myNodes[1]=node2; + myNodes[2]=node3; + myNodes[3]=node4; + myNodes[4]=node5; } SMDS_VolumeOfNodes::SMDS_VolumeOfNodes( - const SMDS_MeshNode * node1, - const SMDS_MeshNode * node2, - const SMDS_MeshNode * node3, - const SMDS_MeshNode * node4, - const SMDS_MeshNode * node5, - const SMDS_MeshNode * node6) -{ - myNbNodes = 6; - myNodes = new const SMDS_MeshNode* [myNbNodes]; - myNodes[0]=node1; - myNodes[1]=node2; - myNodes[2]=node3; - myNodes[3]=node4; - myNodes[4]=node5; - myNodes[5]=node6; + const SMDS_MeshNode * node1, + const SMDS_MeshNode * node2, + const SMDS_MeshNode * node3, + const SMDS_MeshNode * node4, + const SMDS_MeshNode * node5, + const SMDS_MeshNode * node6) +{ + //MESSAGE("***************************************************** SMDS_VolumeOfNodes"); + myNbNodes = 6; + myNodes = new const SMDS_MeshNode* [myNbNodes]; + myNodes[0]=node1; + myNodes[1]=node2; + myNodes[2]=node3; + myNodes[3]=node4; + myNodes[4]=node5; + myNodes[5]=node6; } bool SMDS_VolumeOfNodes::ChangeNodes(const SMDS_MeshNode* nodes[], @@ -132,56 +136,48 @@ SMDS_VolumeOfNodes::~SMDS_VolumeOfNodes() } } -//======================================================================= -//function : Print -//purpose : -//======================================================================= - void SMDS_VolumeOfNodes::Print(ostream & OS) const { - OS << "volume <" << GetID() << "> : "; - int i; - for (i = 0; i < NbNodes()-1; ++i) OS << myNodes[i] << ","; - OS << myNodes[NbNodes()-1]<< ") " << endl; + OS << "volume <" << GetID() << "> : "; + int i; + for (i = 0; i < NbNodes()-1; ++i) OS << myNodes[i] << ","; + OS << myNodes[NbNodes()-1]<< ") " << endl; } int SMDS_VolumeOfNodes::NbFaces() const { - switch(NbNodes()) - { - case 4: return 4; - case 5: return 5; - case 6: return 5; - case 8: return 6; - default: MESSAGE("invalid number of nodes"); - } + switch(NbNodes()) + { + case 4: return 4; + case 5: return 5; + case 6: return 5; + case 8: return 6; + default: MESSAGE("invalid number of nodes"); + } return 0; } int SMDS_VolumeOfNodes::NbNodes() const { - return myNbNodes; + return myNbNodes; } int SMDS_VolumeOfNodes::NbEdges() const { - switch(NbNodes()) - { - case 4: return 6; - case 5: return 8; - case 6: return 9; - case 8: return 12; - default: MESSAGE("invalid number of nodes"); - } + switch(NbNodes()) + { + case 4: return 6; + case 5: return 8; + case 6: return 9; + case 8: return 12; + default: MESSAGE("invalid number of nodes"); + } return 0; } -/// =================================================================== /*! * \brief Iterator on node of volume */ -/// =================================================================== - class SMDS_VolumeOfNodes_MyIterator:public SMDS_NodeArrayElemIterator { public: @@ -189,12 +185,9 @@ class SMDS_VolumeOfNodes_MyIterator:public SMDS_NodeArrayElemIterator SMDS_NodeArrayElemIterator( s, & s[ l ]) {} }; -/// =================================================================== /*! * \brief Iterator on faces or edges of volume */ -/// =================================================================== - class _MySubIterator : public SMDS_ElemIterator { vector< const SMDS_MeshElement* > myElems; @@ -234,7 +227,7 @@ SMDS_ElemIteratorPtr SMDS_VolumeOfNodes::elementsIterator(SMDSAbs_ElementType ty SMDSAbs_ElementType SMDS_VolumeOfNodes::GetType() const { - return SMDSAbs_Volume; + return SMDSAbs_Volume; } /*! @@ -246,3 +239,33 @@ const SMDS_MeshNode* SMDS_VolumeOfNodes::GetNode(const int ind) const { return myNodes[ ind ]; } + +SMDSAbs_EntityType SMDS_VolumeOfNodes::GetEntityType() const +{ + SMDSAbs_EntityType aType = SMDSEntity_Tetra; + switch(myNbNodes) + { + case 4: aType = SMDSEntity_Tetra; break; + case 5: aType = SMDSEntity_Pyramid; break; + case 6: aType = SMDSEntity_Penta; break; + case 8: + default: aType = SMDSEntity_Hexa; break; + } + return aType; +} + +SMDSAbs_GeometryType SMDS_VolumeOfNodes::GetGeomType() const +{ + SMDSAbs_GeometryType aType = SMDSGeom_NONE; + switch(myNbNodes) + { + case 4: aType = SMDSGeom_TETRA; break; + case 5: aType = SMDSGeom_PYRAMID; break; + case 6: aType = SMDSGeom_PENTA; break; + case 12: aType = SMDSGeom_HEXAGONAL_PRISM; break; + case 8: + default: aType = SMDSGeom_HEXA; break; + } + return aType; +} + diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_VolumeTool.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VolumeTool.cpp index 0984cb50557e..c0c506d9cc13 100644 --- a/src/3rdParty/salomesmesh/src/SMDS/SMDS_VolumeTool.cpp +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VolumeTool.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : SMDS_VolumeTool.cxx // Created : Tue Jul 13 12:22:13 2004 // Author : Edward AGAPOV (eap) @@ -31,21 +32,29 @@ #include "SMDS_MeshElement.hxx" #include "SMDS_MeshNode.hxx" -#include "SMDS_PolyhedralVolumeOfNodes.hxx" +#include "SMDS_VtkVolume.hxx" #include "SMDS_Mesh.hxx" #include "utilities.h" #include -#include -#include +#include +#include +#include +#include using namespace std; +namespace +{ // ====================================================== // Node indices in faces depending on volume orientation // making most faces normals external // ====================================================== +// For all elements, 0-th face is bottom based on the first nodes. +// For prismatic elements (tetra,hexa,prisms), 1-th face is a top one. +// For all elements, side faces follow order of bottom nodes +// ====================================================== /* // N3 @@ -66,11 +75,6 @@ static int Tetra_F [4][4] = { // FORWARD == EXTERNAL { 0, 3, 1, 0 }, { 1, 3, 2, 1 }, { 0, 2, 3, 0 }}; -static int Tetra_R [4][4] = { // REVERSED - { 0, 1, 2, 0 }, // All faces but a bottom have external normals - { 0, 1, 3, 0 }, - { 1, 2, 3, 1 }, - { 0, 3, 2, 0 }}; static int Tetra_RE [4][4] = { // REVERSED -> FORWARD (EXTERNAL) { 0, 2, 1, 0 }, // All faces have external normals { 0, 1, 3, 0 }, @@ -86,13 +90,8 @@ static int Pyramid_F [5][5] = { // FORWARD == EXTERNAL { 0, 4, 1, 0, 4 }, { 1, 4, 2, 1, 4 }, { 2, 4, 3, 2, 4 }, - { 3, 4, 0, 3, 4 }}; -static int Pyramid_R [5][5] = { // REVERSED - { 0, 1, 2, 3, 0 }, // All faces but a bottom have external normals - { 0, 1, 4, 0, 4 }, - { 1, 2, 4, 1, 4 }, - { 2, 3, 4, 2, 4 }, - { 3, 0, 4, 3, 4 }}; + { 3, 4, 0, 3, 4 } +}; static int Pyramid_RE [5][5] = { // REVERSED -> FORWARD (EXTERNAL) { 0, 3, 2, 1, 0 }, // All faces but a bottom have external normals { 0, 1, 4, 0, 4 }, @@ -117,29 +116,17 @@ static int Pyramid_nbN [] = { 4, 3, 3, 3, 3 }; // N0 +---------+ N2 */ static int Penta_F [5][5] = { // FORWARD - { 0, 1, 2, 0, 0 }, // Top face has an internal normal, other - external - { 3, 4, 5, 3, 3 }, // 0 is bottom, 1 is top face - { 0, 2, 5, 3, 0 }, - { 1, 4, 5, 2, 1 }, - { 0, 3, 4, 1, 0 }}; -static int Penta_R [5][5] = { // REVERSED - { 0, 1, 2, 0, 0 }, // Bottom face has an internal normal, other - external - { 3, 4, 5, 3, 3 }, // 0 is bottom, 1 is top face - { 0, 3, 5, 2, 0 }, - { 1, 2, 5, 4, 1 }, - { 0, 1, 4, 3, 0 }}; -static int Penta_FE [5][5] = { // FORWARD -> EXTERNAL - { 0, 1, 2, 0, 0 }, - { 3, 5, 4, 3, 3 }, - { 0, 2, 5, 3, 0 }, + { 0, 1, 2, 0, 0 }, // All faces have external normals + { 3, 5, 4, 3, 3 }, // 0 is bottom, 1 is top face + { 0, 3, 4, 1, 0 }, { 1, 4, 5, 2, 1 }, - { 0, 3, 4, 1, 0 }}; + { 0, 2, 5, 3, 0 }}; static int Penta_RE [5][5] = { // REVERSED -> EXTERNAL { 0, 2, 1, 0, 0 }, { 3, 4, 5, 3, 3 }, - { 0, 3, 5, 2, 0 }, + { 0, 1, 4, 3, 0 }, { 1, 2, 5, 4, 1 }, - { 0, 1, 4, 3, 0 }}; + { 0, 3, 5, 2, 0 }}; static int Penta_nbN [] = { 3, 3, 4, 4, 4 }; /* @@ -149,8 +136,6 @@ static int Penta_nbN [] = { 3, 3, 4, 4, 4 }; // / | / | // N4+----------+N7 | // | | | | HEXAHEDRON -// | | | | -// | | | | // | N1+------|---+N2 // | / | / // | / | / @@ -158,34 +143,58 @@ static int Penta_nbN [] = { 3, 3, 4, 4, 4 }; // N0+----------+N3 */ static int Hexa_F [6][5] = { // FORWARD - { 0, 1, 2, 3, 0 }, // opposite faces are neighbouring, - { 4, 5, 6, 7, 4 }, // odd face(1,3,5) normal is internal, even(0,2,4) - external - { 1, 0, 4, 5, 1 }, // same index nodes of opposite faces are linked - { 2, 3, 7, 6, 2 }, - { 0, 3, 7, 4, 0 }, - { 1, 2, 6, 5, 1 }}; -// static int Hexa_R [6][5] = { // REVERSED -// { 0, 3, 2, 1, 0 }, // opposite faces are neighbouring, -// { 4, 7, 6, 5, 4 }, // odd face(1,3,5) normal is external, even(0,2,4) - internal -// { 1, 5, 4, 0, 1 }, // same index nodes of opposite faces are linked -// { 2, 6, 7, 3, 2 }, -// { 0, 4, 7, 3, 0 }, -// { 1, 5, 6, 2, 1 }}; -static int Hexa_FE [6][5] = { // FORWARD -> EXTERNAL - { 0, 1, 2, 3, 0 } , // opposite faces are neighbouring, - { 4, 7, 6, 5, 4 }, // all face normals are external, - { 0, 4, 5, 1, 0 }, // links in opposite faces: 0-0, 1-3, 2-2, 3-1 + { 0, 1, 2, 3, 0 }, + { 4, 7, 6, 5, 4 }, // all face normals are external + { 0, 4, 5, 1, 0 }, + { 1, 5, 6, 2, 1 }, { 3, 2, 6, 7, 3 }, - { 0, 3, 7, 4, 0 }, - { 1, 5, 6, 2, 1 }}; + { 0, 3, 7, 4, 0 }}; static int Hexa_RE [6][5] = { // REVERSED -> EXTERNAL - { 0, 3, 2, 1, 0 }, // opposite faces are neighbouring, - { 4, 5, 6, 7, 4 }, // all face normals are external, - { 0, 1, 5, 4, 0 }, // links in opposite faces: 0-0, 1-3, 2-2, 3-1 + { 0, 3, 2, 1, 0 }, + { 4, 5, 6, 7, 4 }, // all face normals are external + { 0, 1, 5, 4, 0 }, + { 1, 2, 6, 5, 1 }, { 3, 7, 6, 2, 3 }, - { 0, 4, 7, 3, 0 }, - { 1, 2, 6, 5, 1 }}; + { 0, 4, 7, 3, 0 }}; static int Hexa_nbN [] = { 4, 4, 4, 4, 4, 4 }; +static int Hexa_oppF[] = { 1, 0, 4, 5, 2, 3 }; // oppopsite facet indices + +/* +// N8 +------+ N9 +// / \ +// / \ +// N7 + + N10 +// \ / +// \ / +// N6 +------+ N11 +// HEXAGONAL PRISM +// N2 +------+ N3 +// / \ +// / \ +// N1 + + N4 +// \ / +// \ / +// N0 +------+ N5 +*/ +static int HexPrism_F [8][7] = { // FORWARD + { 0, 1, 2, 3, 4, 5, 0 }, + { 6,11,10, 9, 8, 7, 6 }, + { 0, 6, 7, 1, 0, 0, 0 }, + { 1, 7, 8, 2, 1, 1, 1 }, + { 2, 8, 9, 3, 2, 2, 2 }, + { 3, 9,10, 4, 3, 3, 3 }, + { 4,10,11, 5, 4, 4, 4 }, + { 5,11, 6, 0, 5, 5, 5 }}; +static int HexPrism_RE [8][7] = { // REVERSED -> EXTERNAL + { 0, 5, 4, 3, 2, 1, 0 }, + { 6,11,10, 9, 8, 7, 6 }, + { 0, 6, 7, 1, 0, 0, 0 }, + { 1, 7, 8, 2, 1, 1, 1 }, + { 2, 8, 9, 3, 2, 2, 2 }, + { 3, 9,10, 4, 3, 3, 3 }, + { 4,10,11, 5, 4, 4, 4 }, + { 5,11, 6, 0, 5, 5, 5 }}; +static int HexPrism_nbN [] = { 6, 6, 4, 4, 4, 4, 4, 4 }; /* @@ -202,18 +211,13 @@ static int Hexa_nbN [] = { 4, 4, 4, 4, 4, 4 }; // + // N2 */ -static int QuadTetra_F [4][7] = { // FORWARD == EXTERNAL +static int QuadTetra_F [4][7] = { // FORWARD { 0, 4, 1, 5, 2, 6, 0 }, // All faces have external normals { 0, 7, 3, 8, 1, 4, 0 }, { 1, 8, 3, 9, 2, 5, 1 }, { 0, 6, 2, 9, 3, 7, 0 }}; -static int QuadTetra_R [4][7] = { // REVERSED - { 0, 4, 1, 5, 2, 6, 0 }, // All faces but a bottom have external normals - { 0, 4, 1, 8, 3, 7, 0 }, - { 1, 5, 2, 9, 3, 8, 1 }, - { 0, 7, 3, 9, 2, 6, 0 }}; static int QuadTetra_RE [4][7] = { // REVERSED -> FORWARD (EXTERNAL) - { 0, 6, 2, 5, 1, 4, 0 }, // All faces have external normals + { 0, 6, 2, 5, 1, 4, 0 }, // All faces have external normals { 0, 4, 1, 8, 3, 7, 0 }, { 1, 5, 2, 9, 3, 8, 1 }, { 0, 7, 3, 9, 2, 6, 0 }}; @@ -240,18 +244,12 @@ static int QuadTetra_nbN [] = { 6, 6, 6, 6 }; // | | // 0+----+----+3 // 8 -static int QuadPyram_F [5][9] = { // FORWARD == EXTERNAL +static int QuadPyram_F [5][9] = { // FORWARD { 0, 5, 1, 6, 2, 7, 3, 8, 0 }, // All faces have external normals { 0, 9, 4, 10,1, 5, 0, 4, 4 }, { 1, 10,4, 11,2, 6, 1, 4, 4 }, { 2, 11,4, 12,3, 7, 2, 4, 4 }, { 3, 12,4, 9, 0, 8, 3, 4, 4 }}; -static int QuadPyram_R [5][9] = { // REVERSED - { 0, 5, 1, 6, 2, 7, 3, 8, 0 }, // All faces but a bottom have external normals - { 0, 5, 1, 10,4, 9, 0, 4, 4 }, - { 1, 6, 2, 11,4, 10,1, 4, 4 }, - { 2, 7, 3, 12,4, 11,2, 4, 4 }, - { 3, 8, 0, 9, 4, 12,3, 4, 4 }}; static int QuadPyram_RE [5][9] = { // REVERSED -> FORWARD (EXTERNAL) { 0, 8, 3, 7, 2, 6, 1, 5, 0 }, // All faces but a bottom have external normals { 0, 5, 1, 10,4, 9, 0, 4, 4 }, @@ -271,9 +269,6 @@ static int QuadPyram_nbN [] = { 8, 6, 6, 6, 6 }; // | | | // | +13 | QUADRATIC // | | | PENTAHEDRON -// | | | -// | | | -// | | | // 12+ | +14 // | | | // | | | @@ -286,84 +281,74 @@ static int QuadPyram_nbN [] = { 8, 6, 6, 6, 6 }; // 8 */ static int QuadPenta_F [5][9] = { // FORWARD - { 0, 6, 1, 7, 2, 8, 0, 0, 0 }, // Top face has an internal normal, other - external - { 3, 9, 4, 10,5, 11,3, 3, 3 }, // 0 is bottom, 1 is top face - { 0, 8, 2, 14,5, 11,3, 12,0 }, - { 1, 13,4, 10,5, 14,2, 7, 1 }, - { 0, 12,3, 9, 4, 13,1, 6, 0 }}; -static int QuadPenta_R [5][9] = { // REVERSED - { 0, 6, 1, 7, 2, 8, 0, 0, 0 }, // Bottom face has an internal normal, other - external - { 3, 9, 4, 10,5, 11,3, 3, 3 }, // 0 is bottom, 1 is top face - { 0, 12,3, 11,5, 14,2, 8, 0 }, - { 1, 7, 2, 14,5, 10,4, 13,1 }, - { 0, 6, 1, 13,4, 9, 3, 12,0 }}; -static int QuadPenta_FE [5][9] = { // FORWARD -> EXTERNAL { 0, 6, 1, 7, 2, 8, 0, 0, 0 }, - { 3,11, 5, 10,4, 9, 3, 3, 3 }, - { 0, 8, 2, 14,5, 11,3, 12,0 }, + { 3, 11,5, 10,4, 9, 3, 3, 3 }, + { 0, 12,3, 9, 4, 13,1, 6, 0 }, { 1, 13,4, 10,5, 14,2, 7, 1 }, - { 0, 12,3, 9, 4, 13,1, 6, 0 }}; + { 0, 8, 2, 14,5, 11,3, 12,0 }}; static int QuadPenta_RE [5][9] = { // REVERSED -> EXTERNAL { 0, 8, 2, 7, 1, 6, 0, 0, 0 }, { 3, 9, 4, 10,5, 11,3, 3, 3 }, - { 0, 12,3, 11,5, 14,2, 8, 0 }, + { 0, 6, 1, 13,4, 9, 3, 12,0 }, { 1, 7, 2, 14,5, 10,4, 13,1 }, - { 0, 6, 1, 13,4, 9, 3, 12,0 }}; + { 0, 12,3, 11,5, 14,2, 8, 0 }}; static int QuadPenta_nbN [] = { 6, 6, 8, 8, 8 }; /* -// 13 -// N5+-----+-----+N6 -// /| /| -// 12+ | 14+ | -// / | / | -// N4+-----+-----+N7 | QUADRATIC -// | | 15 | | HEXAHEDRON -// | | | | -// | 17+ | +18 -// | | | | -// | | | | -// | | | | -// 16+ | +19 | -// | | | | -// | | 9 | | -// | N1+-----+-|---+N2 -// | / | / -// | +8 | +10 -// |/ |/ -// N0+-----+-----+N3 -// 11 +// 13 +// N5+-----+-----+N6 +-----+-----+ +// /| /| /| /| +// 12+ | 14+ | + | +25 + | +// / | / | / | / | +// N4+-----+-----+N7 | QUADRATIC +-----+-----+ | Central nodes +// | | 15 | | HEXAHEDRON | | | | of tri-quadratic +// | | | | | | | | HEXAHEDRON +// | 17+ | +18 | + 22+ | + +// | | | | |21 | | | +// | | | | | + | 26+ | + | +// | | | | | | |23 | +// 16+ | +19 | + | +24 + | +// | | | | | | | | +// | | 9 | | | | | | +// | N1+-----+-|---+N2 | +-----+-|---+ +// | / | / | / | / +// | +8 | +10 | + 20+ | + +// |/ |/ |/ |/ +// N0+-----+-----+N3 +-----+-----+ +// 11 */ static int QuadHexa_F [6][9] = { // FORWARD - { 0, 8, 1, 9, 2, 10,3, 11,0 }, // opposite faces are neighbouring, - { 4, 12,5, 13,6, 14,7, 15,4 }, // odd face(1,3,5) normal is internal, even(0,2,4) - external - { 1, 8, 0, 16,4, 12,5, 17,1 }, // same index nodes of opposite faces are linked - { 2, 10,3, 19,7, 14,6, 18,2 }, - { 0, 11,3, 19,7, 15,4, 16,0 }, - { 1, 9, 2, 18,6, 13,5, 17,1 }}; -// static int Hexa_R [6][5] = { // REVERSED -// { 0, 3, 2, 1, 0 }, // opposite faces are neighbouring, -// { 4, 7, 6, 5, 4 }, // odd face(1,3,5) normal is external, even(0,2,4) - internal -// { 1, 5, 4, 0, 1 }, // same index nodes of opposite faces are linked -// { 2, 6, 7, 3, 2 }, -// { 0, 4, 7, 3, 0 }, -// { 1, 5, 6, 2, 1 }}; -static int QuadHexa_FE [6][9] = { // FORWARD -> EXTERNAL - { 0, 8, 1, 9, 2, 10,3, 11,0 }, // opposite faces are neighbouring, - { 4, 15,7, 14,6, 13,5, 12,4 }, // all face normals are external, - { 0, 16,4, 12,5, 17,1, 8, 0 }, // links in opposite faces: 0-0, 1-3, 2-2, 3-1 + { 0, 8, 1, 9, 2, 10,3, 11,0 }, // all face normals are external, + { 4, 15,7, 14,6, 13,5, 12,4 }, + { 0, 16,4, 12,5, 17,1, 8, 0 }, + { 1, 17,5, 13,6, 18,2, 9, 1 }, { 3, 10,2, 18,6, 14,7, 19,3 }, - { 0, 11,3, 19,7, 15,4, 16,0 }, - { 1, 17,5, 13,6, 18,2, 9, 1 }}; + { 0, 11,3, 19,7, 15,4, 16,0 }}; static int QuadHexa_RE [6][9] = { // REVERSED -> EXTERNAL - { 0, 11,3, 10,2, 9, 1, 8, 0 }, // opposite faces are neighbouring, - { 4, 12,5, 13,6, 14,7, 15,4 }, // all face normals are external, - { 0, 8, 1, 17,5, 12,4, 16,0 }, // links in opposite faces: 0-0, 1-3, 2-2, 3-1 + { 0, 11,3, 10,2, 9, 1, 8, 0 }, // all face normals are external + { 4, 12,5, 13,6, 14,7, 15,4 }, + { 0, 8, 1, 17,5, 12,4, 16,0 }, + { 1, 9, 2, 18,6, 13,5, 17,1 }, { 3, 19,7, 14,6, 18,2, 10,3 }, - { 0, 16,4, 15,7, 19,3, 11,0 }, - { 1, 9, 2, 18,6, 13,5, 17,1 }}; + { 0, 16,4, 15,7, 19,3, 11,0 }}; static int QuadHexa_nbN [] = { 8, 8, 8, 8, 8, 8 }; +static int TriQuadHexa_F [6][9] = { // FORWARD + { 0, 8, 1, 9, 2, 10,3, 11, 20 }, // all face normals are external + { 4, 15,7, 14,6, 13,5, 12, 25 }, + { 0, 16,4, 12,5, 17,1, 8, 21 }, + { 1, 17,5, 13,6, 18,2, 9, 22 }, + { 3, 10,2, 18,6, 14,7, 19, 23 }, + { 0, 11,3, 19,7, 15,4, 16, 24 }}; +static int TriQuadHexa_RE [6][9] = { // REVERSED -> EXTERNAL + { 0, 11,3, 10,2, 9, 1, 8, 20 }, // opposite faces are neighbouring, + { 4, 12,5, 13,6, 14,7, 15, 25 }, // all face normals are external + { 0, 8, 1, 17,5, 12,4, 16, 21 }, + { 1, 9, 2, 18,6, 13,5, 17, 22 }, + { 3, 19,7, 14,6, 18,2, 10, 23 }, + { 0, 16,4, 15,7, 19,3, 11, 24 }}; +static int TriQuadHexa_nbN [] = { 9, 9, 9, 9, 9, 9 }; + // ======================================================== // to perform some calculations without linkage to CASCADE @@ -376,44 +361,86 @@ struct XYZ { XYZ( double X, double Y, double Z ) { x = X; y = Y; z = Z; } XYZ( const XYZ& other ) { x = other.x; y = other.y; z = other.z; } XYZ( const SMDS_MeshNode* n ) { x = n->X(); y = n->Y(); z = n->Z(); } - XYZ operator-( const XYZ& other ); - XYZ Crossed( const XYZ& other ); - double Dot( const XYZ& other ); - double Magnitude(); + inline XYZ operator-( const XYZ& other ); + inline XYZ operator+( const XYZ& other ); + inline XYZ Crossed( const XYZ& other ); + inline double Dot( const XYZ& other ); + inline double Magnitude(); + inline double SquareMagnitude(); }; -XYZ XYZ::operator-( const XYZ& Right ) { +inline XYZ XYZ::operator-( const XYZ& Right ) { return XYZ(x - Right.x, y - Right.y, z - Right.z); } -XYZ XYZ::Crossed( const XYZ& Right ) { +inline XYZ XYZ::operator+( const XYZ& Right ) { + return XYZ(x + Right.x, y + Right.y, z + Right.z); +} +inline XYZ XYZ::Crossed( const XYZ& Right ) { return XYZ (y * Right.z - z * Right.y, z * Right.x - x * Right.z, x * Right.y - y * Right.x); } -double XYZ::Dot( const XYZ& Other ) { +inline double XYZ::Dot( const XYZ& Other ) { return(x * Other.x + y * Other.y + z * Other.z); } -double XYZ::Magnitude() { +inline double XYZ::Magnitude() { return sqrt (x * x + y * y + z * z); } +inline double XYZ::SquareMagnitude() { + return (x * x + y * y + z * z); +} + + //================================================================================ + /*! + * \brief Return linear type corresponding to a quadratic one + */ + //================================================================================ + + SMDS_VolumeTool::VolumeType quadToLinear(SMDS_VolumeTool::VolumeType quadType) + { + SMDS_VolumeTool::VolumeType linType = SMDS_VolumeTool::VolumeType( int(quadType)-4 ); + const int nbCornersByQuad = SMDS_VolumeTool::NbCornerNodes( quadType ); + if ( SMDS_VolumeTool::NbCornerNodes( linType ) == nbCornersByQuad ) + return linType; + + int iLin = 0; + for ( ; iLin < SMDS_VolumeTool::NB_VOLUME_TYPES; ++iLin ) + if ( SMDS_VolumeTool::NbCornerNodes( SMDS_VolumeTool::VolumeType( iLin )) == nbCornersByQuad) + return SMDS_VolumeTool::VolumeType( iLin ); + + return SMDS_VolumeTool::UNKNOWN; + } + +} // namespace + +//================================================================================ +/*! + * \brief Saver/restorer of a SMDS_VolumeTool::myCurFace + */ +//================================================================================ + +struct SMDS_VolumeTool::SaveFacet +{ + SMDS_VolumeTool::Facet mySaved; + SMDS_VolumeTool::Facet& myToRestore; + SaveFacet( SMDS_VolumeTool::Facet& facet ): myToRestore( facet ) + { + mySaved = facet; + } + ~SaveFacet() + { + if ( myToRestore.myIndex != mySaved.myIndex ) + myToRestore = mySaved; + } +}; //======================================================================= //function : SMDS_VolumeTool -//purpose : +//purpose : //======================================================================= SMDS_VolumeTool::SMDS_VolumeTool () - : myVolume( 0 ), - myPolyedre( 0 ), - myVolForward( true ), - myNbFaces( 0 ), - myVolumeNbNodes( 0 ), - myVolumeNodes( NULL ), - myExternalFaces( false ), - myFaceNbNodes( 0 ), - myCurFace( -1 ), - myFaceNodeIndices( NULL ), - myFaceNodes( NULL ) { + Set( 0 ); } //======================================================================= @@ -421,20 +448,10 @@ SMDS_VolumeTool::SMDS_VolumeTool () //purpose : //======================================================================= -SMDS_VolumeTool::SMDS_VolumeTool (const SMDS_MeshElement* theVolume) - : myVolume( 0 ), - myPolyedre( 0 ), - myVolForward( true ), - myNbFaces( 0 ), - myVolumeNbNodes( 0 ), - myVolumeNodes( NULL ), - myExternalFaces( false ), - myFaceNbNodes( 0 ), - myCurFace( -1 ), - myFaceNodeIndices( NULL ), - myFaceNodes( NULL ) +SMDS_VolumeTool::SMDS_VolumeTool (const SMDS_MeshElement* theVolume, + const bool ignoreCentralNodes) { - Set( theVolume ); + Set( theVolume, ignoreCentralNodes ); } //======================================================================= @@ -444,14 +461,7 @@ SMDS_VolumeTool::SMDS_VolumeTool (const SMDS_MeshElement* theVolume) SMDS_VolumeTool::~SMDS_VolumeTool() { - if (myVolumeNodes != NULL) { - delete [] myVolumeNodes; - myVolumeNodes = NULL; - } - if (myFaceNodes != NULL) { - delete [] myFaceNodes; - myFaceNodes = NULL; - } + myCurFace.myNodeIndices = NULL; } //======================================================================= @@ -459,78 +469,74 @@ SMDS_VolumeTool::~SMDS_VolumeTool() //purpose : Set volume to iterate on //======================================================================= -bool SMDS_VolumeTool::Set (const SMDS_MeshElement* theVolume) +bool SMDS_VolumeTool::Set (const SMDS_MeshElement* theVolume, + const bool ignoreCentralNodes) { + // reset fields myVolume = 0; myPolyedre = 0; + myIgnoreCentralNodes = ignoreCentralNodes; myVolForward = true; myNbFaces = 0; - myVolumeNbNodes = 0; - if (myVolumeNodes != NULL) { - delete [] myVolumeNodes; - myVolumeNodes = NULL; - } + myVolumeNodes.clear(); + myPolyIndices.clear(); + myPolyQuantities.clear(); + myPolyFacetOri.clear(); + myFwdLinks.clear(); myExternalFaces = false; - myFaceNbNodes = 0; - myCurFace = -1; - myFaceNodeIndices = NULL; - if (myFaceNodes != NULL) { - delete [] myFaceNodes; - myFaceNodes = NULL; - } + myAllFacesNodeIndices_F = 0; + myAllFacesNodeIndices_RE = 0; + myAllFacesNbNodes = 0; + + myCurFace.myIndex = -1; + myCurFace.myNodeIndices = NULL; + myCurFace.myNodes.clear(); + + // set volume data + if ( !theVolume || theVolume->GetType() != SMDSAbs_Volume ) + return false; - if ( theVolume && theVolume->GetType() == SMDSAbs_Volume ) + myVolume = theVolume; + myNbFaces = theVolume->NbFaces(); + if ( myVolume->IsPoly() ) { - myVolume = theVolume; + myPolyedre = dynamic_cast( myVolume ); + myPolyFacetOri.resize( myNbFaces, 0 ); + } - myNbFaces = theVolume->NbFaces(); - myVolumeNbNodes = theVolume->NbNodes(); + // set nodes + int iNode = 0; + myVolumeNodes.resize( myVolume->NbNodes() ); + SMDS_ElemIteratorPtr nodeIt = myVolume->nodesIterator(); + while ( nodeIt->more() ) + myVolumeNodes[ iNode++ ] = static_cast( nodeIt->next() ); - // set volume nodes - int iNode = 0; - myVolumeNodes = new const SMDS_MeshNode* [myVolumeNbNodes]; - SMDS_ElemIteratorPtr nodeIt = myVolume->nodesIterator(); - while ( nodeIt->more() ) { - myVolumeNodes[ iNode++ ] = static_cast( nodeIt->next() ); - } + // check validity + if ( !setFace(0) ) + return ( myVolume = 0 ); - if (myVolume->IsPoly()) { - myPolyedre = static_cast( myVolume ); - if (!myPolyedre) { - MESSAGE("Warning: bad volumic element"); - return false; - } - } - else { - switch ( myVolumeNbNodes ) { - case 4: - case 5: - case 6: - case 8: - case 10: - case 13: - case 15: - case 20: { - // define volume orientation - XYZ botNormal; - GetFaceNormal( 0, botNormal.x, botNormal.y, botNormal.z ); - const SMDS_MeshNode* topNode = myVolumeNodes[ myVolumeNbNodes - 1 ]; - const SMDS_MeshNode* botNode = myVolumeNodes[ 0 ]; - XYZ upDir (topNode->X() - botNode->X(), - topNode->Y() - botNode->Y(), - topNode->Z() - botNode->Z() ); - myVolForward = ( botNormal.Dot( upDir ) < 0 ); - break; - } - default: - break; - } + if ( !myPolyedre ) + { + // define volume orientation + XYZ botNormal; + if ( GetFaceNormal( 0, botNormal.x, botNormal.y, botNormal.z )) + { + const SMDS_MeshNode* botNode = myVolumeNodes[ 0 ]; + int topNodeIndex = myVolume->NbCornerNodes() - 1; + while ( !IsLinked( 0, topNodeIndex, /*ignoreMediumNodes=*/true )) --topNodeIndex; + const SMDS_MeshNode* topNode = myVolumeNodes[ topNodeIndex ]; + XYZ upDir (topNode->X() - botNode->X(), + topNode->Y() - botNode->Y(), + topNode->Z() - botNode->Z() ); + myVolForward = ( botNormal.Dot( upDir ) < 0 ); } + if ( !myVolForward ) + myCurFace.myIndex = -1; // previous setFace(0) didn't take myVolForward into account } - return ( myVolume != 0 ); + return true; } //======================================================================= @@ -554,10 +560,10 @@ void SMDS_VolumeTool::Inverse () } myVolForward = !myVolForward; - myCurFace = -1; + myCurFace.myIndex = -1; // inverse top and bottom faces - switch ( myVolumeNbNodes ) { + switch ( myVolumeNodes.size() ) { case 4: SWAP_NODES( myVolumeNodes, 1, 2 ); break; @@ -572,6 +578,12 @@ void SMDS_VolumeTool::Inverse () SWAP_NODES( myVolumeNodes, 1, 3 ); SWAP_NODES( myVolumeNodes, 5, 7 ); break; + case 12: + SWAP_NODES( myVolumeNodes, 1, 5 ); + SWAP_NODES( myVolumeNodes, 2, 4 ); + SWAP_NODES( myVolumeNodes, 7, 11 ); + SWAP_NODES( myVolumeNodes, 8, 10 ); + break; case 10: SWAP_NODES( myVolumeNodes, 1, 2 ); @@ -600,6 +612,17 @@ void SMDS_VolumeTool::Inverse () SWAP_NODES( myVolumeNodes, 13, 14 ); SWAP_NODES( myVolumeNodes, 17, 19 ); break; + case 27: + SWAP_NODES( myVolumeNodes, 1, 3 ); + SWAP_NODES( myVolumeNodes, 5, 7 ); + SWAP_NODES( myVolumeNodes, 8, 11 ); + SWAP_NODES( myVolumeNodes, 9, 10 ); + SWAP_NODES( myVolumeNodes, 12, 15 ); + SWAP_NODES( myVolumeNodes, 13, 14 ); + SWAP_NODES( myVolumeNodes, 17, 19 ); + SWAP_NODES( myVolumeNodes, 21, 24 ); + SWAP_NODES( myVolumeNodes, 22, 23 ); + break; default:; } } @@ -614,26 +637,18 @@ SMDS_VolumeTool::VolumeType SMDS_VolumeTool::GetVolumeType() const if ( myPolyedre ) return POLYHEDA; - if ( myVolume ) { -// static const VolumeType types[] = { -// TETRA, // myVolumeNbNodes = 4 -// PYRAM, // myVolumeNbNodes = 5 -// PENTA, // myVolumeNbNodes = 6 -// UNKNOWN, // myVolumeNbNodes = 7 -// HEXA // myVolumeNbNodes = 8 -// }; -// return types[ myVolumeNbNodes - 4 ]; - switch(myVolumeNbNodes) { - case 4: return TETRA; break; - case 5: return PYRAM; break; - case 6: return PENTA; break; - case 8: return HEXA; break; - case 10: return QUAD_TETRA; break; - case 13: return QUAD_PYRAM; break; - case 15: return QUAD_PENTA; break; - case 20: return QUAD_HEXA; break; - default: break; - } + switch( myVolumeNodes.size() ) { + case 4: return TETRA; + case 5: return PYRAM; + case 6: return PENTA; + case 8: return HEXA; + case 12: return HEX_PRISM; + case 10: return QUAD_TETRA; + case 13: return QUAD_PYRAM; + case 15: return QUAD_PENTA; + case 20: return QUAD_HEXA; + case 27: return QUAD_HEXA; + default: break; } return UNKNOWN; @@ -649,28 +664,18 @@ static double getTetraVolume(const SMDS_MeshNode* n1, const SMDS_MeshNode* n3, const SMDS_MeshNode* n4) { - double X1 = n1->X(); - double Y1 = n1->Y(); - double Z1 = n1->Z(); - - double X2 = n2->X(); - double Y2 = n2->Y(); - double Z2 = n2->Z(); - - double X3 = n3->X(); - double Y3 = n3->Y(); - double Z3 = n3->Z(); - - double X4 = n4->X(); - double Y4 = n4->Y(); - double Z4 = n4->Z(); - - double Q1 = -(X1-X2)*(Y3*Z4-Y4*Z3); - double Q2 = (X1-X3)*(Y2*Z4-Y4*Z2); - double R1 = -(X1-X4)*(Y2*Z3-Y3*Z2); - double R2 = -(X2-X3)*(Y1*Z4-Y4*Z1); - double S1 = (X2-X4)*(Y1*Z3-Y3*Z1); - double S2 = -(X3-X4)*(Y1*Z2-Y2*Z1); + double p1[3], p2[3], p3[3], p4[3]; + n1->GetXYZ( p1 ); + n2->GetXYZ( p2 ); + n3->GetXYZ( p3 ); + n4->GetXYZ( p4 ); + + double Q1 = -(p1[ 0 ]-p2[ 0 ])*(p3[ 1 ]*p4[ 2 ]-p4[ 1 ]*p3[ 2 ]); + double Q2 = (p1[ 0 ]-p3[ 0 ])*(p2[ 1 ]*p4[ 2 ]-p4[ 1 ]*p2[ 2 ]); + double R1 = -(p1[ 0 ]-p4[ 0 ])*(p2[ 1 ]*p3[ 2 ]-p3[ 1 ]*p2[ 2 ]); + double R2 = -(p2[ 0 ]-p3[ 0 ])*(p1[ 1 ]*p4[ 2 ]-p4[ 1 ]*p1[ 2 ]); + double S1 = (p2[ 0 ]-p4[ 0 ])*(p1[ 1 ]*p3[ 2 ]-p3[ 1 ]*p1[ 2 ]); + double S2 = -(p3[ 0 ]-p4[ 0 ])*(p1[ 1 ]*p2[ 2 ]-p2[ 1 ]*p1[ 2 ]); return (Q1+Q2+R1+R2+S1+S2)/6.0; } @@ -693,30 +698,27 @@ double SMDS_VolumeTool::GetSize() const // split a polyhedron into tetrahedrons + SaveFacet savedFacet( myCurFace ); SMDS_VolumeTool* me = const_cast< SMDS_VolumeTool* > ( this ); - XYZ baryCenter; - me->GetBaryCenter(baryCenter.x, baryCenter.y, baryCenter.z); - SMDS_MeshNode bcNode ( baryCenter.x, baryCenter.y, baryCenter.z ); - for ( int f = 0; f < NbFaces(); ++f ) { - bool externalFace = me->IsFaceExternal( f ); // it calls setFace() - for ( int n = 2; n < myFaceNbNodes; ++n ) + me->setFace( f ); + XYZ area (0,0,0), p1( myCurFace.myNodes[0] ); + for ( int n = 0; n < myCurFace.myNbNodes; ++n ) { - double Vn = getTetraVolume( myFaceNodes[ 0 ], - myFaceNodes[ n-1 ], - myFaceNodes[ n ], - & bcNode ); -/// cout <<"++++ " << Vn << " nodes " <GetID() << " " <GetID() << " " <GetID() << " < " << V << endl; - V += externalFace ? -Vn : Vn; + XYZ p2( myCurFace.myNodes[ n+1 ]); + area = area + p1.Crossed( p2 ); + p1 = p2; } + V += p1.Dot( area ); } + V /= 6; } else { const static int ind[] = { - 0, 1, 3, 6, 11, 19, 32, 46, 66}; - const static int vtab[][4] = { + 0, 1, 3, 6, 11, 23, 31, 44, 58, 78 }; + const static int vtab[][4] = { // decomposition into tetra in the order of enum VolumeType // tetrahedron { 0, 1, 2, 3 }, // pyramid @@ -732,6 +734,22 @@ double SMDS_VolumeTool::GetSize() const { 1, 3, 6, 2 }, { 4, 6, 3, 7 }, { 1, 4, 6, 3 }, + // hexagonal prism + { 0, 1, 2, 7 }, + { 0, 7, 8, 6 }, + { 2, 7, 8, 0 }, + + { 0, 3, 4, 9 }, + { 0, 9, 10, 6 }, + { 4, 9, 10, 0 }, + + { 0, 3, 4, 9 }, + { 0, 9, 10, 6 }, + { 4, 9, 10, 0 }, + + { 0, 4, 5, 10 }, + { 0, 10, 11, 6 }, + { 5, 10, 11, 0 }, // quadratic tetrahedron { 0, 4, 6, 7 }, @@ -825,18 +843,44 @@ bool SMDS_VolumeTool::GetBaryCenter(double & X, double & Y, double & Z) const if ( !myVolume ) return false; - for ( int i = 0; i < myVolumeNbNodes; i++ ) { + for ( int i = 0; i < myVolumeNodes.size(); i++ ) { X += myVolumeNodes[ i ]->X(); Y += myVolumeNodes[ i ]->Y(); Z += myVolumeNodes[ i ]->Z(); } - X /= myVolumeNbNodes; - Y /= myVolumeNbNodes; - Z /= myVolumeNbNodes; + X /= myVolumeNodes.size(); + Y /= myVolumeNodes.size(); + Z /= myVolumeNodes.size(); return true; } +//================================================================================ +/*! + * \brief Classify a point + * \param tol - thickness of faces + */ +//================================================================================ + +bool SMDS_VolumeTool::IsOut(double X, double Y, double Z, double tol) const +{ + // LIMITATION: for convex volumes only + XYZ p( X,Y,Z ); + for ( int iF = 0; iF < myNbFaces; ++iF ) + { + XYZ faceNormal; + if ( !GetFaceNormal( iF, faceNormal.x, faceNormal.y, faceNormal.z )) + continue; + if ( !IsFaceExternal( iF )) + faceNormal = XYZ() - faceNormal; // reverse + + XYZ face2p( p - XYZ( myCurFace.myNodes[0] )); + if ( face2p.Dot( faceNormal ) > tol ) + return true; + } + return false; +} + //======================================================================= //function : SetExternalNormal //purpose : Node order will be so that faces normals are external @@ -845,7 +889,7 @@ bool SMDS_VolumeTool::GetBaryCenter(double & X, double & Y, double & Z) const void SMDS_VolumeTool::SetExternalNormal () { myExternalFaces = true; - myCurFace = -1; + myCurFace.myIndex = -1; } //======================================================================= @@ -853,11 +897,11 @@ void SMDS_VolumeTool::SetExternalNormal () //purpose : Return number of nodes in the array of face nodes //======================================================================= -int SMDS_VolumeTool::NbFaceNodes( int faceIndex ) +int SMDS_VolumeTool::NbFaceNodes( int faceIndex ) const { - if ( !setFace( faceIndex )) - return 0; - return myFaceNbNodes; + if ( !setFace( faceIndex )) + return 0; + return myCurFace.myNbNodes; } //======================================================================= @@ -868,11 +912,11 @@ int SMDS_VolumeTool::NbFaceNodes( int faceIndex ) // the last node == the first one. //======================================================================= -const SMDS_MeshNode** SMDS_VolumeTool::GetFaceNodes( int faceIndex ) +const SMDS_MeshNode** SMDS_VolumeTool::GetFaceNodes( int faceIndex ) const { if ( !setFace( faceIndex )) return 0; - return myFaceNodes; + return &myCurFace.myNodes[0]; } //======================================================================= @@ -883,15 +927,12 @@ const SMDS_MeshNode** SMDS_VolumeTool::GetFaceNodes( int faceIndex ) // the last node index == the first one. //======================================================================= -const int* SMDS_VolumeTool::GetFaceNodesIndices( int faceIndex ) +const int* SMDS_VolumeTool::GetFaceNodesIndices( int faceIndex ) const { - if (myVolume->IsPoly()) { - MESSAGE("Warning: attempt to obtain FaceNodesIndices of polyhedral volume"); - return NULL; - } if ( !setFace( faceIndex )) return 0; - return myFaceNodeIndices; + + return myCurFace.myNodeIndices; } //======================================================================= @@ -900,59 +941,233 @@ const int* SMDS_VolumeTool::GetFaceNodesIndices( int faceIndex ) //======================================================================= bool SMDS_VolumeTool::GetFaceNodes (int faceIndex, - set& theFaceNodes ) + set& theFaceNodes ) const { if ( !setFace( faceIndex )) return false; theFaceNodes.clear(); - int iNode, nbNode = myFaceNbNodes; - for ( iNode = 0; iNode < nbNode; iNode++ ) - theFaceNodes.insert( myFaceNodes[ iNode ]); + theFaceNodes.insert( myCurFace.myNodes.begin(), myCurFace.myNodes.end() ); return true; } +namespace +{ + struct NLink : public std::pair + { + int myOri; + NLink(const SMDS_MeshNode* n1=0, const SMDS_MeshNode* n2=0, int ori=1 ) + { + if ( n1 ) + { + if (( myOri = ( n1->GetID() < n2->GetID() ))) + { + first = n1->GetID(); + second = n2->GetID(); + } + else + { + myOri = -1; + first = n2->GetID(); + second = n1->GetID(); + } + myOri *= ori; + } + else + { + myOri = first = second = 0; + } + } + //int Node1() const { return myOri == -1 ? second : first; } + + //bool IsSameOri( const std::pair& link ) const { return link.first == Node1(); } + }; +} + //======================================================================= //function : IsFaceExternal -//purpose : Check normal orientation of a returned face +//purpose : Check normal orientation of a given face //======================================================================= -bool SMDS_VolumeTool::IsFaceExternal( int faceIndex ) +bool SMDS_VolumeTool::IsFaceExternal( int faceIndex ) const { if ( myExternalFaces || !myVolume ) return true; - if (myVolume->IsPoly()) { - XYZ aNormal, baryCenter, p0 (myPolyedre->GetFaceNode(faceIndex + 1, 1)); - GetFaceNormal(faceIndex, aNormal.x, aNormal.y, aNormal.z); - GetBaryCenter(baryCenter.x, baryCenter.y, baryCenter.z); - XYZ insideVec (baryCenter - p0); - if (insideVec.Dot(aNormal) > 0) - return false; + if ( !myPolyedre ) // all classical volumes have external facet normals return true; + + SMDS_VolumeTool* me = const_cast< SMDS_VolumeTool* >( this ); + + if ( myPolyFacetOri[ faceIndex ]) + return myPolyFacetOri[ faceIndex ] > 0; + + int ori = 0; // -1-in, +1-out, 0-undef + double minProj, maxProj; + if ( projectNodesToNormal( faceIndex, minProj, maxProj )) + { + // all nodes are on the same side of the facet + ori = ( minProj < 0 ? +1 : -1 ); + me->myPolyFacetOri[ faceIndex ] = ori; + + if ( !myFwdLinks.empty() ) // concave polyhedron; collect oriented links + for ( int i = 0; i < myCurFace.myNbNodes; ++i ) + { + NLink link( myCurFace.myNodes[i], myCurFace.myNodes[i+1], ori ); + me->myFwdLinks.insert( make_pair( link, link.myOri )); + } + return ori > 0; } - switch ( myVolumeNbNodes ) { - case 4: - case 5: - case 10: - case 13: - // only the bottom of a reversed tetrahedron can be internal - return ( myVolForward || faceIndex != 0 ); - case 6: - case 15: - // in a forward pentahedron, the top is internal, in a reversed one - bottom - return ( myVolForward ? faceIndex != 1 : faceIndex != 0 ); - case 8: - case 20: { - // in a forward hexahedron, even face normal is external, odd - internal - bool odd = faceIndex % 2; - return ( myVolForward ? !odd : odd ); + SaveFacet savedFacet( myCurFace ); + + // concave polyhedron + + if ( myFwdLinks.empty() ) // get links of the least ambiguously oriented facet + { + for ( size_t i = 0; i < myPolyFacetOri.size() && !ori; ++i ) + ori = myPolyFacetOri[ i ]; + + if ( !ori ) // none facet is oriented yet + { + // find the least ambiguously oriented facet + int faceMostConvex = -1; + std::map< double, int > convexity2face; + for ( size_t iF = 0; iF < myPolyFacetOri.size() && faceMostConvex < 0; ++iF ) + { + if ( projectNodesToNormal( iF, minProj, maxProj )) + { + // all nodes are on the same side of the facet + me->myPolyFacetOri[ iF ] = ( minProj < 0 ? +1 : -1 ); + faceMostConvex = iF; + } + else + { + ori = ( -minProj < maxProj ? -1 : +1 ); + double convexity = std::min( -minProj, maxProj ) / std::max( -minProj, maxProj ); + convexity2face.insert( make_pair( convexity, iF * ori )); + } + } + if ( faceMostConvex < 0 ) // none facet has nodes on the same side + { + // use the least ambiguous facet + faceMostConvex = convexity2face.begin()->second; + ori = ( faceMostConvex < 0 ? -1 : +1 ); + faceMostConvex = std::abs( faceMostConvex ); + me->myPolyFacetOri[ faceMostConvex ] = ori; + } + } + // collect links of the oriented facets in myFwdLinks + for ( size_t iF = 0; iF < myPolyFacetOri.size(); ++iF ) + { + ori = myPolyFacetOri[ iF ]; + if ( !ori ) continue; + setFace( iF ); + for ( int i = 0; i < myCurFace.myNbNodes; ++i ) + { + NLink link( myCurFace.myNodes[i], myCurFace.myNodes[i+1], ori ); + me->myFwdLinks.insert( make_pair( link, link.myOri )); + } + } } - default:; + + // compare orientation of links of the facet with myFwdLinks + ori = 0; + setFace( faceIndex ); + vector< NLink > links( myCurFace.myNbNodes ), links2; + for ( int i = 0; i < myCurFace.myNbNodes && !ori; ++i ) + { + NLink link( myCurFace.myNodes[i], myCurFace.myNodes[i+1] ); + std::map::const_iterator l2o = myFwdLinks.find( link ); + if ( l2o != myFwdLinks.end() ) + ori = link.myOri * l2o->second * -1; + links[ i ] = link; } - return false; + while ( !ori ) // the facet has no common links with already oriented facets + { + // orient and collect links of other non-oriented facets + for ( size_t iF = 0; iF < myPolyFacetOri.size(); ++iF ) + { + if ( myPolyFacetOri[ iF ] ) continue; // already oriented + setFace( iF ); + links2.clear(); + ori = 0; + for ( int i = 0; i < myCurFace.myNbNodes && !ori; ++i ) + { + NLink link( myCurFace.myNodes[i], myCurFace.myNodes[i+1] ); + std::map::const_iterator l2o = myFwdLinks.find( link ); + if ( l2o != myFwdLinks.end() ) + ori = link.myOri * l2o->second * -1; + links2.push_back( link ); + } + if ( ori ) // one more facet oriented + { + me->myPolyFacetOri[ iF ] = ori; + for ( size_t i = 0; i < links2.size(); ++i ) + me->myFwdLinks.insert( make_pair( links2[i], links2[i].myOri * ori )); + break; + } + } + if ( !ori ) + return false; // error in algorithm: infinite loop + + // try to orient the facet again + ori = 0; + for ( size_t i = 0; i < links.size() && !ori; ++i ) + { + std::map::const_iterator l2o = myFwdLinks.find( links[i] ); + if ( l2o != myFwdLinks.end() ) + ori = links[i].myOri * l2o->second * -1; + } + me->myPolyFacetOri[ faceIndex ] = ori; + } + + return ori > 0; +} + +//======================================================================= +//function : projectNodesToNormal +//purpose : compute min and max projections of all nodes to normal of a facet. +//======================================================================= + +bool SMDS_VolumeTool::projectNodesToNormal( int faceIndex, + double& minProj, + double& maxProj ) const +{ + minProj = std::numeric_limits::max(); + maxProj = std::numeric_limits::min(); + + XYZ normal; + if ( !GetFaceNormal( faceIndex, normal.x, normal.y, normal.z )) + return false; + XYZ p0 ( myCurFace.myNodes[0] ); + for ( size_t i = 0; i < myVolumeNodes.size(); ++i ) + { + if ( std::find( myCurFace.myNodes.begin() + 1, + myCurFace.myNodes.end(), + myVolumeNodes[ i ] ) != myCurFace.myNodes.end() ) + continue; // node of the faceIndex-th facet + + double proj = normal.Dot( XYZ( myVolumeNodes[ i ]) - p0 ); + if ( proj < minProj ) minProj = proj; + if ( proj > maxProj ) maxProj = proj; + } + const double tol = 1e-7; + minProj += tol; + maxProj -= tol; + bool diffSize = ( minProj * maxProj < 0 ); + // if ( diffSize ) + // { + // minProj = -minProj; + // } + // else if ( minProj < 0 ) + // { + // minProj = -minProj; + // maxProj = -maxProj; + // } + + return !diffSize; // ? 0 : (minProj >= 0); } //======================================================================= @@ -960,30 +1175,28 @@ bool SMDS_VolumeTool::IsFaceExternal( int faceIndex ) //purpose : Return a normal to a face //======================================================================= -bool SMDS_VolumeTool::GetFaceNormal (int faceIndex, double & X, double & Y, double & Z) +bool SMDS_VolumeTool::GetFaceNormal (int faceIndex, double & X, double & Y, double & Z) const { if ( !setFace( faceIndex )) return false; - XYZ p1 ( myFaceNodes[0] ); - XYZ p2 ( myFaceNodes[1] ); - XYZ p3 ( myFaceNodes[2] ); + const int iQuad = ( !myPolyedre && myCurFace.myNbNodes > 6 ) ? 2 : 1; + XYZ p1 ( myCurFace.myNodes[0*iQuad] ); + XYZ p2 ( myCurFace.myNodes[1*iQuad] ); + XYZ p3 ( myCurFace.myNodes[2*iQuad] ); XYZ aVec12( p2 - p1 ); XYZ aVec13( p3 - p1 ); XYZ cross = aVec12.Crossed( aVec13 ); - //if ( myFaceNbNodes == 4 ) { - if ( myFaceNbNodes >3 ) { - XYZ p4 ( myFaceNodes[3] ); + if ( myCurFace.myNbNodes >3*iQuad ) { + XYZ p4 ( myCurFace.myNodes[3*iQuad] ); XYZ aVec14( p4 - p1 ); XYZ cross2 = aVec13.Crossed( aVec14 ); - cross.x += cross2.x; - cross.y += cross2.y; - cross.z += cross2.z; + cross = cross + cross2; } double size = cross.Magnitude(); - if ( size <= DBL_MIN ) + if ( size <= numeric_limits::min() ) return false; X = cross.x / size; @@ -993,34 +1206,84 @@ bool SMDS_VolumeTool::GetFaceNormal (int faceIndex, double & X, double & Y, doub return true; } +//================================================================================ +/*! + * \brief Return barycenter of a face + */ +//================================================================================ + +bool SMDS_VolumeTool::GetFaceBaryCenter (int faceIndex, double & X, double & Y, double & Z) const +{ + if ( !setFace( faceIndex )) + return false; + + X = Y = Z = 0.0; + for ( int i = 0; i < myCurFace.myNbNodes; ++i ) + { + X += myCurFace.myNodes[i]->X() / myCurFace.myNbNodes; + Y += myCurFace.myNodes[i]->Y() / myCurFace.myNbNodes; + Z += myCurFace.myNodes[i]->Z() / myCurFace.myNbNodes; + } + return true; +} + //======================================================================= //function : GetFaceArea //purpose : Return face area //======================================================================= -double SMDS_VolumeTool::GetFaceArea( int faceIndex ) +double SMDS_VolumeTool::GetFaceArea( int faceIndex ) const { - if (myVolume->IsPoly()) { - MESSAGE("Warning: attempt to obtain area of a face of polyhedral volume"); - return 0; - } - + double area = 0; if ( !setFace( faceIndex )) - return 0; + return area; - XYZ p1 ( myFaceNodes[0] ); - XYZ p2 ( myFaceNodes[1] ); - XYZ p3 ( myFaceNodes[2] ); + XYZ p1 ( myCurFace.myNodes[0] ); + XYZ p2 ( myCurFace.myNodes[1] ); + XYZ p3 ( myCurFace.myNodes[2] ); XYZ aVec12( p2 - p1 ); XYZ aVec13( p3 - p1 ); - double area = aVec12.Crossed( aVec13 ).Magnitude() * 0.5; + area += aVec12.Crossed( aVec13 ).Magnitude(); - if ( myFaceNbNodes == 4 ) { - XYZ p4 ( myFaceNodes[3] ); - XYZ aVec14( p4 - p1 ); - area += aVec14.Crossed( aVec13 ).Magnitude() * 0.5; + if (myVolume->IsPoly()) + { + for ( int i = 3; i < myCurFace.myNbNodes; ++i ) + { + XYZ pI ( myCurFace.myNodes[i] ); + XYZ aVecI( pI - p1 ); + area += aVec13.Crossed( aVecI ).Magnitude(); + aVec13 = aVecI; + } + } + else + { + if ( myCurFace.myNbNodes == 4 ) { + XYZ p4 ( myCurFace.myNodes[3] ); + XYZ aVec14( p4 - p1 ); + area += aVec14.Crossed( aVec13 ).Magnitude(); + } } - return area; + return area / 2; +} + +//================================================================================ +/*! + * \brief Return index of the node located at face center of a quadratic element like HEX27 + */ +//================================================================================ + +int SMDS_VolumeTool::GetCenterNodeIndex( int faceIndex ) const +{ + if ( myAllFacesNbNodes && myVolumeNodes.size() == 27 ) // classic element with 27 nodes + { + switch ( faceIndex ) { + case 0: return 20; + case 1: return 25; + default: + return faceIndex + 19; + } + } + return -1; } //======================================================================= @@ -1031,19 +1294,32 @@ double SMDS_VolumeTool::GetFaceArea( int faceIndex ) int SMDS_VolumeTool::GetOppFaceIndex( int faceIndex ) const { int ind = -1; - if (myVolume->IsPoly()) { + if (myPolyedre) { MESSAGE("Warning: attempt to obtain opposite face on polyhedral volume"); return ind; } + const int nbHoriFaces = 2; + if ( faceIndex >= 0 && faceIndex < NbFaces() ) { - switch ( myVolumeNbNodes ) { + switch ( myVolumeNodes.size() ) { case 6: + case 15: if ( faceIndex == 0 || faceIndex == 1 ) ind = 1 - faceIndex; break; case 8: - ind = faceIndex + ( faceIndex % 2 ? -1 : 1 ); + case 12: + if ( faceIndex <= 1 ) // top or bottom + ind = 1 - faceIndex; + else { + const int nbSideFaces = myAllFacesNbNodes[0]; + ind = ( faceIndex - nbHoriFaces + nbSideFaces/2 ) % nbSideFaces + nbHoriFaces; + } + break; + case 20: + case 27: + ind = GetOppFaceIndexOfHex( faceIndex ); break; default:; } @@ -1051,13 +1327,25 @@ int SMDS_VolumeTool::GetOppFaceIndex( int faceIndex ) const return ind; } +//======================================================================= +//function : GetOppFaceIndexOfHex +//purpose : Return index of the opposite face of the hexahedron +//======================================================================= + +int SMDS_VolumeTool::GetOppFaceIndexOfHex( int faceIndex ) +{ + return Hexa_oppF[ faceIndex ]; +} + //======================================================================= //function : IsLinked //purpose : return true if theNode1 is linked with theNode2 +// If theIgnoreMediumNodes then corner nodes of quadratic cell are considered linked as well //======================================================================= bool SMDS_VolumeTool::IsLinked (const SMDS_MeshNode* theNode1, - const SMDS_MeshNode* theNode2) const + const SMDS_MeshNode* theNode2, + const bool theIgnoreMediumNodes) const { if ( !myVolume ) return false; @@ -1067,35 +1355,47 @@ bool SMDS_VolumeTool::IsLinked (const SMDS_MeshNode* theNode1, MESSAGE("Warning: bad volumic element"); return false; } - bool isLinked = false; - int iface; - for (iface = 1; iface <= myNbFaces && !isLinked; iface++) { - int inode, nbFaceNodes = myPolyedre->NbFaceNodes(iface); - - for (inode = 1; inode <= nbFaceNodes && !isLinked; inode++) { - const SMDS_MeshNode* curNode = myPolyedre->GetFaceNode(iface, inode); - - if (curNode == theNode1 || curNode == theNode2) { - int inextnode = (inode == nbFaceNodes) ? 1 : inode + 1; - const SMDS_MeshNode* nextNode = myPolyedre->GetFaceNode(iface, inextnode); - - if ((curNode == theNode1 && nextNode == theNode2) || - (curNode == theNode2 && nextNode == theNode1)) { - isLinked = true; - } - } + if ( !myAllFacesNbNodes ) { + SMDS_VolumeTool* me = const_cast< SMDS_VolumeTool* >( this ); + me->myPolyQuantities = myPolyedre->GetQuantities(); + myAllFacesNbNodes = &myPolyQuantities[0]; + } + int from, to = 0, d1 = 1, d2 = 2; + if ( myPolyedre->IsQuadratic() ) { + if ( theIgnoreMediumNodes ) { + d1 = 2; d2 = 0; } + } else { + d2 = 0; } - return isLinked; + vector::const_iterator i; + for (int iface = 0; iface < myNbFaces; iface++) + { + from = to; + to += myPolyQuantities[iface]; + i = std::find( myVolumeNodes.begin() + from, myVolumeNodes.begin() + to, theNode1 ); + if ( i != myVolumeNodes.end() ) + { + if (( theNode2 == *( i-d1 ) || + theNode2 == *( i+d1 ))) + return true; + if (( d2 ) && + (( theNode2 == *( i-d2 ) || + theNode2 == *( i+d2 )))) + return true; + } + } + return false; } // find nodes indices - int i1 = -1, i2 = -1; - for ( int i = 0; i < myVolumeNbNodes; i++ ) { + int i1 = -1, i2 = -1, nbFound = 0; + for ( int i = 0; i < myVolumeNodes.size() && nbFound < 2; i++ ) + { if ( myVolumeNodes[ i ] == theNode1 ) - i1 = i; + i1 = i, ++nbFound; else if ( myVolumeNodes[ i ] == theNode2 ) - i2 = i; + i2 = i, ++nbFound; } return IsLinked( i1, i2 ); } @@ -1104,10 +1404,12 @@ bool SMDS_VolumeTool::IsLinked (const SMDS_MeshNode* theNode1, //function : IsLinked //purpose : return true if the node with theNode1Index is linked // with the node with theNode2Index +// If theIgnoreMediumNodes then corner nodes of quadratic cell are considered linked as well //======================================================================= bool SMDS_VolumeTool::IsLinked (const int theNode1Index, - const int theNode2Index) const + const int theNode2Index, + bool theIgnoreMediumNodes) const { if ( myVolume->IsPoly() ) { return IsLinked(myVolumeNodes[theNode1Index], myVolumeNodes[theNode2Index]); @@ -1116,13 +1418,36 @@ bool SMDS_VolumeTool::IsLinked (const int theNode1Index, int minInd = min( theNode1Index, theNode2Index ); int maxInd = max( theNode1Index, theNode2Index ); - if ( minInd < 0 || maxInd > myVolumeNbNodes - 1 || maxInd == minInd ) + if ( minInd < 0 || maxInd > myVolumeNodes.size() - 1 || maxInd == minInd ) return false; - switch ( myVolumeNbNodes ) { - case 4: + VolumeType type = GetVolumeType(); + if ( myVolume->IsQuadratic() ) + { + int firstMediumInd = myVolume->NbCornerNodes(); + if ( minInd >= firstMediumInd ) + return false; // both nodes are medium - not linked + if ( maxInd < firstMediumInd ) // both nodes are corners + { + if ( theIgnoreMediumNodes ) + type = quadToLinear(type); // to check linkage of corner nodes only + else + return false; // corner nodes are not linked directly in a quadratic cell + } + } + + switch ( type ) { + case TETRA: return true; - case 5: + case HEXA: + switch ( maxInd - minInd ) { + case 1: return minInd != 3; + case 3: return minInd == 0 || minInd == 4; + case 4: return true; + default:; + } + break; + case PYRAM: if ( maxInd == 4 ) return true; switch ( maxInd - minInd ) { @@ -1131,7 +1456,7 @@ bool SMDS_VolumeTool::IsLinked (const int theNode1Index, default:; } break; - case 6: + case PENTA: switch ( maxInd - minInd ) { case 1: return minInd != 2; case 2: return minInd == 0 || minInd == 3; @@ -1139,15 +1464,7 @@ bool SMDS_VolumeTool::IsLinked (const int theNode1Index, default:; } break; - case 8: - switch ( maxInd - minInd ) { - case 1: return minInd != 3; - case 3: return minInd == 0 || minInd == 4; - case 4: return true; - default:; - } - break; - case 10: + case QUAD_TETRA: { switch ( minInd ) { case 0: if( maxInd==4 || maxInd==6 || maxInd==7 ) return true; @@ -1158,7 +1475,22 @@ bool SMDS_VolumeTool::IsLinked (const int theNode1Index, } break; } - case 13: + case QUAD_HEXA: + { + switch ( minInd ) { + case 0: if( maxInd==8 || maxInd==11 || maxInd==16 ) return true; + case 1: if( maxInd==8 || maxInd==9 || maxInd==17 ) return true; + case 2: if( maxInd==9 || maxInd==10 || maxInd==18 ) return true; + case 3: if( maxInd==10 || maxInd==11 || maxInd==19 ) return true; + case 4: if( maxInd==12 || maxInd==15 || maxInd==16 ) return true; + case 5: if( maxInd==12 || maxInd==13 || maxInd==17 ) return true; + case 6: if( maxInd==13 || maxInd==14 || maxInd==18 ) return true; + case 7: if( maxInd==14 || maxInd==15 || maxInd==19 ) return true; + default:; + } + break; + } + case QUAD_PYRAM: { switch ( minInd ) { case 0: if( maxInd==5 || maxInd==8 || maxInd==9 ) return true; @@ -1170,7 +1502,7 @@ bool SMDS_VolumeTool::IsLinked (const int theNode1Index, } break; } - case 15: + case QUAD_PENTA: { switch ( minInd ) { case 0: if( maxInd==6 || maxInd==8 || maxInd==12 ) return true; @@ -1183,20 +1515,12 @@ bool SMDS_VolumeTool::IsLinked (const int theNode1Index, } break; } - case 20: + case HEX_PRISM: { - switch ( minInd ) { - case 0: if( maxInd==8 || maxInd==11 || maxInd==16 ) return true; - case 1: if( maxInd==8 || maxInd==9 || maxInd==17 ) return true; - case 2: if( maxInd==9 || maxInd==10 || maxInd==18 ) return true; - case 3: if( maxInd==10 || maxInd==11 || maxInd==19 ) return true; - case 4: if( maxInd==12 || maxInd==15 || maxInd==16 ) return true; - case 5: if( maxInd==12 || maxInd==13 || maxInd==17 ) return true; - case 6: if( maxInd==13 || maxInd==14 || maxInd==18 ) return true; - case 7: if( maxInd==14 || maxInd==15 || maxInd==19 ) return true; - default:; - } - break; + const int diff = maxInd-minInd; + if ( diff > 6 ) return false;// not linked top and bottom + if ( diff == 6 ) return true; // linked top and bottom + return diff == 1 || diff == 7; } default:; } @@ -1211,7 +1535,7 @@ bool SMDS_VolumeTool::IsLinked (const int theNode1Index, int SMDS_VolumeTool::GetNodeIndex(const SMDS_MeshNode* theNode) const { if ( myVolume ) { - for ( int i = 0; i < myVolumeNbNodes; i++ ) { + for ( int i = 0; i < myVolumeNodes.size(); i++ ) { if ( myVolumeNodes[ i ] == theNode ) return i; } @@ -1227,28 +1551,35 @@ int SMDS_VolumeTool::GetNodeIndex(const SMDS_MeshNode* theNode) const */ //================================================================================ -int SMDS_VolumeTool::GetAllExistingFaces(vector & faces) +int SMDS_VolumeTool::GetAllExistingFaces(vector & faces) const { faces.clear(); - faces.reserve( NbFaces() ); - for ( int iF = 0; iF < NbFaces(); ++iF ) { - const SMDS_MeshFace* face = 0; - const SMDS_MeshNode** nodes = GetFaceNodes( iF ); - switch ( NbFaceNodes( iF )) { - case 3: - face = SMDS_Mesh::FindFace( nodes[0], nodes[1], nodes[2] ); break; - case 4: - face = SMDS_Mesh::FindFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break; - case 6: - face = SMDS_Mesh::FindFace( nodes[0], nodes[1], nodes[2], - nodes[3], nodes[4], nodes[5]); break; - case 8: - face = SMDS_Mesh::FindFace( nodes[0], nodes[1], nodes[2], nodes[3], - nodes[4], nodes[5], nodes[6], nodes[7]); break; + SaveFacet savedFacet( myCurFace ); + if ( IsPoly() ) + for ( int iF = 0; iF < NbFaces(); ++iF ) { + if ( setFace( iF )) + if ( const SMDS_MeshElement* face = SMDS_Mesh::FindFace( myCurFace.myNodes )) + faces.push_back( face ); + } + else + for ( int iF = 0; iF < NbFaces(); ++iF ) { + const SMDS_MeshFace* face = 0; + const SMDS_MeshNode** nodes = GetFaceNodes( iF ); + switch ( NbFaceNodes( iF )) { + case 3: + face = SMDS_Mesh::FindFace( nodes[0], nodes[1], nodes[2] ); break; + case 4: + face = SMDS_Mesh::FindFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break; + case 6: + face = SMDS_Mesh::FindFace( nodes[0], nodes[1], nodes[2], + nodes[3], nodes[4], nodes[5]); break; + case 8: + face = SMDS_Mesh::FindFace( nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], nodes[5], nodes[6], nodes[7]); break; + } + if ( face ) + faces.push_back( face ); } - if ( face ) - faces.push_back( face ); - } return faces.size(); } @@ -1256,17 +1587,17 @@ int SMDS_VolumeTool::GetAllExistingFaces(vector & faces //================================================================================ /*! * \brief Fill vector with boundary edges existing in the mesh - * \param edges - vector of found edges - * \retval int - nb of found faces + * \param edges - vector of found edges + * \retval int - nb of found faces */ //================================================================================ int SMDS_VolumeTool::GetAllExistingEdges(vector & edges) const { edges.clear(); - edges.reserve( myVolumeNbNodes * 2 ); - for ( int i = 0; i < myVolumeNbNodes; ++i ) { - for ( int j = i + 1; j < myVolumeNbNodes; ++j ) { + edges.reserve( myVolumeNodes.size() * 2 ); + for ( int i = 0; i < myVolumeNodes.size()-1; ++i ) { + for ( int j = i + 1; j < myVolumeNodes.size(); ++j ) { if ( IsLinked( i, j )) { const SMDS_MeshElement* edge = SMDS_Mesh::FindEdge( myVolumeNodes[i], myVolumeNodes[j] ); @@ -1278,47 +1609,148 @@ int SMDS_VolumeTool::GetAllExistingEdges(vector & edges return edges.size(); } -//======================================================================= -//function : IsFreeFace -//purpose : check that only one volume is build on the face nodes -//======================================================================= +//================================================================================ +/*! + * \brief Return minimal square distance between connected corner nodes + */ +//================================================================================ + +double SMDS_VolumeTool::MinLinearSize2() const +{ + double minSize = 1e+100; + int iQ = myVolume->IsQuadratic() ? 2 : 1; + + SaveFacet savedFacet( myCurFace ); + + // it seems that compute distance twice is faster than organization of a sole computing + myCurFace.myIndex = -1; + for ( int iF = 0; iF < myNbFaces; ++iF ) + { + setFace( iF ); + for ( int iN = 0; iN < myCurFace.myNbNodes; iN += iQ ) + { + XYZ n1( myCurFace.myNodes[ iN ]); + XYZ n2( myCurFace.myNodes[(iN + iQ) % myCurFace.myNbNodes]); + minSize = std::min( minSize, (n1 - n2).SquareMagnitude()); + } + } + + return minSize; +} + +//================================================================================ +/*! + * \brief Return maximal square distance between connected corner nodes + */ +//================================================================================ -bool SMDS_VolumeTool::IsFreeFace( int faceIndex ) +double SMDS_VolumeTool::MaxLinearSize2() const { - const int free = true; + double maxSize = -1e+100; + int iQ = myVolume->IsQuadratic() ? 2 : 1; + + SaveFacet savedFacet( myCurFace ); + + // it seems that compute distance twice is faster than organization of a sole computing + myCurFace.myIndex = -1; + for ( int iF = 0; iF < myNbFaces; ++iF ) + { + setFace( iF ); + for ( int iN = 0; iN < myCurFace.myNbNodes; iN += iQ ) + { + XYZ n1( myCurFace.myNodes[ iN ]); + XYZ n2( myCurFace.myNodes[(iN + iQ) % myCurFace.myNbNodes]); + maxSize = std::max( maxSize, (n1 - n2).SquareMagnitude()); + } + } + + return maxSize; +} + +//================================================================================ +/*! + * \brief fast check that only one volume is build on the face nodes + * This check is valid for conformal meshes only + */ +//================================================================================ + +bool SMDS_VolumeTool::IsFreeFace( int faceIndex, const SMDS_MeshElement** otherVol/*=0*/ ) const +{ + const bool isFree = true; + + if ( !setFace( faceIndex )) + return !isFree; + + const SMDS_MeshNode** nodes = GetFaceNodes( faceIndex ); + + const int di = myVolume->IsQuadratic() ? 2 : 1; + const int nbN = ( myCurFace.myNbNodes/di <= 4 && !IsPoly()) ? 3 : myCurFace.myNbNodes/di; // nb nodes to check + + SMDS_ElemIteratorPtr eIt = nodes[0]->GetInverseElementIterator( SMDSAbs_Volume ); + while ( eIt->more() ) + { + const SMDS_MeshElement* vol = eIt->next(); + if ( vol == myVolume ) + continue; + int iN; + for ( iN = 1; iN < nbN; ++iN ) + if ( vol->GetNodeIndex( nodes[ iN*di ]) < 0 ) + break; + if ( iN == nbN ) // nbN nodes are shared with vol + { + // if ( vol->IsPoly() || vol->NbFaces() > 6 ) // vol is polyhed or hex prism + // { + // int nb = myCurFace.myNbNodes; + // if ( myVolume->GetEntityType() != vol->GetEntityType() ) + // nb -= ( GetCenterNodeIndex(0) > 0 ); + // set faceNodes( nodes, nodes + nb ); + // if ( SMDS_VolumeTool( vol ).GetFaceIndex( faceNodes ) < 0 ) + // continue; + // } + if ( otherVol ) *otherVol = vol; + return !isFree; + } + } + if ( otherVol ) *otherVol = 0; + return isFree; +} + +//================================================================================ +/*! + * \brief Thorough check that only one volume is build on the face nodes + */ +//================================================================================ + +bool SMDS_VolumeTool::IsFreeFaceAdv( int faceIndex, const SMDS_MeshElement** otherVol/*=0*/ ) const +{ + const bool isFree = true; if (!setFace( faceIndex )) - return !free; + return !isFree; const SMDS_MeshNode** nodes = GetFaceNodes( faceIndex ); - int nbFaceNodes = myFaceNbNodes; + const int nbFaceNodes = myCurFace.myNbNodes; - // evaluate nb of face nodes shared by other volume + // evaluate nb of face nodes shared by other volumes int maxNbShared = -1; typedef map< const SMDS_MeshElement*, int > TElemIntMap; TElemIntMap volNbShared; TElemIntMap::iterator vNbIt; for ( int iNode = 0; iNode < nbFaceNodes; iNode++ ) { const SMDS_MeshNode* n = nodes[ iNode ]; - SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator(); + SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator( SMDSAbs_Volume ); while ( eIt->more() ) { const SMDS_MeshElement* elem = eIt->next(); - if ( elem != myVolume && elem->GetType() == SMDSAbs_Volume ) { - int nbShared = 1; - vNbIt = volNbShared.find( elem ); - if ( vNbIt == volNbShared.end() ) { - volNbShared.insert ( TElemIntMap::value_type( elem, nbShared )); - } - else { - nbShared = ++(*vNbIt).second; - } - if ( nbShared > maxNbShared ) - maxNbShared = nbShared; + if ( elem != myVolume ) { + vNbIt = volNbShared.insert( make_pair( elem, 0 )).first; + (*vNbIt).second++; + if ( vNbIt->second > maxNbShared ) + maxNbShared = vNbIt->second; } } } if ( maxNbShared < 3 ) - return free; // is free + return isFree; // is free // find volumes laying on the opposite side of the face // and sharing all nodes @@ -1327,55 +1759,81 @@ bool SMDS_VolumeTool::IsFreeFace( int faceIndex ) if ( IsFaceExternal( faceIndex )) intNormal = XYZ( -intNormal.x, -intNormal.y, -intNormal.z ); XYZ p0 ( nodes[0] ), baryCenter; - for ( vNbIt = volNbShared.begin(); vNbIt != volNbShared.end(); vNbIt++ ) { - int nbShared = (*vNbIt).second; + for ( vNbIt = volNbShared.begin(); vNbIt != volNbShared.end(); ) { + const int& nbShared = (*vNbIt).second; if ( nbShared >= 3 ) { SMDS_VolumeTool volume( (*vNbIt).first ); volume.GetBaryCenter( baryCenter.x, baryCenter.y, baryCenter.z ); XYZ intNormal2( baryCenter - p0 ); - if ( intNormal.Dot( intNormal2 ) < 0 ) - continue; // opposite side + if ( intNormal.Dot( intNormal2 ) < 0 ) { + // opposite side + if ( nbShared >= nbFaceNodes ) + { + // a volume shares the whole facet + if ( otherVol ) *otherVol = vNbIt->first; + return !isFree; + } + ++vNbIt; + continue; + } } // remove a volume from volNbShared map - volNbShared.erase( vNbIt-- ); + volNbShared.erase( vNbIt++ ); } - // here volNbShared contains only volumes laying on the - // opposite side of the face - if ( volNbShared.empty() ) { - return free; // is free + // here volNbShared contains only volumes laying on the opposite side of + // the face and sharing 3 or more but not all face nodes with myVolume + if ( volNbShared.size() < 2 ) { + return isFree; // is free } // check if the whole area of a face is shared - bool isShared[] = { false, false, false, false }; // 4 triangle parts of a quadrangle - for ( vNbIt = volNbShared.begin(); vNbIt != volNbShared.end(); vNbIt++ ) { - SMDS_VolumeTool volume( (*vNbIt).first ); - bool prevLinkShared = false; - int nbSharedLinks = 0; - for ( int iNode = 0; iNode < nbFaceNodes; iNode++ ) { - bool linkShared = volume.IsLinked( nodes[ iNode ], nodes[ iNode + 1] ); - if ( linkShared ) - nbSharedLinks++; - if ( linkShared && prevLinkShared && - volume.IsLinked( nodes[ iNode - 1 ], nodes[ iNode + 1] )) - isShared[ iNode ] = true; - prevLinkShared = linkShared; - } - if ( nbSharedLinks == nbFaceNodes ) - return !free; // is not free - if ( nbFaceNodes == 4 ) { - // check traingle parts 1 & 3 - if ( isShared[1] && isShared[3] ) - return !free; // is not free - // check triangle parts 0 & 2; - // 0 part could not be checked in the loop; check it here - if ( isShared[2] && prevLinkShared && - volume.IsLinked( nodes[ 0 ], nodes[ 1 ] ) && - volume.IsLinked( nodes[ 1 ], nodes[ 3 ] ) ) - return !free; // is not free - } + for ( int iNode = 0; iNode < nbFaceNodes; iNode++ ) + { + const SMDS_MeshNode* n = nodes[ iNode ]; + // check if n is shared by one of volumes of volNbShared + bool isShared = false; + SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator( SMDSAbs_Volume ); + while ( eIt->more() && !isShared ) + isShared = volNbShared.count( eIt->next() ); + if ( !isShared ) + return isFree; } - return free; + if ( otherVol ) *otherVol = volNbShared.begin()->first; + return !isFree; + +// if ( !myVolume->IsPoly() ) +// { +// bool isShared[] = { false, false, false, false }; // 4 triangle parts of a quadrangle +// for ( vNbIt = volNbShared.begin(); vNbIt != volNbShared.end(); vNbIt++ ) { +// SMDS_VolumeTool volume( (*vNbIt).first ); +// bool prevLinkShared = false; +// int nbSharedLinks = 0; +// for ( int iNode = 0; iNode < nbFaceNodes; iNode++ ) { +// bool linkShared = volume.IsLinked( nodes[ iNode ], nodes[ iNode + 1] ); +// if ( linkShared ) +// nbSharedLinks++; +// if ( linkShared && prevLinkShared && +// volume.IsLinked( nodes[ iNode - 1 ], nodes[ iNode + 1] )) +// isShared[ iNode ] = true; +// prevLinkShared = linkShared; +// } +// if ( nbSharedLinks == nbFaceNodes ) +// return !free; // is not free +// if ( nbFaceNodes == 4 ) { +// // check traingle parts 1 & 3 +// if ( isShared[1] && isShared[3] ) +// return !free; // is not free +// // check triangle parts 0 & 2; +// // 0 part could not be checked in the loop; check it here +// if ( isShared[2] && prevLinkShared && +// volume.IsLinked( nodes[ 0 ], nodes[ 1 ] ) && +// volume.IsLinked( nodes[ 1 ], nodes[ 3 ] ) ) +// return !free; // is not free +// } +// } +// } +// return free; } //======================================================================= @@ -1383,16 +1841,40 @@ bool SMDS_VolumeTool::IsFreeFace( int faceIndex ) //purpose : Return index of a face formed by theFaceNodes //======================================================================= -int SMDS_VolumeTool::GetFaceIndex( const set& theFaceNodes ) +int SMDS_VolumeTool::GetFaceIndex( const set& theFaceNodes, + const int theFaceIndexHint ) const { - for ( int iFace = 0; iFace < myNbFaces; iFace++ ) { - const SMDS_MeshNode** nodes = GetFaceNodes( iFace ); - int nbFaceNodes = NbFaceNodes( iFace ); - set nodeSet; - for ( int iNode = 0; iNode < nbFaceNodes; iNode++ ) - nodeSet.insert( nodes[ iNode ] ); - if ( theFaceNodes == nodeSet ) - return iFace; + if ( theFaceIndexHint >= 0 ) + { + int nbNodes = NbFaceNodes( theFaceIndexHint ); + if ( nbNodes == (int) theFaceNodes.size() ) + { + const SMDS_MeshNode** nodes = GetFaceNodes( theFaceIndexHint ); + while ( nbNodes ) + if ( theFaceNodes.count( nodes[ nbNodes-1 ])) + --nbNodes; + else + break; + if ( nbNodes == 0 ) + return theFaceIndexHint; + } + } + for ( int iFace = 0; iFace < myNbFaces; iFace++ ) + { + if ( iFace == theFaceIndexHint ) + continue; + int nbNodes = NbFaceNodes( iFace ); + if ( nbNodes == (int) theFaceNodes.size() ) + { + const SMDS_MeshNode** nodes = GetFaceNodes( iFace ); + while ( nbNodes ) + if ( theFaceNodes.count( nodes[ nbNodes-1 ])) + --nbNodes; + else + break; + if ( nbNodes == 0 ) + return iFace; + } } return -1; } @@ -1421,120 +1903,152 @@ int SMDS_VolumeTool::GetFaceIndex( const set& theFaceNodes //purpose : //======================================================================= -bool SMDS_VolumeTool::setFace( int faceIndex ) +bool SMDS_VolumeTool::setFace( int faceIndex ) const { if ( !myVolume ) return false; - if ( myCurFace == faceIndex ) + if ( myCurFace.myIndex == faceIndex ) return true; - myCurFace = -1; + myCurFace.myIndex = -1; if ( faceIndex < 0 || faceIndex >= NbFaces() ) return false; - if (myFaceNodes != NULL) { - delete [] myFaceNodes; - myFaceNodes = NULL; - } - - if (myVolume->IsPoly()) { + if (myVolume->IsPoly()) + { if (!myPolyedre) { MESSAGE("Warning: bad volumic element"); return false; } - // check orientation - bool isGoodOri = true; - if (myExternalFaces) - isGoodOri = IsFaceExternal( faceIndex ); - // set face nodes - int iNode; - myFaceNbNodes = myPolyedre->NbFaceNodes(faceIndex + 1); - myFaceNodes = new const SMDS_MeshNode* [myFaceNbNodes + 1]; - if (isGoodOri) { - for ( iNode = 0; iNode < myFaceNbNodes; iNode++ ) - myFaceNodes[ iNode ] = myPolyedre->GetFaceNode(faceIndex + 1, iNode + 1); - } else { - for ( iNode = 0; iNode < myFaceNbNodes; iNode++ ) - myFaceNodes[ iNode ] = myPolyedre->GetFaceNode(faceIndex + 1, myFaceNbNodes - iNode); + SMDS_VolumeTool* me = const_cast< SMDS_VolumeTool* >( this ); + if ( !myAllFacesNbNodes ) { + me->myPolyQuantities = myPolyedre->GetQuantities(); + myAllFacesNbNodes = &myPolyQuantities[0]; } - myFaceNodes[ myFaceNbNodes ] = myFaceNodes[ 0 ]; // last = first + myCurFace.myNbNodes = myAllFacesNbNodes[ faceIndex ]; + myCurFace.myNodes.resize( myCurFace.myNbNodes + 1 ); + me->myPolyIndices.resize( myCurFace.myNbNodes + 1 ); + myCurFace.myNodeIndices = & me->myPolyIndices[0]; + int shift = std::accumulate( myAllFacesNbNodes, myAllFacesNbNodes+faceIndex, 0 ); + for ( int iNode = 0; iNode < myCurFace.myNbNodes; iNode++ ) + { + myCurFace.myNodes [ iNode ] = myVolumeNodes[ shift + iNode ]; + myCurFace.myNodeIndices[ iNode ] = shift + iNode; + } + myCurFace.myNodes [ myCurFace.myNbNodes ] = myCurFace.myNodes[ 0 ]; // last = first + myCurFace.myNodeIndices[ myCurFace.myNbNodes ] = myCurFace.myNodeIndices[ 0 ]; + // check orientation + if (myExternalFaces) + { + myCurFace.myIndex = faceIndex; // avoid infinite recursion in IsFaceExternal() + myExternalFaces = false; // force normal computation by IsFaceExternal() + if ( !IsFaceExternal( faceIndex )) + std::reverse( myCurFace.myNodes.begin(), myCurFace.myNodes.end() ); + myExternalFaces = true; + } } - else { - // choose face node indices - switch ( myVolumeNbNodes ) { - case 4: - myFaceNbNodes = Tetra_nbN[ faceIndex ]; - if ( myExternalFaces ) - myFaceNodeIndices = myVolForward ? Tetra_F[ faceIndex ] : Tetra_RE[ faceIndex ]; - else - myFaceNodeIndices = myVolForward ? Tetra_F[ faceIndex ] : Tetra_R[ faceIndex ]; - break; - case 5: - myFaceNbNodes = Pyramid_nbN[ faceIndex ]; - if ( myExternalFaces ) - myFaceNodeIndices = myVolForward ? Pyramid_F[ faceIndex ] : Pyramid_RE[ faceIndex ]; - else - myFaceNodeIndices = myVolForward ? Pyramid_F[ faceIndex ] : Pyramid_R[ faceIndex ]; - break; - case 6: - myFaceNbNodes = Penta_nbN[ faceIndex ]; - if ( myExternalFaces ) - myFaceNodeIndices = myVolForward ? Penta_FE[ faceIndex ] : Penta_RE[ faceIndex ]; - else - myFaceNodeIndices = myVolForward ? Penta_F[ faceIndex ] : Penta_R[ faceIndex ]; - break; - case 8: - myFaceNbNodes = Hexa_nbN[ faceIndex ]; - if ( myExternalFaces ) - myFaceNodeIndices = myVolForward ? Hexa_FE[ faceIndex ] : Hexa_RE[ faceIndex ]; - else - myFaceNodeIndices = Hexa_F[ faceIndex ]; - break; - case 10: - myFaceNbNodes = QuadTetra_nbN[ faceIndex ]; - if ( myExternalFaces ) - myFaceNodeIndices = myVolForward ? QuadTetra_F[ faceIndex ] : QuadTetra_RE[ faceIndex ]; - else - myFaceNodeIndices = myVolForward ? QuadTetra_F[ faceIndex ] : QuadTetra_R[ faceIndex ]; - break; - case 13: - myFaceNbNodes = QuadPyram_nbN[ faceIndex ]; - if ( myExternalFaces ) - myFaceNodeIndices = myVolForward ? QuadPyram_F[ faceIndex ] : QuadPyram_RE[ faceIndex ]; - else - myFaceNodeIndices = myVolForward ? QuadPyram_F[ faceIndex ] : QuadPyram_R[ faceIndex ]; - break; - case 15: - myFaceNbNodes = QuadPenta_nbN[ faceIndex ]; - if ( myExternalFaces ) - myFaceNodeIndices = myVolForward ? QuadPenta_FE[ faceIndex ] : QuadPenta_RE[ faceIndex ]; - else - myFaceNodeIndices = myVolForward ? QuadPenta_F[ faceIndex ] : QuadPenta_R[ faceIndex ]; - break; - case 20: - myFaceNbNodes = QuadHexa_nbN[ faceIndex ]; - if ( myExternalFaces ) - myFaceNodeIndices = myVolForward ? QuadHexa_FE[ faceIndex ] : QuadHexa_RE[ faceIndex ]; - else - myFaceNodeIndices = QuadHexa_F[ faceIndex ]; - break; - default: - return false; + else + { + if ( !myAllFacesNodeIndices_F ) + { + // choose data for an element type + switch ( myVolumeNodes.size() ) { + case 4: + myAllFacesNodeIndices_F = &Tetra_F [0][0]; + //myAllFacesNodeIndices_FE = &Tetra_F [0][0]; + myAllFacesNodeIndices_RE = &Tetra_RE[0][0]; + myAllFacesNbNodes = Tetra_nbN; + myMaxFaceNbNodes = sizeof(Tetra_F[0])/sizeof(Tetra_F[0][0]); + break; + case 5: + myAllFacesNodeIndices_F = &Pyramid_F [0][0]; + //myAllFacesNodeIndices_FE = &Pyramid_F [0][0]; + myAllFacesNodeIndices_RE = &Pyramid_RE[0][0]; + myAllFacesNbNodes = Pyramid_nbN; + myMaxFaceNbNodes = sizeof(Pyramid_F[0])/sizeof(Pyramid_F[0][0]); + break; + case 6: + myAllFacesNodeIndices_F = &Penta_F [0][0]; + //myAllFacesNodeIndices_FE = &Penta_FE[0][0]; + myAllFacesNodeIndices_RE = &Penta_RE[0][0]; + myAllFacesNbNodes = Penta_nbN; + myMaxFaceNbNodes = sizeof(Penta_F[0])/sizeof(Penta_F[0][0]); + break; + case 8: + myAllFacesNodeIndices_F = &Hexa_F [0][0]; + ///myAllFacesNodeIndices_FE = &Hexa_FE[0][0]; + myAllFacesNodeIndices_RE = &Hexa_RE[0][0]; + myAllFacesNbNodes = Hexa_nbN; + myMaxFaceNbNodes = sizeof(Hexa_F[0])/sizeof(Hexa_F[0][0]); + break; + case 10: + myAllFacesNodeIndices_F = &QuadTetra_F [0][0]; + //myAllFacesNodeIndices_FE = &QuadTetra_F [0][0]; + myAllFacesNodeIndices_RE = &QuadTetra_RE[0][0]; + myAllFacesNbNodes = QuadTetra_nbN; + myMaxFaceNbNodes = sizeof(QuadTetra_F[0])/sizeof(QuadTetra_F[0][0]); + break; + case 13: + myAllFacesNodeIndices_F = &QuadPyram_F [0][0]; + //myAllFacesNodeIndices_FE = &QuadPyram_F [0][0]; + myAllFacesNodeIndices_RE = &QuadPyram_RE[0][0]; + myAllFacesNbNodes = QuadPyram_nbN; + myMaxFaceNbNodes = sizeof(QuadPyram_F[0])/sizeof(QuadPyram_F[0][0]); + break; + case 15: + myAllFacesNodeIndices_F = &QuadPenta_F [0][0]; + //myAllFacesNodeIndices_FE = &QuadPenta_FE[0][0]; + myAllFacesNodeIndices_RE = &QuadPenta_RE[0][0]; + myAllFacesNbNodes = QuadPenta_nbN; + myMaxFaceNbNodes = sizeof(QuadPenta_F[0])/sizeof(QuadPenta_F[0][0]); + break; + case 20: + case 27: + myAllFacesNodeIndices_F = &QuadHexa_F [0][0]; + //myAllFacesNodeIndices_FE = &QuadHexa_FE[0][0]; + myAllFacesNodeIndices_RE = &QuadHexa_RE[0][0]; + myAllFacesNbNodes = QuadHexa_nbN; + myMaxFaceNbNodes = sizeof(QuadHexa_F[0])/sizeof(QuadHexa_F[0][0]); + if ( !myIgnoreCentralNodes && myVolumeNodes.size() == 27 ) + { + myAllFacesNodeIndices_F = &TriQuadHexa_F [0][0]; + //myAllFacesNodeIndices_FE = &TriQuadHexa_FE[0][0]; + myAllFacesNodeIndices_RE = &TriQuadHexa_RE[0][0]; + myAllFacesNbNodes = TriQuadHexa_nbN; + myMaxFaceNbNodes = sizeof(TriQuadHexa_F[0])/sizeof(TriQuadHexa_F[0][0]); + } + break; + case 12: + myAllFacesNodeIndices_F = &HexPrism_F [0][0]; + //myAllFacesNodeIndices_FE = &HexPrism_FE[0][0]; + myAllFacesNodeIndices_RE = &HexPrism_RE[0][0]; + myAllFacesNbNodes = HexPrism_nbN; + myMaxFaceNbNodes = sizeof(HexPrism_F[0])/sizeof(HexPrism_F[0][0]); + break; + default: + return false; + } } + myCurFace.myNbNodes = myAllFacesNbNodes[ faceIndex ]; + // if ( myExternalFaces ) + // myCurFace.myNodeIndices = (int*)( myVolForward ? myAllFacesNodeIndices_FE + faceIndex*myMaxFaceNbNodes : myAllFacesNodeIndices_RE + faceIndex*myMaxFaceNbNodes ); + // else + // myCurFace.myNodeIndices = (int*)( myAllFacesNodeIndices_F + faceIndex*myMaxFaceNbNodes ); + myCurFace.myNodeIndices = (int*)( myVolForward ? myAllFacesNodeIndices_F + faceIndex*myMaxFaceNbNodes : myAllFacesNodeIndices_RE + faceIndex*myMaxFaceNbNodes ); // set face nodes - myFaceNodes = new const SMDS_MeshNode* [myFaceNbNodes + 1]; - for ( int iNode = 0; iNode < myFaceNbNodes; iNode++ ) - myFaceNodes[ iNode ] = myVolumeNodes[ myFaceNodeIndices[ iNode ]]; - myFaceNodes[ myFaceNbNodes ] = myFaceNodes[ 0 ]; + myCurFace.myNodes.resize( myCurFace.myNbNodes + 1 ); + for ( int iNode = 0; iNode < myCurFace.myNbNodes; iNode++ ) + myCurFace.myNodes[ iNode ] = myVolumeNodes[ myCurFace.myNodeIndices[ iNode ]]; + myCurFace.myNodes[ myCurFace.myNbNodes ] = myCurFace.myNodes[ 0 ]; } - myCurFace = faceIndex; + myCurFace.myIndex = faceIndex; return true; } @@ -1554,7 +2068,9 @@ SMDS_VolumeTool::VolumeType SMDS_VolumeTool::GetType(int nbNodes) case 10: return QUAD_TETRA; case 13: return QUAD_PYRAM; case 15: return QUAD_PENTA; - case 20: return QUAD_HEXA; + case 20: + case 27: return QUAD_HEXA; + case 12: return HEX_PRISM; default:return UNKNOWN; } } @@ -1575,7 +2091,8 @@ int SMDS_VolumeTool::NbFaces( VolumeType type ) case QUAD_PENTA: return 5; case HEXA : case QUAD_HEXA : return 6; - default: return 0; + case HEX_PRISM : return 8; + default: return 0; } } @@ -1598,7 +2115,8 @@ int SMDS_VolumeTool::NbCornerNodes(VolumeType type) case QUAD_PENTA: return 6; case HEXA : case QUAD_HEXA : return 8; - default: return 0; + case HEX_PRISM : return 12; + default: return 0; } return 0; } @@ -1619,12 +2137,14 @@ const int* SMDS_VolumeTool::GetFaceNodesIndices(VolumeType type, switch ( type ) { case TETRA: return Tetra_F[ faceIndex ]; case PYRAM: return Pyramid_F[ faceIndex ]; - case PENTA: return external ? Penta_FE[ faceIndex ] : Penta_F[ faceIndex ]; - case HEXA: return external ? Hexa_FE[ faceIndex ] : Hexa_F[ faceIndex ]; + case PENTA: return external ? Penta_F[ faceIndex ] : Penta_F[ faceIndex ]; + case HEXA: return external ? Hexa_F[ faceIndex ] : Hexa_F[ faceIndex ]; case QUAD_TETRA: return QuadTetra_F[ faceIndex ]; case QUAD_PYRAM: return QuadPyram_F[ faceIndex ]; - case QUAD_PENTA: return external ? QuadPenta_FE[ faceIndex ] : QuadPenta_F[ faceIndex ]; - case QUAD_HEXA: return external ? QuadHexa_FE[ faceIndex ] : QuadHexa_F[ faceIndex ]; + case QUAD_PENTA: return external ? QuadPenta_F[ faceIndex ] : QuadPenta_F[ faceIndex ]; + // what about SMDSEntity_TriQuad_Hexa? + case QUAD_HEXA: return external ? QuadHexa_F[ faceIndex ] : QuadHexa_F[ faceIndex ]; + case HEX_PRISM: return external ? HexPrism_F[ faceIndex ] : HexPrism_F[ faceIndex ]; default:; } return 0; @@ -1646,18 +2166,20 @@ int SMDS_VolumeTool::NbFaceNodes(VolumeType type, case QUAD_TETRA: return QuadTetra_nbN[ faceIndex ]; case QUAD_PYRAM: return QuadPyram_nbN[ faceIndex ]; case QUAD_PENTA: return QuadPenta_nbN[ faceIndex ]; + // what about SMDSEntity_TriQuad_Hexa? case QUAD_HEXA: return QuadHexa_nbN[ faceIndex ]; + case HEX_PRISM: return HexPrism_nbN[ faceIndex ]; default:; } return 0; } //======================================================================= -//function : Get +//function : Element //purpose : return element //======================================================================= -const SMDS_MeshVolume* SMDS_VolumeTool::Get() const +const SMDS_MeshVolume* SMDS_VolumeTool::Element() const { return static_cast( myVolume ); } diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkCellIterator.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkCellIterator.cpp new file mode 100644 index 000000000000..d050097fba31 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkCellIterator.cpp @@ -0,0 +1,215 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +#include "SMDS_VtkCellIterator.hxx" +#include "utilities.h" + +SMDS_VtkCellIterator::SMDS_VtkCellIterator(SMDS_Mesh* mesh, int vtkCellId, SMDSAbs_EntityType aType) : + _mesh(mesh), _cellId(vtkCellId), _index(0), _type(aType) +{ + vtkUnstructuredGrid* grid = _mesh->getGrid(); + _vtkIdList = vtkIdList::New(); + const std::vector& interlace = SMDS_MeshCell::fromVtkOrder( aType ); + if ( interlace.empty() ) + { + grid->GetCellPoints(_cellId, _vtkIdList); + _nbNodes = _vtkIdList->GetNumberOfIds(); + } + else + { + vtkIdType npts, *pts; + grid->GetCellPoints( _cellId, npts, pts ); + _vtkIdList->SetNumberOfIds( _nbNodes = npts ); + for (int i = 0; i < _nbNodes; i++) + _vtkIdList->SetId(i, pts[interlace[i]]); + } +} + +SMDS_VtkCellIterator::~SMDS_VtkCellIterator() +{ + _vtkIdList->Delete(); +} + +bool SMDS_VtkCellIterator::more() +{ + return (_index < _nbNodes); +} + +const SMDS_MeshElement* SMDS_VtkCellIterator::next() +{ + vtkIdType id = _vtkIdList->GetId(_index++); + return _mesh->FindNodeVtk(id); +} + +SMDS_VtkCellIteratorToUNV::SMDS_VtkCellIteratorToUNV(SMDS_Mesh* mesh, int vtkCellId, SMDSAbs_EntityType aType) : + SMDS_VtkCellIterator() +{ + _mesh = mesh; + _cellId = vtkCellId; + _index = 0; + _type = aType; + //MESSAGE("SMDS_VtkCellInterlacedIterator (UNV)" << _type); + + _vtkIdList = vtkIdList::New(); + vtkIdType* pts; + vtkUnstructuredGrid* grid = _mesh->getGrid(); + grid->GetCellPoints((vtkIdType)_cellId, (vtkIdType&)_nbNodes, pts); + _vtkIdList->SetNumberOfIds(_nbNodes); + const int *ids = 0; + switch (_type) + { + case SMDSEntity_Quad_Edge: + { + static int id[] = { 0, 2, 1 }; + ids = id; + break; + } + case SMDSEntity_Quad_Triangle: + case SMDSEntity_BiQuad_Triangle: + { + static int id[] = { 0, 3, 1, 4, 2, 5 }; + ids = id; + _nbNodes = 6; + break; + } + case SMDSEntity_Quad_Quadrangle: + case SMDSEntity_BiQuad_Quadrangle: + { + static int id[] = { 0, 4, 1, 5, 2, 6, 3, 7 }; + ids = id; + _nbNodes = 8; + break; + } + case SMDSEntity_Quad_Tetra: + { + static int id[] = { 0, 4, 1, 5, 2, 6, 7, 8, 9, 3 }; + ids = id; + break; + } + case SMDSEntity_Quad_Pyramid: + { + static int id[] = { 0, 5, 1, 6, 2, 7, 3, 8, 9, 10, 11, 12, 4 }; + ids = id; + break; + } + case SMDSEntity_Penta: + { + static int id[] = { 0, 2, 1, 3, 5, 4 }; + ids = id; + break; + } + case SMDSEntity_Quad_Penta: + { + static int id[] = { 0, 8, 2, 7, 1, 6, 12, 14, 13, 3, 11, 5, 10, 4, 9 }; + ids = id; + break; + } + case SMDSEntity_Quad_Hexa: + case SMDSEntity_TriQuad_Hexa: + { + static int id[] = { 0, 8, 1, 9, 2, 10, 3, 11, 16, 17, 18, 19, 4, 12, 5, 13, 6, 14, 7, 15 }; + ids = id; + _nbNodes = 20; + break; + } + case SMDSEntity_Polygon: + case SMDSEntity_Quad_Polygon: + case SMDSEntity_Polyhedra: + case SMDSEntity_Quad_Polyhedra: + default: + const std::vector& i = SMDS_MeshCell::interlacedSmdsOrder(aType, _nbNodes); + if ( !i.empty() ) + ids = & i[0]; + } + + if ( ids ) + for (int i = 0; i < _nbNodes; i++) + _vtkIdList->SetId(i, pts[ids[i]]); + else + for (int i = 0; i < _nbNodes; i++) + _vtkIdList->SetId(i, pts[i]); +} + +bool SMDS_VtkCellIteratorToUNV::more() +{ + return SMDS_VtkCellIterator::more(); +} + +const SMDS_MeshNode* SMDS_VtkCellIteratorToUNV::next() +{ + return static_cast< const SMDS_MeshNode* >( SMDS_VtkCellIterator::next() ); +} + +SMDS_VtkCellIteratorToUNV::~SMDS_VtkCellIteratorToUNV() +{ +} + +SMDS_VtkCellIteratorPolyH::SMDS_VtkCellIteratorPolyH(SMDS_Mesh* mesh, int vtkCellId, SMDSAbs_EntityType aType) : + SMDS_VtkCellIterator() +{ + _mesh = mesh; + _cellId = vtkCellId; + _index = 0; + _type = aType; + //MESSAGE("SMDS_VtkCellIteratorPolyH " << _type); + _vtkIdList = vtkIdList::New(); + vtkUnstructuredGrid* grid = _mesh->getGrid(); + grid->GetCellPoints(_cellId, _vtkIdList); + _nbNodes = _vtkIdList->GetNumberOfIds(); + switch (_type) + { + case SMDSEntity_Polyhedra: + { + //MESSAGE("SMDS_VtkCellIterator Polyhedra"); + vtkIdType nFaces = 0; + vtkIdType* ptIds = 0; + grid->GetFaceStream(_cellId, nFaces, ptIds); + int id = 0; + _nbNodesInFaces = 0; + for (int i = 0; i < nFaces; i++) + { + int nodesInFace = ptIds[id]; // nodeIds in ptIds[id+1 .. id+nodesInFace] + _nbNodesInFaces += nodesInFace; + id += (nodesInFace + 1); + } + _vtkIdList->SetNumberOfIds(_nbNodesInFaces); + id = 0; + int n = 0; + for (int i = 0; i < nFaces; i++) + { + int nodesInFace = ptIds[id]; // nodeIds in ptIds[id+1 .. id+nodesInFace] + for (int k = 1; k <= nodesInFace; k++) + _vtkIdList->SetId(n++, ptIds[id + k]); + id += (nodesInFace + 1); + } + break; + } + default: + assert(0); + } +} + +SMDS_VtkCellIteratorPolyH::~SMDS_VtkCellIteratorPolyH() +{ +} + +bool SMDS_VtkCellIteratorPolyH::more() +{ + return (_index < _nbNodesInFaces); +} diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkEdge.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkEdge.cpp new file mode 100644 index 000000000000..9786abf9aaeb --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkEdge.cpp @@ -0,0 +1,173 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +#include "SMDS_VtkEdge.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMDS_Mesh.hxx" +#include "SMDS_VtkCellIterator.hxx" + +#include "utilities.h" + +#include +#include + +using namespace std; + +SMDS_VtkEdge::SMDS_VtkEdge() +{ +} + +SMDS_VtkEdge::SMDS_VtkEdge(std::vector& nodeIds, SMDS_Mesh* mesh) +{ + init(nodeIds, mesh); +} + +SMDS_VtkEdge::~SMDS_VtkEdge() +{ +} + +void SMDS_VtkEdge::init(std::vector& nodeIds, SMDS_Mesh* mesh) +{ + SMDS_MeshEdge::init(); + vtkUnstructuredGrid* grid = mesh->getGrid(); + myMeshId = mesh->getMeshId(); + vtkIdType aType = VTK_LINE; + if (nodeIds.size() == 3) + aType = VTK_QUADRATIC_EDGE; + + myVtkID = grid->InsertNextLinkedCell(aType, nodeIds.size(), &nodeIds[0]); + + mesh->setMyModified(); + //MESSAGE("SMDS_VtkEdge::init myVtkID " << myVtkID); +} + +bool SMDS_VtkEdge::ChangeNodes(const SMDS_MeshNode * node1, const SMDS_MeshNode * node2) +{ + const SMDS_MeshNode* nodes[] = { node1, node2 }; + SMDS_Mesh::_meshList[myMeshId]->setMyModified(); + return ChangeNodes(nodes, 2); +} + +bool SMDS_VtkEdge::ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(myVtkID, npts, pts); + if (nbNodes != npts) + { + MESSAGE("ChangeNodes problem: not the same number of nodes " << npts << " -> " << nbNodes); + return false; + } + for (int i = 0; i < nbNodes; i++) + { + pts[i] = nodes[i]->getVtkId(); + } + SMDS_Mesh::_meshList[myMeshId]->setMyModified(); + return true; +} + +bool SMDS_VtkEdge::IsMediumNode(const SMDS_MeshNode* node) const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(myVtkID, npts, pts); + //MESSAGE("IsMediumNode " << npts << " " << (node->getVtkId() == pts[npts-1])); + return ((npts == 3) && (node->getVtkId() == pts[2])); +} + +void SMDS_VtkEdge::Print(std::ostream & OS) const +{ + OS << "edge <" << GetID() << "> : "; +} + +int SMDS_VtkEdge::NbNodes() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + int nbPoints = grid->GetCell(myVtkID)->GetNumberOfPoints(); + assert(nbPoints >= 2); + return nbPoints; +} + +int SMDS_VtkEdge::NbEdges() const +{ + return 1; +} + +SMDSAbs_EntityType SMDS_VtkEdge::GetEntityType() const +{ + if (NbNodes() == 2) + return SMDSEntity_Edge; + else + return SMDSEntity_Quad_Edge; +} + +vtkIdType SMDS_VtkEdge::GetVtkType() const +{ + if (NbNodes() == 2) + return VTK_LINE; + else + return VTK_QUADRATIC_EDGE; + +} + +/*! + * \brief Return node by its index + * \param ind - node index + * \retval const SMDS_MeshNode* - the node + */ +const SMDS_MeshNode* +SMDS_VtkEdge::GetNode(const int ind) const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType npts, *pts; + grid->GetCellPoints( this->myVtkID, npts, pts ); + return SMDS_Mesh::_meshList[myMeshId]->FindNodeVtk( pts[ ind ]); +} + +bool SMDS_VtkEdge::IsQuadratic() const +{ + if (this->NbNodes() > 2) + return true; + else + return false; +} + +SMDS_ElemIteratorPtr SMDS_VtkEdge::elementsIterator(SMDSAbs_ElementType type) const +{ + switch (type) + { + case SMDSAbs_Node: + return SMDS_ElemIteratorPtr(new SMDS_VtkCellIterator(SMDS_Mesh::_meshList[myMeshId], myVtkID, GetEntityType())); + default: + MESSAGE("ERROR : Iterator not implemented"); + return SMDS_ElemIteratorPtr((SMDS_ElemIterator*) NULL); + } +} + +SMDS_NodeIteratorPtr SMDS_VtkEdge::nodesIteratorToUNV() const +{ + return SMDS_NodeIteratorPtr(new SMDS_VtkCellIteratorToUNV(SMDS_Mesh::_meshList[myMeshId], myVtkID, GetEntityType())); +} + +SMDS_NodeIteratorPtr SMDS_VtkEdge::interlacedNodesIterator() const +{ + return nodesIteratorToUNV(); +} diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkFace.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkFace.cpp new file mode 100644 index 000000000000..0a772f53bc6b --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkFace.cpp @@ -0,0 +1,348 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +#include "SMDS_VtkFace.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMDS_Mesh.hxx" +#include "SMDS_VtkCellIterator.hxx" + +#include "utilities.h" + +#include + +using namespace std; + +SMDS_VtkFace::SMDS_VtkFace() +{ +} + +SMDS_VtkFace::SMDS_VtkFace(const std::vector& nodeIds, SMDS_Mesh* mesh) +{ + init(nodeIds, mesh); +} + +SMDS_VtkFace::~SMDS_VtkFace() +{ +} + +void SMDS_VtkFace::init(const std::vector& nodeIds, SMDS_Mesh* mesh) +{ + SMDS_MeshFace::init(); + vtkUnstructuredGrid* grid = mesh->getGrid(); + myMeshId = mesh->getMeshId(); + vtkIdType aType = VTK_TRIANGLE; + switch (nodeIds.size()) + { + case 3: + aType = VTK_TRIANGLE; + break; + case 4: + aType = VTK_QUAD; + break; + case 6: + aType = VTK_QUADRATIC_TRIANGLE; + break; + case 8: + aType = VTK_QUADRATIC_QUAD; + break; + case 9: + aType = VTK_BIQUADRATIC_QUAD; + break; + case 7: + aType = VTK_BIQUADRATIC_TRIANGLE; + break; + default: + aType = VTK_POLYGON; + break; + } + myVtkID = grid->InsertNextLinkedCell(aType, nodeIds.size(), (vtkIdType*) &nodeIds[0]); + mesh->setMyModified(); + //MESSAGE("SMDS_VtkFace::init myVtkID " << myVtkID); +} + +void SMDS_VtkFace::initPoly(const std::vector& nodeIds, SMDS_Mesh* mesh) +{ + SMDS_MeshFace::init(); + vtkUnstructuredGrid* grid = mesh->getGrid(); + myMeshId = mesh->getMeshId(); + myVtkID = grid->InsertNextLinkedCell(VTK_POLYGON, nodeIds.size(), (vtkIdType*) &nodeIds[0]); + mesh->setMyModified(); +} + +void SMDS_VtkFace::initQuadPoly(const std::vector& nodeIds, SMDS_Mesh* mesh) +{ + SMDS_MeshFace::init(); + vtkUnstructuredGrid* grid = mesh->getGrid(); + myMeshId = mesh->getMeshId(); + myVtkID = grid->InsertNextLinkedCell(VTK_QUADRATIC_POLYGON, nodeIds.size(), (vtkIdType*) &nodeIds[0]); + mesh->setMyModified(); +} + +bool SMDS_VtkFace::ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(myVtkID, npts, pts); + if (nbNodes != npts) + { + MESSAGE("ChangeNodes problem: not the same number of nodes " << npts << " -> " << nbNodes); + return false; + } + for (int i = 0; i < nbNodes; i++) + { + pts[i] = nodes[i]->getVtkId(); + } + SMDS_Mesh::_meshList[myMeshId]->setMyModified(); + return true; +} + +void SMDS_VtkFace::Print(std::ostream & OS) const +{ + OS << "face <" << GetID() << "> : "; +} + +int SMDS_VtkFace::NbEdges() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + int nbEdges = 3; + switch (aVtkType) + { + case VTK_TRIANGLE: + case VTK_QUADRATIC_TRIANGLE: + case VTK_BIQUADRATIC_TRIANGLE: + nbEdges = 3; + break; + case VTK_QUAD: + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: + nbEdges = 4; + break; + case VTK_QUADRATIC_POLYGON: + nbEdges = grid->GetCell(myVtkID)->GetNumberOfPoints() / 2; + break; + case VTK_POLYGON: + default: + nbEdges = grid->GetCell(myVtkID)->GetNumberOfPoints(); + break; + } + return nbEdges; +} + +int SMDS_VtkFace::NbFaces() const +{ + return 1; +} + +int SMDS_VtkFace::NbNodes() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + int nbPoints = grid->GetCell(myVtkID)->GetNumberOfPoints(); + return nbPoints; +} + +/*! + * \brief Return node by its index + * \param ind - node index + * \retval const SMDS_MeshNode* - the node + */ +const SMDS_MeshNode* +SMDS_VtkFace::GetNode(const int ind) const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType npts, *pts; + grid->GetCellPoints( this->myVtkID, npts, pts ); + return SMDS_Mesh::_meshList[myMeshId]->FindNodeVtk( pts[ ind ]); +} + +/*! + * \brief Check if a node belongs to the element + * \param node - the node to check + * \retval int - node index within the element, -1 if not found + */ +int SMDS_VtkFace::GetNodeIndex( const SMDS_MeshNode* node ) const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType npts, *pts; + grid->GetCellPoints( this->myVtkID, npts, pts ); + for ( vtkIdType i = 0; i < npts; ++i ) + if ( pts[i] == node->getVtkId() ) + return i; + return -1; +} + +bool SMDS_VtkFace::IsQuadratic() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + // TODO quadratic polygons ? + switch (aVtkType) + { + case VTK_QUADRATIC_TRIANGLE: + case VTK_QUADRATIC_QUAD: + case VTK_QUADRATIC_POLYGON: + case VTK_BIQUADRATIC_QUAD: + case VTK_BIQUADRATIC_TRIANGLE: + return true; + break; + default: + return false; + } +} + +bool SMDS_VtkFace::IsPoly() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + return ( aVtkType == VTK_POLYGON || aVtkType == VTK_QUADRATIC_POLYGON ); +} + +bool SMDS_VtkFace::IsMediumNode(const SMDS_MeshNode* node) const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + int rankFirstMedium = 0; + switch (aVtkType) + { + case VTK_QUADRATIC_TRIANGLE: + case VTK_BIQUADRATIC_TRIANGLE: + rankFirstMedium = 3; // medium nodes are of rank 3,4,5 + break; + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: + rankFirstMedium = 4; // medium nodes are of rank 4,5,6,7 + break; + case VTK_QUADRATIC_POLYGON: + rankFirstMedium = grid->GetCell(myVtkID)->GetNumberOfPoints() / 2; + break; + default: + //MESSAGE("wrong element type " << aVtkType); + return false; + } + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(myVtkID, npts, pts); + vtkIdType nodeId = node->getVtkId(); + for (int rank = 0; rank < npts; rank++) + { + if (pts[rank] == nodeId) + { + //MESSAGE("rank " << rank << " is medium node " << (rank < rankFirstMedium)); + if (rank < rankFirstMedium) + return false; + else + return true; + } + } + //throw SALOME_Exception(LOCALIZED("node does not belong to this element")); + MESSAGE("======================================================"); + MESSAGE("= IsMediumNode: node does not belong to this element ="); + MESSAGE("======================================================"); + return false; +} + +int SMDS_VtkFace::NbCornerNodes() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + int nbPoints = grid->GetCell(myVtkID)->GetNumberOfPoints(); + vtkIdType aVtkType = grid->GetCellType(myVtkID); + switch ( aVtkType ) + { + case VTK_POLYGON: + break; + case VTK_QUADRATIC_POLYGON: + nbPoints /= 2; + break; + default: + if ( nbPoints > 4 ) + nbPoints /= 2; + } + return nbPoints; +} + +SMDSAbs_EntityType SMDS_VtkFace::GetEntityType() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + return SMDS_MeshCell::toSmdsType( VTKCellType( aVtkType )); +} + +SMDSAbs_GeometryType SMDS_VtkFace::GetGeomType() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + switch ( aVtkType ) { + case VTK_TRIANGLE: + case VTK_QUADRATIC_TRIANGLE: + case VTK_BIQUADRATIC_TRIANGLE: return SMDSGeom_TRIANGLE; + + case VTK_QUAD: + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: return SMDSGeom_QUADRANGLE; + + case VTK_POLYGON: + case VTK_QUADRATIC_POLYGON: return SMDSGeom_POLYGON; + default:; + } + return SMDSGeom_NONE; +} + +vtkIdType SMDS_VtkFace::GetVtkType() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + return aVtkType; +} + +SMDS_ElemIteratorPtr SMDS_VtkFace::elementsIterator(SMDSAbs_ElementType type) const +{ + switch (type) + { + case SMDSAbs_Node: + return SMDS_ElemIteratorPtr(new SMDS_VtkCellIterator(SMDS_Mesh::_meshList[myMeshId], myVtkID, GetEntityType())); + default: + MESSAGE("ERROR : Iterator not implemented") + ; + return SMDS_ElemIteratorPtr((SMDS_ElemIterator*) NULL); + } +} + +SMDS_NodeIteratorPtr SMDS_VtkFace::nodesIteratorToUNV() const +{ + return SMDS_NodeIteratorPtr(new SMDS_VtkCellIteratorToUNV(SMDS_Mesh::_meshList[myMeshId], myVtkID, GetEntityType())); +} + +SMDS_NodeIteratorPtr SMDS_VtkFace::interlacedNodesIterator() const +{ + return nodesIteratorToUNV(); +} + +//! change only the first node, used for temporary triangles in quadrangle to triangle adaptor +void SMDS_VtkFace::ChangeApex(SMDS_MeshNode* node) +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(myVtkID, npts, pts); + grid->RemoveReferenceToCell(pts[0], myVtkID); + pts[0] = node->getVtkId(); + node->AddInverseElement(this), + SMDS_Mesh::_meshList[myMeshId]->setMyModified(); +} diff --git a/src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkVolume.cpp b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkVolume.cpp new file mode 100644 index 000000000000..015edf75fd26 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMDS/SMDS_VtkVolume.cpp @@ -0,0 +1,724 @@ +// Copyright (C) 2010-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +#include "SMDS_VtkVolume.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMDS_Mesh.hxx" +#include "SMDS_VtkCellIterator.hxx" + +#include "utilities.h" + +#include + +SMDS_VtkVolume::SMDS_VtkVolume() +{ +} + +SMDS_VtkVolume::SMDS_VtkVolume(const std::vector& nodeIds, SMDS_Mesh* mesh) +{ + init(nodeIds, mesh); +} +/*! + * typed used are vtk types (@see vtkCellType.h) + * see GetEntityType() for conversion in SMDS type (@see SMDSAbs_ElementType.hxx) + */ +void SMDS_VtkVolume::init(const std::vector& nodeIds, SMDS_Mesh* mesh) +{ + SMDS_MeshVolume::init(); + vtkUnstructuredGrid* grid = mesh->getGrid(); + myMeshId = mesh->getMeshId(); + vtkIdType aType = VTK_TETRA; + switch (nodeIds.size()) // cases are in order of usage frequency + { + case 4: + aType = VTK_TETRA; + break; + case 8: + aType = VTK_HEXAHEDRON; + break; + case 5: + aType = VTK_PYRAMID; + break; + case 6: + aType = VTK_WEDGE; + break; + case 10: + aType = VTK_QUADRATIC_TETRA; + break; + case 20: + aType = VTK_QUADRATIC_HEXAHEDRON; + break; + case 13: + aType = VTK_QUADRATIC_PYRAMID; + break; + case 15: + aType = VTK_QUADRATIC_WEDGE; + break; + case 12: + aType = VTK_HEXAGONAL_PRISM; + break; + case 27: + aType = VTK_TRIQUADRATIC_HEXAHEDRON; + break; + default: + aType = VTK_HEXAHEDRON; + break; + } + myVtkID = grid->InsertNextLinkedCell(aType, nodeIds.size(), (vtkIdType *) &nodeIds[0]); + mesh->setMyModified(); + //MESSAGE("SMDS_VtkVolume::init myVtkID " << myVtkID); +} + +//#ifdef VTK_HAVE_POLYHEDRON +void SMDS_VtkVolume::initPoly(const std::vector& nodeIds, + const std::vector& nbNodesPerFace, + SMDS_Mesh* mesh) +{ + SMDS_MeshVolume::init(); + //MESSAGE("SMDS_VtkVolume::initPoly"); + SMDS_UnstructuredGrid* grid = mesh->getGrid(); + //double center[3]; + //this->gravityCenter(grid, &nodeIds[0], nodeIds.size(), ¢er[0]); + vector ptIds; + vtkIdType nbFaces = nbNodesPerFace.size(); + int k = 0; + for (int i = 0; i < nbFaces; i++) + { + int nf = nbNodesPerFace[i]; + ptIds.push_back(nf); + // EAP: a right approach is: + // - either the user should care of order of nodes or + // - the user should use a service method arranging nodes if he + // don't want or can't to do it by him-self + // The method below works OK only with planar faces and convex polyhedrones + // + // double a[3]; + // double b[3]; + // double c[3]; + // grid->GetPoints()->GetPoint(nodeIds[k], a); + // grid->GetPoints()->GetPoint(nodeIds[k + 1], b); + // grid->GetPoints()->GetPoint(nodeIds[k + 2], c); + // bool isFaceForward = this->isForward(a, b, c, center); + //MESSAGE("isFaceForward " << i << " " << isFaceForward); + const vtkIdType *facePts = &nodeIds[k]; + //if (isFaceForward) + for (int n = 0; n < nf; n++) + ptIds.push_back(facePts[n]); + // else + // for (int n = nf - 1; n >= 0; n--) + // ptIds.push_back(facePts[n]); + k += nf; + } + myVtkID = grid->InsertNextLinkedCell(VTK_POLYHEDRON, nbFaces, &ptIds[0]); + mesh->setMyModified(); +} +//#endif + +bool SMDS_VtkVolume::ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(myVtkID, npts, pts); + if (nbNodes != npts) + { + MESSAGE("ChangeNodes problem: not the same number of nodes " << npts << " -> " << nbNodes); + return false; + } + for (int i = 0; i < nbNodes; i++) + { + pts[i] = nodes[i]->getVtkId(); + } + SMDS_Mesh::_meshList[myMeshId]->setMyModified(); + return true; +} + +/*! + * Reorder in VTK order a list of nodes given in SMDS order. + * To be used before ChangeNodes: lists are given or computed in SMDS order. + */ +bool SMDS_VtkVolume::vtkOrder(const SMDS_MeshNode* nodes[], const int nbNodes) +{ + if (nbNodes != this->NbNodes()) + { + MESSAGE("vtkOrder, wrong number of nodes " << nbNodes << " instead of "<< this->NbNodes()); + return false; + } + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + const std::vector& interlace = SMDS_MeshCell::toVtkOrder( VTKCellType( aVtkType )); + if ( !interlace.empty() ) + { + ASSERT( interlace.size() == nbNodes ); + std::vector initNodes( nodes, nodes+nbNodes ); + for ( size_t i = 0; i < interlace.size(); ++i ) + nodes[i] = initNodes[ interlace[i] ]; + } + return true; +} + +SMDS_VtkVolume::~SMDS_VtkVolume() +{ +} + +void SMDS_VtkVolume::Print(ostream & OS) const +{ + OS << "volume <" << GetID() << "> : "; +} + +int SMDS_VtkVolume::NbFaces() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + int nbFaces = 4; + switch (aVtkType) + { + case VTK_TETRA: + case VTK_QUADRATIC_TETRA: + nbFaces = 4; + break; + case VTK_PYRAMID: + case VTK_WEDGE: + case VTK_QUADRATIC_PYRAMID: + case VTK_QUADRATIC_WEDGE: + nbFaces = 5; + break; + case VTK_HEXAHEDRON: + case VTK_QUADRATIC_HEXAHEDRON: + case VTK_TRIQUADRATIC_HEXAHEDRON: + nbFaces = 6; + break; + case VTK_POLYHEDRON: + { + vtkIdType nFaces = 0; + vtkIdType* ptIds = 0; + grid->GetFaceStream(this->myVtkID, nFaces, ptIds); + nbFaces = nFaces; + break; + } + case VTK_HEXAGONAL_PRISM: + nbFaces = 8; + break; + default: + MESSAGE("invalid volume type") + ; + nbFaces = 0; + break; + } + return nbFaces; +} + +int SMDS_VtkVolume::NbNodes() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + int nbPoints = 0; + if (aVtkType != VTK_POLYHEDRON) + { + nbPoints = grid->GetCell(myVtkID)->GetNumberOfPoints(); + } + else + { + vtkIdType nFaces = 0; + vtkIdType* ptIds = 0; + grid->GetFaceStream(this->myVtkID, nFaces, ptIds); + int id = 0; + for (int i = 0; i < nFaces; i++) + { + int nodesInFace = ptIds[id]; + nbPoints += nodesInFace; + id += (nodesInFace + 1); + } + } + return nbPoints; +} + +int SMDS_VtkVolume::NbEdges() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + int nbEdges = 6; + switch (aVtkType) + { + case VTK_TETRA: + case VTK_QUADRATIC_TETRA: + nbEdges = 6; + break; + case VTK_PYRAMID: + case VTK_QUADRATIC_PYRAMID: + nbEdges = 8; + break; + case VTK_WEDGE: + case VTK_QUADRATIC_WEDGE: + nbEdges = 9; + break; + case VTK_HEXAHEDRON: + case VTK_QUADRATIC_HEXAHEDRON: + case VTK_TRIQUADRATIC_HEXAHEDRON: + nbEdges = 12; + break; + case VTK_POLYHEDRON: + { + vtkIdType nFaces = 0; + vtkIdType* ptIds = 0; + grid->GetFaceStream(this->myVtkID, nFaces, ptIds); + nbEdges = 0; + int id = 0; + for (int i = 0; i < nFaces; i++) + { + int edgesInFace = ptIds[id]; + id += (edgesInFace + 1); + nbEdges += edgesInFace; + } + nbEdges = nbEdges / 2; + break; + } + case VTK_HEXAGONAL_PRISM: + nbEdges = 18; + break; + default: + MESSAGE("invalid volume type") + ; + nbEdges = 0; + break; + } + return nbEdges; +} + +/*! polyhedron only, + * 1 <= face_ind <= NbFaces() + */ +int SMDS_VtkVolume::NbFaceNodes(const int face_ind) const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + int nbNodes = 0; + if (aVtkType == VTK_POLYHEDRON) + { + vtkIdType nFaces = 0; + vtkIdType* ptIds = 0; + grid->GetFaceStream(this->myVtkID, nFaces, ptIds); + int id = 0; + for (int i = 0; i < nFaces; i++) + { + int nodesInFace = ptIds[id]; + id += (nodesInFace + 1); + if (i == face_ind - 1) + { + nbNodes = nodesInFace; + break; + } + } + } + return nbNodes; +} + +/*! polyhedron only, + * 1 <= face_ind <= NbFaces() + * 1 <= node_ind <= NbFaceNodes() + */ +const SMDS_MeshNode* SMDS_VtkVolume::GetFaceNode(const int face_ind, const int node_ind) const +{ + SMDS_Mesh *mesh = SMDS_Mesh::_meshList[myMeshId]; + vtkUnstructuredGrid* grid = mesh->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + const SMDS_MeshNode* node = 0; + if (aVtkType == VTK_POLYHEDRON) + { + vtkIdType nFaces = 0; + vtkIdType* ptIds = 0; + grid->GetFaceStream(this->myVtkID, nFaces, ptIds); + int id = 0; + for (int i = 0; i < nFaces; i++) + { + int nodesInFace = ptIds[id]; // nodeIds in ptIds[id+1 .. id+nodesInFace] + if (i == face_ind - 1) // first face is number 1 + { + if ((node_ind > 0) && (node_ind <= nodesInFace)) + node = mesh->FindNodeVtk(ptIds[id + node_ind]); // ptIds[id+1] : first node + break; + } + id += (nodesInFace + 1); + } + } + return node; +} + +/*! polyhedron only, + * return number of nodes for each face + */ +std::vector SMDS_VtkVolume::GetQuantities() const +{ + vector quantities; + SMDS_Mesh *mesh = SMDS_Mesh::_meshList[myMeshId]; + vtkUnstructuredGrid* grid = mesh->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + if (aVtkType == VTK_POLYHEDRON) + { + vtkIdType nFaces = 0; + vtkIdType* ptIds = 0; + grid->GetFaceStream(this->myVtkID, nFaces, ptIds); + int id = 0; + for (int i = 0; i < nFaces; i++) + { + int nodesInFace = ptIds[id]; // nodeIds in ptIds[id+1 .. id+nodesInFace] + quantities.push_back(nodesInFace); + id += (nodesInFace + 1); + } + } + return quantities; +} + +SMDS_ElemIteratorPtr SMDS_VtkVolume::elementsIterator(SMDSAbs_ElementType type) const +{ + switch (type) + { + case SMDSAbs_Node: + { + SMDSAbs_EntityType aType = this->GetEntityType(); + if (aType == SMDSEntity_Polyhedra) + return SMDS_ElemIteratorPtr(new SMDS_VtkCellIteratorPolyH(SMDS_Mesh::_meshList[myMeshId], myVtkID, aType)); + else + return SMDS_ElemIteratorPtr(new SMDS_VtkCellIterator(SMDS_Mesh::_meshList[myMeshId], myVtkID, aType)); + } + default: + MESSAGE("ERROR : Iterator not implemented"); + return SMDS_ElemIteratorPtr((SMDS_ElemIterator*) NULL); + } +} + +SMDS_NodeIteratorPtr SMDS_VtkVolume::nodesIteratorToUNV() const +{ + return SMDS_NodeIteratorPtr(new SMDS_VtkCellIteratorToUNV(SMDS_Mesh::_meshList[myMeshId], myVtkID, GetEntityType())); +} + +SMDS_NodeIteratorPtr SMDS_VtkVolume::interlacedNodesIterator() const +{ + return SMDS_NodeIteratorPtr(new SMDS_VtkCellIteratorToUNV(SMDS_Mesh::_meshList[myMeshId], myVtkID, GetEntityType())); +} + +SMDSAbs_ElementType SMDS_VtkVolume::GetType() const +{ + return SMDSAbs_Volume; +} + +/*! + * \brief Return node by its index + * \param ind - node index + * \retval const SMDS_MeshNode* - the node + */ +const SMDS_MeshNode* SMDS_VtkVolume::GetNode(const int ind) const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + if ( aVtkType == VTK_POLYHEDRON) + { + vtkIdType nFaces = 0; + vtkIdType* ptIds = 0; + grid->GetFaceStream(this->myVtkID, nFaces, ptIds); + int id = 0, nbPoints = 0; + for (int i = 0; i < nFaces; i++) + { + int nodesInFace = ptIds[id]; + if ( ind < nbPoints + nodesInFace ) + return SMDS_Mesh::_meshList[myMeshId]->FindNodeVtk( ptIds[ ind + i ]); + nbPoints += nodesInFace; + id += (nodesInFace + 1); + } + return 0; + } + vtkIdType npts, *pts; + grid->GetCellPoints( this->myVtkID, npts, pts ); + const std::vector& interlace = SMDS_MeshCell::fromVtkOrder( VTKCellType( aVtkType )); + return SMDS_Mesh::_meshList[myMeshId]->FindNodeVtk( pts[ interlace.empty() ? ind : interlace[ind]] ); +} +/*! + * \brief Check if a node belongs to the element + * \param node - the node to check + * \retval int - node index within the element, -1 if not found + */ +int SMDS_VtkVolume::GetNodeIndex( const SMDS_MeshNode* node ) const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + const vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + if ( aVtkType == VTK_POLYHEDRON) + { + vtkIdType nFaces = 0; + vtkIdType* ptIds = 0; + grid->GetFaceStream(this->myVtkID, nFaces, ptIds); + int id = 0; + for (int iF = 0; iF < nFaces; iF++) + { + int nodesInFace = ptIds[id]; + for ( vtkIdType i = 0; i < nodesInFace; ++i ) + if ( ptIds[id+i+1] == node->getVtkId() ) + return id+i-iF; + id += (nodesInFace + 1); + } + return -1; + } + vtkIdType npts, *pts; + grid->GetCellPoints( this->myVtkID, npts, pts ); + for ( vtkIdType i = 0; i < npts; ++i ) + if ( pts[i] == node->getVtkId() ) + { + const std::vector& interlace = SMDS_MeshCell::toVtkOrder( VTKCellType( aVtkType )); + return interlace.empty() ? i : interlace[i]; + } + return -1; +} + +bool SMDS_VtkVolume::IsQuadratic() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + // TODO quadratic polyhedrons ? + switch (aVtkType) + { + case VTK_QUADRATIC_TETRA: + case VTK_QUADRATIC_PYRAMID: + case VTK_QUADRATIC_WEDGE: + case VTK_QUADRATIC_HEXAHEDRON: + case VTK_TRIQUADRATIC_HEXAHEDRON: + return true; + break; + default: + return false; + } +} + +bool SMDS_VtkVolume::IsPoly() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + return (aVtkType == VTK_POLYHEDRON); +} + +bool SMDS_VtkVolume::IsMediumNode(const SMDS_MeshNode* node) const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + int rankFirstMedium = 0; + switch (aVtkType) + { + case VTK_QUADRATIC_TETRA: + rankFirstMedium = 4; // medium nodes are of rank 4 to 9 + break; + case VTK_QUADRATIC_PYRAMID: + rankFirstMedium = 5; // medium nodes are of rank 5 to 12 + break; + case VTK_QUADRATIC_WEDGE: + rankFirstMedium = 6; // medium nodes are of rank 6 to 14 + break; + case VTK_QUADRATIC_HEXAHEDRON: + case VTK_TRIQUADRATIC_HEXAHEDRON: + rankFirstMedium = 8; // medium nodes are of rank 8 to 19 + break; + default: + return false; + } + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(myVtkID, npts, pts); + vtkIdType nodeId = node->getVtkId(); + for (int rank = 0; rank < npts; rank++) + { + if (pts[rank] == nodeId) + { + if (rank < rankFirstMedium) + return false; + else + return true; + } + } + //throw SALOME_Exception(LOCALIZED("node does not belong to this element")); + MESSAGE("======================================================"); + MESSAGE("= IsMediumNode: node does not belong to this element ="); + MESSAGE("======================================================"); + return false; +} + +int SMDS_VtkVolume::NbCornerNodes() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(myVtkID); + switch (aVtkType) + { + case VTK_QUADRATIC_TETRA: return 4; + case VTK_QUADRATIC_PYRAMID: return 5; + case VTK_QUADRATIC_WEDGE: return 6; + case VTK_QUADRATIC_HEXAHEDRON: + case VTK_TRIQUADRATIC_HEXAHEDRON: return 8; + default:; + } + return NbNodes(); +} + +SMDSAbs_EntityType SMDS_VtkVolume::GetEntityType() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + + SMDSAbs_EntityType aType = SMDSEntity_Tetra; + switch (aVtkType) + { + case VTK_TETRA: + aType = SMDSEntity_Tetra; + break; + case VTK_PYRAMID: + aType = SMDSEntity_Pyramid; + break; + case VTK_WEDGE: + aType = SMDSEntity_Penta; + break; + case VTK_HEXAHEDRON: + aType = SMDSEntity_Hexa; + break; + case VTK_QUADRATIC_TETRA: + aType = SMDSEntity_Quad_Tetra; + break; + case VTK_QUADRATIC_PYRAMID: + aType = SMDSEntity_Quad_Pyramid; + break; + case VTK_QUADRATIC_WEDGE: + aType = SMDSEntity_Quad_Penta; + break; + case VTK_QUADRATIC_HEXAHEDRON: + aType = SMDSEntity_Quad_Hexa; + break; + case VTK_TRIQUADRATIC_HEXAHEDRON: + aType = SMDSEntity_TriQuad_Hexa; + break; + case VTK_HEXAGONAL_PRISM: + aType = SMDSEntity_Hexagonal_Prism; + break; +//#ifdef VTK_HAVE_POLYHEDRON + case VTK_POLYHEDRON: + aType = SMDSEntity_Polyhedra; + break; +//#endif + default: + aType = SMDSEntity_Polyhedra; + break; + } + return aType; +} + +SMDSAbs_GeometryType SMDS_VtkVolume::GetGeomType() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aVtkType = grid->GetCellType(this->myVtkID); + + SMDSAbs_GeometryType aType = SMDSGeom_NONE; + switch (aVtkType) + { + case VTK_TETRA: + case VTK_QUADRATIC_TETRA: + aType = SMDSGeom_TETRA; + break; + case VTK_PYRAMID: + case VTK_QUADRATIC_PYRAMID: + aType = SMDSGeom_PYRAMID; + break; + case VTK_WEDGE: + case VTK_QUADRATIC_WEDGE: + aType = SMDSGeom_PENTA; + break; + case VTK_HEXAHEDRON: + case VTK_QUADRATIC_HEXAHEDRON: + case VTK_TRIQUADRATIC_HEXAHEDRON: + aType = SMDSGeom_HEXA; + break; + case VTK_HEXAGONAL_PRISM: + aType = SMDSGeom_HEXAGONAL_PRISM; + break; +//#ifdef VTK_HAVE_POLYHEDRON + case VTK_POLYHEDRON: + aType = SMDSGeom_POLYHEDRA; + break; +//#endif + default: + aType = SMDSGeom_POLYHEDRA; + break; + } + return aType; +} + +vtkIdType SMDS_VtkVolume::GetVtkType() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + vtkIdType aType = grid->GetCellType(myVtkID); + return aType; +} + +void SMDS_VtkVolume::gravityCenter(SMDS_UnstructuredGrid* grid, + const vtkIdType * nodeIds, + int nbNodes, + double* result) +{ + for (int j = 0; j < 3; j++) + result[j] = 0; + if (nbNodes <= 0) + return; + for (int i = 0; i < nbNodes; i++) + { + double *coords = grid->GetPoint(nodeIds[i]); + for (int j = 0; j < 3; j++) + result[j] += coords[j]; + } + for (int j = 0; j < 3; j++) + result[j] = result[j] / nbNodes; + //MESSAGE("center " << result[0] << " " << result[1] << " " << result[2]); + return; +} + +bool SMDS_VtkVolume::isForward(double* a, double* b, double* c, double* d) +{ + double u[3], v[3], w[3]; + for (int j = 0; j < 3; j++) + { + //MESSAGE("a,b,c,d " << a[j] << " " << b[j] << " " << c[j] << " " << d[j]); + u[j] = b[j] - a[j]; + v[j] = c[j] - a[j]; + w[j] = d[j] - a[j]; + //MESSAGE("u,v,w " << u[j] << " " << v[j] << " " << w[j]); + } + double prodmixte = (u[1]*v[2] - u[2]*v[1]) * w[0] + + (u[2]*v[0] - u[0]*v[2]) * w[1] + + (u[0]*v[1] - u[1]*v[0]) * w[2]; + return (prodmixte < 0); +} + +/*! For polyhedron only + * @return actual number of nodes (not the sum of nodes of all faces) + */ +int SMDS_VtkVolume::NbUniqueNodes() const +{ + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); + return grid->GetCell(myVtkID)->GetNumberOfPoints(); +} + +/*! For polyhedron use only + * @return iterator on actual nodes (not through the faces) + */ +SMDS_ElemIteratorPtr SMDS_VtkVolume::uniqueNodesIterator() const +{ + //MESSAGE("uniqueNodesIterator"); + return SMDS_ElemIteratorPtr(new SMDS_VtkCellIterator(SMDS_Mesh::_meshList[myMeshId], myVtkID, GetEntityType())); +} diff --git a/src/3rdParty/salomesmesh/src/SMDS/Utils_SALOME_Exception.cpp b/src/3rdParty/salomesmesh/src/SMDS/Utils_SALOME_Exception.cpp new file mode 100644 index 000000000000..035d48b27a59 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMDS/Utils_SALOME_Exception.cpp @@ -0,0 +1,122 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SALOME Utils : general SALOME's definitions and tools +// File : Utils_SALOME_Exception.cxx +// Author : Antoine YESSAYAN, EDF +// Module : SALOME +// $Header$ +// +#include +#include "Utils_SALOME_Exception.hxx" +#include "utilities.h" + +#ifndef WIN32 +extern "C" +{ +#endif +#include +#include +#include +#ifndef WIN32 +} +#endif + + +const char* duplicate( const char *const str ) ; + +SALOME_Exception::SALOME_Exception( void ): exception() , _text(0) +{ + MESSAGE( "You must use the standard builder: SALOME_Exception::SALOME_Exception( const char *text )" ) ; + INTERRUPTION(1) ; +} + + + +const char *makeText( const char *text, const char *fileName, const unsigned int lineNumber ) +{ + char *newText = 0 ; + + ASSERT(text) ; + const size_t l1 = 1+strlen(text) ; + ASSERT(l1>1) ; + + const char* prefix = "Salome Exception" ; + const size_t l0 = 2+strlen(prefix) ; + + if ( fileName ) + { + const size_t l2 = 4+strlen(fileName) ; + ASSERT(l2>4) ; + + ASSERT(lineNumber>=1) ; + const size_t l3 = 4+int(log10(float(lineNumber))) ; + + newText = new char [ 1+l0+l1+l2+l3 ] ; + sprintf( newText , "%s in %s [%u] : %s" , prefix, fileName, lineNumber, text ) ; + } + else + { + newText = new char [ 1+l0+l1 ] ; + sprintf( newText , "%s : %s" , prefix, text ) ; + } + ASSERT(newText) ; + return newText ; +} + + +SALOME_Exception::SALOME_Exception( const char *text, const char *fileName, const unsigned int lineNumber ) : exception(), _text( makeText( text , fileName , lineNumber ) ) +{ +} + + +SALOME_Exception::~SALOME_Exception() throw () +{ + if ( _text ) + { + delete [] ((char*)_text); + char** pRef = (char**)&_text; + *pRef = 0; + } + ASSERT(_text==NULL) ; +} + + + +SALOME_Exception::SALOME_Exception( const SALOME_Exception &ex ): _text(duplicate(ex._text)) +{ + ; +} + + +std::ostream & operator<<( std::ostream &os , const SALOME_Exception &ex ) +{ + os << ex._text ; + return os ; +} + + + +const char* SALOME_Exception::what( void ) const throw () +{ + return _text ; +} diff --git a/src/3rdParty/salomesmesh/src/SMDS/chrono.cpp b/src/3rdParty/salomesmesh/src/SMDS/chrono.cpp new file mode 100644 index 000000000000..cdbdb7ccb677 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMDS/chrono.cpp @@ -0,0 +1,87 @@ +// Copyright (C) 2006-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +#include "chrono.hxx" +#include "utilities.h" + +using namespace std; + +cntStruct* counters::_ctrs = 0; +int counters::_nbChrono = 0; + +counters::counters(int nb) +{ + MESSAGE("counters::counters(int nb)"); + _nbChrono = nb; + _ctrs = new cntStruct[_nbChrono]; + + for (int i = 0; i < _nbChrono; i++) + { + _ctrs[i]._ctrNames = 0; + _ctrs[i]._ctrLines = 0; + _ctrs[i]._ctrOccur = 0; + _ctrs[i]._ctrCumul = 0; + } + + MESSAGE("counters::counters()"); +} + +counters::~counters() +{ + stats(); +} + +void counters::stats() +{ + MESSAGE("counters::stats()"); + for (int i = 0; i < _nbChrono; i++) + if (_ctrs[i]._ctrOccur) + { + MESSAGE("Compteur[" << i << "]: "<< _ctrs[i]._ctrNames << "[" << _ctrs[i]._ctrLines << "]"); + MESSAGE(" " << _ctrs[i]._ctrOccur); + MESSAGE(" " << _ctrs[i]._ctrCumul); + } +} +/* +chrono::chrono(int i) : + _ctr(i), _run(true) +{ + //MESSAGE("chrono::chrono " << _ctr << " " << _run); + _start = clock(); +} + +chrono::~chrono() +{ + if (_run) + stop(); +} + +void chrono::stop() +{ + //MESSAGE("chrono::stop " << _ctr << " " << _run); + if (_run) + { + _run = false; + _end = clock(); + double elapse = double(_end - _start) / double(CLOCKS_PER_SEC); + counters::_ctrs[_ctr]._ctrOccur++; + counters::_ctrs[_ctr]._ctrCumul += elapse; + } +} +*/ diff --git a/src/3rdParty/salomesmesh/src/SMDS/duplicate.cpp b/src/3rdParty/salomesmesh/src/SMDS/duplicate.cpp new file mode 100644 index 000000000000..276265b98149 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMDS/duplicate.cpp @@ -0,0 +1,51 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SALOME Utils : general SALOME's definitions and tools +// File : duplicate.cxx +// Author : Antoine YESSAYAN, EDF +// Module : SALOME +// $Header$ +// +/*! + * This function can be changed by strdup() if strdup() is ANSI. + * It is strongly (and only) used in the Registry environment + * (RegistryService, RegistryConnexion, Identity, ...) + */ +extern "C" +{ +#include +#include +} +#include "utilities.h" +#include "OpUtil.hxx" + +const char* duplicate( const char *const str ) +{ + ASSERT(str!=NULL) ; + const size_t length = strlen( str ) ; + ASSERT(length>0) ; + char *new_str = new char[ 1+length ] ; + ASSERT(new_str) ; + strcpy( new_str , str ) ; + return new_str ; +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/DriverGMF.cpp b/src/3rdParty/salomesmesh/src/SMESH/DriverGMF.cpp new file mode 100644 index 000000000000..d72ff2363f39 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/DriverGMF.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : DriverGMF.hxx +// Created : Thu Nov 15 16:45:58 2012 +// Author : Edward AGAPOV (eap) + +#include "DriverGMF.hxx" + +#include + +extern "C" +{ +#include "libmesh5.h" +} + +namespace DriverGMF +{ + + //================================================================================ + /*! + * \brief Closes GMF mesh at destruction + */ + //================================================================================ + + MeshCloser::~MeshCloser() + { + if ( _gmfMeshID ) + GmfCloseMesh( _gmfMeshID ); + } + + //================================================================================ + /*! + * \brief Checks GMF file extension + */ + //================================================================================ + + bool isExtensionCorrect( const std::string& fileName ) + { + std::string ext = boost::filesystem::extension(fileName); + switch ( ext.size() ) { + case 5: return ( ext == ".mesh" || ext == ".solb" ); + case 6: return ( ext == ".meshb" ); + case 4: return ( ext == ".sol" ); + } + return false; + } +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/DriverGMF_Read.cpp b/src/3rdParty/salomesmesh/src/SMESH/DriverGMF_Read.cpp new file mode 100644 index 000000000000..f1b9d4a184dc --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/DriverGMF_Read.cpp @@ -0,0 +1,486 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : DriverGMF_Read.cxx +// Created : Mon Sep 17 17:03:02 2012 +// Author : Edward AGAPOV (eap) + +#include "DriverGMF_Read.hxx" +#include "DriverGMF.hxx" + +#include "SMESHDS_Group.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_Comment.hxx" +#include "SMESH_TypeDefs.hxx" + +#include + +extern "C" +{ +#include "libmesh5.h" +} + +#include + +// -------------------------------------------------------------------------------- +DriverGMF_Read::DriverGMF_Read(): + Driver_SMESHDS_Mesh(), + _makeRequiredGroups( true ) +{ +} +// -------------------------------------------------------------------------------- +DriverGMF_Read::~DriverGMF_Read() +{ +} + +//================================================================================ +/*! + * \brief Read a GMF file + */ +//================================================================================ + +Driver_Mesh::Status DriverGMF_Read::Perform() +{ + Kernel_Utils::Localizer loc; + + Status status = DRS_OK; + + int dim, version; + + // open the file + int meshID = GmfOpenMesh( myFile.c_str(), GmfRead, &version, &dim ); + if ( !meshID ) + { + if ( DriverGMF::isExtensionCorrect( myFile )) + return addMessage( SMESH_Comment("Can't open for reading ") << myFile, + /*fatal=*/true ); + else + return addMessage( SMESH_Comment("Not '.mesh' or '.meshb' extension of file ") << myFile, + /*fatal=*/true ); + } + DriverGMF::MeshCloser aMeshCloser( meshID ); // An object closing GMF mesh at destruction + + // Read nodes + + int nbNodes = GmfStatKwd(meshID, GmfVertices); + if ( nbNodes < 1 ) + return addMessage( "No nodes in the mesh", /*fatal=*/true ); + + GmfGotoKwd(meshID, GmfVertices); + + int ref; + + const int nodeIDShift = myMesh->GetMeshInfo().NbNodes(); + if ( version != GmfFloat ) + { + double x, y, z; + for ( int i = 1; i <= nbNodes; ++i ) + { + GmfGetLin(meshID, GmfVertices, &x, &y, &z, &ref); + myMesh->AddNodeWithID( x,y,z, nodeIDShift + i); + } + } + else + { + float x, y, z; + for ( int i = 1; i <= nbNodes; ++i ) + { + GmfGetLin(meshID, GmfVertices, &x, &y, &z, &ref); + myMesh->AddNodeWithID( x,y,z, nodeIDShift + i); + } + } + + // Read elements + + int iN[28]; // 28 - nb nodes in HEX27 (+ 1 for safety :) + + /* Read edges */ + const int edgeIDShift = myMesh->GetMeshInfo().NbElements(); + if ( int nbEdges = GmfStatKwd(meshID, GmfEdges)) + { + // read extra vertices for quadratic edges + std::vector quadNodesAtEdges( nbEdges + 1, -1 ); + if ( int nbQuadEdges = GmfStatKwd(meshID, GmfExtraVerticesAtEdges)) + { + GmfGotoKwd(meshID, GmfExtraVerticesAtEdges); + for ( int i = 1; i <= nbQuadEdges; ++i ) + { + GmfGetLin(meshID, GmfExtraVerticesAtEdges, &iN[0], &iN[1], &iN[2]); + if ( iN[1] >= 1 ) + quadNodesAtEdges[ iN[0] ] = iN[2]; + } + } + // create edges + GmfGotoKwd(meshID, GmfEdges); + for ( int i = 1; i <= nbEdges; ++i ) + { + GmfGetLin(meshID, GmfEdges, &iN[0], &iN[1], &ref); + const int midN = quadNodesAtEdges[ i ]; + if ( midN > 0 ) + { + if ( !myMesh->AddEdgeWithID( iN[0], iN[1], midN, edgeIDShift + i )) + status = storeBadNodeIds( "GmfEdges + GmfExtraVerticesAtEdges",i, + 3, iN[0], iN[1], midN); + } + else + { + if ( !myMesh->AddEdgeWithID( iN[0], iN[1], edgeIDShift + i )) + status = storeBadNodeIds( "GmfEdges",i, 2, iN[0], iN[1] ); + } + } + } + + /* Read triangles */ + const int triaIDShift = myMesh->GetMeshInfo().NbElements(); + if ( int nbTria = GmfStatKwd(meshID, GmfTriangles)) + { + // read extra vertices for quadratic triangles + std::vector< std::vector > quadNodesAtTriangles( nbTria + 1 ); + if ( int nbQuadTria = GmfStatKwd(meshID, GmfExtraVerticesAtTriangles )) + { + GmfGotoKwd( meshID, GmfExtraVerticesAtTriangles ); + for ( int i = 1; i <= nbQuadTria; ++i ) + { + GmfGetLin(meshID, GmfExtraVerticesAtTriangles, + &iN[0], &iN[1], &iN[2], &iN[3], &iN[4], + &iN[5]); // iN[5] - preview TRIA7 + if ( iN[0] <= nbTria ) + { + std::vector& nodes = quadNodesAtTriangles[ iN[0] ]; + nodes.insert( nodes.end(), & iN[2], & iN[5+1] ); + nodes.resize( iN[1] ); + } + } + } + // create triangles + GmfGotoKwd(meshID, GmfTriangles); + for ( int i = 1; i <= nbTria; ++i ) + { + GmfGetLin(meshID, GmfTriangles, &iN[0], &iN[1], &iN[2], &ref); + std::vector& midN = quadNodesAtTriangles[ i ]; + if ( midN.size() >= 3 ) + { + if ( !myMesh->AddFaceWithID( iN[0],iN[1],iN[2], midN[0],midN[1],midN[2], + triaIDShift + i )) + status = storeBadNodeIds( "GmfTriangles + GmfExtraVerticesAtTriangles",i, 6, + iN[0],iN[1],iN[2], midN[0],midN[1],midN[2] ); + } + else + { + if ( !myMesh->AddFaceWithID( iN[0], iN[1], iN[2], triaIDShift + i )) + status = storeBadNodeIds( "GmfTriangles",i, 3, iN[0], iN[1], iN[2] ); + } + if ( !midN.empty() ) SMESHUtils::FreeVector( midN ); + } + } + + /* Read quadrangles */ + const int quadIDShift = myMesh->GetMeshInfo().NbElements(); + if ( int nbQuad = GmfStatKwd(meshID, GmfQuadrilaterals)) + { + // read extra vertices for quadratic quadrangles + std::vector< std::vector > quadNodesAtQuadrilaterals( nbQuad + 1 ); + if ( int nbQuadQuad = GmfStatKwd( meshID, GmfExtraVerticesAtQuadrilaterals )) + { + GmfGotoKwd(meshID, GmfExtraVerticesAtQuadrilaterals); + for ( int i = 1; i <= nbQuadQuad; ++i ) + { + GmfGetLin(meshID, GmfExtraVerticesAtQuadrilaterals, + &iN[0], &iN[1], &iN[2], &iN[3], &iN[4], &iN[5], &iN[6]); + if ( iN[0] <= nbQuad ) + { + std::vector& nodes = quadNodesAtQuadrilaterals[ iN[0] ]; + nodes.insert( nodes.end(), & iN[2], & iN[6+1] ); + nodes.resize( iN[1] ); + } + } + } + // create quadrangles + GmfGotoKwd(meshID, GmfQuadrilaterals); + for ( int i = 1; i <= nbQuad; ++i ) + { + GmfGetLin(meshID, GmfQuadrilaterals, &iN[0], &iN[1], &iN[2], &iN[3], &ref); + std::vector& midN = quadNodesAtQuadrilaterals[ i ]; + if ( midN.size() == 8-4 ) // QUAD8 + { + if ( !myMesh->AddFaceWithID( iN[0], iN[1], iN[2], iN[3], + midN[0], midN[1], midN[2], midN[3], + quadIDShift + i )) + status = storeBadNodeIds( "GmfQuadrilaterals + GmfExtraVerticesAtQuadrilaterals",i, 8, + iN[0], iN[1],iN[2], iN[3], + midN[0], midN[1], midN[2], midN[3]); + } + else if ( midN.size() > 8-4 ) // QUAD9 + { + if ( !myMesh->AddFaceWithID( iN[0], iN[1], iN[2], iN[3], + midN[0], midN[1], midN[2], midN[3], midN[4], + quadIDShift + i )) + status = storeBadNodeIds( "GmfQuadrilaterals + GmfExtraVerticesAtQuadrilaterals",i, 9, + iN[0], iN[1],iN[2], iN[3], + midN[0], midN[1], midN[2], midN[3], midN[4]); + } + else // QUAD4 + { + if ( !myMesh->AddFaceWithID( iN[0], iN[1], iN[2], iN[3], quadIDShift + i )) + status = storeBadNodeIds( "GmfQuadrilaterals",i, 4, iN[0], iN[1],iN[2], iN[3] ); + } + if ( !midN.empty() ) SMESHUtils::FreeVector( midN ); + } + } + + /* Read terahedra */ + const int tetIDShift = myMesh->GetMeshInfo().NbElements(); + if ( int nbTet = GmfStatKwd( meshID, GmfTetrahedra )) + { + // read extra vertices for quadratic tetrahedra + std::vector< std::vector > quadNodesAtTetrahedra( nbTet + 1 ); + if ( int nbQuadTetra = GmfStatKwd( meshID, GmfExtraVerticesAtTetrahedra )) + { + GmfGotoKwd(meshID, GmfExtraVerticesAtTetrahedra); + for ( int i = 1; i <= nbQuadTetra; ++i ) + { + GmfGetLin(meshID, GmfExtraVerticesAtTetrahedra, + &iN[0], &iN[1], &iN[2], &iN[3], &iN[4], &iN[5], &iN[6], &iN[7]); + if ( iN[0] <= nbTet ) + { + std::vector& nodes = quadNodesAtTetrahedra[ iN[0] ]; + nodes.insert( nodes.end(), & iN[2], & iN[7+1] ); + nodes.resize( iN[1] ); + } + } + } + // create tetrahedra + GmfGotoKwd(meshID, GmfTetrahedra); + for ( int i = 1; i <= nbTet; ++i ) + { + GmfGetLin(meshID, GmfTetrahedra, &iN[0], &iN[1], &iN[2], &iN[3], &ref); + std::vector& midN = quadNodesAtTetrahedra[ i ]; + if ( midN.size() >= 10-4 ) // TETRA10 + { + if ( !myMesh->AddVolumeWithID( iN[0], iN[2], iN[1], iN[3], + midN[2], midN[1], midN[0], midN[3], midN[5], midN[4], + tetIDShift + i )) + status = storeBadNodeIds( "GmfTetrahedra + GmfExtraVerticesAtTetrahedra",i, 10, + iN[0], iN[2], iN[1], iN[3], + midN[2], midN[1], midN[0], midN[3], midN[5], midN[4] ); + } + else // TETRA4 + { + if ( !myMesh->AddVolumeWithID( iN[0], iN[2], iN[1], iN[3], tetIDShift + i )) + status = storeBadNodeIds( "GmfTetrahedra" ,i, 4, iN[0], iN[2], iN[1], iN[3] ); + } + if ( !midN.empty() ) SMESHUtils::FreeVector( midN ); + } + } + + /* Read pyramids */ + const int pyrIDShift = myMesh->GetMeshInfo().NbElements(); + if ( int nbPyr = GmfStatKwd(meshID, GmfPyramids)) + { + GmfGotoKwd(meshID, GmfPyramids); + for ( int i = 1; i <= nbPyr; ++i ) + { + GmfGetLin(meshID, GmfPyramids, &iN[0], &iN[1], &iN[2], &iN[3], &iN[4], &ref); + if ( !myMesh->AddVolumeWithID( iN[0], iN[2], iN[1], iN[3], iN[4], pyrIDShift + i )) + status = storeBadNodeIds( "GmfPyramids",i, 5, iN[0], iN[1],iN[2], iN[3], iN[4] ); + } + } + + /* Read hexahedra */ + const int hexIDShift = myMesh->GetMeshInfo().NbElements(); + if ( int nbHex = GmfStatKwd(meshID, GmfHexahedra)) + { + // read extra vertices for quadratic hexahedra + std::vector< std::vector > quadNodesAtHexahedra( nbHex + 1 ); + if ( int nbQuadHexa = GmfStatKwd( meshID, GmfExtraVerticesAtHexahedra )) + { + GmfGotoKwd(meshID, GmfExtraVerticesAtHexahedra); + for ( int i = 1; i <= nbQuadHexa; ++i ) + { + GmfGetLin(meshID, GmfExtraVerticesAtHexahedra, &iN[0], &iN[1], // Hexa Id, Nb extra vertices + &iN[2], &iN[3], &iN[4], &iN[5], + &iN[6], &iN[7], &iN[8], &iN[9], + &iN[10], &iN[11], &iN[12], &iN[13], // HEXA20 + &iN[14], + &iN[15], &iN[16], &iN[17], &iN[18], + &iN[19], + &iN[20]); // HEXA27 + if ( iN[0] <= nbHex ) + { + std::vector& nodes = quadNodesAtHexahedra[ iN[0] ]; + nodes.insert( nodes.end(), & iN[2], & iN[20+1] ); + nodes.resize( iN[1] ); + } + } + } + // create hexhedra + GmfGotoKwd(meshID, GmfHexahedra); + for ( int i = 1; i <= nbHex; ++i ) + { + GmfGetLin(meshID, GmfHexahedra, &iN[0], &iN[1], &iN[2], &iN[3], + &iN[4], &iN[5], &iN[6], &iN[7], &ref); + std::vector& midN = quadNodesAtHexahedra[ i ]; + if ( midN.size() == 20-8 ) // HEXA20 + { + if ( !myMesh->AddVolumeWithID( iN[0], iN[3], iN[2], iN[1], + iN[4], iN[7], iN[6], iN[5], + midN[3], midN[2], midN[1], midN[0], + midN[7], midN[6], midN[5], midN[4], + midN[8], midN[11], midN[10], midN[9], + hexIDShift + i )) + status = storeBadNodeIds( "GmfHexahedra + GmfExtraVerticesAtHexahedra",i, 20, + iN[0], iN[3], iN[2], iN[1], + iN[4], iN[7], iN[6], iN[5], + midN[3], midN[2], midN[1], midN[0], + midN[7], midN[6], midN[5], midN[4], + midN[8], midN[11], midN[10], midN[9]); + } + else if ( midN.size() >= 27-8 ) // HEXA27 + { + if ( !myMesh->AddVolumeWithID( iN[0], iN[3], iN[2], iN[1], + iN[4], iN[7], iN[6], iN[5], + midN[3], midN[2], midN[1], midN[0], + midN[7], midN[6], midN[5], midN[4], + midN[8], midN[11], midN[10], midN[9], + midN[12], + midN[16], midN[15], midN[14], midN[13], + midN[17], + midN[18], + hexIDShift + i )) + status = storeBadNodeIds( "GmfHexahedra + GmfExtraVerticesAtHexahedra",i, 27, + iN[0], iN[3], iN[2], iN[1], + iN[4], iN[7], iN[6], iN[5], + midN[3], midN[2], midN[1], midN[0], + midN[7], midN[6], midN[5], midN[4], + midN[8], midN[11], midN[10], midN[9], + midN[12], + midN[16], midN[15], midN[14], midN[13], + midN[17], + midN[18]); + } + else // HEXA8 + { + if ( !myMesh->AddVolumeWithID( iN[0], iN[3], iN[2], iN[1], + iN[4], iN[7], iN[6], iN[5], hexIDShift + i ) ) + status = storeBadNodeIds( "GmfHexahedra" ,i, 8, iN[0], iN[3], iN[2], iN[1], + iN[4], iN[7], iN[6], iN[5] ); + } + if ( !midN.empty() ) SMESHUtils::FreeVector( midN ); + } + } + + /* Read prism */ + const int prismIDShift = myMesh->GetMeshInfo().NbElements(); + if ( int nbPrism = GmfStatKwd(meshID, GmfPrisms)) + { + GmfGotoKwd(meshID, GmfPrisms); + for ( int i = 1; i <= nbPrism; ++i ) + { + GmfGetLin(meshID, GmfPrisms, &iN[0], &iN[1], &iN[2], &iN[3], &iN[4], &iN[5], &ref); + if ( !myMesh->AddVolumeWithID( iN[0], iN[2], iN[1], iN[3], iN[5], iN[4], prismIDShift + i)) + status = storeBadNodeIds( "GmfPrisms",i, + 6, iN[0], iN[1],iN[2], iN[3], iN[4], iN[5] ); + } + } + + // Read required entities into groups + + if ( _makeRequiredGroups ) + { + // get ids of existing groups + std::set< int > groupIDs; + const std::set& groups = myMesh->GetGroups(); + std::set::const_iterator grIter = groups.begin(); + for ( ; grIter != groups.end(); ++grIter ) + groupIDs.insert( (*grIter)->GetID() ); + if ( groupIDs.empty() ) groupIDs.insert( 0 ); + + const int kes[4][3] = { { GmfRequiredVertices, SMDSAbs_Node, nodeIDShift }, + { GmfRequiredEdges, SMDSAbs_Edge, edgeIDShift }, + { GmfRequiredTriangles, SMDSAbs_Face, triaIDShift }, + { GmfRequiredQuadrilaterals,SMDSAbs_Face, quadIDShift }}; + const char* names[4] = { "_required_Vertices" , + "_required_Edges" , + "_required_Triangles" , + "_required_Quadrilaterals" }; + for ( int i = 0; i < 4; ++i ) + { + int gmfKwd = kes[i][0]; + SMDSAbs_ElementType entity = (SMDSAbs_ElementType) kes[i][1]; + int shift = kes[i][2]; + if ( int nb = GmfStatKwd(meshID, gmfKwd)) + { + const int newID = *groupIDs.rbegin() + 1; + groupIDs.insert( newID ); + SMESHDS_Group* group = new SMESHDS_Group( newID, myMesh, entity ); + group->SetStoreName( names[i] ); + myMesh->AddGroup( group ); + + GmfGotoKwd(meshID, gmfKwd); + for ( int i = 0; i < nb; ++i ) + { + GmfGetLin(meshID, gmfKwd, &iN[0] ); + group->Add( shift + iN[0] ); + } + } + } + } + + return status; +} + +//================================================================================ +/*! + * \brief Store a message about invalid IDs of nodes + */ +//================================================================================ + +Driver_Mesh::Status DriverGMF_Read::storeBadNodeIds(const char* gmfKwd, int elemNb, int nb, ...) +{ + if ( myStatus != DRS_OK ) + return myStatus; + + SMESH_Comment msg; + + va_list VarArg; + va_start(VarArg, nb); + + for ( int i = 0; i < nb; ++i ) + { + int id = va_arg(VarArg, int ); + if ( !myMesh->FindNode( id )) + msg << " " << id; + } + va_end(VarArg); + + if ( !msg.empty() ) + { + std::string nbStr; + const char* nbNames[] = { "1-st ", "2-nd ", "3-d " }; + if ( elemNb < 3 ) nbStr = nbNames[ elemNb-1 ]; + else nbStr = SMESH_Comment(elemNb) << "-th "; + + return addMessage + ( SMESH_Comment("Wrong node IDs of ")<< nbStr << gmfKwd << ":" << msg, + /*fatal=*/false ); + } + return DRS_OK; +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/DriverGMF_Write.cpp b/src/3rdParty/salomesmesh/src/SMESH/DriverGMF_Write.cpp new file mode 100644 index 000000000000..7dc2a1fb9812 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/DriverGMF_Write.cpp @@ -0,0 +1,426 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : DriverGMF_Write.cxx +// Created : Mon Sep 17 17:03:02 2012 +// Author : Edward AGAPOV (eap) + +#include "DriverGMF_Write.hxx" +#include "DriverGMF.hxx" + +#include "SMESHDS_GroupBase.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_Comment.hxx" + +#include + +#include "utilities.h" + +extern "C" +{ +#include "libmesh5.h" +} + +#include + +#define BEGIN_ELEM_WRITE( SMDSEntity, GmfKwd, elem ) \ + elemIt = elementIterator( SMDSEntity ); \ + if ( elemIt->more() ) \ + { \ + GmfSetKwd(meshID, GmfKwd, myMesh->GetMeshInfo().NbElements( SMDSEntity )); \ + for ( int gmfID = 1; elemIt->more(); ++gmfID ) \ + { \ + const SMDS_MeshElement* elem = elemIt->next(); \ + GmfSetLin(meshID, GmfKwd, + +#define BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom, LinType, GmfKwd, elem ) \ + elemIt = elementIterator( SMDSGeom ); \ + if ( elemIt->more() ) \ + { \ + int totalNbElems = myMesh->GetMeshInfo().NbElements( SMDSGeom ); \ + int nbLinearElems = myMesh->GetMeshInfo().NbElements( LinType ); \ + if ( totalNbElems - nbLinearElems > 0 ) \ + { \ + GmfSetKwd(meshID, GmfKwd, totalNbElems - nbLinearElems); \ + for ( int gmfID = 1; elemIt->more(); ++gmfID ) \ + { \ + const SMDS_MeshElement* elem = elemIt->next(); \ + if ( elem->IsQuadratic() ) { \ + GmfSetLin(meshID, GmfKwd, gmfID, elem->NbNodes() - elem->NbCornerNodes(), + +#define END_ELEM_WRITE( elem ) \ + elem->getshapeId() ); \ + }} + +#define END_ELEM_WRITE_ADD_TO_MAP( elem, e2id ) \ + elem->getshapeId() ); \ + e2id.insert( e2id.end(), std::make_pair( elem, gmfID )); \ + }} + +#define END_EXTRA_VERTICES_WRITE() \ + ); \ + }}}} + + +Control_Pnt::Control_Pnt(): gp_Pnt() +{ + size=0; +} +Control_Pnt::Control_Pnt( const gp_Pnt& aPnt, + double theSize): gp_Pnt( aPnt ) +{ + size=theSize; +} +Control_Pnt::Control_Pnt(double theX, + double theY, + double theZ): gp_Pnt(theX, theY, theZ) +{ + size=0; +} +Control_Pnt::Control_Pnt(double theX, + double theY, + double theZ, + double theSize): gp_Pnt(theX, theY, theZ) +{ + size=theSize; +} + +DriverGMF_Write::DriverGMF_Write(): + Driver_SMESHDS_Mesh(), _exportRequiredGroups( true ) +{ +} +DriverGMF_Write::~DriverGMF_Write() +{ +} + +//================================================================================ +/*! + * \brief Reads a GMF file + */ +//================================================================================ + +Driver_Mesh::Status DriverGMF_Write::Perform() +{ + Kernel_Utils::Localizer loc; + + const int dim = 3, version = sizeof(double) < 8 ? 1 : 2; + + int meshID = GmfOpenMesh( myFile.c_str(), GmfWrite, version, dim ); + if ( !meshID ) + { + if ( DriverGMF::isExtensionCorrect( myFile )) + return addMessage( SMESH_Comment("Can't open for writing ") << myFile, /*fatal=*/true ); + else + return addMessage( SMESH_Comment("Not '.mesh' or '.meshb' extension of file ") << myFile, /*fatal=*/true ); + } + + DriverGMF::MeshCloser aMeshCloser( meshID ); // An object closing GMF mesh at destruction + + // nodes + std::map< const SMDS_MeshNode* , int > node2IdMap; + int iN = 0, nbNodes = myMesh->NbNodes(); + GmfSetKwd( meshID, GmfVertices, nbNodes ); + double xyz[3]; + SMDS_NodeIteratorPtr nodeIt = myMesh->nodesIterator(); + while ( nodeIt->more() ) + { + const SMDS_MeshNode* n = nodeIt->next(); + n->GetXYZ( xyz ); + GmfSetLin( meshID, GmfVertices, xyz[0], xyz[1], xyz[2], n->getshapeId() ); + node2IdMap.insert( node2IdMap.end(), std::make_pair( n, ++iN )); + } + if ( iN != nbNodes ) + return addMessage("Wrong nb of nodes returned by nodesIterator", /*fatal=*/true); + + + SMDS_ElemIteratorPtr elemIt; + typedef std::map< const SMDS_MeshElement*, size_t, TIDCompare > TElem2IDMap; + + // edges + TElem2IDMap edge2IDMap; + BEGIN_ELEM_WRITE( SMDSGeom_EDGE, GmfEdges, edge ) + node2IdMap[ edge->GetNode( 0 )], + node2IdMap[ edge->GetNode( 1 )], + END_ELEM_WRITE_ADD_TO_MAP( edge, edge2IDMap ); + + // nodes of quadratic edges + BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_EDGE, SMDSEntity_Edge, + GmfExtraVerticesAtEdges, edge ) + node2IdMap[ edge->GetNode( 2 )] + END_EXTRA_VERTICES_WRITE(); + + // triangles + TElem2IDMap tria2IDMap; + BEGIN_ELEM_WRITE( SMDSGeom_TRIANGLE, GmfTriangles, tria ) + node2IdMap[ tria->GetNode( 0 )], + node2IdMap[ tria->GetNode( 1 )], + node2IdMap[ tria->GetNode( 2 )], + END_ELEM_WRITE_ADD_TO_MAP( tria, tria2IDMap ); + + // nodes of quadratic triangles + BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_TRIANGLE, SMDSEntity_Triangle, + GmfExtraVerticesAtTriangles, tria ) + node2IdMap[ tria->GetNode( 3 )], + node2IdMap[ tria->GetNode( 4 )], + node2IdMap[ tria->GetNode( 5 )], + node2IdMap[ tria->GetNodeWrap( 6 )] // for TRIA7 + END_EXTRA_VERTICES_WRITE(); + + // quadrangles + TElem2IDMap quad2IDMap; + BEGIN_ELEM_WRITE( SMDSGeom_QUADRANGLE, GmfQuadrilaterals, quad ) + node2IdMap[ quad->GetNode( 0 )], + node2IdMap[ quad->GetNode( 1 )], + node2IdMap[ quad->GetNode( 2 )], + node2IdMap[ quad->GetNode( 3 )], + END_ELEM_WRITE_ADD_TO_MAP( quad, quad2IDMap ); + + // nodes of quadratic quadrangles + BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_QUADRANGLE, SMDSEntity_Quadrangle, + GmfExtraVerticesAtQuadrilaterals, quad ) + node2IdMap[ quad->GetNode( 4 )], + node2IdMap[ quad->GetNode( 5 )], + node2IdMap[ quad->GetNode( 6 )], + node2IdMap[ quad->GetNode( 7 )], + node2IdMap[ quad->GetNodeWrap( 8 )] // for QUAD9 + END_EXTRA_VERTICES_WRITE(); + + // terahedra + BEGIN_ELEM_WRITE( SMDSGeom_TETRA, GmfTetrahedra, tetra ) + node2IdMap[ tetra->GetNode( 0 )], + node2IdMap[ tetra->GetNode( 2 )], + node2IdMap[ tetra->GetNode( 1 )], + node2IdMap[ tetra->GetNode( 3 )], + END_ELEM_WRITE( tetra ); + + // nodes of quadratic terahedra + BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_TETRA, SMDSEntity_Tetra, + GmfExtraVerticesAtTetrahedra, tetra ) + node2IdMap[ tetra->GetNode( 6 )], + node2IdMap[ tetra->GetNode( 5 )], + node2IdMap[ tetra->GetNode( 4 )], + node2IdMap[ tetra->GetNode( 7 )], + node2IdMap[ tetra->GetNode( 9 )], + node2IdMap[ tetra->GetNode( 8 )] + //node2IdMap[ tetra->GetNodeWrap( 10 )], // for TETRA11 + END_EXTRA_VERTICES_WRITE(); + + // pyramids + BEGIN_ELEM_WRITE( SMDSEntity_Pyramid, GmfPyramids, pyra ) + node2IdMap[ pyra->GetNode( 0 )], + node2IdMap[ pyra->GetNode( 2 )], + node2IdMap[ pyra->GetNode( 1 )], + node2IdMap[ pyra->GetNode( 3 )], + node2IdMap[ pyra->GetNode( 4 )], + END_ELEM_WRITE( pyra ); + + // hexahedra + BEGIN_ELEM_WRITE( SMDSGeom_HEXA, GmfHexahedra, hexa ) + node2IdMap[ hexa->GetNode( 0 )], + node2IdMap[ hexa->GetNode( 3 )], + node2IdMap[ hexa->GetNode( 2 )], + node2IdMap[ hexa->GetNode( 1 )], + node2IdMap[ hexa->GetNode( 4 )], + node2IdMap[ hexa->GetNode( 7 )], + node2IdMap[ hexa->GetNode( 6 )], + node2IdMap[ hexa->GetNode( 5 )], + END_ELEM_WRITE( hexa ); + + // nodes of quadratic hexahedra + BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_HEXA, SMDSEntity_Hexa, + GmfExtraVerticesAtHexahedra, hexa ) + node2IdMap[ hexa->GetNode( 11 )], // HEXA20 + node2IdMap[ hexa->GetNode( 10 )], + node2IdMap[ hexa->GetNode( 9 )], + node2IdMap[ hexa->GetNode( 8 )], + node2IdMap[ hexa->GetNode( 15 )], + node2IdMap[ hexa->GetNode( 14 )], + node2IdMap[ hexa->GetNode( 13 )], + node2IdMap[ hexa->GetNode( 12 )], + node2IdMap[ hexa->GetNode( 16 )], + node2IdMap[ hexa->GetNode( 19 )], + node2IdMap[ hexa->GetNodeWrap( 18 )], // + HEXA27 + node2IdMap[ hexa->GetNodeWrap( 17 )], + node2IdMap[ hexa->GetNodeWrap( 20 )], + node2IdMap[ hexa->GetNodeWrap( 24 )], + node2IdMap[ hexa->GetNodeWrap( 23 )], + node2IdMap[ hexa->GetNodeWrap( 22 )], + node2IdMap[ hexa->GetNodeWrap( 21 )], + node2IdMap[ hexa->GetNodeWrap( 25 )], + node2IdMap[ hexa->GetNodeWrap( 26 )] + END_EXTRA_VERTICES_WRITE(); + + // prism + BEGIN_ELEM_WRITE( SMDSEntity_Penta, GmfPrisms, prism ) + node2IdMap[ prism->GetNode( 0 )], + node2IdMap[ prism->GetNode( 2 )], + node2IdMap[ prism->GetNode( 1 )], + node2IdMap[ prism->GetNode( 3 )], + node2IdMap[ prism->GetNode( 5 )], + node2IdMap[ prism->GetNode( 4 )], + END_ELEM_WRITE( prism ); + + + if ( _exportRequiredGroups ) + { + // required entities + SMESH_Comment badGroups; + const std::set& groupSet = myMesh->GetGroups(); + std::set::const_iterator grIt = groupSet.begin(); + for ( ; grIt != groupSet.end(); ++grIt ) + { + const SMESHDS_GroupBase* group = *grIt; + std::string groupName = group->GetStoreName(); + std::string::size_type pos = groupName.find( "_required_" ); + if ( pos == std::string::npos ) continue; + + int gmfKwd; + SMDSAbs_EntityType smdsEntity; + std::string entity = groupName.substr( pos + strlen("_required_")); + if ( entity == "Vertices" ) { + gmfKwd = GmfRequiredVertices; + smdsEntity = SMDSEntity_Node; + } + else if ( entity == "Edges" ) { + gmfKwd = GmfRequiredEdges; + smdsEntity = SMDSEntity_Edge; + } + else if ( entity == "Triangles" ) { + gmfKwd = GmfRequiredTriangles; + smdsEntity = SMDSEntity_Triangle; + } + else if ( entity == "Quadrilaterals" ) { + gmfKwd = GmfRequiredQuadrilaterals; + smdsEntity = SMDSEntity_Quadrangle; + } + else { + addMessage( SMESH_Comment("Invalig gmf entity name: ") << entity, /*fatal=*/false ); + continue; + } + + // check elem type in the group + int nbOkElems = 0; + SMDS_ElemIteratorPtr elemIt = group->GetElements(); + while ( elemIt->more() ) + nbOkElems += ( elemIt->next()->GetEntityType() == smdsEntity ); + + if ( nbOkElems != group->Extent() && nbOkElems == 0 ) + { + badGroups << " " << groupName; + continue; + } + + // choose a TElem2IDMap + TElem2IDMap* elem2IDMap = 0; + if ( smdsEntity == SMDSEntity_Quadrangle && nbOkElems != myMesh->NbFaces() ) + elem2IDMap = & quad2IDMap; + else if ( smdsEntity == SMDSEntity_Triangle && nbOkElems != myMesh->NbFaces() ) + elem2IDMap = & tria2IDMap; + else if ( smdsEntity == SMDSEntity_Edge && nbOkElems != myMesh->NbEdges() ) + elem2IDMap = & edge2IDMap; + + // write the group + GmfSetKwd( meshID, gmfKwd, nbOkElems ); + elemIt = group->GetElements(); + if ( elem2IDMap ) + for ( ; elemIt->more(); ) + { + const SMDS_MeshElement* elem = elemIt->next(); + if ( elem->GetEntityType() == smdsEntity ) + GmfSetLin( meshID, gmfKwd, (*elem2IDMap)[ elem ] ); + } + else + for ( int gmfID = 1; elemIt->more(); ++gmfID) + { + const SMDS_MeshElement* elem = elemIt->next(); + if ( elem->GetEntityType() == smdsEntity ) + GmfSetLin( meshID, gmfKwd, gmfID ); + } + + } // loop on groups + + if ( !badGroups.empty() ) + addMessage( SMESH_Comment("Groups of elements of inappropriate geometry:") + << badGroups, /*fatal=*/false ); + } + + return DRS_OK; +} + +Driver_Mesh::Status DriverGMF_Write::PerformSizeMap( const std::vector& points ) +{ +// const int dim = 3, version = sizeof(long) == 4 ? 2 : 3; + const int dim = 3, version = 2; // Version 3 not supported by mg-hexa + + // Open files + int verticesFileID = GmfOpenMesh( myVerticesFile.c_str(), GmfWrite, version, dim ); + int solFileID = GmfOpenMesh( mySolFile.c_str(), GmfWrite, version, dim ); + + int pointsNumber = points.size(); + + // Vertices Keyword + GmfSetKwd( verticesFileID, GmfVertices, pointsNumber ); + // SolAtVertices Keyword + int TypTab[] = {GmfSca}; + GmfSetKwd(solFileID, GmfSolAtVertices, pointsNumber, 1, TypTab); + + // Read the control points information from the vector and write it into the files + std::vector::const_iterator points_it; + for (points_it = points.begin(); points_it != points.end(); points_it++ ) + { + GmfSetLin( verticesFileID, GmfVertices, points_it->X(), points_it->Y(), points_it->Z(), 0 ); + double ValTab[] = {points_it->Size()}; + GmfSetLin( solFileID, GmfSolAtVertices, ValTab); + } + + // Close Files + GmfCloseMesh( verticesFileID ); + GmfCloseMesh( solFileID ); + + return DRS_OK; +} + +std::vector DriverGMF_Write::GetSizeMapFiles() +{ + std::vector files; + files.push_back(myVerticesFile); + files.push_back(mySolFile); + return files; +} + +//================================================================================ +/*! + * \brief Returns an iterator on elements of a certain type + */ +//================================================================================ + +SMDS_ElemIteratorPtr DriverGMF_Write::elementIterator(SMDSAbs_ElementType type) +{ + return myMesh->elementsIterator(type); +} +SMDS_ElemIteratorPtr DriverGMF_Write::elementIterator(SMDSAbs_EntityType type) +{ + return myMesh->elementEntityIterator(type); +} +SMDS_ElemIteratorPtr DriverGMF_Write::elementIterator(SMDSAbs_GeometryType type) +{ + return myMesh->elementGeomIterator(type); +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/DriverMED_Family.cpp b/src/3rdParty/salomesmesh/src/SMESH/DriverMED_Family.cpp new file mode 100644 index 000000000000..85311092735d --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/DriverMED_Family.cpp @@ -0,0 +1,549 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH DriverMED : tool to split groups on families +// File : DriverMED_Family.cxx +// Author : Julia DOROVSKIKH +// Module : SMESH +// +#include "DriverMED_Family.h" +#include "MED_Factory.hxx" + +#include + +using namespace std; + +//============================================================================= +/*! + * Default constructor + */ +//============================================================================= +DriverMED_Family +::DriverMED_Family(): + myGroupAttributVal(0) +{} + + +//============================================================================= +const ElementsSet& +DriverMED_Family +::GetElements () const +{ + return myElements; +} + +int +DriverMED_Family +::GetId () const +{ + return myId; +} + +void +DriverMED_Family +::SetId (const int theId) +{ + myId = theId; +} + +void +DriverMED_Family +::AddElement(const SMDS_MeshElement* theElement) +{ + myElements.insert( myElements.end(), theElement ); +} + +void +DriverMED_Family +::AddGroupName(std::string theGroupName) +{ + myGroupNames.insert(theGroupName); +} + +void +DriverMED_Family +::SetType(const SMDSAbs_ElementType theType) +{ + myTypes.insert( myType = theType ); +} + +SMDSAbs_ElementType +DriverMED_Family +::GetType() +{ + return myType; +} + +const std::set< SMDSAbs_ElementType >& +DriverMED_Family +::GetTypes() const +{ + return myTypes; +} + +bool +DriverMED_Family +::MemberOf(std::string theGroupName) const +{ + return myGroupNames.find(theGroupName) != myGroupNames.end(); +} + +const MED::TStringSet& +DriverMED_Family +::GetGroupNames () const +{ + return myGroupNames; +} + + +int +DriverMED_Family +::GetGroupAttributVal() const +{ + return myGroupAttributVal; +} + +void +DriverMED_Family +::SetGroupAttributVal( int theValue) +{ + myGroupAttributVal = theValue; +} + +bool +DriverMED_Family +::IsEmpty () const +{ + return myElements.empty(); +} + +//============================================================================= +/*! + * Split each group from list on some parts (families) + * on the basis of the elements membership in other groups from this list. + * Resulting families have no common elements. + */ +//============================================================================= +DriverMED_FamilyPtrList +DriverMED_Family +::MakeFamilies(SMESHDS_SubMeshIteratorPtr theSubMeshes, + const SMESHDS_GroupBasePtrList& theGroups, + const bool doGroupOfNodes, + const bool doGroupOfEdges, + const bool doGroupOfFaces, + const bool doGroupOfVolumes, + const bool doGroupOf0DElems, + const bool doGroupOfBalls) +{ + DriverMED_FamilyPtrList aFamilies; + + string anAllNodesGroupName = "Group_Of_All_Nodes"; + string anAllEdgesGroupName = "Group_Of_All_Edges"; + string anAllFacesGroupName = "Group_Of_All_Faces"; + string anAllVolumesGroupName = "Group_Of_All_Volumes"; + string anAll0DElemsGroupName = "Group_Of_All_0DElems"; + string anAllBallsGroupName = "Group_Of_All_Balls"; + + // Reserve 6 ids for families of free elements + // (1 - nodes, -1 - edges, -2 - faces, -3 - volumes, -4 - 0D, -5 - balls). + // 'Free' means here not belonging to any group. + int aNodeFamId = FIRST_NODE_FAMILY; + int aElemFamId = FIRST_ELEM_FAMILY; + + // Process sub-meshes + while ( theSubMeshes->more() ) + { + SMESHDS_SubMesh* aSubMesh = const_cast< SMESHDS_SubMesh* >( theSubMeshes->next() ); + const int anId = aSubMesh->GetID(); + if ( aSubMesh->IsComplexSubmesh() ) + continue; // submesh containing other submeshs + DriverMED_FamilyPtrList aSMFams = SplitByType(aSubMesh,anId); + DriverMED_FamilyPtrList::iterator aSMFamsIter = aSMFams.begin(); + for (; aSMFamsIter != aSMFams.end(); aSMFamsIter++) + { + DriverMED_FamilyPtr aFam2 = (*aSMFamsIter); + DriverMED_FamilyPtrList::iterator aFamsIter = aFamilies.begin(); + while (aFamsIter != aFamilies.end()) + { + DriverMED_FamilyPtr aFam1 = *aFamsIter; + DriverMED_FamilyPtrList::iterator aCurrIter = aFamsIter++; + if (aFam1->myType == aFam2->myType) + { + DriverMED_FamilyPtr aCommon (new DriverMED_Family); + aFam1->Split(aFam2, aCommon); + if (!aCommon->IsEmpty()) + { + aFamilies.push_back(aCommon); + } + if (aFam1->IsEmpty()) + { + aFamilies.erase(aCurrIter); + } + if (aFam2->IsEmpty()) + break; + } + } + // The rest elements of family + if (!aFam2->IsEmpty()) + { + aFamilies.push_back(aFam2); + } + } + } + + // Process groups + SMESHDS_GroupBasePtrList::const_iterator aGroupsIter = theGroups.begin(); + for (; aGroupsIter != theGroups.end(); aGroupsIter++) + { + DriverMED_FamilyPtr aFam2 (new DriverMED_Family); + aFam2->Init(*aGroupsIter); + + DriverMED_FamilyPtrList::iterator aFamsIter = aFamilies.begin(); + while (aFamsIter != aFamilies.end()) + { + DriverMED_FamilyPtr aFam1 = *aFamsIter; + DriverMED_FamilyPtrList::iterator aCurrIter = aFamsIter++; + if (aFam1->myType == aFam2->myType) + { + DriverMED_FamilyPtr aCommon (new DriverMED_Family); + aFam1->Split(aFam2, aCommon); + if (!aCommon->IsEmpty()) + { + aCommon->SetGroupAttributVal(0); + aFamilies.push_back(aCommon); + } + if (aFam1->IsEmpty()) + { + aFamilies.erase(aCurrIter); + } + if (aFam2->IsEmpty()) + break; + } + } + // The rest elements of group + if (!aFam2->IsEmpty()) + { + aFamilies.push_back(aFam2); + } + } + + DriverMED_FamilyPtrList::iterator aFamsIter = aFamilies.begin(); + for (; aFamsIter != aFamilies.end(); aFamsIter++) + { + DriverMED_FamilyPtr aFam = *aFamsIter; + if (aFam->myType == SMDSAbs_Node) { + aFam->SetId(aNodeFamId++); + if (doGroupOfNodes) aFam->myGroupNames.insert(anAllNodesGroupName); + } + else { + aFam->SetId(aElemFamId--); + if (aFam->myType == SMDSAbs_Edge) { + if (doGroupOfEdges) aFam->myGroupNames.insert(anAllEdgesGroupName); + } + else if (aFam->myType == SMDSAbs_Face) { + if (doGroupOfFaces) aFam->myGroupNames.insert(anAllFacesGroupName); + } + else if (aFam->myType == SMDSAbs_Volume) { + if (doGroupOfVolumes) aFam->myGroupNames.insert(anAllVolumesGroupName); + } + else if (aFam->myType == SMDSAbs_0DElement) { + if (doGroupOfVolumes) aFam->myGroupNames.insert(anAll0DElemsGroupName); + } + else if (aFam->myType == SMDSAbs_Ball) { + if (doGroupOfVolumes) aFam->myGroupNames.insert(anAllBallsGroupName); + } + } + } + + // Create families for elements, not belonging to any group + if (doGroupOfNodes) + { + DriverMED_FamilyPtr aFreeNodesFam (new DriverMED_Family); + aFreeNodesFam->SetId(REST_NODES_FAMILY); + aFreeNodesFam->myType = SMDSAbs_Node; + aFreeNodesFam->myGroupNames.insert(anAllNodesGroupName); + aFamilies.push_back(aFreeNodesFam); + } + + if (doGroupOfEdges) + { + DriverMED_FamilyPtr aFreeEdgesFam (new DriverMED_Family); + aFreeEdgesFam->SetId(REST_EDGES_FAMILY); + aFreeEdgesFam->myType = SMDSAbs_Edge; + aFreeEdgesFam->myGroupNames.insert(anAllEdgesGroupName); + aFamilies.push_back(aFreeEdgesFam); + } + + if (doGroupOfFaces) + { + DriverMED_FamilyPtr aFreeFacesFam (new DriverMED_Family); + aFreeFacesFam->SetId(REST_FACES_FAMILY); + aFreeFacesFam->myType = SMDSAbs_Face; + aFreeFacesFam->myGroupNames.insert(anAllFacesGroupName); + aFamilies.push_back(aFreeFacesFam); + } + + if (doGroupOfVolumes) + { + DriverMED_FamilyPtr aFreeVolumesFam (new DriverMED_Family); + aFreeVolumesFam->SetId(REST_VOLUMES_FAMILY); + aFreeVolumesFam->myType = SMDSAbs_Volume; + aFreeVolumesFam->myGroupNames.insert(anAllVolumesGroupName); + aFamilies.push_back(aFreeVolumesFam); + } + + if (doGroupOf0DElems) + { + DriverMED_FamilyPtr aFree0DFam (new DriverMED_Family); + aFree0DFam->SetId(REST_0DELEM_FAMILY); + aFree0DFam->myType = SMDSAbs_0DElement; + aFree0DFam->myGroupNames.insert(anAll0DElemsGroupName); + aFamilies.push_back(aFree0DFam); + } + + if (doGroupOfBalls) + { + DriverMED_FamilyPtr aFreeBallsFam (new DriverMED_Family); + aFreeBallsFam->SetId(REST_BALL_FAMILY); + aFreeBallsFam->myType = SMDSAbs_Ball; + aFreeBallsFam->myGroupNames.insert(anAllBallsGroupName); + aFamilies.push_back(aFreeBallsFam); + } + + DriverMED_FamilyPtr aNullFam (new DriverMED_Family); + aNullFam->SetId(0); + aNullFam->myType = SMDSAbs_All; + aFamilies.push_back(aNullFam); + + return aFamilies; +} + +//============================================================================= +/*! + * Create TFamilyInfo for this family + */ +//============================================================================= +MED::PFamilyInfo +DriverMED_Family::GetFamilyInfo(const MED::PWrapper& theWrapper, + const MED::PMeshInfo& theMeshInfo) const +{ + ostringstream aStr; + aStr << "FAM_" << myId; + set::const_iterator aGrIter = myGroupNames.begin(); + for(; aGrIter != myGroupNames.end(); aGrIter++){ + aStr << "_" << *aGrIter; + } + string aValue = aStr.str(); + // PAL19785,0019867 - med forbids whitespace to be the last char in the name + int maxSize; + //if ( theWrapper->GetVersion() == MED::eV2_1 ) + // maxSize = MED::GetNOMLength(); + //else +// maxSize = MED::GetNOMLength(); + maxSize = 2048; + int lastCharPos = min( maxSize, (int) aValue.size() ) - 1; + while ( isspace( aValue[ lastCharPos ] )) + aValue.resize( lastCharPos-- ); + + MED::PFamilyInfo anInfo; + if(myId == 0 || myGroupAttributVal == 0){ + anInfo = theWrapper->CrFamilyInfo(theMeshInfo, + aValue, + myId, + myGroupNames); + }else{ + MED::TStringVector anAttrDescs (1, ""); // 1 attribute with empty description, + MED::TIntVector anAttrIds (1, myId); // Id=0, + MED::TIntVector anAttrVals (1, myGroupAttributVal); + anInfo = theWrapper->CrFamilyInfo(theMeshInfo, + aValue, + myId, + myGroupNames, + anAttrDescs, + anAttrIds, + anAttrVals); + } + +// cout << endl; +// cout << "Groups: "; +// set::iterator aGrIter = myGroupNames.begin(); +// for (; aGrIter != myGroupNames.end(); aGrIter++) +// { +// cout << " " << *aGrIter; +// } +// cout << endl; +// +// cout << "Elements: "; +// set::iterator anIter = myElements.begin(); +// for (; anIter != myElements.end(); anIter++) +// { +// cout << " " << (*anIter)->GetID(); +// } +// cout << endl; + + return anInfo; +} + +//============================================================================= +/*! + * Initialize the tool by SMESHDS_GroupBase + */ +//============================================================================= +void DriverMED_Family::Init (SMESHDS_GroupBase* theGroup) +{ + // Elements + myElements.clear(); + SMDS_ElemIteratorPtr elemIt = theGroup->GetElements(); + while (elemIt->more()) + { + myElements.insert( myElements.end(), elemIt->next() ); + } + + // Type + myType = theGroup->GetType(); + + // Groups list + myGroupNames.clear(); + myGroupNames.insert(string(theGroup->GetStoreName())); + + Quantity_Color aColor = theGroup->GetColor(); + double aRed = aColor.Red(); + double aGreen = aColor.Green(); + double aBlue = aColor.Blue(); + int aR = int( aRed*255 ); + int aG = int( aGreen*255 ); + int aB = int( aBlue*255 ); +// cout << "aRed = " << aR << endl; +// cout << "aGreen = " << aG << endl; +// cout << "aBlue = " << aB << endl; + myGroupAttributVal = (int)(aR*1000000 + aG*1000 + aB); + //cout << "myGroupAttributVal = " << myGroupAttributVal << endl; +} + +//============================================================================= +/*! + * Split on some parts (families) + * on the basis of the elements type. + */ +//============================================================================= +DriverMED_FamilyPtrList +DriverMED_Family +::SplitByType (SMESHDS_SubMesh* theSubMesh, + const int theId) +{ + DriverMED_FamilyPtrList aFamilies; + DriverMED_FamilyPtr aNodesFamily (new DriverMED_Family); + DriverMED_FamilyPtr anEdgesFamily (new DriverMED_Family); + DriverMED_FamilyPtr aFacesFamily (new DriverMED_Family); + DriverMED_FamilyPtr aVolumesFamily (new DriverMED_Family); + // DriverMED_FamilyPtr a0DElemsFamily (new DriverMED_Family); + // DriverMED_FamilyPtr aBallsFamily (new DriverMED_Family); + + char submeshGrpName[ 30 ]; + sprintf( submeshGrpName, "SubMesh %d", theId ); + + SMDS_NodeIteratorPtr aNodesIter = theSubMesh->GetNodes(); + while (aNodesIter->more()) + { + const SMDS_MeshNode* aNode = aNodesIter->next(); + aNodesFamily->AddElement(aNode); + } + + SMDS_ElemIteratorPtr anElemsIter = theSubMesh->GetElements(); + while (anElemsIter->more()) + { + const SMDS_MeshElement* anElem = anElemsIter->next(); + switch (anElem->GetType()) + { + case SMDSAbs_Edge: + anEdgesFamily->AddElement(anElem); + break; + case SMDSAbs_Face: + aFacesFamily->AddElement(anElem); + break; + case SMDSAbs_Volume: + aVolumesFamily->AddElement(anElem); + break; + default: + break; + } + } + + if (!aNodesFamily->IsEmpty()) { + aNodesFamily->SetType(SMDSAbs_Node); + aNodesFamily->AddGroupName(submeshGrpName); + aFamilies.push_back(aNodesFamily); + } + if (!anEdgesFamily->IsEmpty()) { + anEdgesFamily->SetType(SMDSAbs_Edge); + anEdgesFamily->AddGroupName(submeshGrpName); + aFamilies.push_back(anEdgesFamily); + } + if (!aFacesFamily->IsEmpty()) { + aFacesFamily->SetType(SMDSAbs_Face); + aFacesFamily->AddGroupName(submeshGrpName); + aFamilies.push_back(aFacesFamily); + } + if (!aVolumesFamily->IsEmpty()) { + aVolumesFamily->SetType(SMDSAbs_Volume); + aVolumesFamily->AddGroupName(submeshGrpName); + aFamilies.push_back(aVolumesFamily); + } + + return aFamilies; +} + +//============================================================================= +/*! + * Remove from elements, common with , + * Remove from elements, common with , + * Create family from common elements, with combined groups list. + */ +//============================================================================= +void DriverMED_Family::Split (DriverMED_FamilyPtr by, + DriverMED_FamilyPtr common) +{ + // Elements + ElementsSet::iterator anIter = by->myElements.begin(), elemInMe; + while ( anIter != by->myElements.end()) + { + elemInMe = myElements.find(*anIter); + if (elemInMe != myElements.end()) + { + common->myElements.insert(*anIter); + myElements.erase(elemInMe); + by->myElements.erase(anIter++); + } + else + anIter++; + } + + if (!common->IsEmpty()) + { + // Groups list + common->myGroupNames = myGroupNames; + common->myGroupNames.insert( by->myGroupNames.begin(), by->myGroupNames.end() ); + + // Type + common->myType = myType; + } +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/DriverMED_R_SMESHDS_Mesh.cpp b/src/3rdParty/salomesmesh/src/SMESH/DriverMED_R_SMESHDS_Mesh.cpp new file mode 100644 index 000000000000..4e922c872aef --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/DriverMED_R_SMESHDS_Mesh.cpp @@ -0,0 +1,1299 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH DriverMED : driver to read and write 'med' files +// File : DriverMED_R_SMESHDS_Mesh.cxx +// Module : SMESH + +#include "DriverMED_R_SMESHDS_Mesh.h" + +#include "DriverMED_Family.h" +#include "SMESHDS_Group.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_Comment.hxx" + +#include "MED_CoordUtils.hxx" +#include "MED_Factory.hxx" +#include "MED_Utilities.hxx" + +#include + +#include "utilities.h" + +//#include + +#ifdef _DEBUG_ +static int MYDEBUG = 1; +//#define _DEXCEPT_ +#else +static int MYDEBUG = 0; +#endif + +#define _EDF_NODE_IDS_ + +using namespace MED; +using namespace std; + +typedef std::map TID2FamilyMap; + +namespace DriverMED +{ + bool buildMeshGrille(const MED::PWrapper& theWrapper, + const MED::PMeshInfo& theMeshInfo, + SMESHDS_Mesh* theMesh, + const TID2FamilyMap& myFamilies); + /*! + * \brief Ensure aFamily has a required ID + * \param aFamily - a family to check + * \param anID - an ID aFamily should have + * \param myFamilies - a map of the family ID to the Family + * \retval bool - true if successful + */ + bool checkFamilyID(DriverMED_FamilyPtr & aFamily, + int anID, + const TID2FamilyMap& myFamilies); + + + const SMDS_MeshNode* FindNode(const SMDS_Mesh* theMesh, TInt theId) + { + const SMDS_MeshNode* aNode = theMesh->FindNode(theId); + if(aNode) return aNode; + EXCEPTION(runtime_error,"SMDS_Mesh::FindNode - cannot find a SMDS_MeshNode for ID = "<GetNbMeshes(); + for (int iMesh = 0; iMesh < aNbMeshes; iMesh++) + { + // Reading the MED mesh + //--------------------- + PMeshInfo aMeshInfo = aMed->GetPMeshInfo(iMesh+1); + + string aMeshName; + if (myMeshId != -1) aMeshName = SMESH_Comment( myMeshId ); + else aMeshName = myMeshName; + + if(MYDEBUG) MESSAGE("Perform - aMeshName : "<GetName()); + if ( aMeshName != aMeshInfo->GetName() ) continue; + aResult = DRS_OK; + + // Reading MED families to the temporary structure + //------------------------------------------------ + TErr anErr; + TInt aNbFams = aMed->GetNbFamilies(aMeshInfo); + if(MYDEBUG) MESSAGE("Read " << aNbFams << " families"); + for (TInt iFam = 0; iFam < aNbFams; iFam++) + { + PFamilyInfo aFamilyInfo = aMed->GetPFamilyInfo(aMeshInfo,iFam+1,&anErr); + if(anErr >= 0){ + TInt aFamId = aFamilyInfo->GetId(); + if(MYDEBUG) MESSAGE("Family " << aFamId << " :"); + + DriverMED_FamilyPtr aFamily (new DriverMED_Family); + + TInt aNbGrp = aFamilyInfo->GetNbGroup(); + if(MYDEBUG) MESSAGE("belong to " << aNbGrp << " groups"); + bool isAttrOk = false; + if(aFamilyInfo->GetNbAttr() == aNbGrp) + isAttrOk = true; + for (TInt iGr = 0; iGr < aNbGrp; iGr++) + { + string aGroupName = aFamilyInfo->GetGroupName(iGr); + if ( isAttrOk ) { + TInt anAttrVal = aFamilyInfo->GetAttrVal(iGr); + aFamily->SetGroupAttributVal(anAttrVal); + } + if(MYDEBUG) MESSAGE(aGroupName); + aFamily->AddGroupName(aGroupName); + } + aFamily->SetId( aFamId ); + myFamilies[aFamId] = aFamily; + } + } + + if (aMeshInfo->GetType() == MED::eSTRUCTURE) + { + /*bool aRes = */DriverMED::buildMeshGrille(aMed,aMeshInfo,myMesh,myFamilies); + continue; + } + + // Reading MED nodes to the corresponding SMDS structure + //------------------------------------------------------ + PNodeInfo aNodeInfo = aMed->GetPNodeInfo(aMeshInfo); + if (!aNodeInfo) { + aResult = addMessage("No nodes", /*isFatal=*/true ); + continue; + } + aMeshInfo->myDim=aMeshInfo->mySpaceDim;// ignore meshdim in MEDFile because it can be false + PCoordHelper aCoordHelper = GetCoordHelper(aNodeInfo); + + EBooleen anIsNodeNum = aNodeInfo->IsElemNum(); + TInt aNbElems = aNodeInfo->GetNbElem(); + if(MYDEBUG) MESSAGE("Perform - aNodeInfo->GetNbElem() = "<AddElement(anElement); + aFamily->SetType(anElement->GetType()); + } + } + } + break; + } + case ePOLYEDRE: { + PPolyedreInfo aPolyedreInfo = aMed->GetPPolyedreInfo(aMeshInfo,anEntity,aGeom); + EBooleen anIsElemNum = takeNumbers ? aPolyedreInfo->IsElemNum() : eFAUX; + + TInt aNbElem = aPolyedreInfo->GetNbElem(); + for(TInt iElem = 0; iElem < aNbElem; iElem++){ + MED::TCConnSliceArr aConnSliceArr = aPolyedreInfo->GetConnSliceArr(iElem); + TInt aNbFaces = aConnSliceArr.size(); + typedef MED::TVector TQuantities; + TQuantities aQuantities(aNbFaces); + TInt aNbNodes = aPolyedreInfo->GetNbNodes(iElem); + TNodeIds aNodeIds(aNbNodes); + for(TInt iFace = 0, iNode = 0; iFace < aNbFaces; iFace++){ + MED::TCConnSlice aConnSlice = aConnSliceArr[iFace]; + TInt aNbConn = aConnSlice.size(); + aQuantities[iFace] = aNbConn; +#ifdef _EDF_NODE_IDS_ + if(anIsNodeNum) + for(TInt iConn = 0; iConn < aNbConn; iConn++) + { + aNodeIds[iNode] = aNodeInfo->GetElemNum(aConnSlice[iConn] - 1); + iNode++; + } + else + for(TInt iConn = 0; iConn < aNbConn; iConn++) + { + aNodeIds[iNode++] = aConnSlice[iConn]; + } +#else + for(TInt iConn = 0; iConn < aNbConn; iConn++) + { + aNodeIds[iNode++] = aConnSlice[iConn]; + } +#endif + } + + bool isRenum = false; + SMDS_MeshElement* anElement = NULL; + TInt aFamNum = aPolyedreInfo->GetFamNum(iElem); + +#ifndef _DEXCEPT_ + try{ +#endif + if(anIsElemNum){ + TInt anElemId = aPolyedreInfo->GetElemNum(iElem); + anElement = myMesh->AddPolyhedralVolumeWithID(aNodeIds,aQuantities,anElemId); + } + if(!anElement){ + vector aNodes(aNbNodes); + for(TInt iConn = 0; iConn < aNbNodes; iConn++) + aNodes[iConn] = FindNode(myMesh,aNodeIds[iConn]); + anElement = myMesh->AddPolyhedralVolume(aNodes,aQuantities); + isRenum = anIsElemNum; + } +#ifndef _DEXCEPT_ + }catch(const std::exception& exc){ + aResult = DRS_FAIL; + }catch(...){ + aResult = DRS_FAIL; + } +#endif + if(!anElement){ + aResult = DRS_WARN_SKIP_ELEM; + }else{ + if(isRenum){ + anIsElemNum = eFAUX; + takeNumbers = false; + if (aResult < DRS_WARN_RENUMBER) + aResult = DRS_WARN_RENUMBER; + } + if ( DriverMED::checkFamilyID ( aFamily, aFamNum, myFamilies )) { + // Save reference to this element from its family + aFamily->AddElement(anElement); + aFamily->SetType(anElement->GetType()); + } + } + } + break; + } + default: { + PCellInfo aCellInfo = aMed->GetPCellInfo(aMeshInfo,anEntity,aGeom); + EBooleen anIsElemNum = takeNumbers ? aCellInfo->IsElemNum() : eFAUX; + TInt aNbElems = aCellInfo->GetNbElem(); + if(MYDEBUG) MESSAGE("Perform - anEntity = "<GetFamNum(iElem); +#ifndef _DEXCEPT_ + try{ +#endif + //MESSAGE("Try to create element # " << iElem << " with id = " + // << aCellInfo->GetElemNum(iElem)); + switch(aGeom) { + case ePOINT1: + //anElement = FindNode(myMesh,aNodeIds[0]); + if(anIsElemNum) + anElement = myMesh->Add0DElementWithID + (aNodeIds[0], aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->Add0DElement(FindNode(myMesh,aNodeIds[0])); + isRenum = anIsElemNum; + } + break; + case eSEG2: + if(anIsElemNum) + anElement = myMesh->AddEdgeWithID(aNodeIds[0], + aNodeIds[1], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddEdge(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1])); + isRenum = anIsElemNum; + } + break; + case eSEG3: + if(anIsElemNum) + anElement = myMesh->AddEdgeWithID(aNodeIds[0], + aNodeIds[1], + aNodeIds[2], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddEdge(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2])); + isRenum = anIsElemNum; + } + break; + case eTRIA3: + aNbNodes = 3; + if(anIsElemNum) + anElement = myMesh->AddFaceWithID(aNodeIds[0], + aNodeIds[1], + aNodeIds[2], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2])); + isRenum = anIsElemNum; + } + break; + case eTRIA6: + aNbNodes = 6; + if(anIsElemNum) + anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5])); + isRenum = anIsElemNum; + } + break; + case eTRIA7: + aNbNodes = 7; + if(anIsElemNum) + anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], aNodeIds[6], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6])); + isRenum = anIsElemNum; + } + break; + case eQUAD4: + aNbNodes = 4; + if(anIsElemNum) + anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3])); + isRenum = anIsElemNum; + } + break; + case eQUAD8: + aNbNodes = 8; + if(anIsElemNum) + anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], + aNodeIds[6], aNodeIds[7], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7])); + isRenum = anIsElemNum; + } + break; + case eQUAD9: + aNbNodes = 9; + if(anIsElemNum) + anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], + aNodeIds[6], aNodeIds[7], aNodeIds[8], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7]), + FindNode(myMesh,aNodeIds[8])); + isRenum = anIsElemNum; + } + break; + case eTETRA4: + aNbNodes = 4; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3])); + isRenum = anIsElemNum; + } + break; + case eTETRA10: + aNbNodes = 10; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], + aNodeIds[6], aNodeIds[7], + aNodeIds[8], aNodeIds[9], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7]), + FindNode(myMesh,aNodeIds[8]), + FindNode(myMesh,aNodeIds[9])); + isRenum = anIsElemNum; + } + break; + case ePYRA5: + aNbNodes = 5; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4])); + isRenum = anIsElemNum; + } + break; + case ePYRA13: + aNbNodes = 13; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], + aNodeIds[6], aNodeIds[7], + aNodeIds[8], aNodeIds[9], + aNodeIds[10], aNodeIds[11], + aNodeIds[12], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7]), + FindNode(myMesh,aNodeIds[8]), + FindNode(myMesh,aNodeIds[9]), + FindNode(myMesh,aNodeIds[10]), + FindNode(myMesh,aNodeIds[11]), + FindNode(myMesh,aNodeIds[12])); + isRenum = anIsElemNum; + } + break; + case ePENTA6: + aNbNodes = 6; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], + aNodeIds[1], + aNodeIds[2], + aNodeIds[3], + aNodeIds[4], + aNodeIds[5], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5])); + isRenum = anIsElemNum; + } + break; + case ePENTA15: + aNbNodes = 15; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], + aNodeIds[6], aNodeIds[7], + aNodeIds[8], aNodeIds[9], + aNodeIds[10], aNodeIds[11], + aNodeIds[12], aNodeIds[13], + aNodeIds[14], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7]), + FindNode(myMesh,aNodeIds[8]), + FindNode(myMesh,aNodeIds[9]), + FindNode(myMesh,aNodeIds[10]), + FindNode(myMesh,aNodeIds[11]), + FindNode(myMesh,aNodeIds[12]), + FindNode(myMesh,aNodeIds[13]), + FindNode(myMesh,aNodeIds[14])); + isRenum = anIsElemNum; + } + break; + case eHEXA8: + aNbNodes = 8; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], + aNodeIds[1], + aNodeIds[2], + aNodeIds[3], + aNodeIds[4], + aNodeIds[5], + aNodeIds[6], + aNodeIds[7], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7])); + isRenum = anIsElemNum; + } + break; + + case eHEXA20: + aNbNodes = 20; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], + aNodeIds[6], aNodeIds[7], + aNodeIds[8], aNodeIds[9], + aNodeIds[10], aNodeIds[11], + aNodeIds[12], aNodeIds[13], + aNodeIds[14], aNodeIds[15], + aNodeIds[16], aNodeIds[17], + aNodeIds[18], aNodeIds[19], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7]), + FindNode(myMesh,aNodeIds[8]), + FindNode(myMesh,aNodeIds[9]), + FindNode(myMesh,aNodeIds[10]), + FindNode(myMesh,aNodeIds[11]), + FindNode(myMesh,aNodeIds[12]), + FindNode(myMesh,aNodeIds[13]), + FindNode(myMesh,aNodeIds[14]), + FindNode(myMesh,aNodeIds[15]), + FindNode(myMesh,aNodeIds[16]), + FindNode(myMesh,aNodeIds[17]), + FindNode(myMesh,aNodeIds[18]), + FindNode(myMesh,aNodeIds[19])); + isRenum = anIsElemNum; + } + break; + + case eHEXA27: + aNbNodes = 27; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], + aNodeIds[6], aNodeIds[7], + aNodeIds[8], aNodeIds[9], + aNodeIds[10], aNodeIds[11], + aNodeIds[12], aNodeIds[13], + aNodeIds[14], aNodeIds[15], + aNodeIds[16], aNodeIds[17], + aNodeIds[18], aNodeIds[19], + aNodeIds[20], aNodeIds[21], + aNodeIds[22], aNodeIds[23], + aNodeIds[24], aNodeIds[25], + aNodeIds[26], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7]), + FindNode(myMesh,aNodeIds[8]), + FindNode(myMesh,aNodeIds[9]), + FindNode(myMesh,aNodeIds[10]), + FindNode(myMesh,aNodeIds[11]), + FindNode(myMesh,aNodeIds[12]), + FindNode(myMesh,aNodeIds[13]), + FindNode(myMesh,aNodeIds[14]), + FindNode(myMesh,aNodeIds[15]), + FindNode(myMesh,aNodeIds[16]), + FindNode(myMesh,aNodeIds[17]), + FindNode(myMesh,aNodeIds[18]), + FindNode(myMesh,aNodeIds[19]), + FindNode(myMesh,aNodeIds[20]), + FindNode(myMesh,aNodeIds[21]), + FindNode(myMesh,aNodeIds[22]), + FindNode(myMesh,aNodeIds[23]), + FindNode(myMesh,aNodeIds[24]), + FindNode(myMesh,aNodeIds[25]), + FindNode(myMesh,aNodeIds[26])); + isRenum = anIsElemNum; + } + break; + + case eOCTA12: + aNbNodes = 12; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], + aNodeIds[6], aNodeIds[7], + aNodeIds[8], aNodeIds[9], + aNodeIds[10], aNodeIds[11], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7]), + FindNode(myMesh,aNodeIds[8]), + FindNode(myMesh,aNodeIds[9]), + FindNode(myMesh,aNodeIds[10]), + FindNode(myMesh,aNodeIds[11])); + isRenum = anIsElemNum; + } + break; + + default:; + + } // switch(aGeom) + +#ifndef _DEXCEPT_ + } catch(const std::exception& exc) { + INFOS("The following exception was caught:\n\t"<AddElement(anElement); + aFamily->SetType(anElement->GetType()); + } + } + } // loop on aNbElems + }} // switch(aGeom) + } // loop on aGeom2Size + } // loop on aEntityInfo + + if (aDescendingEntitiesMap.Extent()) isDescConn = true; // Mantis issue 0020483 + + } // for(int iMesh = 0; iMesh < aNbMeshes; iMesh++) +#ifndef _DEXCEPT_ + } + catch(const std::exception& exc) + { + INFOS("The following exception was caught:\n\t"<compactMesh(); + + // Mantis issue 0020483 + if (aResult == DRS_OK && isDescConn) { + INFOS("There are some elements in descending connectivity in med file. They were not read !!!"); + aResult = DRS_WARN_DESCENDING; + } + + if(MYDEBUG) MESSAGE("Perform - aResult status = "< DriverMED_R_SMESHDS_Mesh::GetMeshNames(Status& theStatus) +{ + list aMeshNames; + + try { + if(MYDEBUG) MESSAGE("GetMeshNames - myFile : " << myFile); + theStatus = DRS_OK; + PWrapper aMed = CrWrapper(myFile); + + if (TInt aNbMeshes = aMed->GetNbMeshes()) { + for (int iMesh = 0; iMesh < aNbMeshes; iMesh++) { + // Reading the MED mesh + //--------------------- + PMeshInfo aMeshInfo = aMed->GetPMeshInfo(iMesh+1); + aMeshNames.push_back(aMeshInfo->GetName()); + } + } + } catch(const std::exception& exc) { + INFOS("Following exception was caught:\n\t"< DriverMED_R_SMESHDS_Mesh::GetGroupNamesAndTypes() +{ + list aResult; + set aResGroupNames; + + map::iterator aFamsIter = myFamilies.begin(); + for (; aFamsIter != myFamilies.end(); aFamsIter++) + { + DriverMED_FamilyPtr aFamily = (*aFamsIter).second; + const MED::TStringSet& aGroupNames = aFamily->GetGroupNames(); + set::const_iterator aGrNamesIter = aGroupNames.begin(); + for (; aGrNamesIter != aGroupNames.end(); aGrNamesIter++) + { + const set< SMDSAbs_ElementType >& types = aFamily->GetTypes(); + set< SMDSAbs_ElementType >::const_iterator type = types.begin(); + for ( ; type != types.end(); ++type ) + { + TNameAndType aNameAndType = make_pair( *aGrNamesIter, *type ); + if ( aResGroupNames.insert( aNameAndType ).second ) { + aResult.push_back( aNameAndType ); + } + } + } + } + + return aResult; +} + +void DriverMED_R_SMESHDS_Mesh::GetGroup(SMESHDS_Group* theGroup) +{ + string aGroupName (theGroup->GetStoreName()); + if(MYDEBUG) MESSAGE("Get Group " << aGroupName); + + map::iterator aFamsIter = myFamilies.begin(); + for (; aFamsIter != myFamilies.end(); aFamsIter++) + { + DriverMED_FamilyPtr aFamily = (*aFamsIter).second; + if (aFamily->GetTypes().count( theGroup->GetType() ) && aFamily->MemberOf(aGroupName)) + { + const ElementsSet& anElements = aFamily->GetElements(); + ElementsSet::const_iterator anElemsIter = anElements.begin(); + for (; anElemsIter != anElements.end(); anElemsIter++) + { + const SMDS_MeshElement * element = *anElemsIter; + if ( element->GetType() == theGroup->GetType() ) // Issue 0020576 + theGroup->SMDSGroup().Add(element); + } + int aGroupAttrVal = aFamily->GetGroupAttributVal(); + if( aGroupAttrVal != 0) + theGroup->SetColorGroup(aGroupAttrVal); +// if ( element ) -- Issue 0020576 +// theGroup->SetType( theGroup->SMDSGroup().GetType() ); + } + } +} + +void DriverMED_R_SMESHDS_Mesh::GetSubMesh (SMESHDS_SubMesh* theSubMesh, + const int theId) +{ + char submeshGrpName[ 30 ]; + sprintf( submeshGrpName, "SubMesh %d", theId ); + string aName (submeshGrpName); + map::iterator aFamsIter = myFamilies.begin(); + for (; aFamsIter != myFamilies.end(); aFamsIter++) + { + DriverMED_FamilyPtr aFamily = (*aFamsIter).second; + if (aFamily->MemberOf(aName)) + { + const ElementsSet& anElements = aFamily->GetElements(); + ElementsSet::const_iterator anElemsIter = anElements.begin(); + if (aFamily->GetType() == SMDSAbs_Node) + { + for (; anElemsIter != anElements.end(); anElemsIter++) + { + const SMDS_MeshNode* node = static_cast(*anElemsIter); + theSubMesh->AddNode(node); + } + } + else + { + for (; anElemsIter != anElements.end(); anElemsIter++) + { + theSubMesh->AddElement(*anElemsIter); + } + } + } + } +} + +void DriverMED_R_SMESHDS_Mesh::CreateAllSubMeshes () +{ + map::iterator aFamsIter = myFamilies.begin(); + for (; aFamsIter != myFamilies.end(); aFamsIter++) + { + DriverMED_FamilyPtr aFamily = (*aFamsIter).second; + MED::TStringSet aGroupNames = aFamily->GetGroupNames(); + set::iterator aGrNamesIter = aGroupNames.begin(); + for (; aGrNamesIter != aGroupNames.end(); aGrNamesIter++) + { + string aName = *aGrNamesIter; + // Check, if this is a Group or SubMesh name + if (aName.substr(0, 7) == string("SubMesh")) + { + int Id = atoi(string(aName).substr(7).c_str()); + const ElementsSet& anElements = aFamily->GetElements(); + ElementsSet::const_iterator anElemsIter = anElements.begin(); + if (aFamily->GetType() == SMDSAbs_Node) + { + for (; anElemsIter != anElements.end(); anElemsIter++) + { + const SMDS_MeshNode* node = static_cast( *anElemsIter ); + // find out a shape type + TopoDS_Shape aShape = myMesh->IndexToShape( Id ); + int aShapeType = ( aShape.IsNull() ? -1 : aShape.ShapeType() ); + switch ( aShapeType ) { + case TopAbs_FACE: + myMesh->SetNodeOnFace(node, Id); break; + case TopAbs_EDGE: + myMesh->SetNodeOnEdge(node, Id); break; + case TopAbs_VERTEX: + myMesh->SetNodeOnVertex(node, Id); break; + default: + myMesh->SetNodeInVolume(node, Id); + } + } + } + else + { + for (; anElemsIter != anElements.end(); anElemsIter++) + { + myMesh->SetMeshElementOnShape(*anElemsIter, Id); + } + } + } + } + } +} +/*! + * \brief Ensure aFamily to have required ID + * \param aFamily - a family to check and update + * \param anID - an ID aFamily should have + * \retval bool - true if successful + */ +bool DriverMED::checkFamilyID(DriverMED_FamilyPtr & aFamily, + int anID, + const TID2FamilyMap& myFamilies) +{ + if ( !aFamily || aFamily->GetId() != anID ) { + map::const_iterator i_fam = myFamilies.find(anID); + if ( i_fam == myFamilies.end() ) + return false; + aFamily = i_fam->second; + } + return ( aFamily->GetId() == anID ); +} + +/*! + * \brief Reading the structured mesh and convert to non structured + * (by filling of smesh structure for non structured mesh) + * \param theWrapper - PWrapper const pointer + * \param theMeshInfo - PMeshInfo const pointer + * \param myFamilies - a map of the family ID to the Family + * \return TRUE, if successfully. Else FALSE + */ +bool DriverMED::buildMeshGrille(const MED::PWrapper& theWrapper, + const MED::PMeshInfo& theMeshInfo, + SMESHDS_Mesh* myMesh, + const TID2FamilyMap& myFamilies) +{ + bool res = true; + + MED::PGrilleInfo aGrilleInfo = theWrapper->GetPGrilleInfo(theMeshInfo); + MED::TInt aNbNodes = aGrilleInfo->GetNbNodes(); + MED::TInt aNbCells = aGrilleInfo->GetNbCells(); + MED::TInt aMeshDim = theMeshInfo->GetDim(); + DriverMED_FamilyPtr aFamily; + for(MED::TInt iNode=0;iNode < aNbNodes; iNode++){ + double aCoords[3] = {0.0, 0.0, 0.0}; + const SMDS_MeshNode* aNode; + MED::TNodeCoord aMEDNodeCoord = aGrilleInfo->GetCoord(iNode); + for(MED::TInt iDim=0;iDimAddNodeWithID(aCoords[0],aCoords[1],aCoords[2],iNode+1); + if (!aNode) { + EXCEPTION(runtime_error,"buildMeshGrille Error. Node not created! "<<(int)iNode); + } + + if((aGrilleInfo->myFamNumNode).size() > 0){ + TInt aFamNum = aGrilleInfo->GetFamNumNode(iNode); + if ( DriverMED::checkFamilyID ( aFamily, aFamNum, myFamilies )) + { + aFamily->AddElement(aNode); + aFamily->SetType(SMDSAbs_Node); + } + } + + } + + SMDS_MeshElement* anElement = NULL; + MED::TIntVector aNodeIds; + for(MED::TInt iCell=0;iCell < aNbCells; iCell++){ + aNodeIds = aGrilleInfo->GetConn(iCell); + switch(aGrilleInfo->GetGeom()){ + case MED::eSEG2: + if(aNodeIds.size() != 2){ + res = false; + EXCEPTION(runtime_error,"buildMeshGrille Error. Incorrect size of ids 2!="<AddEdgeWithID(aNodeIds[0]+1, + aNodeIds[1]+1, + iCell+1); + break; + case MED::eQUAD4: + if(aNodeIds.size() != 4){ + res = false; + EXCEPTION(runtime_error,"buildMeshGrille Error. Incorrect size of ids 4!="<AddFaceWithID(aNodeIds[0]+1, + aNodeIds[2]+1, + aNodeIds[3]+1, + aNodeIds[1]+1, + iCell+1); + break; + case MED::eHEXA8: + if(aNodeIds.size() != 8){ + res = false; + EXCEPTION(runtime_error,"buildMeshGrille Error. Incorrect size of ids 8!="<AddVolumeWithID(aNodeIds[0]+1, + aNodeIds[2]+1, + aNodeIds[3]+1, + aNodeIds[1]+1, + aNodeIds[4]+1, + aNodeIds[6]+1, + aNodeIds[7]+1, + aNodeIds[5]+1, + iCell+1); + break; + default: + break; + } + if (!anElement) { + EXCEPTION(runtime_error,"buildMeshGrille Error. Element not created! "<myFamNum).size() > 0){ + TInt aFamNum = aGrilleInfo->GetFamNum(iCell); + if ( DriverMED::checkFamilyID ( aFamily, aFamNum, myFamilies )){ + aFamily->AddElement(anElement); + aFamily->SetType(anElement->GetType()); + } + } + } + + return res; +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/DriverMED_W_Field.cpp b/src/3rdParty/salomesmesh/src/SMESH/DriverMED_W_Field.cpp new file mode 100644 index 000000000000..e4a7e4220129 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/DriverMED_W_Field.cpp @@ -0,0 +1,430 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : DriverMED_W_Field.cxx +// Created : Thu Feb 27 17:45:00 2014 +// Author : eap + +#include "DriverMED_W_Field.h" + +#include "DriverMED.hxx" +#include "DriverMED_W_SMESHDS_Mesh.h" +#include "MED_Factory.hxx" +#include "MED_Utilities.hxx" +#include "MED_Wrapper.hxx" +#include "SMDS_IteratorOnIterators.hxx" +#include "SMDS_MeshElement.hxx" +#include "SMDS_PolyhedralVolumeOfNodes.hxx" +#include "SMDS_SetIterator.hxx" +#include "SMESHDS_Mesh.hxx" + +//================================================================================ +/*! + * \brief Constructor + */ +//================================================================================ + +DriverMED_W_Field::DriverMED_W_Field(): + //_medFileID( -1 ), + _elemType( SMDSAbs_All ), + _dt( -1 ), + _it( -1 ) +{ +} + +//================================================================================ +/*! + * \brief Sets basic data + * \param [in] mesh - supporting mesh + * \param [in] fieldName - name of a field + * \param [in] type - type of supporting elements + * \param [in] nbComps - number of components + * \param [in] isIntData - type of data: double or integer + */ +//================================================================================ + +bool DriverMED_W_Field::Set(SMESHDS_Mesh * mesh, + const std::string & fieldName, + SMDSAbs_ElementType type, + const int nbComps, + const bool isIntData) +{ + _fieldName = fieldName; + _compNames.resize( nbComps, "" ); + + if ( type == SMDSAbs_All ) + { + if ( mesh->NbVolumes() > 0 ) + type = SMDSAbs_Volume; + else if ( mesh->NbFaces() > 0 ) + type = SMDSAbs_Face; + else if ( mesh->NbEdges() > 0 ) + type = SMDSAbs_Edge; + else + type = SMDSAbs_Node; + } + if ( myMesh != mesh ) + { + _nbElemsByGeom.clear(); + for ( int iG = 0; iG < SMDSEntity_Last; ++iG ) + _elemsByGeom[iG].clear(); + SetMesh( mesh ); + } + + // find out "MED order" of elements - sort elements by geom type + int nbElems; + if ( _nbElemsByGeom.empty() || _elemType != type ) + { + _elemType = type; + _nbElemsByGeom.resize( 1, std::make_pair( SMDSEntity_Last, 0 )); + + // count nb of elems of each geometry + for ( int iG = 0; iG < SMDSEntity_Last; ++iG ) + { + SMDSAbs_EntityType geom = (SMDSAbs_EntityType) iG; + SMDSAbs_ElementType t = SMDS_MeshCell::toSmdsType( geom ); + if ( t != _elemType ) continue; + + nbElems = mesh->GetMeshInfo().NbElements( geom ); + if ( nbElems < 1 ) continue; + + _nbElemsByGeom.push_back( std::make_pair( geom, nbElems + _nbElemsByGeom.back().second )); + } + // add nodes of missing 0D elements on VERTEXes + if ( _addODOnVertices && _elemType == SMDSAbs_0DElement ) + { + std::vector< const SMDS_MeshElement* >& nodes = _elemsByGeom[SMDSEntity_Node]; + if ( nodes.empty() ) + DriverMED_W_SMESHDS_Mesh::getNodesOfMissing0DOnVert( myMesh, nodes ); + if ( !nodes.empty() ) + { + if ( _nbElemsByGeom.size() == 1 ) + _nbElemsByGeom.push_back( std::make_pair( SMDSEntity_0D, 0)); + _nbElemsByGeom.push_back( std::make_pair( SMDSEntity_Node, + nodes.size() + _nbElemsByGeom.back().second )); + } + } + + // sort elements by their geometry + int iGeoType, nbGeomTypes = _nbElemsByGeom.size() - 1; + if ( nbGeomTypes > 1 ) + { + for ( size_t iG = 1; iG < _nbElemsByGeom.size(); ++iG ) + { + iGeoType = _nbElemsByGeom[iG].first; + nbElems = _nbElemsByGeom[iG].second - _nbElemsByGeom[iG-1].second; + _elemsByGeom[ iGeoType ].reserve( nbElems ); + } + iGeoType = _nbElemsByGeom[1].first; // for missing 0D + if ( _elemsByGeom[ iGeoType ].empty() ) + { + nbElems = mesh->GetMeshInfo().NbElements( _elemType ); + SMDS_ElemIteratorPtr eIt = mesh->elementsIterator( _elemType ); + for ( int iE = 0; iE < nbElems && eIt->more(); ++iE ) + { + const SMDS_MeshElement* e = eIt->next(); + _elemsByGeom[ e->GetEntityType() ].push_back( e ); + } + } + } + } + _intValues.clear(); + _dblValues.clear(); + + // allocate memory for values + nbElems = _nbElemsByGeom.empty() ? 0 : _nbElemsByGeom.back().second; + if ( isIntData ) + _intValues.reserve( nbElems * nbComps ); + else + _dblValues.reserve( nbElems * nbComps ); + + return nbElems * nbComps; +} + +//================================================================================ +/*! + * \brief Set a name of a component countered from zero + */ +//================================================================================ + +void DriverMED_W_Field::SetCompName(const int iComp, const char* name) +{ + if ( (int)_compNames.size() <= iComp ) + _compNames.resize( iComp + 1 ); + _compNames[ iComp ] = name; +} + +//================================================================================ +/*! + * \brief Sets numdt and numit field features. Call this fun before AddValue()! + */ +//================================================================================ + +void DriverMED_W_Field::SetDtIt(const int dt, const int it) +{ + _dt = dt; + _it = it; + _intValues.clear(); + _dblValues.clear(); +} + +//================================================================================ +/*! + * \brief Adds a float field value + */ +//================================================================================ + +void DriverMED_W_Field::AddValue( double val ) +{ + _dblValues.push_back( val ); +} + +//================================================================================ +/*! + * \brief Adds an integer field value + */ +//================================================================================ + +void DriverMED_W_Field::AddValue( int val ) +{ + _intValues.push_back( val ); +} + +//================================================================================ +/*! + * Returns elements in the order they are written in MED file + */ +//================================================================================ + +SMDS_ElemIteratorPtr DriverMED_W_Field::GetOrderedElems() +{ + if ( _nbElemsByGeom.size() < 2 ) + return SMDS_ElemIteratorPtr(); + + if ( _nbElemsByGeom.size() == 2 ) + // sole geom type of elements + return myMesh->elementsIterator( _elemType ); + + std::vector< SMDS_ElemIteratorPtr > iterVec( _nbElemsByGeom.size()-1 ); + for ( size_t iG = 1; iG < _nbElemsByGeom.size(); ++iG ) + { + int iGeoType = _nbElemsByGeom[ iG ].first; + iterVec[ iG-1 ] = SMDS_ElemIteratorPtr + ( new SMDS_ElementVectorIterator( _elemsByGeom[ iGeoType ].begin(), + _elemsByGeom[ iGeoType ].end() )); + } + typedef SMDS_IteratorOnIterators + < const SMDS_MeshElement *, std::vector< SMDS_ElemIteratorPtr > > TItIterator; + return SMDS_ElemIteratorPtr( new TItIterator( iterVec )); +} + +//================================================================================ +/*! + * Writes a field to the file + */ +//================================================================================ + +Driver_Mesh::Status DriverMED_W_Field::Perform() +{ + if ( myFile.empty() ) + return addMessage("File name not set", /*isFatal=*/true ); // 'fatal' means 'bug' + if ( myMeshId < 0 && myMeshName.empty() ) + return addMessage("Mesh in file not specified", /*isFatal=*/true ); + if ( _nbElemsByGeom.size() < 2 ) + return addMessage("No values to write", /*isFatal=*/false ); + if ( !myMesh ) + return addMessage("Supporting mesh not set", /*isFatal=*/true ); + + MED::PWrapper medFile = MED::CrWrapper( myFile, MED::eV2_2 ); + MED::PMeshInfo meshInfo; + if ( myMeshId > 0 ) + { + meshInfo = medFile->GetPMeshInfo( myMeshId ); + } + else + { + // look for a mesh by name + int aNbMeshes = medFile->GetNbMeshes(); + for ( int iMesh = aNbMeshes; iMesh > 0 && myMeshId < 1; --iMesh ) + { + meshInfo = medFile->GetPMeshInfo( iMesh ); + if ( !meshInfo || meshInfo->GetName() != myMeshName ) + meshInfo.reset(); + else + myMeshId = iMesh; + } + } + if (( !meshInfo ) || + ( !myMeshName.empty() && meshInfo->GetName() != myMeshName )) + { + myMeshId = -1; + return addMessage("Specified mesh not found in the file", /*isFatal=*/true ); + } + + // create a field + MED::ETypeChamp dataType = _dblValues.empty() ? MED::eINT : MED::eFLOAT64; + MED::PFieldInfo fieldInfo = medFile->CrFieldInfo( meshInfo, + _compNames.size(), + dataType ); + fieldInfo->SetName( _fieldName ); + for ( size_t iC = 0; iC < _compNames.size(); ++iC ) + { + fieldInfo->SetCompName( iC, _compNames[ iC ]); + fieldInfo->SetUnitName( iC, ""); + } + if ( _compNames.size() > 1 ) + { + for ( size_t i = 0; i < fieldInfo->myCompNames.size()-1; ++i ) + if ( !fieldInfo->myCompNames[i] ) + fieldInfo->myCompNames[i] = ' '; + } + medFile->SetFieldInfo( fieldInfo ); + + // specific treatment of added 0D elements + if ( _nbElemsByGeom.size() == 3 && + _nbElemsByGeom[1].first == SMDSEntity_0D ) + { + _nbElemsByGeom[1].second += _nbElemsByGeom[2].second; + _nbElemsByGeom.resize( 2 ); + } + + // create a time stamp + MED::TGeom2Size type2nb; + for ( size_t iG = 1; iG < _nbElemsByGeom.size(); ++iG ) + { + SMDSAbs_EntityType smdsType = _nbElemsByGeom[iG].first; + MED::EGeometrieElement medType = (MED::EGeometrieElement) DriverMED::GetMedGeoType( smdsType ); + int nbElems = _nbElemsByGeom[iG].second - _nbElemsByGeom[iG-1].second; + type2nb.insert( std::make_pair( medType, nbElems )); + } + + MED::EEntiteMaillage entity = ( _elemType == SMDSAbs_Node ? MED::eNOEUD : MED::eMAILLE ); + MED::PTimeStampInfo timeStampInfo = medFile->CrTimeStampInfo( fieldInfo, entity, type2nb ); + timeStampInfo->myNumDt = _dt; + timeStampInfo->myNumOrd = _it; + + MED::PTimeStampValueBase timeStampVal = medFile->CrTimeStampValue( timeStampInfo, dataType ); + MED::PFloatTimeStampValue timeStampFltVal = timeStampVal; + MED::PIntTimeStampValue timeStampIntVal = timeStampVal; + + // set values + int iVal = 0; + MED::TFloat* ptrDbl = 0; + MED::TInt* ptrInt = 0; + for ( size_t iG = 1; iG < _nbElemsByGeom.size(); ++iG ) + { + SMDSAbs_EntityType smdsType = _nbElemsByGeom[iG].first; + MED::EGeometrieElement medType = (MED::EGeometrieElement) DriverMED::GetMedGeoType( smdsType ); + int nbElems = ( _nbElemsByGeom[iG].second - _nbElemsByGeom[iG-1].second ) * _compNames.size(); + if ( dataType == MED::eFLOAT64 ) + { + ptrDbl = timeStampFltVal->GetMeshValue( medType ).GetPointer(); + for ( int i = 0; i < nbElems; ++i, ++iVal ) + ptrDbl[ i ] = _dblValues[ iVal ]; + } + else + { + ptrInt = timeStampIntVal->GetMeshValue( medType ).GetPointer(); + for ( int i = 0; i < nbElems; ++i, ++iVal ) + ptrInt[ i ] = _intValues[ iVal ]; + } + } + + // write + medFile->SetTimeStampValue( timeStampVal ); + + _dblValues.clear(); + _intValues.clear(); + + return DRS_OK; +} + +namespace DriverMED // Implemetation of fuctions declared in DriverMED.hxx +{ + //================================================================================ + /*! + * Returns a vector containing MED::EGeometrieElement for each SMDSAbs_EntityType + */ + //================================================================================ + + const std::vector< MED::EGeometrieElement >& getMedTypesVec() + { + static std::vector< MED::EGeometrieElement > theVec; + if ( theVec.empty() ) + { + theVec.resize( SMDSEntity_Last, MED::eAllGeoType ); + theVec[ SMDSEntity_Node ] = MED::eNONE ; + theVec[ SMDSEntity_0D ] = MED::ePOINT1 ; + theVec[ SMDSEntity_Edge ] = MED::eSEG2 ; + theVec[ SMDSEntity_Quad_Edge ] = MED::eSEG3 ; + theVec[ SMDSEntity_Triangle ] = MED::eTRIA3 ; + theVec[ SMDSEntity_Quad_Triangle ] = MED::eTRIA6 ; + theVec[ SMDSEntity_BiQuad_Triangle ] = MED::eTRIA7 ; + theVec[ SMDSEntity_Quadrangle ] = MED::eQUAD4 ; + theVec[ SMDSEntity_Quad_Quadrangle ] = MED::eQUAD8 ; + theVec[ SMDSEntity_BiQuad_Quadrangle ] = MED::eQUAD9 ; + theVec[ SMDSEntity_Polygon ] = MED::ePOLYGONE; + //theVec[ SMDSEntity_Quad_Polygon ] = MED::ePOLYGONE; // !! + theVec[ SMDSEntity_Tetra ] = MED::eTETRA4 ; + theVec[ SMDSEntity_Quad_Tetra ] = MED::eTETRA10 ; + theVec[ SMDSEntity_Pyramid ] = MED::ePYRA5 ; + theVec[ SMDSEntity_Quad_Pyramid ] = MED::ePYRA13 ; + theVec[ SMDSEntity_Hexa ] = MED::eHEXA8 ; + theVec[ SMDSEntity_Quad_Hexa ] = MED::eHEXA20 ; + theVec[ SMDSEntity_TriQuad_Hexa ] = MED::eHEXA27 ; + theVec[ SMDSEntity_Penta ] = MED::ePENTA6 ; + theVec[ SMDSEntity_Quad_Penta ] = MED::ePENTA15 ; + theVec[ SMDSEntity_Hexagonal_Prism ] = MED::eOCTA12 ; + theVec[ SMDSEntity_Polyhedra ] = MED::ePOLYEDRE; + //theVec[ SMDSEntity_Quad_Polyhedra ] = MED::ePOLYEDRE; // !! + theVec[ SMDSEntity_Ball ] = MED::eBALL ; + } + return theVec; + } + + //================================================================================ + /*! + * Returns MED element geom type (MED::EGeometrieElement) by SMDS type + */ + //================================================================================ + + int GetMedGeoType( SMDSAbs_EntityType smdsType ) + { + return getMedTypesVec()[ smdsType ]; + } + + //================================================================================ + /*! + * Returns SMDS element geom type by MED type (MED::EGeometrieElement) + */ + //================================================================================ + + SMDSAbs_EntityType GetSMDSType( int medType ) + { + const std::vector< MED::EGeometrieElement >& theVec = getMedTypesVec(); + + std::vector< MED::EGeometrieElement >::const_iterator i = + std::find( theVec.begin(), theVec.end(), medType ); + + return SMDSAbs_EntityType( std::distance( theVec.begin(), i )); + } +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/DriverMED_W_SMESHDS_Mesh.cpp b/src/3rdParty/salomesmesh/src/SMESH/DriverMED_W_SMESHDS_Mesh.cpp new file mode 100644 index 000000000000..e7aaac1063ec --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/DriverMED_W_SMESHDS_Mesh.cpp @@ -0,0 +1,1007 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH DriverMED : driver to read and write 'med' files +// File : DriverMED_W_SMESHDS_Mesh.cxx +// Module : SMESH +// + +#include "DriverMED_W_SMESHDS_Mesh.h" + +#include "DriverMED_Family.h" +#include "MED_Factory.hxx" +#include "MED_Utilities.hxx" +#include "SMDS_IteratorOnIterators.hxx" +#include "SMDS_MeshElement.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMDS_PolyhedralVolumeOfNodes.hxx" +#include "SMDS_SetIterator.hxx" +#include "SMESHDS_Mesh.hxx" + +#include +#include +#include + +#include + + +#define _EDF_NODE_IDS_ +//#define _ELEMENTS_BY_DIM_ + +using namespace std; +using namespace MED; + + +DriverMED_W_SMESHDS_Mesh::DriverMED_W_SMESHDS_Mesh(): + myMedVersion(MED::eV2_2), + myAllSubMeshes (false), + myDoGroupOfNodes (false), + myDoGroupOfEdges (false), + myDoGroupOfFaces (false), + myDoGroupOfVolumes (false), + myDoGroupOf0DElems(false), + myDoGroupOfBalls(false), + myAutoDimension(true), + myAddODOnVertices(false) +{} + +void DriverMED_W_SMESHDS_Mesh::SetFile(const std::string& theFileName, + MED::EVersion theId) +{ + Driver_SMESHDS_Mesh::SetFile(theFileName); + myMedVersion = theId; +} + +void DriverMED_W_SMESHDS_Mesh::SetFile(const std::string& theFileName) +{ + Driver_SMESHDS_Mesh::SetFile(theFileName); +} + +string DriverMED_W_SMESHDS_Mesh::GetVersionString(const MED::EVersion theVersion, int theNbDigits) +{ + TInt majeur, mineur, release; + majeur = mineur = release = 0; +// if ( theVersion == eV2_1 ) +// MED::GetVersionRelease(majeur, mineur, release); +// else +// MED::GetVersionRelease(majeur, mineur, release); + majeur = 3; + mineur = 2; + release = 1; + ostringstream name; + if ( theNbDigits > 0 ) + name << majeur; + if ( theNbDigits > 1 ) + name << "." << mineur; + if ( theNbDigits > 2 ) + name << "." << release; + return name.str(); +} + +void DriverMED_W_SMESHDS_Mesh::AddGroup(SMESHDS_GroupBase* theGroup) +{ + myGroups.push_back(theGroup); +} + +void DriverMED_W_SMESHDS_Mesh::AddAllSubMeshes() +{ + myAllSubMeshes = true; +} + +void DriverMED_W_SMESHDS_Mesh::AddSubMesh(SMESHDS_SubMesh* theSubMesh, int theID) +{ + mySubMeshes.push_back( theSubMesh ); +} + +void DriverMED_W_SMESHDS_Mesh::AddGroupOfNodes() +{ + myDoGroupOfNodes = true; +} + +void DriverMED_W_SMESHDS_Mesh::AddGroupOfEdges() +{ + myDoGroupOfEdges = true; +} + +void DriverMED_W_SMESHDS_Mesh::AddGroupOfFaces() +{ + myDoGroupOfFaces = true; +} + +void DriverMED_W_SMESHDS_Mesh::AddGroupOfVolumes() +{ + myDoGroupOfVolumes = true; +} + +namespace +{ + typedef double (SMDS_MeshNode::* TGetCoord)() const; + typedef const char* TName; + typedef const char* TUnit; + + // name length in a mesh must be equal to 16 : + // 1234567890123456 + TName M = "m "; + TName X = "x "; + TName Y = "y "; + TName Z = "z "; + + TUnit aUnit[3] = {M,M,M}; + + // 3 dim + TGetCoord aXYZGetCoord[3] = { + &SMDS_MeshNode::X, + &SMDS_MeshNode::Y, + &SMDS_MeshNode::Z + }; + TName aXYZName[3] = {X,Y,Z}; + + // 2 dim + TGetCoord aXYGetCoord[2] = { + &SMDS_MeshNode::X, + &SMDS_MeshNode::Y + }; + TName aXYName[2] = {X,Y}; + + TGetCoord aYZGetCoord[2] = { + &SMDS_MeshNode::Y, + &SMDS_MeshNode::Z + }; + TName aYZName[2] = {Y,Z}; + + TGetCoord aXZGetCoord[2] = { + &SMDS_MeshNode::X, + &SMDS_MeshNode::Z + }; + TName aXZName[2] = {X,Z}; + + // 1 dim + TGetCoord aXGetCoord[1] = { + &SMDS_MeshNode::X + }; + TName aXName[1] = {X}; + + TGetCoord aYGetCoord[1] = { + &SMDS_MeshNode::Y + }; + TName aYName[1] = {Y}; + + TGetCoord aZGetCoord[1] = { + &SMDS_MeshNode::Z + }; + TName aZName[1] = {Z}; + + + class TCoordHelper{ + SMDS_NodeIteratorPtr myNodeIter; + const SMDS_MeshNode* myCurrentNode; + TGetCoord* myGetCoord; + TName* myName; + TUnit* myUnit; + public: + TCoordHelper(const SMDS_NodeIteratorPtr& theNodeIter, + TGetCoord* theGetCoord, + TName* theName, + TUnit* theUnit = aUnit): + myNodeIter(theNodeIter), + myGetCoord(theGetCoord), + myName(theName), + myUnit(theUnit) + {} + virtual ~TCoordHelper(){} + bool Next(){ + return myNodeIter->more() && + (myCurrentNode = myNodeIter->next()); + } + const SMDS_MeshNode* GetNode(){ + return myCurrentNode; + } + MED::TIntVector::value_type GetID(){ + return myCurrentNode->GetID(); + } + MED::TFloatVector::value_type GetCoord(TInt theCoodId){ + return (myCurrentNode->*myGetCoord[theCoodId])(); + } + MED::TStringVector::value_type GetName(TInt theDimId){ + return myName[theDimId]; + } + MED::TStringVector::value_type GetUnit(TInt theDimId){ + return myUnit[theDimId]; + } + }; + typedef boost::shared_ptr TCoordHelperPtr; + + //------------------------------------------------------- + /*! + * \brief Structure describing element type + */ + //------------------------------------------------------- + struct TElemTypeData + { + EEntiteMaillage _entity; + EGeometrieElement _geomType; + TInt _nbElems; + SMDSAbs_ElementType _smdsType; + + TElemTypeData (EEntiteMaillage entity, EGeometrieElement geom, TInt nb, SMDSAbs_ElementType type) + : _entity(entity), _geomType(geom), _nbElems( nb ), _smdsType( type ) {} + }; + + + typedef NCollection_DataMap< Standard_Address, int > TElemFamilyMap; + + //================================================================================ + /*! + * \brief Fills element to famaly ID map for element type. + * Removes all families of anElemType + */ + //================================================================================ + + void fillElemFamilyMap( TElemFamilyMap & anElemFamMap, + list & aFamilies, + const SMDSAbs_ElementType anElemType) + { + anElemFamMap.Clear(); + list::iterator aFamsIter = aFamilies.begin(); + while ( aFamsIter != aFamilies.end() ) + { + if ((*aFamsIter)->GetType() != anElemType) { + aFamsIter++; + } + else { + int aFamId = (*aFamsIter)->GetId(); + const ElementsSet& anElems = (*aFamsIter)->GetElements(); + ElementsSet::const_iterator anElemsIter = anElems.begin(); + for (; anElemsIter != anElems.end(); anElemsIter++) + { + anElemFamMap.Bind( (Standard_Address)*anElemsIter, aFamId ); + } + // remove a family from the list + aFamilies.erase( aFamsIter++ ); + } + } + } + + //================================================================================ + /*! + * \brief For an element, return family ID found in the map or a default one + */ + //================================================================================ + + int getFamilyId( const TElemFamilyMap & anElemFamMap, + const SMDS_MeshElement* anElement, + const int aDefaultFamilyId) + { + if ( anElemFamMap.IsBound( (Standard_Address) anElement )) + return anElemFamMap( (Standard_Address) anElement ); + + return aDefaultFamilyId; + } + + //================================================================================ + /*! + * \brief Returns iterator on sub-meshes + */ + //================================================================================ + + SMESHDS_SubMeshIteratorPtr getIterator( std::vector& mySubMeshes ) + { + return SMESHDS_SubMeshIteratorPtr + ( new SMDS_SetIterator + < const SMESHDS_SubMesh*, std::vector< SMESHDS_SubMesh* >::iterator >( mySubMeshes.begin(), + mySubMeshes.end() )); + } +} + +Driver_Mesh::Status DriverMED_W_SMESHDS_Mesh::Perform() +{ + Status aResult = DRS_OK; + if (myMesh->hasConstructionEdges() || myMesh->hasConstructionFaces()) { + INFOS("SMDS_MESH with hasConstructionEdges() or hasConstructionFaces() do not supports!!!"); + return DRS_FAIL; + } + try { + MESSAGE("Perform - myFile : "<nodesIterator(); + double aBounds[6]; + if(aNodesIter->more()){ + const SMDS_MeshNode* aNode = aNodesIter->next(); + aBounds[0] = aBounds[1] = aNode->X(); + aBounds[2] = aBounds[3] = aNode->Y(); + aBounds[4] = aBounds[5] = aNode->Z(); + } + while(aNodesIter->more()){ + const SMDS_MeshNode* aNode = aNodesIter->next(); + aBounds[0] = min(aBounds[0],aNode->X()); + aBounds[1] = max(aBounds[1],aNode->X()); + + aBounds[2] = min(aBounds[2],aNode->Y()); + aBounds[3] = max(aBounds[3],aNode->Y()); + + aBounds[4] = min(aBounds[4],aNode->Z()); + aBounds[5] = max(aBounds[5],aNode->Z()); + } + + double EPS = 1.0E-7; + TopoDS_Shape mainShape = myMesh->ShapeToMesh(); + bool hasShapeToMesh = ( myMesh->SubMeshIndices().size() > 1 ); + if ( !mainShape.IsNull() && hasShapeToMesh ) + { + // define EPS by max tolerance of the mainShape (IPAL53097) + TopExp_Explorer subShape; + for ( subShape.Init( mainShape, TopAbs_FACE ); subShape.More(); subShape.Next() ) { + EPS = Max( EPS, BRep_Tool::Tolerance( TopoDS::Face( subShape.Current() ))); + } + for ( subShape.Init( mainShape, TopAbs_EDGE ); subShape.More(); subShape.Next() ) { + EPS = Max( EPS, BRep_Tool::Tolerance( TopoDS::Edge( subShape.Current() ))); + } + for ( subShape.Init( mainShape, TopAbs_VERTEX ); subShape.More(); subShape.Next() ) { + EPS = Max( EPS, BRep_Tool::Tolerance( TopoDS::Vertex( subShape.Current() ))); + } + EPS *= 2.; + } + anIsXDimension = (aBounds[1] - aBounds[0]) + abs(aBounds[1]) + abs(aBounds[0]) > EPS; + anIsYDimension = (aBounds[3] - aBounds[2]) + abs(aBounds[3]) + abs(aBounds[2]) > EPS; + anIsZDimension = (aBounds[5] - aBounds[4]) + abs(aBounds[5]) + abs(aBounds[4]) > EPS; + aSpaceDimension = anIsXDimension + anIsYDimension + anIsZDimension; + if ( !aSpaceDimension ) + aSpaceDimension = 3; + // PAL16857(SMESH not conform to the MED convention): + if ( aSpaceDimension == 2 && anIsZDimension ) // 2D only if mesh is in XOY plane + aSpaceDimension = 3; + // PAL18941(a saved study with a mesh belong Z is opened and the mesh is belong X) + if ( aSpaceDimension == 1 && !anIsXDimension ) {// 1D only if mesh is along OX + if ( anIsYDimension ) { + aSpaceDimension = 2; + anIsXDimension = true; + } else { + aSpaceDimension = 3; + } + } + } + + SMDS_NodeIteratorPtr aNodesIter = myMesh->nodesIterator(/*idInceasingOrder=*/true); + switch ( aSpaceDimension ) { + case 3: + aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aXYZGetCoord,aXYZName)); + break; + case 2: + if(anIsXDimension && anIsYDimension) + aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aXYGetCoord,aXYName)); + if(anIsYDimension && anIsZDimension) + aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aYZGetCoord,aYZName)); + if(anIsXDimension && anIsZDimension) + aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aXZGetCoord,aXZName)); + break; + case 1: + if(anIsXDimension) + aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aXGetCoord,aXName)); + if(anIsYDimension) + aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aYGetCoord,aYName)); + if(anIsZDimension) + aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aZGetCoord,aZName)); + break; + } + } + TInt aMeshDimension = 0; + if ( myMesh->NbEdges() > 0 ) + aMeshDimension = 1; + if ( myMesh->NbFaces() > 0 ) + aMeshDimension = 2; + if ( myMesh->NbVolumes() > 0 ) + aMeshDimension = 3; + + MED::PWrapper myMed = CrWrapper(myFile,myMedVersion); + PMeshInfo aMeshInfo = myMed->CrMeshInfo(aMeshDimension,aSpaceDimension,aMeshName); + MESSAGE("Add - aMeshName : "<GetName()); + myMed->SetMeshInfo(aMeshInfo); + + // Storing SMDS groups and sub-meshes as med families + //---------------------------------------------------- + int myNodesDefaultFamilyId = 0; + int my0DElementsDefaultFamilyId = 0; + int myBallsDefaultFamilyId = 0; + int myEdgesDefaultFamilyId = 0; + int myFacesDefaultFamilyId = 0; + int myVolumesDefaultFamilyId = 0; + int nbNodes = myMesh->NbNodes(); + int nb0DElements = myMesh->Nb0DElements(); + int nbBalls = myMesh->NbBalls(); + int nbEdges = myMesh->NbEdges(); + int nbFaces = myMesh->NbFaces(); + int nbVolumes = myMesh->NbVolumes(); + if (myDoGroupOfNodes && nbNodes) myNodesDefaultFamilyId = REST_NODES_FAMILY; + if (myDoGroupOfEdges && nbEdges) myEdgesDefaultFamilyId = REST_EDGES_FAMILY; + if (myDoGroupOfFaces && nbFaces) myFacesDefaultFamilyId = REST_FACES_FAMILY; + if (myDoGroupOfVolumes && nbVolumes) myVolumesDefaultFamilyId = REST_VOLUMES_FAMILY; + if (myDoGroupOf0DElems && nb0DElements) my0DElementsDefaultFamilyId = REST_0DELEM_FAMILY; + if (myDoGroupOfBalls && nbBalls) myBallsDefaultFamilyId = REST_BALL_FAMILY; + + MESSAGE("Perform - aFamilyInfo"); + list aFamilies; + if (myAllSubMeshes) { + aFamilies = DriverMED_Family::MakeFamilies + (myMesh->SubMeshes(), myGroups, + myDoGroupOfNodes && nbNodes, + myDoGroupOfEdges && nbEdges, + myDoGroupOfFaces && nbFaces, + myDoGroupOfVolumes && nbVolumes, + myDoGroupOf0DElems && nb0DElements, + myDoGroupOfBalls && nbBalls); + } + else { + aFamilies = DriverMED_Family::MakeFamilies + (getIterator( mySubMeshes ), myGroups, + myDoGroupOfNodes && nbNodes, + myDoGroupOfEdges && nbEdges, + myDoGroupOfFaces && nbFaces, + myDoGroupOfVolumes && nbVolumes, + myDoGroupOf0DElems && nb0DElements, + myDoGroupOfBalls && nbBalls); + } + list::iterator aFamsIter; + for (aFamsIter = aFamilies.begin(); aFamsIter != aFamilies.end(); aFamsIter++) + { + PFamilyInfo aFamilyInfo = (*aFamsIter)->GetFamilyInfo(myMed,aMeshInfo); + myMed->SetFamilyInfo(aFamilyInfo); + } + + // Storing SMDS nodes to the MED file for the MED mesh + //---------------------------------------------------- +#ifdef _EDF_NODE_IDS_ + typedef map TNodeIdMap; + TNodeIdMap aNodeIdMap; +#endif + const EModeSwitch theMode = eFULL_INTERLACE; + const ERepere theSystem = eCART; + const EBooleen theIsElemNum = eVRAI; + const EBooleen theIsElemNames = eFAUX; + const EConnectivite theConnMode = eNOD; + + TInt aNbNodes = myMesh->NbNodes(); + PNodeInfo aNodeInfo = myMed->CrNodeInfo(aMeshInfo, aNbNodes, + theMode, theSystem, theIsElemNum, theIsElemNames); + + // find family numbers for nodes + TElemFamilyMap anElemFamMap; + fillElemFamilyMap( anElemFamMap, aFamilies, SMDSAbs_Node ); + + for (TInt iNode = 0; aCoordHelperPtr->Next(); iNode++) + { + // coordinates + TCoordSlice aTCoordSlice = aNodeInfo->GetCoordSlice( iNode ); + for(TInt iCoord = 0; iCoord < aSpaceDimension; iCoord++){ + aTCoordSlice[iCoord] = aCoordHelperPtr->GetCoord(iCoord); + } + // node number + int aNodeID = aCoordHelperPtr->GetID(); + aNodeInfo->SetElemNum( iNode, aNodeID ); +#ifdef _EDF_NODE_IDS_ + aNodeIdMap.insert( aNodeIdMap.end(), make_pair( aNodeID, iNode+1 )); +#endif + // family number + const SMDS_MeshNode* aNode = aCoordHelperPtr->GetNode(); + int famNum = getFamilyId( anElemFamMap, aNode, myNodesDefaultFamilyId ); + aNodeInfo->SetFamNum( iNode, famNum ); + } + anElemFamMap.Clear(); + + // coordinate names and units + for (TInt iCoord = 0; iCoord < aSpaceDimension; iCoord++) { + aNodeInfo->SetCoordName( iCoord, aCoordHelperPtr->GetName(iCoord)); + aNodeInfo->SetCoordUnit( iCoord, aCoordHelperPtr->GetUnit(iCoord)); + } + + //cout << " SetNodeInfo(aNodeInfo)" << endl; + MESSAGE("Perform - aNodeInfo->GetNbElem() = "<SetNodeInfo(aNodeInfo); + aNodeInfo.reset(); // free memory used for arrays + + + // Storing SMDS elements to the MED file for the MED mesh + //------------------------------------------------------- + // Write one element type at once in order to minimize memory usage (PAL19276) + + const SMDS_MeshInfo& nbElemInfo = myMesh->GetMeshInfo(); + + // poly elements are not supported by med-2.1 + bool polyTypesSupported = ( myMed->CrPolygoneInfo(aMeshInfo,eMAILLE,ePOLYGONE,0,0).get() != 0 ); + TInt nbPolygonNodes = 0, nbPolyhedronNodes = 0, nbPolyhedronFaces = 0; + + // nodes on VERTEXes where 0D elements are absent + std::vector nodesOf0D; + std::vector< SMDS_ElemIteratorPtr > iterVec; + SMDS_ElemIteratorPtr iterVecIter; + if ( myAddODOnVertices && getNodesOfMissing0DOnVert( myMesh, nodesOf0D )) + { + iterVec.resize(2); + iterVec[0] = myMesh->elementsIterator( SMDSAbs_0DElement ); + iterVec[1] = SMDS_ElemIteratorPtr + ( new SMDS_ElementVectorIterator( nodesOf0D.begin(), nodesOf0D.end() )); + + typedef SMDS_IteratorOnIterators + < const SMDS_MeshElement *, std::vector< SMDS_ElemIteratorPtr > > TItIterator; + iterVecIter = SMDS_ElemIteratorPtr( new TItIterator( iterVec )); + } + + // collect info on all geom types + + list< TElemTypeData > aTElemTypeDatas; + + EEntiteMaillage anEntity = eMAILLE; +#ifdef _ELEMENTS_BY_DIM_ + anEntity = eNOEUD_ELEMENT; +#endif + aTElemTypeDatas.push_back(TElemTypeData(anEntity, + ePOINT1, + nbElemInfo.Nb0DElements() + nodesOf0D.size(), + SMDSAbs_0DElement)); +#ifdef _ELEMENTS_BY_DIM_ + anEntity = eSTRUCT_ELEMENT; +#endif + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eBALL, + nbElemInfo.NbBalls(), + SMDSAbs_Ball)); +#ifdef _ELEMENTS_BY_DIM_ + anEntity = eARETE; +#endif + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eSEG2, + nbElemInfo.NbEdges( ORDER_LINEAR ), + SMDSAbs_Edge)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eSEG3, + nbElemInfo.NbEdges( ORDER_QUADRATIC ), + SMDSAbs_Edge)); +#ifdef _ELEMENTS_BY_DIM_ + anEntity = eFACE; +#endif + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eTRIA3, + nbElemInfo.NbTriangles( ORDER_LINEAR ), + SMDSAbs_Face)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eTRIA6, + nbElemInfo.NbTriangles( ORDER_QUADRATIC ) - + nbElemInfo.NbBiQuadTriangles(), + SMDSAbs_Face)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eTRIA7, + nbElemInfo.NbBiQuadTriangles(), + SMDSAbs_Face)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eQUAD4, + nbElemInfo.NbQuadrangles( ORDER_LINEAR ), + SMDSAbs_Face)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eQUAD8, + nbElemInfo.NbQuadrangles( ORDER_QUADRATIC ) - + nbElemInfo.NbBiQuadQuadrangles(), + SMDSAbs_Face)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eQUAD9, + nbElemInfo.NbBiQuadQuadrangles(), + SMDSAbs_Face)); + if ( polyTypesSupported ) { + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + ePOLYGONE, + nbElemInfo.NbPolygons( ORDER_LINEAR ), + SMDSAbs_Face)); + // we need one more loop on poly elements to count nb of their nodes + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + ePOLYGONE, + nbElemInfo.NbPolygons( ORDER_LINEAR ), + SMDSAbs_Face)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + ePOLYGON2, + nbElemInfo.NbPolygons( ORDER_QUADRATIC ), + SMDSAbs_Face)); + // we need one more loop on QUAD poly elements to count nb of their nodes + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + ePOLYGON2, + nbElemInfo.NbPolygons( ORDER_QUADRATIC ), + SMDSAbs_Face)); + } +#ifdef _ELEMENTS_BY_DIM_ + anEntity = eMAILLE; +#endif + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eTETRA4, + nbElemInfo.NbTetras( ORDER_LINEAR ), + SMDSAbs_Volume)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eTETRA10, + nbElemInfo.NbTetras( ORDER_QUADRATIC ), + SMDSAbs_Volume)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + ePYRA5, + nbElemInfo.NbPyramids( ORDER_LINEAR ), + SMDSAbs_Volume)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + ePYRA13, + nbElemInfo.NbPyramids( ORDER_QUADRATIC ), + SMDSAbs_Volume)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + ePENTA6, + nbElemInfo.NbPrisms( ORDER_LINEAR ), + SMDSAbs_Volume)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + ePENTA15, + nbElemInfo.NbPrisms( ORDER_QUADRATIC ), + SMDSAbs_Volume)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eHEXA8, + nbElemInfo.NbHexas( ORDER_LINEAR ), + SMDSAbs_Volume)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eHEXA20, + nbElemInfo.NbHexas( ORDER_QUADRATIC )- + nbElemInfo.NbTriQuadHexas(), + SMDSAbs_Volume)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eHEXA27, + nbElemInfo.NbTriQuadHexas(), + SMDSAbs_Volume)); + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + eOCTA12, + nbElemInfo.NbHexPrisms(), + SMDSAbs_Volume)); + if ( polyTypesSupported ) { + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + ePOLYEDRE, + nbElemInfo.NbPolyhedrons(), + SMDSAbs_Volume)); + // we need one more loop on poly elements to count nb of their nodes + aTElemTypeDatas.push_back( TElemTypeData(anEntity, + ePOLYEDRE, + nbElemInfo.NbPolyhedrons(), + SMDSAbs_Volume)); + } + + vector< bool > isElemFamMapBuilt( SMDSAbs_NbElementTypes, false ); + + // loop on all geom types of elements + + list< TElemTypeData >::iterator aElemTypeData = aTElemTypeDatas.begin(); + for ( ; aElemTypeData != aTElemTypeDatas.end(); ++aElemTypeData ) + { + if ( aElemTypeData->_nbElems == 0 ) + continue; + + int defaultFamilyId = 0; + switch ( aElemTypeData->_smdsType ) { + case SMDSAbs_0DElement: defaultFamilyId = my0DElementsDefaultFamilyId; break; + case SMDSAbs_Ball: defaultFamilyId = myBallsDefaultFamilyId; break; + case SMDSAbs_Edge: defaultFamilyId = myEdgesDefaultFamilyId; break; + case SMDSAbs_Face: defaultFamilyId = myFacesDefaultFamilyId; break; + case SMDSAbs_Volume: defaultFamilyId = myVolumesDefaultFamilyId; break; + default: + continue; + } + + // iterator on elements of a current type + SMDS_ElemIteratorPtr elemIterator; + int iElem = 0; + + // Treat POLYGONs + // --------------- + if ( aElemTypeData->_geomType == ePOLYGONE || + aElemTypeData->_geomType == ePOLYGON2 ) + { + if ( aElemTypeData->_geomType == ePOLYGONE ) + elemIterator = myMesh->elementEntityIterator( SMDSEntity_Polygon ); + else + elemIterator = myMesh->elementEntityIterator( SMDSEntity_Quad_Polygon ); + + if ( nbPolygonNodes == 0 ) { + // Count nb of nodes + while ( elemIterator->more() ) { + const SMDS_MeshElement* anElem = elemIterator->next(); + nbPolygonNodes += anElem->NbNodes(); + if ( ++iElem == aElemTypeData->_nbElems ) + break; + } + } + else { + // Store in med file + PPolygoneInfo aPolygoneInfo = myMed->CrPolygoneInfo(aMeshInfo, + aElemTypeData->_entity, + aElemTypeData->_geomType, + aElemTypeData->_nbElems, + nbPolygonNodes, + theConnMode, theIsElemNum, + theIsElemNames); + TElemNum & index = *(aPolygoneInfo->myIndex.get()); + index[0] = 1; + + while ( elemIterator->more() ) + { + const SMDS_MeshElement* anElem = elemIterator->next(); + // index + TInt aNbNodes = anElem->NbNodes(); + index[ iElem+1 ] = index[ iElem ] + aNbNodes; + + // connectivity + TConnSlice aTConnSlice = aPolygoneInfo->GetConnSlice( iElem ); + for(TInt iNode = 0; iNode < aNbNodes; iNode++) { + const SMDS_MeshElement* aNode = anElem->GetNode( iNode ); +#ifdef _EDF_NODE_IDS_ + aTConnSlice[ iNode ] = aNodeIdMap[aNode->GetID()]; +#else + aTConnSlice[ iNode ] = aNode->GetID(); +#endif + } + // element number + aPolygoneInfo->SetElemNum( iElem, anElem->GetID() ); + + // family number + int famNum = getFamilyId( anElemFamMap, anElem, defaultFamilyId ); + aPolygoneInfo->SetFamNum( iElem, famNum ); + + if ( ++iElem == aPolygoneInfo->GetNbElem() ) + break; + } + myMed->SetPolygoneInfo(aPolygoneInfo); + + nbPolygonNodes = 0; // to treat next polygon type + } + } + + // Treat POLYEDREs + // ---------------- + else if (aElemTypeData->_geomType == ePOLYEDRE ) + { + elemIterator = myMesh->elementGeomIterator( SMDSGeom_POLYHEDRA ); + + if ( nbPolyhedronNodes == 0 ) { + // Count nb of nodes + while ( elemIterator->more() ) { + const SMDS_MeshElement* anElem = elemIterator->next(); + const SMDS_VtkVolume *aPolyedre = dynamic_cast(anElem); + if ( !aPolyedre ) continue; + nbPolyhedronNodes += aPolyedre->NbNodes(); + nbPolyhedronFaces += aPolyedre->NbFaces(); + if ( ++iElem == aElemTypeData->_nbElems ) + break; + } + } + else { + // Store in med file + PPolyedreInfo aPolyhInfo = myMed->CrPolyedreInfo(aMeshInfo, + aElemTypeData->_entity, + aElemTypeData->_geomType, + aElemTypeData->_nbElems, + nbPolyhedronFaces+1, + nbPolyhedronNodes, + theConnMode, + theIsElemNum, + theIsElemNames); + TElemNum & index = *(aPolyhInfo->myIndex.get()); + TElemNum & faces = *(aPolyhInfo->myFaces.get()); + TElemNum & conn = *(aPolyhInfo->myConn.get()); + index[0] = 1; + faces[0] = 1; + + TInt iFace = 0, iNode = 0; + while ( elemIterator->more() ) + { + const SMDS_MeshElement* anElem = elemIterator->next(); + const SMDS_VtkVolume *aPolyedre = dynamic_cast(anElem); + if ( !aPolyedre ) continue; + // index + TInt aNbFaces = aPolyedre->NbFaces(); + index[ iElem+1 ] = index[ iElem ] + aNbFaces; + + // face index + for (TInt f = 1; f <= aNbFaces; ++f, ++iFace ) { + int aNbFaceNodes = aPolyedre->NbFaceNodes( f ); + faces[ iFace+1 ] = faces[ iFace ] + aNbFaceNodes; + } + // connectivity + SMDS_ElemIteratorPtr nodeIt = anElem->nodesIterator(); + while ( nodeIt->more() ) { + const SMDS_MeshElement* aNode = nodeIt->next(); +#ifdef _EDF_NODE_IDS_ + conn[ iNode ] = aNodeIdMap[aNode->GetID()]; +#else + conn[ iNode ] = aNode->GetID(); +#endif + ++iNode; + } + // element number + aPolyhInfo->SetElemNum( iElem, anElem->GetID() ); + + // family number + int famNum = getFamilyId( anElemFamMap, anElem, defaultFamilyId ); + aPolyhInfo->SetFamNum( iElem, famNum ); + + if ( ++iElem == aPolyhInfo->GetNbElem() ) + break; + } + myMed->SetPolyedreInfo(aPolyhInfo); + } + } // if (aElemTypeData->_geomType == ePOLYEDRE ) + + // Treat BALLs + // ---------------- + else if (aElemTypeData->_geomType == eBALL ) + { + // allocate data arrays + PBallInfo aBallInfo = myMed->CrBallInfo( aMeshInfo, aElemTypeData->_nbElems ); + + // build map of family numbers for this type + if ( !isElemFamMapBuilt[ aElemTypeData->_smdsType ]) + { + fillElemFamilyMap( anElemFamMap, aFamilies, aElemTypeData->_smdsType ); + isElemFamMapBuilt[ aElemTypeData->_smdsType ] = true; + } + + elemIterator = myMesh->elementsIterator( SMDSAbs_Ball ); + while ( elemIterator->more() ) + { + const SMDS_MeshElement* anElem = elemIterator->next(); + // connectivity + const SMDS_MeshElement* aNode = anElem->GetNode( 0 ); +#ifdef _EDF_NODE_IDS_ + (*aBallInfo->myConn)[ iElem ] = aNodeIdMap[aNode->GetID()]; +#else + (*aBallInfo->myConn)[ iElem ] = aNode->GetID(); +#endif + // element number + aBallInfo->SetElemNum( iElem, anElem->GetID() ); + + // diameter + aBallInfo->myDiameters[ iElem ] = + static_cast( anElem )->GetDiameter(); + + // family number + int famNum = getFamilyId( anElemFamMap, anElem, defaultFamilyId ); + aBallInfo->SetFamNum( iElem, famNum ); + ++iElem; + } + // store data in a file + myMed->SetBallInfo(aBallInfo); + } + + else + { + // Treat standard types + // --------------------- + + // allocate data arrays + PCellInfo aCellInfo = myMed->CrCellInfo( aMeshInfo, + aElemTypeData->_entity, + aElemTypeData->_geomType, + aElemTypeData->_nbElems, + theConnMode, + theIsElemNum, + theIsElemNames); + // build map of family numbers for this type + if ( !isElemFamMapBuilt[ aElemTypeData->_smdsType ]) + { + //cout << " fillElemFamilyMap()" << endl; + fillElemFamilyMap( anElemFamMap, aFamilies, aElemTypeData->_smdsType ); + isElemFamMapBuilt[ aElemTypeData->_smdsType ] = true; + } + + TInt aNbNodes = MED::GetNbNodes(aElemTypeData->_geomType); + elemIterator = myMesh->elementsIterator( aElemTypeData->_smdsType ); + if ( aElemTypeData->_smdsType == SMDSAbs_0DElement && ! nodesOf0D.empty() ) + elemIterator = iterVecIter; + while ( elemIterator->more() ) + { + const SMDS_MeshElement* anElem = elemIterator->next(); + if ( anElem->NbNodes() != aNbNodes || anElem->IsPoly() ) + continue; // other geometry + + // connectivity + TConnSlice aTConnSlice = aCellInfo->GetConnSlice( iElem ); + for (TInt iNode = 0; iNode < aNbNodes; iNode++) { + const SMDS_MeshElement* aNode = anElem->GetNode( iNode ); +#ifdef _EDF_NODE_IDS_ + aTConnSlice[ iNode ] = aNodeIdMap[aNode->GetID()]; +#else + aTConnSlice[ iNode ] = aNode->GetID(); +#endif + } + // element number + aCellInfo->SetElemNum( iElem, anElem->GetID() ); + + // family number + int famNum = getFamilyId( anElemFamMap, anElem, defaultFamilyId ); + aCellInfo->SetFamNum( iElem, famNum ); + + if ( ++iElem == aCellInfo->GetNbElem() ) + break; + } + // store data in a file + myMed->SetCellInfo(aCellInfo); + } + + } // loop on geom types + + + } + catch(const std::exception& exc) { + INFOS("The following exception was caught:\n\t"<& nodes) +{ + nodes.clear(); + for ( int i = 1; i <= meshDS->MaxShapeIndex(); ++i ) + { + if ( meshDS->IndexToShape( i ).ShapeType() != TopAbs_VERTEX ) + continue; + if ( SMESHDS_SubMesh* sm = meshDS->MeshElements(i) ) { + SMDS_NodeIteratorPtr nIt= sm->GetNodes(); + while (nIt->more()) + { + const SMDS_MeshNode* n = nIt->next(); + if ( n->NbInverseElements( SMDSAbs_0DElement ) == 0 ) + nodes.push_back( n ); + } + } + } + return !nodes.empty(); +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/GEOMUtils.cpp b/src/3rdParty/salomesmesh/src/SMESH/GEOMUtils.cpp new file mode 100644 index 000000000000..df6952778978 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/GEOMUtils.cpp @@ -0,0 +1,1290 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +#include + +#include + +#include + +#include +#include + +// OCCT Includes +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC + +#define MAX2(X, Y) (Abs(X) > Abs(Y) ? Abs(X) : Abs(Y)) +#define MAX3(X, Y, Z) (MAX2(MAX2(X,Y), Z)) + +#define STD_SORT_ALGO 1 + +// When the following macro is defined, ShapeFix_ShapeTolerance function is used to set max tolerance of curve +// in GEOMUtils::FixShapeCurves function; otherwise less restrictive BRep_Builder::UpdateEdge/UpdateVertex +// approach is used +// VSR (29/12/2014): macro disabled +//#define USE_LIMIT_TOLERANCE + +namespace +{ + /** + * This function constructs and returns modified shape from the original one + * for singular cases. It is used for the method GetMinDistanceSingular. + * + * \param theShape the original shape + * \param theModifiedShape output parameter. The modified shape. + * \param theAddDist output parameter. The added distance for modified shape. + * \retval true if the shape is modified; false otherwise. + * + * \internal + */ + Standard_Boolean ModifyShape(const TopoDS_Shape &theShape, + TopoDS_Shape &theModifiedShape, + Standard_Real &theAddDist) + { + TopExp_Explorer anExp; + int nbf = 0; + + theAddDist = 0.; + theModifiedShape.Nullify(); + + for ( anExp.Init( theShape, TopAbs_FACE ); anExp.More(); anExp.Next() ) { + nbf++; + theModifiedShape = anExp.Current(); + } + if(nbf==1) { + TopoDS_Shape sh = theShape; + while(sh.ShapeType()==TopAbs_COMPOUND) { + TopoDS_Iterator it(sh); + sh = it.Value(); + } + Handle(Geom_Surface) S = BRep_Tool::Surface(TopoDS::Face(theModifiedShape)); + if( S->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) || + S->IsKind(STANDARD_TYPE(Geom_ToroidalSurface)) || + S->IsUPeriodic()) { + const Standard_Boolean isShell = + (sh.ShapeType()==TopAbs_SHELL || sh.ShapeType()==TopAbs_FACE); + + if ( !isShell && S->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) ) { + Handle(Geom_SphericalSurface) SS = Handle(Geom_SphericalSurface)::DownCast(S); + gp_Pnt PC = SS->Location(); + BRep_Builder B; + TopoDS_Vertex V; + B.MakeVertex(V,PC,1.e-7); + theModifiedShape = V; + theAddDist = SS->Radius(); + return Standard_True; + } + if ( !isShell && S->IsKind(STANDARD_TYPE(Geom_ToroidalSurface)) ) { + Handle(Geom_ToroidalSurface) TS = Handle(Geom_ToroidalSurface)::DownCast(S); + gp_Ax3 ax3 = TS->Position(); + Handle(Geom_Circle) C = new Geom_Circle(ax3.Ax2(),TS->MajorRadius()); + BRep_Builder B; + TopoDS_Edge E; + B.MakeEdge(E,C,1.e-7); + theModifiedShape = E; + theAddDist = TS->MinorRadius(); + return Standard_True; + } + + // non solid case or any periodic surface (Mantis 22454). + double U1,U2,V1,V2; + // changes for 0020677: EDF 1219 GEOM: MinDistance gives 0 instead of 20.88 + //S->Bounds(U1,U2,V1,V2); changed by + ShapeAnalysis::GetFaceUVBounds(TopoDS::Face(theModifiedShape),U1,U2,V1,V2); + // end of changes for 020677 (dmv) + Handle(Geom_RectangularTrimmedSurface) TrS1 = + new Geom_RectangularTrimmedSurface(S,U1,(U1+U2)/2.,V1,V2); + Handle(Geom_RectangularTrimmedSurface) TrS2 = + new Geom_RectangularTrimmedSurface(S,(U1+U2)/2.,U2,V1,V2); + TopoDS_Shape aMShape; + + TopoDS_Face F1 = BRepBuilderAPI_MakeFace(TrS1, Precision::Confusion()); + TopoDS_Face F2 = BRepBuilderAPI_MakeFace(TrS2, Precision::Confusion()); + + if (isShell) { + BRep_Builder B; + B.MakeCompound(TopoDS::Compound(aMShape)); + B.Add(aMShape, F1); + B.Add(aMShape, F2); + } else { + // The original shape is a solid. + BRepBuilderAPI_Sewing aSewing (Precision::Confusion()*10.0); + aSewing.Add(F1); + aSewing.Add(F2); + aSewing.Perform(); + aMShape = aSewing.SewedShape(); + BRep_Builder B; + TopoDS_Solid aSolid; + B.MakeSolid(aSolid); + B.Add(aSolid, aMShape); + aMShape = aSolid; + } + + Handle(ShapeFix_Shape) sfs = new ShapeFix_Shape; + sfs->Init(aMShape); + sfs->SetPrecision(1.e-6); + sfs->SetMaxTolerance(1.0); + sfs->Perform(); + theModifiedShape = sfs->Shape(); + return Standard_True; + } + } + + theModifiedShape = theShape; + return Standard_False; + } + + void parseWard( const GEOMUtils::LevelsList &theLevelList, std::string &treeStr ) + { + treeStr.append( "{" ); + for( GEOMUtils::LevelsList::const_iterator j = theLevelList.begin(); + j != theLevelList.end(); ++j ) { + if ( j != theLevelList.begin() ) { + treeStr.append( ";" ); + } + GEOMUtils::LevelInfo level = (*j); + GEOMUtils::LevelInfo::iterator upIter; + for ( upIter = level.begin(); upIter != level.end(); ++upIter ) { + if ( upIter != level.begin() ) { + treeStr.append( "," ); + } + treeStr.append( upIter->first ); + for ( std::vector::iterator k = upIter->second.begin(); k != upIter->second.end(); ++k ) { + treeStr.append( "_" ); + treeStr.append( *k ); + } + } + } + treeStr.append( "}" ); + } + + GEOMUtils::LevelsList parseWard( const std::string& theData, std::size_t& theCursor ) + { + std::size_t indexStart = theData.find( "{", theCursor ) + 1; + std::size_t indexEnd = theData.find( "}", indexStart ); + + std::string ward = theData.substr( indexStart, indexEnd - indexStart ); + std::stringstream ss(ward); + std::string substr; + std::vector levelsListStr; + while ( std::getline( ss, substr, ';' ) ) { + if ( !substr.empty() ) + levelsListStr.push_back( substr ); + } + GEOMUtils::LevelsList levelsListData; + for( int level = 0; level < levelsListStr.size(); level++ ) { + std::vector namesListStr; + std::stringstream ss1( levelsListStr[level] ); + while ( std::getline( ss1, substr, ',' ) ) { + if ( !substr.empty() ) + namesListStr.push_back( substr ); + } + GEOMUtils::LevelInfo levelInfoData; + for( int node = 0; node < namesListStr.size(); node++ ) { + std::vector linksListStr; + std::stringstream ss2( namesListStr[node] ); + while ( std::getline( ss2, substr, '_' ) ) { + if ( !substr.empty() ) + linksListStr.push_back( substr ); + } + std::string nodeItem = linksListStr[0]; + if( !nodeItem.empty() ) { + GEOMUtils::NodeLinks linksListData; + for( int link = 1; link < linksListStr.size(); link++ ) { + std::string linkItem = linksListStr[link]; + linksListData.push_back( linkItem ); + }// Links + levelInfoData[nodeItem] = linksListData; + } + }// Level's objects + levelsListData.push_back(levelInfoData); + }// Levels + + theCursor = indexEnd + 1; + return levelsListData; + } + +} + +//======================================================================= +//function : ShapeToDouble +//purpose : used by CompareShapes::operator() +//======================================================================= +std::pair GEOMUtils::ShapeToDouble (const TopoDS_Shape& S, bool isOldSorting) +{ + // Computing of CentreOfMass + gp_Pnt GPoint; + double Len; + + if (S.ShapeType() == TopAbs_VERTEX) { + GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S)); + Len = (double)S.Orientation(); + } + else { + GProp_GProps GPr; + // BEGIN: fix for Mantis issue 0020842 + if (isOldSorting) { + BRepGProp::LinearProperties(S, GPr); + } + else { + if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) { + BRepGProp::LinearProperties(S, GPr); + } + else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) { + BRepGProp::SurfaceProperties(S, GPr); + } + else { + BRepGProp::VolumeProperties(S, GPr); + } + } + // END: fix for Mantis issue 0020842 + GPoint = GPr.CentreOfMass(); + Len = GPr.Mass(); + } + + double dMidXYZ = GPoint.X() * 999.0 + GPoint.Y() * 99.0 + GPoint.Z() * 0.9; + return std::make_pair(dMidXYZ, Len); +} + +//======================================================================= +//function : GetPosition +//purpose : +//======================================================================= +gp_Ax3 GEOMUtils::GetPosition (const TopoDS_Shape& theShape) +{ + gp_Ax3 aResult; + + if (theShape.IsNull()) + return aResult; + + // Axes + aResult.Transform(theShape.Location().Transformation()); + if (theShape.ShapeType() == TopAbs_FACE) { + Handle(Geom_Surface) aGS = BRep_Tool::Surface(TopoDS::Face(theShape)); + if (!aGS.IsNull() && aGS->IsKind(STANDARD_TYPE(Geom_Plane))) { + Handle(Geom_Plane) aGPlane = Handle(Geom_Plane)::DownCast(aGS); + gp_Pln aPln = aGPlane->Pln(); + aResult = aPln.Position(); + // In case of reverse orinetation of the face invert the plane normal + // (the face's normal does not mathc the plane's normal in this case) + if(theShape.Orientation() == TopAbs_REVERSED) + { + gp_Dir Vx = aResult.XDirection(); + gp_Dir N = aResult.Direction().Mirrored(Vx); + gp_Pnt P = aResult.Location(); + aResult = gp_Ax3(P, N, Vx); + } + } + } + + // Origin + gp_Pnt aPnt; + + TopAbs_ShapeEnum aShType = theShape.ShapeType(); + + if (aShType == TopAbs_VERTEX) { + aPnt = BRep_Tool::Pnt(TopoDS::Vertex(theShape)); + } + else { + if (aShType == TopAbs_COMPOUND) { + aShType = GetTypeOfSimplePart(theShape); + } + + GProp_GProps aSystem; + if (aShType == TopAbs_EDGE || aShType == TopAbs_WIRE) + BRepGProp::LinearProperties(theShape, aSystem); + else if (aShType == TopAbs_FACE || aShType == TopAbs_SHELL) + BRepGProp::SurfaceProperties(theShape, aSystem); + else + BRepGProp::VolumeProperties(theShape, aSystem); + + aPnt = aSystem.CentreOfMass(); + } + + aResult.SetLocation(aPnt); + + return aResult; +} + +//======================================================================= +//function : GetVector +//purpose : +//======================================================================= +gp_Vec GEOMUtils::GetVector (const TopoDS_Shape& theShape, + Standard_Boolean doConsiderOrientation) +{ + if (theShape.IsNull()) + Standard_NullObject::Raise("Null shape is given for a vector"); + + if (theShape.ShapeType() != TopAbs_EDGE) + Standard_TypeMismatch::Raise("Invalid shape is given, must be a vector or an edge"); + + TopoDS_Edge anE = TopoDS::Edge(theShape); + + TopoDS_Vertex V1, V2; + TopExp::Vertices(anE, V1, V2, doConsiderOrientation); + + if (V1.IsNull() || V2.IsNull()) + Standard_NullObject::Raise("Invalid edge is given, it must have two points"); + + gp_Vec aV (BRep_Tool::Pnt(V1), BRep_Tool::Pnt(V2)); + if (aV.Magnitude() < gp::Resolution()) { + Standard_ConstructionError::Raise("Vector of zero length is given"); + } + + return aV; +} + +//======================================================================= +//function : CompareShapes::operator() +//purpose : used by std::sort(), called from SortShapes() +//======================================================================= +bool GEOMUtils::CompareShapes::operator() (const TopoDS_Shape& theShape1, + const TopoDS_Shape& theShape2) +{ + if (!myMap.IsBound(theShape1)) { + myMap.Bind(theShape1, ShapeToDouble(theShape1, myIsOldSorting)); + } + + if (!myMap.IsBound(theShape2)) { + myMap.Bind(theShape2, ShapeToDouble(theShape2, myIsOldSorting)); + } + + std::pair val1 = myMap.Find(theShape1); + std::pair val2 = myMap.Find(theShape2); + + double tol = Precision::Confusion(); + bool exchange = Standard_False; + + double dMidXYZ = val1.first - val2.first; + if (dMidXYZ >= tol) { + exchange = Standard_True; + } + else if (Abs(dMidXYZ) < tol) { + double dLength = val1.second - val2.second; + if (dLength >= tol) { + exchange = Standard_True; + } + else if (Abs(dLength) < tol && theShape1.ShapeType() <= TopAbs_FACE) { + // PAL17233 + // equal values possible on shapes such as two halves of a sphere and + // a membrane inside the sphere + Bnd_Box box1,box2; + BRepBndLib::Add(theShape1, box1); + if (!box1.IsVoid()) { + BRepBndLib::Add(theShape2, box2); + Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent(); + if (dSquareExtent >= tol) { + exchange = Standard_True; + } + else if (Abs(dSquareExtent) < tol) { + Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2; + box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); + val1 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9; + box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); + val2 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9; + if ((val1 - val2) >= tol) { + exchange = Standard_True; + } + } + } + } + } + + //return val1 < val2; + return !exchange; +} + +//======================================================================= +//function : SortShapes +//purpose : +//======================================================================= +void GEOMUtils::SortShapes (TopTools_ListOfShape& SL, + const Standard_Boolean isOldSorting) +{ +#ifdef STD_SORT_ALGO + std::vector aShapesVec; + aShapesVec.reserve(SL.Extent()); + + TopTools_ListIteratorOfListOfShape it (SL); + for (; it.More(); it.Next()) { + aShapesVec.push_back(it.Value()); + } + SL.Clear(); + + CompareShapes shComp (isOldSorting); + std::stable_sort(aShapesVec.begin(), aShapesVec.end(), shComp); + //std::sort(aShapesVec.begin(), aShapesVec.end(), shComp); + + std::vector::const_iterator anIter = aShapesVec.begin(); + for (; anIter != aShapesVec.end(); ++anIter) { + SL.Append(*anIter); + } +#else + // old implementation + Standard_Integer MaxShapes = SL.Extent(); + TopTools_Array1OfShape aShapes (1,MaxShapes); + TColStd_Array1OfInteger OrderInd(1,MaxShapes); + TColStd_Array1OfReal MidXYZ (1,MaxShapes); //X,Y,Z; + TColStd_Array1OfReal Length (1,MaxShapes); //X,Y,Z; + + // Computing of CentreOfMass + Standard_Integer Index; + GProp_GProps GPr; + gp_Pnt GPoint; + TopTools_ListIteratorOfListOfShape it(SL); + for (Index=1; it.More(); Index++) + { + TopoDS_Shape S = it.Value(); + SL.Remove( it ); // == it.Next() + aShapes(Index) = S; + OrderInd.SetValue (Index, Index); + if (S.ShapeType() == TopAbs_VERTEX) { + GPoint = BRep_Tool::Pnt( TopoDS::Vertex( S )); + Length.SetValue( Index, (Standard_Real) S.Orientation()); + } + else { + // BEGIN: fix for Mantis issue 0020842 + if (isOldSorting) { + BRepGProp::LinearProperties (S, GPr); + } + else { + if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) { + BRepGProp::LinearProperties (S, GPr); + } + else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) { + BRepGProp::SurfaceProperties(S, GPr); + } + else { + BRepGProp::VolumeProperties(S, GPr); + } + } + // END: fix for Mantis issue 0020842 + GPoint = GPr.CentreOfMass(); + Length.SetValue(Index, GPr.Mass()); + } + MidXYZ.SetValue(Index, GPoint.X()*999.0 + GPoint.Y()*99.0 + GPoint.Z()*0.9); + //cout << Index << " L: " << Length(Index) << "CG: " << MidXYZ(Index) << endl; + } + + // Sorting + Standard_Integer aTemp; + Standard_Boolean exchange, Sort = Standard_True; + Standard_Real tol = Precision::Confusion(); + while (Sort) + { + Sort = Standard_False; + for (Index=1; Index < MaxShapes; Index++) + { + exchange = Standard_False; + Standard_Real dMidXYZ = MidXYZ(OrderInd(Index)) - MidXYZ(OrderInd(Index+1)); + Standard_Real dLength = Length(OrderInd(Index)) - Length(OrderInd(Index+1)); + if ( dMidXYZ >= tol ) { +// cout << "MidXYZ: " << MidXYZ(OrderInd(Index))<< " > " <= tol ) { +// cout << "Length: " << Length(OrderInd(Index))<< " > " <= tol ) { +// cout << "SquareExtent: " << box1.SquareExtent()<<" > "< val2; + if ((val1 - val2) >= tol) { + exchange = Standard_True; + } + //cout << "box: " << val1<<" > "< 1) { + Standard_ConstructionError::Raise("Multiple edges near the given point are found"); + } + else if (nbFound == 0) { + Standard_ConstructionError::Raise("There are no edges near the given point"); + } + else { + } + + return aResult; +} + +//======================================================================= +//function : PreciseBoundingBox +//purpose : +//======================================================================= +Standard_Boolean GEOMUtils::PreciseBoundingBox + (const TopoDS_Shape &theShape, Bnd_Box &theBox) +{ + if ( theBox.IsVoid() ) BRepBndLib::Add( theShape, theBox ); + if ( theBox.IsVoid() ) return Standard_False; + + Standard_Real aBound[6]; + theBox.Get(aBound[0], aBound[2], aBound[4], aBound[1], aBound[3], aBound[5]); + + Standard_Integer i; + const gp_Pnt aMid(0.5*(aBound[1] + aBound[0]), // XMid + 0.5*(aBound[3] + aBound[2]), // YMid + 0.5*(aBound[5] + aBound[4])); // ZMid + const gp_XYZ aSize(aBound[1] - aBound[0], // DX + aBound[3] - aBound[2], // DY + aBound[5] - aBound[4]); // DZ + const gp_Pnt aPnt[6] = + { + gp_Pnt(aBound[0] - (aBound[1] - aBound[0]), aMid.Y(), aMid.Z()), // XMin + gp_Pnt(aBound[1] + (aBound[1] - aBound[0]), aMid.Y(), aMid.Z()), // XMax + gp_Pnt(aMid.X(), aBound[2] - (aBound[3] - aBound[2]), aMid.Z()), // YMin + gp_Pnt(aMid.X(), aBound[3] + (aBound[3] - aBound[2]), aMid.Z()), // YMax + gp_Pnt(aMid.X(), aMid.Y(), aBound[4] - (aBound[5] - aBound[4])), // ZMin + gp_Pnt(aMid.X(), aMid.Y(), aBound[5] + (aBound[5] - aBound[4])) // ZMax + }; + const gp_Dir aDir[3] = { gp::DX(), gp::DY(), gp::DZ() }; + const Standard_Real aPlnSize[3] = + { + 0.5*Max(aSize.Y(), aSize.Z()), // XMin, XMax planes + 0.5*Max(aSize.X(), aSize.Z()), // YMin, YMax planes + 0.5*Max(aSize.X(), aSize.Y()) // ZMin, ZMax planes + }; + gp_Pnt aPMin[2]; + + for (i = 0; i < 6; i++) { + const Standard_Integer iHalf = i/2; + const gp_Pln aPln(aPnt[i], aDir[iHalf]); + BRepBuilderAPI_MakeFace aMkFace(aPln, -aPlnSize[iHalf], aPlnSize[iHalf], + -aPlnSize[iHalf], aPlnSize[iHalf]); + + if (!aMkFace.IsDone()) { + return Standard_False; + } + + TopoDS_Shape aFace = aMkFace.Shape(); + + // Get minimal distance between planar face and shape. + Standard_Real aMinDist = + GEOMUtils::GetMinDistance(aFace, theShape, aPMin[0], aPMin[1]); + + if (aMinDist < 0.) { + return Standard_False; + } + + aBound[i] = aPMin[1].Coord(iHalf + 1); + } + + // Update Bounding box with the new values. + theBox.SetVoid(); + theBox.Update(aBound[0], aBound[2], aBound[4], aBound[1], aBound[3], aBound[5]); + + return Standard_True; +} + +//======================================================================= +//function : GetMinDistanceSingular +//purpose : +//======================================================================= +double GEOMUtils::GetMinDistanceSingular(const TopoDS_Shape& aSh1, + const TopoDS_Shape& aSh2, + gp_Pnt& Ptmp1, gp_Pnt& Ptmp2) +{ + TopoDS_Shape tmpSh1; + TopoDS_Shape tmpSh2; + Standard_Real AddDist1 = 0.; + Standard_Real AddDist2 = 0.; + Standard_Boolean IsChange1 = ModifyShape(aSh1, tmpSh1, AddDist1); + Standard_Boolean IsChange2 = ModifyShape(aSh2, tmpSh2, AddDist2); + + if( !IsChange1 && !IsChange2 ) + return -2.0; + + BRepExtrema_DistShapeShape dst(tmpSh1,tmpSh2); + if (dst.IsDone()) { + double MinDist = 1.e9; + gp_Pnt PMin1, PMin2, P1, P2; + for (int i = 1; i <= dst.NbSolution(); i++) { + P1 = dst.PointOnShape1(i); + P2 = dst.PointOnShape2(i); + Standard_Real Dist = P1.Distance(P2); + if (MinDist > Dist) { + MinDist = Dist; + PMin1 = P1; + PMin2 = P2; + } + } + if(MinDist<1.e-7) { + Ptmp1 = PMin1; + Ptmp2 = PMin2; + } + else { + gp_Dir aDir(gp_Vec(PMin1,PMin2)); + if( MinDist > (AddDist1+AddDist2) ) { + Ptmp1 = gp_Pnt( PMin1.X() + aDir.X()*AddDist1, + PMin1.Y() + aDir.Y()*AddDist1, + PMin1.Z() + aDir.Z()*AddDist1 ); + Ptmp2 = gp_Pnt( PMin2.X() - aDir.X()*AddDist2, + PMin2.Y() - aDir.Y()*AddDist2, + PMin2.Z() - aDir.Z()*AddDist2 ); + return (MinDist - AddDist1 - AddDist2); + } + else { + if( AddDist1 > 0 ) { + Ptmp1 = gp_Pnt( PMin1.X() + aDir.X()*AddDist1, + PMin1.Y() + aDir.Y()*AddDist1, + PMin1.Z() + aDir.Z()*AddDist1 ); + Ptmp2 = Ptmp1; + } + else { + Ptmp2 = gp_Pnt( PMin2.X() - aDir.X()*AddDist2, + PMin2.Y() - aDir.Y()*AddDist2, + PMin2.Z() - aDir.Z()*AddDist2 ); + Ptmp1 = Ptmp2; + } + } + } + double res = MinDist - AddDist1 - AddDist2; + if(res<0.) res = 0.0; + return res; + } + return -2.0; +} + +//======================================================================= +//function : GetMinDistance +//purpose : +//======================================================================= +Standard_Real GEOMUtils::GetMinDistance + (const TopoDS_Shape& theShape1, + const TopoDS_Shape& theShape2, + gp_Pnt& thePnt1, gp_Pnt& thePnt2) +{ + Standard_Real aResult = 1.e9; + + // Issue 0020231: A min distance bug with torus and vertex. + // Make GetMinDistance() return zero if a sole VERTEX is inside any of SOLIDs + + // which of shapes consists of only one vertex? + TopExp_Explorer exp1(theShape1,TopAbs_VERTEX), exp2(theShape2,TopAbs_VERTEX); + TopoDS_Shape V1 = exp1.More() ? exp1.Current() : TopoDS_Shape(); + TopoDS_Shape V2 = exp2.More() ? exp2.Current() : TopoDS_Shape(); + exp1.Next(); exp2.Next(); + if ( exp1.More() ) V1.Nullify(); + if ( exp2.More() ) V2.Nullify(); + // vertex and container of solids + TopoDS_Shape V = V1.IsNull() ? V2 : V1; + TopoDS_Shape S = V1.IsNull() ? theShape1 : theShape2; + if ( !V.IsNull() ) { + // classify vertex against solids + gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( V ) ); + for ( exp1.Init( S, TopAbs_SOLID ); exp1.More(); exp1.Next() ) { + BRepClass3d_SolidClassifier classifier( exp1.Current(), p, 1e-6); + if ( classifier.State() == TopAbs_IN ) { + thePnt1 = p; + thePnt2 = p; + return 0.0; + } + } + } + // End Issue 0020231 + + // skl 30.06.2008 + // additional workaround for bugs 19899, 19908 and 19910 from Mantis + double dist = GEOMUtils::GetMinDistanceSingular + (theShape1, theShape2, thePnt1, thePnt2); + + if (dist > -1.0) { + return dist; + } + + BRepExtrema_DistShapeShape dst (theShape1, theShape2); + if (dst.IsDone()) { + gp_Pnt P1, P2; + + for (int i = 1; i <= dst.NbSolution(); i++) { + P1 = dst.PointOnShape1(i); + P2 = dst.PointOnShape2(i); + + Standard_Real Dist = P1.Distance(P2); + if (aResult > Dist) { + aResult = Dist; + thePnt1 = P1; + thePnt2 = P2; + } + } + } + + return aResult; +} + +//======================================================================= +// function : ConvertClickToPoint() +// purpose : Returns the point clicked in 3D view +//======================================================================= +// vejmarie ISSUE +gp_Pnt GEOMUtils::ConvertClickToPoint( int x, int y, Handle(V3d_View) aView ) +{ + V3d_Coordinate XEye, YEye, ZEye, XAt, YAt, ZAt; +// aView->Eye( XEye, YEye, ZEye ); + + // aView->At( XAt, YAt, ZAt ); + gp_Pnt EyePoint( XEye, YEye, ZEye ); + gp_Pnt AtPoint( XAt, YAt, ZAt ); + + gp_Vec EyeVector( EyePoint, AtPoint ); + gp_Dir EyeDir( EyeVector ); + + gp_Pln PlaneOfTheView = gp_Pln( AtPoint, EyeDir ); + Standard_Real X, Y, Z; + //aView->Convert( x, y, X, Y, Z ); + gp_Pnt ConvertedPoint( X, Y, Z ); + + gp_Pnt2d ConvertedPointOnPlane = ProjLib::Project( PlaneOfTheView, ConvertedPoint ); + gp_Pnt ResultPoint = ElSLib::Value( ConvertedPointOnPlane.X(), ConvertedPointOnPlane.Y(), PlaneOfTheView ); + return ResultPoint; +} + +//======================================================================= +// function : ConvertTreeToString() +// purpose : Returns the string representation of dependency tree +//======================================================================= +void GEOMUtils::ConvertTreeToString( const TreeModel& tree, + std::string& dependencyStr ) +{ + TreeModel::const_iterator i; + for ( i = tree.begin(); i != tree.end(); ++i ) { + dependencyStr.append( i->first ); + dependencyStr.append( "-" ); + std::vector upLevelList = i->second.first; + dependencyStr.append( "upward" ); + parseWard( upLevelList, dependencyStr ); + std::vector downLevelList = i->second.second; + dependencyStr.append( "downward" ); + parseWard( downLevelList, dependencyStr ); + } +} + +//======================================================================= +// function : ConvertStringToTree() +// purpose : Returns the dependency tree +//======================================================================= +void GEOMUtils::ConvertStringToTree( const std::string& dependencyStr, + TreeModel& tree ) +{ + std::size_t cursor = 0; + + while( dependencyStr.find('-',cursor) != std::string::npos ) //find next selected object + { + std::size_t objectIndex = dependencyStr.find( '-', cursor ); + std::string objectEntry = dependencyStr.substr( cursor, objectIndex - cursor ); + cursor = objectIndex; + + std::size_t upwardIndexBegin = dependencyStr.find("{",cursor) + 1; + std::size_t upwardIndexFinish = dependencyStr.find("}",upwardIndexBegin); + LevelsList upwardList = parseWard( dependencyStr, cursor ); + + LevelsList downwardList = parseWard( dependencyStr, cursor ); + + tree[objectEntry] = std::pair( upwardList, downwardList ); + } +} + +bool GEOMUtils::CheckShape( TopoDS_Shape& shape, + bool checkGeometry ) +{ + BRepCheck_Analyzer analyzer( shape, checkGeometry ); + return analyzer.IsValid(); +} + +bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape, + TopAbs_ShapeEnum type, + Standard_Real tolerance, + bool checkGeometry ) +{ + ShapeFix_ShapeTolerance aSft; + aSft.LimitTolerance( shape, tolerance, tolerance, type ); + Handle(ShapeFix_Shape) aSfs = new ShapeFix_Shape( shape ); + aSfs->Perform(); + shape = aSfs->Shape(); + return CheckShape( shape, checkGeometry ); +} + +bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape, + Standard_Real tolerance, + bool checkGeometry ) +{ + return FixShapeTolerance( shape, TopAbs_SHAPE, tolerance, checkGeometry ); +} + +bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape, + bool checkGeometry ) +{ + return FixShapeTolerance( shape, Precision::Confusion(), checkGeometry ); +} + +bool GEOMUtils::FixShapeCurves( TopoDS_Shape& shape ) +{ + Standard_Real aT, aTolE, aD, aDMax; + TopExp_Explorer aExpF, aExpE; + NCollection_DataMap aDMETol; + aExpF.Init(shape, TopAbs_FACE); + for (; aExpF.More(); aExpF.Next()) { + const TopoDS_Face& aF = *(TopoDS_Face*)&aExpF.Current(); + aExpE.Init(aF, TopAbs_EDGE); + for (; aExpE.More(); aExpE.Next()) { + const TopoDS_Edge& aE = *(TopoDS_Edge*)&aExpE.Current(); + try { + if (!BOPTools_AlgoTools::ComputeTolerance(aF, aE, aDMax, aT)) { + continue; + } + } + catch(...) { + continue; + } + aTolE = BRep_Tool::Tolerance(aE); + if (aDMax < aTolE) continue; + if (aDMETol.IsBound(aE)) { + aD = aDMETol.Find(aE); + if (aDMax > aD) { + aDMETol.UnBind(aE); + aDMETol.Bind(aE, aDMax); + } + } + else { + aDMETol.Bind(aE, aDMax); + } + } + } + NCollection_DataMap::Iterator aDMETolIt(aDMETol); +#ifdef USE_LIMIT_TOLERANCE + ShapeFix_ShapeTolerance sat; +#else + BRep_Builder b; +#endif + for (; aDMETolIt.More(); aDMETolIt.Next()) { +#ifdef USE_LIMIT_TOLERANCE + sat.LimitTolerance(aDMETolIt.Key(), aDMETolIt.Value()*1.001); +#else + TopoDS_Iterator itv(aDMETolIt.Key()); + for (; itv.More(); itv.Next()) + b.UpdateVertex(TopoDS::Vertex(itv.Value()), aDMETolIt.Value()*1.001); + b.UpdateEdge(aDMETolIt.Key(), aDMETolIt.Value()*1.001); +#endif + } + return CheckShape( shape ); +} + +bool GEOMUtils::Write( const TopoDS_Shape& shape, const char* fileName ) +{ + return BRepTools::Write( shape, fileName ); +} + +TopoDS_Shape GEOMUtils::ReduceCompound( const TopoDS_Shape& shape ) +{ + TopoDS_Shape result = shape; + + if ( shape.ShapeType() == TopAbs_COMPOUND || + shape.ShapeType() == TopAbs_COMPSOLID ) { + + TopTools_ListOfShape l; + + TopoDS_Iterator it ( shape ); + for ( ; it.More(); it.Next() ) + l.Append( it.Value() ); + if ( l.Extent() == 1 && l.First() != shape ) + result = ReduceCompound( l.First() ); + } + + return result; +} + +void GEOMUtils::MeshShape( const TopoDS_Shape shape, + double deflection, bool theForced ) +{ + Standard_Real aDeflection = ( deflection <= 0 ) ? DefaultDeflection() : deflection; + + // Is shape triangulated? + Standard_Boolean alreadyMeshed = true; + TopExp_Explorer ex; + TopLoc_Location aLoc; + for ( ex.Init( shape, TopAbs_FACE ); ex.More() && alreadyMeshed; ex.Next() ) { + const TopoDS_Face& aFace = TopoDS::Face( ex.Current() ); + Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation( aFace, aLoc ); + alreadyMeshed = !aPoly.IsNull(); + } + + if ( !alreadyMeshed || theForced ) { + // Compute bounding box + Bnd_Box B; + BRepBndLib::Add( shape, B ); + if ( B.IsVoid() ) + return; // NPAL15983 (Bug when displaying empty groups) + Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax; + B.Get( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax ); + + // This magic line comes from Prs3d_ShadedShape.gxx in OCCT + aDeflection = MAX3(aXmax-aXmin, aYmax-aYmin, aZmax-aZmin) * aDeflection * 4; + + // Clean triangulation before compute incremental mesh + BRepTools::Clean( shape ); + + // Compute triangulation + BRepMesh_IncrementalMesh mesh( shape, aDeflection ); + } +} + +double GEOMUtils::DefaultDeflection() +{ + return 0.001; +} + +//======================================================================= +//function : IsOpenPath +//purpose : +//======================================================================= +bool GEOMUtils::IsOpenPath(const TopoDS_Shape &theShape) +{ + bool isOpen = true; + + if (theShape.IsNull() == Standard_False) { + if (theShape.Closed()) { + // The shape is closed + isOpen = false; + } else { + const TopAbs_ShapeEnum aType = theShape.ShapeType(); + + if (aType == TopAbs_EDGE || aType == TopAbs_WIRE) { + // Check if path ends are coinsident. + TopoDS_Vertex aV[2]; + + if (aType == TopAbs_EDGE) { + // Edge + TopExp::Vertices(TopoDS::Edge(theShape), aV[0], aV[1]); + } else { + // Wire + TopExp::Vertices(TopoDS::Wire(theShape), aV[0], aV[1]); + } + + if (aV[0].IsNull() == Standard_False && + aV[1].IsNull() == Standard_False) { + if (aV[0].IsSame(aV[1])) { + // The shape is closed + isOpen = false; + } else { + const Standard_Real aTol1 = BRep_Tool::Tolerance(aV[0]); + const Standard_Real aTol2 = BRep_Tool::Tolerance(aV[1]); + const gp_Pnt aPnt1 = BRep_Tool::Pnt(aV[0]); + const gp_Pnt aPnt2 = BRep_Tool::Pnt(aV[1]); + + if (aPnt1.Distance(aPnt2) <= aTol1 + aTol2) { + // The shape is closed + isOpen = false; + } + } + } + } + } + } + + return isOpen; +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/MED_Algorithm.cpp b/src/3rdParty/salomesmesh/src/SMESH/MED_Algorithm.cpp new file mode 100644 index 000000000000..effa5cd1d9f4 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/MED_Algorithm.cpp @@ -0,0 +1,374 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// +#include "MED_Algorithm.hxx" +#include "MED_Wrapper.hxx" + +#include "MED_Utilities.hxx" + +#ifdef _DEBUG_ +static int MYDEBUG = 0; +static int MYVALUEDEBUG = 0; +#else +// static int MYDEBUG = 0; +// static int MYVALUEDEBUG = 0; +#endif + +namespace MED +{ + //--------------------------------------------------------------- + TEntity2TGeom2ElemInfo + GetEntity2TGeom2ElemInfo(const PWrapper& theWrapper, + const PMeshInfo& theMeshInfo, + const MED::TEntityInfo& theEntityInfo) + { + MSG(MYDEBUG,"GetElemsByEntity(...)"); + TEntity2TGeom2ElemInfo anEntity2TGeom2ElemInfo; + MED::TEntityInfo::const_iterator anIter = theEntityInfo.begin(); + PElemInfo anElemInfo; + TErr anErr; + for(; anIter != theEntityInfo.end(); anIter++){ + const EEntiteMaillage& anEntity = anIter->first; + const TGeom2Size& aGeom2Size = anIter->second; + TGeom2ElemInfo& aGeom2ElemInfo = anEntity2TGeom2ElemInfo[anEntity]; + + if(anEntity == eNOEUD){ + aGeom2ElemInfo[ePOINT1] = theWrapper->GetPElemInfo(theMeshInfo); + continue; + } + + TGeom2Size::const_iterator anIter2 = aGeom2Size.begin(); + for(; anIter2 != aGeom2Size.end(); anIter2++){ + const EGeometrieElement& aGeom = anIter2->first; + aGeom2ElemInfo[aGeom] = theWrapper->GetPElemInfo(theMeshInfo,anEntity,aGeom,MED::eNOD,&anErr); + } + } + ADDMSG(MYDEBUG,"\n"); + return anEntity2TGeom2ElemInfo; + } + + + //--------------------------------------------------------------- + TFamilyInfoSet + GetFamilyInfoSet(const PWrapper& theWrapper, + const PMeshInfo& theMeshInfo) + { + MSG(MYDEBUG,"GetFamilies(...)"); + TErr anErr; + TFamilyInfoSet aFamilyInfoSet; + TInt aNbFam = theWrapper->GetNbFamilies(*theMeshInfo); + INITMSG(MYDEBUG,"GetNbFamilies() = "<GetPFamilyInfo(theMeshInfo,iFam,&anErr); + if(anErr >= 0) + aFamilyInfoSet.insert(aFamilyInfo); + } + ADDMSG(MYDEBUG,"\n"); + return aFamilyInfoSet; + } + + + //--------------------------------------------------------------- + TGroupInfo + GetGroupInfo(const TFamilyInfoSet& theFamilyInfoSet) + { + MSG(MYDEBUG,"GetFamiliesByGroup(...)"); + TGroupInfo aGroup; + TFamilyInfoSet::const_iterator anIter = theFamilyInfoSet.begin(); + for(; anIter != theFamilyInfoSet.end(); anIter++){ + const PFamilyInfo& aFamilyInfo = *anIter; + TInt aNbGroup = aFamilyInfo->GetNbGroup(); + for(TInt iGroup = 0; iGroup < aNbGroup; iGroup++){ + aGroup[aFamilyInfo->GetGroupName(iGroup)].insert(aFamilyInfo); + } + } + +#ifdef _DEBUG_ + if(MYDEBUG){ + TGroupInfo::const_iterator anIter = aGroup.begin(); + for(; anIter != aGroup.end(); anIter++){ + const std::string& aName = anIter->first; + INITMSG(MYDEBUG,"aGroupName = '"<second; + TFamilyInfoSet::const_iterator anFamIter = aFamilyInfoSet.begin(); + for(; anFamIter != aFamilyInfoSet.end(); anFamIter++){ + const PFamilyInfo& aFamilyInfo = *anFamIter; + INITMSG(MYDEBUG,"aFamilyName = '"<GetName()<<"'\n"); + } + } + ADDMSG(MYDEBUG,"\n"); + } +#endif + + return aGroup; + } + + + //--------------------------------------------------------------- + TFieldInfo2TimeStampInfoSet + GetFieldInfo2TimeStampInfoSet(const PWrapper& theWrapper, + const PMeshInfo& theMeshInfo, + const MED::TEntityInfo& theEntityInfo) + { + MSG(MYDEBUG,"GetFieldsByEntity(...)"); + TFieldInfo2TimeStampInfoSet aFieldInfo2TimeStampInfoSet; + TInt aNbFields = theWrapper->GetNbFields(); + INITMSG(MYDEBUG,"GetNbFields() = "<GetPFieldInfo(theMeshInfo,iField); + INITMSG(MYDEBUG,"aFieldName = '"<GetName()<< + "'; aNbComp = "<GetNbComp()<<"; "); + TGeom2Size aGeom2Size; + EEntiteMaillage anEntity = EEntiteMaillage(-1); + TInt aNbTimeStamps = theWrapper->GetNbTimeStamps(aFieldInfo,theEntityInfo,anEntity,aGeom2Size); + ADDMSG(MYDEBUG,"anEntity = "<GetPTimeStampInfo(aFieldInfo,anEntity,aGeom2Size,iTimeStamp); + aFieldInfo2TimeStampInfoSet[aFieldInfo].insert(aTimeStamp); + INITMSG(MYDEBUG, + "aDt = "<GetDt()<< + ", Unit = \'"<GetUnitDt()<<"\n"); + } + } + ADDMSG(MYDEBUG,"\n"); + return aFieldInfo2TimeStampInfoSet; + } + + + //--------------------------------------------------------------- + TEntite2TFieldInfo2TimeStampInfoSet + GetEntite2TFieldInfo2TimeStampInfoSet(const TFieldInfo2TimeStampInfoSet& theFieldInfo2TimeStampInfoSet) + { + TEntite2TFieldInfo2TimeStampInfoSet anEntite2TFieldInfo2TimeStampInfoSet; + TFieldInfo2TimeStampInfoSet::const_iterator anIter = theFieldInfo2TimeStampInfoSet.begin(); + for(; anIter != theFieldInfo2TimeStampInfoSet.end(); anIter++){ + const TTimeStampInfoSet& aTimeStampInfoSet = anIter->second; + //const PFieldInfo& aFieldInfo = anIter->first; + if(aTimeStampInfoSet.empty()) + continue; + const PTimeStampInfo& aTimeStampInfo = *aTimeStampInfoSet.begin(); + anEntite2TFieldInfo2TimeStampInfoSet[ConvertEntity(aTimeStampInfo->GetEntity())].insert(*anIter); + } + return anEntite2TFieldInfo2TimeStampInfoSet; + } + + + //--------------------------------------------------------------- + bool + operator<(const TFamilyTSize& theLeft, const TFamilyTSize& theRight) + { + const MED::PFamilyInfo& aLeftInfo = boost::get<0>(theLeft); + const MED::PFamilyInfo& aRightInfo = boost::get<0>(theRight); + return aLeftInfo->GetId() < aRightInfo->GetId(); + } + + + //--------------------------------------------------------------- + TEntity2FamilySet + GetEntity2FamilySet(const PWrapper& theWrapper, + const TEntity2TGeom2ElemInfo& theEntity2TGeom2ElemInfo, + const TFamilyInfoSet& theFamilyInfoSet) + { + MSG(MYDEBUG,"GetFamiliesByEntity(...)"); + TEntity2FamilySet anEntity2FamilySet; + + typedef std::map TId2Family; + TId2Family anId2Family; + TFamilyInfoSet::const_iterator anIter = theFamilyInfoSet.begin(); + for(; anIter != theFamilyInfoSet.end(); anIter++){ + const PFamilyInfo& aFamilyInfo = *anIter; + anId2Family.insert(TId2Family::value_type(aFamilyInfo->GetId(),aFamilyInfo)); + } + + if(!anId2Family.empty()){ + typedef std::map TFamilyID2Size; + typedef std::map TEntity2FamilyID; + TEntity2FamilyID anEntity2FamilyID; + + if(!theEntity2TGeom2ElemInfo.empty()){ + TEntity2TGeom2ElemInfo::const_iterator anIter = theEntity2TGeom2ElemInfo.begin(); + for(; anIter != theEntity2TGeom2ElemInfo.end(); anIter++){ + const EEntiteMaillage& anEntity = anIter->first; + TFamilyID2Size& aFamilyID2Size = anEntity2FamilyID[anEntity]; + const TGeom2ElemInfo& aGeom2ElemInfo = anIter->second; + TGeom2ElemInfo::const_iterator aGeom2ElemInfoIter = aGeom2ElemInfo.begin(); + for(; aGeom2ElemInfoIter != aGeom2ElemInfo.end(); aGeom2ElemInfoIter++){ + const PElemInfo& aElemInfo = aGeom2ElemInfoIter->second; + if(TInt aNbElem = aElemInfo->GetNbElem()){ + for(TInt i = 0; i < aNbElem; i++){ + aFamilyID2Size[aElemInfo->GetFamNum(i)] += 1; + } + } + } + } + } + + if(!anEntity2FamilyID.empty()){ + TEntity2FamilyID::const_iterator anIter = anEntity2FamilyID.begin(); + for(; anIter != anEntity2FamilyID.end(); anIter++){ + const EEntiteMaillage& anEntity = anIter->first; + INITMSG(MYDEBUG,"anEntity = "<second; + TFamilyID2Size::const_iterator anIter2 = aFamilyID2Size.begin(); + for(; anIter2 != aFamilyID2Size.end(); anIter2++){ + TInt anId = anIter2->first; + TInt aSize = anIter2->second; + TId2Family::const_iterator anIter3 = anId2Family.find(anId); + if(anIter3 != anId2Family.end()){ + const PFamilyInfo& aFamilyInfo = anIter3->second; + anEntity2FamilySet[anEntity].insert(TFamilyTSize(aFamilyInfo,aSize)); + INITMSG(MYDEBUG, + "aFamilyName = '"<GetName()<< + "' anId = "<GetId()<<"\n"); + } + } + } + } + } + ADDMSG(MYDEBUG,"\n"); + return anEntity2FamilySet; + } + + + //--------------------------------------------------------------- + TKey2Gauss + GetKey2Gauss(const PWrapper& theWrapper, + TErr* theErr, + EModeSwitch theMode) + { + INITMSG(MYDEBUG,"GetKey2Gauss - theMode = "<GetNbGauss(theErr); + for(TInt anId = 1; anId <= aNbGauss; anId++){ + TGaussInfo::TInfo aPreInfo = theWrapper->GetGaussPreInfo(anId); + PGaussInfo anInfo = theWrapper->CrGaussInfo(aPreInfo,theMode); + theWrapper->GetGaussInfo(anId,anInfo,theErr); + TGaussInfo::TKey aKey = boost::get<0>(aPreInfo); + aKey2Gauss[aKey] = anInfo; + +#ifdef _DEBUG_ + const EGeometrieElement& aGeom = boost::get<0>(aKey); + const std::string& aName = boost::get<1>(aKey); + INITMSG(MYDEBUG, + "- aGeom = "<GetNbProfiles(theErr); + for(TInt anId = 1; anId <= aNbProfiles; anId++){ + TProfileInfo::TInfo aPreInfo = theWrapper->GetProfilePreInfo(anId); + const std::string& aName = boost::get<0>(aPreInfo); + if(aName == theProfileName) + return theWrapper->GetPProfileInfo(anId,theMode,theErr); + } + return anInfo; + } + + + //--------------------------------------------------------------- + TMKey2Profile + GetMKey2Profile(const PWrapper& theWrapper, + TErr* theErr, + EModeProfil theMode) + { + INITMSG(MYDEBUG,"GetMKey2Profile - theMode = "<GetNbProfiles(theErr); + for(TInt anId = 1; anId <= aNbProfiles; anId++){ + TProfileInfo::TInfo aPreInfo = theWrapper->GetProfilePreInfo(anId); + PProfileInfo anInfo = theWrapper->GetPProfileInfo(anId,theMode,theErr); + const std::string& aName = boost::get<0>(aPreInfo); + aKey2Profile[aName] = anInfo; + +#ifdef _DEBUG_ + INITMSG(MYDEBUG, + "- aName = '"<GetSize(); + for(TInt iElem = 0; iElem < aNbElem; iElem++){ + ADDMSG(MYVALUEDEBUG,anInfo->GetElemNum(iElem)<<", "); + } + ADDMSG(MYVALUEDEBUG, std::endl); +#endif + + } + return TMKey2Profile(theMode,aKey2Profile); + } + + //--------------------------------------------------------------- + EEntiteMaillage + GetEntityByFamilyId(PGrilleInfo& theInfo,TInt theId){ + TElemNum::iterator aNodeFamIter = (theInfo->myFamNumNode).begin(); + for(;aNodeFamIter != (theInfo->myFamNumNode).end(); aNodeFamIter++){ + if(theId == *aNodeFamIter) + return eNOEUD; + } + TElemNum::iterator aCellFamIter = (theInfo->myFamNum).begin(); + for(;aCellFamIter != (theInfo->myFamNum).end(); aCellFamIter++){ + if(theId == *aCellFamIter) + return eMAILLE; + } + EXCEPTION(std::runtime_error, "GetEntityByFamilyId - fails"); + return EEntiteMaillage(-1); + } + + TFamilyID2NbCells + GetFamilyID2NbCells(PGrilleInfo& theInfo){ + TFamilyID2NbCells aFamily2NbCells; + TInt aNbNodes = theInfo->myFamNumNode.size(); + TInt aNbCells = theInfo->myFamNum.size(); + for(TInt i=0; iGetFamNumNode(i)] = 0; + for(TInt i=0; iGetFamNum(i)] = 0; + for(TInt i=0; iGetFamNumNode(i)] += 1; + for(TInt i=0; iGetFamNum(i)] += 1; + return aFamily2NbCells; + } + + EEntiteMaillage ConvertEntity(const EEntiteMaillage& aEntity){ + switch( aEntity ){ + + case eNOEUD_ELEMENT: + case eMAILLE: return eMAILLE; //eNOEUD_ELEMENT it is eMAILLE + + case eFACE: + case eARETE: + case eNOEUD: return aEntity; break; + default: return EEntiteMaillage(-1); + + } + } +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/MED_CoordUtils.cpp b/src/3rdParty/salomesmesh/src/SMESH/MED_CoordUtils.cpp new file mode 100644 index 000000000000..203a0565b50d --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/MED_CoordUtils.cpp @@ -0,0 +1,159 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// +#include "MED_CoordUtils.hxx" +#include "MED_Utilities.hxx" + +namespace MED +{ + + enum ECoordName{eX, eY, eZ, eNone}; + + template + TFloat + GetCoord(const TCCoordSlice& theCoordSlice) + { + return theCoordSlice[TCoordId]; + } + + template<> + TFloat + GetCoord(const TCCoordSlice& theCoordSlice) + { + return 0.0; + } + + TGetCoord + aXYZGetCoord[3] = { + &GetCoord, + &GetCoord, + &GetCoord + }; + + TGetCoord + aXYGetCoord[3] = { + &GetCoord, + &GetCoord, + &GetCoord + }; + + TGetCoord + aYZGetCoord[3] = { + &GetCoord, + &GetCoord, + &GetCoord + }; + + TGetCoord + aXZGetCoord[3] = { + &GetCoord, + &GetCoord, + &GetCoord + }; + + + TGetCoord + aXGetCoord[3] = { + &GetCoord, + &GetCoord, + &GetCoord + }; + + TGetCoord + aYGetCoord[3] = { + &GetCoord, + &GetCoord, + &GetCoord + }; + + TGetCoord + aZGetCoord[3] = { + &GetCoord, + &GetCoord, + &GetCoord + }; + + + //--------------------------------------------------------------- + TCoordHelper + ::TCoordHelper(TGetCoord* theGetCoord): + myGetCoord(theGetCoord) + {} + + TFloat + TCoordHelper + ::GetCoord(TCCoordSlice& theCoordSlice, + TInt theCoordId) + { + return (*myGetCoord[theCoordId])(theCoordSlice); + } + + + //--------------------------------------------------------------- + PCoordHelper + GetCoordHelper(PNodeInfo theNodeInfo) + { + PCoordHelper aCoordHelper; + { + PMeshInfo aMeshInfo = theNodeInfo->GetMeshInfo(); + TInt aMeshDimension = aMeshInfo->GetDim(); + bool anIsDimPresent[3] = {false, false, false}; + for(int iDim = 0; iDim < aMeshDimension; iDim++){ + // PAL16857(SMESH not conform to the MED convention) -> + // 1D - always along X + // 2D - always in XOY plane + anIsDimPresent[iDim] = iDim < aMeshDimension; +// std::string aName = theNodeInfo->GetCoordName(iDim); +// if ( aName.size() > 1 ) // PAL12148, aName has size 8 or 16 +// aName = aName.substr(0,1); +// if(aName == "x" || aName == "X") +// anIsDimPresent[eX] = true; +// else if(aName == "y" || aName == "Y") +// anIsDimPresent[eY] = true; +// else if(aName == "z" || aName == "Z") +// anIsDimPresent[eZ] = true; + } + + switch(aMeshDimension){ + case 3: + aCoordHelper.reset(new TCoordHelper(aXYZGetCoord)); + break; + case 2: + if(anIsDimPresent[eY] && anIsDimPresent[eZ]) + aCoordHelper.reset(new TCoordHelper(aYZGetCoord)); + else if(anIsDimPresent[eX] && anIsDimPresent[eZ]) + aCoordHelper.reset(new TCoordHelper(aXZGetCoord)); + else + aCoordHelper.reset(new TCoordHelper(aXYGetCoord)); + break; + case 1: + if(anIsDimPresent[eY]) + aCoordHelper.reset(new TCoordHelper(aYGetCoord)); + else if(anIsDimPresent[eZ]) + aCoordHelper.reset(new TCoordHelper(aZGetCoord)); + else + aCoordHelper.reset(new TCoordHelper(aXGetCoord)); + break; + } + } + return aCoordHelper; + } +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/MED_Factory.cpp b/src/3rdParty/salomesmesh/src/SMESH/MED_Factory.cpp new file mode 100644 index 000000000000..3e1ea197260e --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/MED_Factory.cpp @@ -0,0 +1,165 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +#include "MED_Factory.hxx" +#include "MED_Utilities.hxx" +#include "MED_V2_2_Wrapper.hxx" + +#include +#include + +#include +extern "C" +{ +#ifndef WIN32 + #include +#endif +} + +#ifdef _DEBUG_ +static int MYDEBUG = 0; +#else +static int MYDEBUG = 0; +#endif + +namespace MED +{ + + EVersion GetVersionId(const std::string& theFileName, + bool theDoPreCheckInSeparateProcess) + { + INITMSG(MYDEBUG,"GetVersionId - theFileName = '"<&1 > /dev/null"; + + std::string aCommand = aStr.str(); + int aStatus = system(aCommand.c_str()); + + BEGMSG(MYDEBUG,"aCommand = '"< alfa + const double a = (6 + sqrt(15.))/21.; + const double b = (6 - sqrt(15.))/21.; + const double P1 = (155 + sqrt(15.))/2400.; + const double P2 = (155 - sqrt(15.))/2400.; //___ + add( -d, 1/3., 1/3., c1*9/80. );//___ + add( -d, a, a, c1*P1 ); + add( -d, 1-2*a, a, c1*P1 ); + add( -d, a, 1-2*a, c1*P1 );//___ + add( -d, b, b, c1*P2 ); + add( -d, 1-2*b, b, c1*P2 ); + add( -d, b, 1-2*b, c1*P2 );//___ + add( 0., 1/3., 1/3., c2*9/80. );//___ + add( 0., a, a, c2*P1 ); + add( 0., 1-2*a, a, c2*P1 ); + add( 0., a, 1-2*a, c2*P1 );//___ + add( 0., b, b, c2*P2 ); + add( 0., 1-2*b, b, c2*P2 ); + add( 0., b, 1-2*b, c2*P2 );//___ + add( d, 1/3., 1/3., c1*9/80. );//___ + add( d, a, a, c1*P1 ); + add( d, 1-2*a, a, c1*P1 ); + add( d, a, 1-2*a, c1*P1 );//___ + add( d, b, b, c1*P2 ); + add( d, 1-2*b, b, c1*P2 ); + add( d, b, 1-2*b, c1*P2 );//___ + break; + } + default: + EXCEPTION( logic_error,"Invalid nb of gauss points for PENTA: " < EPS) + return fabs(theLeft-theRight)/(fabs(theLeft)+fabs(theRight)) < EPS; + return true; + } + + + //--------------------------------------------------------------- + class TShapeFun::TFun + { + TFloatVector myFun; + TInt myNbRef; + + public: + + void + Init(TInt theNbGauss, + TInt theNbRef) + { + myFun.resize(theNbGauss*theNbRef); + myNbRef = theNbRef; + } + + TCFloatVecSlice + GetFunSlice(TInt theGaussId) const + { + return TCFloatVecSlice(myFun,std::slice(theGaussId*myNbRef,myNbRef,1)); + } + + TFloatVecSlice + GetFunSlice(TInt theGaussId) + { + return TFloatVecSlice(myFun,std::slice(theGaussId*myNbRef,myNbRef,1)); + } + }; + + //--------------------------------------------------------------- + + TShapeFun::TShapeFun(TInt theDim, TInt theNbRef): + myRefCoord(theNbRef*theDim), + myDim(theDim), + myNbRef(theNbRef) + {} + + TCCoordSlice + TShapeFun::GetCoord(TInt theRefId) const + { + return TCCoordSlice(myRefCoord,std::slice(theRefId*myDim,myDim,1)); + } + + TCoordSlice + TShapeFun::GetCoord(TInt theRefId) + { + return TCoordSlice(myRefCoord,std::slice(theRefId*myDim,myDim,1)); + } + + void + TShapeFun::GetFun(const TCCoordSliceArr& theRef, + const TCCoordSliceArr& theGauss, + TFun& theFun) const + { + TInt aNbRef = theRef.size(); + TInt aNbGauss = theGauss.size(); + theFun.Init(aNbGauss,aNbRef); + } + + bool + TShapeFun::IsSatisfy(const TCCoordSliceArr& theRefCoord) const + { + TInt aNbRef = theRefCoord.size(); + TInt aNbRef2 = GetNbRef(); + INITMSG(MYDEBUG,"TShapeFun::IsSatisfy "<< + "- aNbRef("<GetDim(); + TInt aNbGauss = theGauss.size(); + + bool anIsSubMesh = !theElemNum.empty(); + TInt aNbElem; + if(anIsSubMesh) + aNbElem = theElemNum.size(); + else + aNbElem = theCellInfo.GetNbElem(); + + theGaussCoord.Init(aNbElem,aNbGauss,aDim,theMode); + + TFun aFun; + InitFun(theRef,theGauss,aFun); + TInt aConnDim = theCellInfo.GetConnDim(); + + INITMSG(MYDEBUG,"aDim = "<GetDim(); + static TInt aNbGauss = 1; + + bool anIsSubMesh = !theElemNum.empty(); + TInt aNbElem; + if(anIsSubMesh) + aNbElem = theElemNum.size(); + else + aNbElem = theCellInfo.GetNbElem(); + + theGaussCoord.Init(aNbElem,aNbGauss,aDim,theMode); + + TInt aConnDim = theCellInfo.GetConnDim(); + + INITMSGA(MYDEBUG,0, + "- aDim = "<GetDim(); + static TInt aNbGauss = 1; + + bool anIsSubMesh = !theElemNum.empty(); + TInt aNbElem; + if(anIsSubMesh) + aNbElem = theElemNum.size(); + else + aNbElem = thePolygoneInfo.GetNbElem(); + + theGaussCoord.Init(aNbElem,aNbGauss,aDim,theMode); + + INITMSGA(MYDEBUG,0, + "- aDim = "<GetDim(); + static TInt aNbGauss = 1; + + bool anIsSubMesh = !theElemNum.empty(); + TInt aNbElem; + if(anIsSubMesh) + aNbElem = theElemNum.size(); + else + aNbElem = thePolyedreInfo.GetNbElem(); + + theGaussCoord.Init(aNbElem,aNbGauss,aDim,theMode); + + INITMSGA(MYDEBUG,0, + "- aDim = "< + +using namespace MED; + +namespace MED +{ + TInt + GetNbNodes(EGeometrieElement typmai) + { + return typmai%100; + } + + std::string + GetString(TInt theId, + TInt theStep, + const TString& theString) + { + const char* aPos = &theString[theId*theStep]; + TInt aSize = std::min(TInt(strlen(aPos)),theStep); + return std::string(aPos,aSize); + } + + void + SetString(TInt theId, + TInt theStep, + TString& theString, + const std::string& theValue) + { + TInt aSize = std::min(TInt(theValue.size()+1),theStep); + char* aPos = &theString[theId*theStep]; + strncpy(aPos,theValue.c_str(),aSize); + } + + void + SetString(TInt theId, + TInt theStep, + TString& theString, + const TString& theValue) + { + TInt aSize = std::min(TInt(theValue.size()+1),theStep); + char* aPos = &theString[theId*theStep]; + const char* aValue = &theValue[0]; + strncpy(aPos,aValue,aSize); + } + + TInt + GetDimGaussCoord(EGeometrieElement theGeom) + { + return theGeom/100; + } + + TInt + GetNbRefCoord(EGeometrieElement theGeom) + { + return (theGeom%100); + } + + //--------------------------------------------------------------- + PFloatTimeStampValue + CastToFloatTimeStampValue(const PTimeStampValueBase& theTimeStampValue) + { + return theTimeStampValue; + } + + PIntTimeStampValue + CastToIntTimeStampValue(const PTimeStampValueBase& theTimeStampValue) + { + return theTimeStampValue; + } +} + +//--------------------------------------------------------------- +TInt +TFamilyInfo +::GetAttrId(TInt theId) const +{ + return myAttrId[theId]; +} + +TInt +TFamilyInfo +::GetAttrVal(TInt theId) const +{ + return myAttrVal[theId]; +} + +void +TFamilyInfo +::SetAttrId(TInt theId,TInt theVal) +{ + myAttrId[theId] = theVal; +} + +void +TFamilyInfo +::SetAttrVal(TInt theId,TInt theVal) +{ + myAttrVal[theId] = theVal; +} + +//--------------------------------------------------------------- +TInt +TElemInfo +::GetFamNum(TInt theId) const +{ + return (*myFamNum)[theId]; +} + +void +TElemInfo +::SetFamNum(TInt theId, TInt theVal) +{ + (*myFamNum)[theId] = theVal; + myIsFamNum = eVRAI; +} + +TInt +TElemInfo +::GetElemNum(TInt theId) const +{ + return (*myElemNum)[theId]; +} + +void +TElemInfo +::SetElemNum(TInt theId, TInt theVal) +{ + (*myElemNum)[theId] = theVal; +} + +//--------------------------------------------------------------- +TCCoordSlice +TNodeInfo +::GetCoordSlice(TInt theId) const +{ + TInt aDim = myMeshInfo->GetSpaceDim(); + if(GetModeSwitch() == eFULL_INTERLACE) + return TCCoordSlice(*myCoord, std::slice(theId*aDim, aDim, 1)); + else + return TCCoordSlice(*myCoord, std::slice(theId, aDim, aDim)); +} + +TCoordSlice +TNodeInfo +::GetCoordSlice(TInt theId) +{ + TInt aDim = myMeshInfo->GetSpaceDim(); + if(GetModeSwitch() == eFULL_INTERLACE) + return TCoordSlice(*myCoord, std::slice(theId*aDim,aDim,1)); + else + return TCoordSlice(*myCoord, std::slice(theId,aDim,aDim)); +} + +//--------------------------------------------------------------- +TCConnSlice +TCellInfo +::GetConnSlice(TInt theElemId) const +{ + if(GetModeSwitch() == eFULL_INTERLACE) + return TCConnSlice(*myConn, std::slice(GetConnDim()*theElemId, GetNbNodes(myGeom), 1)); + else + return TCConnSlice(*myConn, std::slice(theElemId, GetNbNodes(myGeom), GetConnDim())); +} + +TConnSlice +TCellInfo +::GetConnSlice(TInt theElemId) +{ + if(GetModeSwitch() == eFULL_INTERLACE) + return TConnSlice(*myConn, std::slice(GetConnDim()*theElemId, GetNbNodes(myGeom), 1)); + else + return TConnSlice(*myConn, std::slice(theElemId, GetNbNodes(myGeom), GetConnDim())); +} + + +//--------------------------------------------------------------- +TInt +TPolygoneInfo +::GetNbConn(TInt theElemId) const +{ + return (*myIndex)[theElemId + 1] - (*myIndex)[theElemId]; +} + +TCConnSlice +TPolygoneInfo +::GetConnSlice(TInt theElemId) const +{ + return TCConnSlice(*myConn, std::slice((*myIndex)[theElemId] - 1, GetNbConn(theElemId), 1)); +} + +TConnSlice +TPolygoneInfo +::GetConnSlice(TInt theElemId) +{ + return TConnSlice(*myConn, std::slice((*myIndex)[theElemId] - 1, GetNbConn(theElemId), 1)); +} + + +//--------------------------------------------------------------- +TInt +TPolyedreInfo +::GetNbFaces(TInt theElemId) const +{ + return (*myIndex)[theElemId+1] - (*myIndex)[theElemId]; +} + +TInt +TPolyedreInfo +::GetNbNodes(TInt theElemId) const +{ + TInt aNbNodes = 0; + TInt aNbFaces = GetNbFaces(theElemId); + TInt aStartFaceId = (*myIndex)[theElemId] - 1; + for(TInt aFaceId = 0; aFaceId < aNbFaces; aFaceId++, aStartFaceId++){ + TInt aCurrentId = (*myFaces)[aStartFaceId]; + TInt aDiff = (*myFaces)[aStartFaceId + 1] - aCurrentId; + aNbNodes += aDiff; + } + return aNbNodes; +} + +TCConnSliceArr +TPolyedreInfo +::GetConnSliceArr(TInt theElemId) const +{ + TInt aNbFaces = GetNbFaces(theElemId); + TCConnSliceArr aConnSliceArr(aNbFaces); + TInt aStartFaceId = (*myIndex)[theElemId] - 1; + for(TInt aFaceId = 0; aFaceId < aNbFaces; aFaceId++, aStartFaceId++){ + TInt aCurrentId = (*myFaces)[aStartFaceId]; + TInt aDiff = (*myFaces)[aStartFaceId + 1] - aCurrentId; + aConnSliceArr[aFaceId] = + TCConnSlice(*myConn, std::slice(aCurrentId - 1, aDiff, 1)); + } + return aConnSliceArr; +} + +TConnSliceArr +TPolyedreInfo +::GetConnSliceArr(TInt theElemId) +{ + TInt aNbFaces = GetNbFaces(theElemId); + TConnSliceArr aConnSliceArr(aNbFaces); + TInt aStartFaceId = (*myIndex)[theElemId] - 1; + for(TInt aFaceId = 0; aFaceId < aNbFaces; aFaceId++, aStartFaceId++){ + TInt aCurrentId = (*myFaces)[aStartFaceId]; + TInt aDiff = (*myFaces)[aStartFaceId + 1] - aCurrentId; + aConnSliceArr[aFaceId] = + TConnSlice(*myConn, std::slice(aCurrentId - 1, aDiff, 1)); + } + return aConnSliceArr; +} + + +//--------------------------------------------------------------- +TMeshValueBase +::TMeshValueBase(): + myNbElem(0), + myNbComp(0), + myNbGauss(0), + myStep(0) +{} + +void +TMeshValueBase +::Allocate(TInt theNbElem, + TInt theNbGauss, + TInt theNbComp, + EModeSwitch theMode) +{ + myModeSwitch = theMode; + + myNbElem = theNbElem; + myNbGauss = theNbGauss; + myNbComp = theNbComp; + + myStep = theNbComp*theNbGauss; +} + +size_t +TMeshValueBase +::GetSize() const +{ + return myNbElem * myStep; +} + +size_t +TMeshValueBase +::GetNbVal() const +{ + return myNbElem * myNbGauss; +} + +size_t +TMeshValueBase +::GetNbGauss() const +{ + return myNbGauss; +} + +size_t +TMeshValueBase +::GetStep() const +{ + return myStep; +} + + +//--------------------------------------------------------------- +TInt +TProfileInfo +::GetElemNum(TInt theId) const +{ + return (*myElemNum)[theId]; +} + +void +TProfileInfo +::SetElemNum(TInt theId,TInt theVal) +{ + (*myElemNum)[theId] = theVal; +} + +//--------------------------------------------------------------- +bool +TGaussInfo::TLess +::operator()(const TKey& theLeft, const TKey& theRight) const +{ + EGeometrieElement aLGeom = boost::get<0>(theLeft); + EGeometrieElement aRGeom = boost::get<0>(theRight); + if(aLGeom != aRGeom) + return aLGeom < aRGeom; + + const std::string& aLStr = boost::get<1>(theLeft); + const std::string& aRStr = boost::get<1>(theRight); + return aLStr < aRStr; +} + +bool +TGaussInfo::TLess +::operator()(const TGaussInfo& theLeft, const TGaussInfo& theRight) const +{ + if(!&theLeft) + return true; + + if(!&theRight) + return false; + + if(theLeft.myGeom != theRight.myGeom) + return theLeft.myGeom < theRight.myGeom; + + if(theLeft.myRefCoord != theRight.myRefCoord) + return theLeft.myRefCoord < theRight.myRefCoord; + + return theLeft.myGaussCoord < theRight.myGaussCoord; +} + +TCCoordSlice +TGaussInfo +::GetRefCoordSlice(TInt theId) const +{ + if(GetModeSwitch() == eFULL_INTERLACE) + return TCCoordSlice(myRefCoord,std::slice(theId*GetDim(),GetDim(),1)); + else + return TCCoordSlice(myRefCoord,std::slice(theId,GetDim(),GetDim())); +} + +TCoordSlice +TGaussInfo +::GetRefCoordSlice(TInt theId) +{ + if(GetModeSwitch() == eFULL_INTERLACE) + return TCoordSlice(myRefCoord,std::slice(theId*GetDim(),GetDim(),1)); + else + return TCoordSlice(myRefCoord,std::slice(theId,GetDim(),GetDim())); +} + +TCCoordSlice +TGaussInfo +::GetGaussCoordSlice(TInt theId) const +{ + if(GetModeSwitch() == eFULL_INTERLACE) + return TCCoordSlice(myGaussCoord,std::slice(theId*GetDim(),GetDim(),1)); + else + return TCCoordSlice(myGaussCoord,std::slice(theId,GetDim(),GetDim())); +} + +TCoordSlice +TGaussInfo +::GetGaussCoordSlice(TInt theId) +{ + if(GetModeSwitch() == eFULL_INTERLACE) + return TCoordSlice(myGaussCoord,std::slice(theId*GetDim(),GetNbGauss(),1)); + else + return TCoordSlice(myGaussCoord,std::slice(theId,GetNbGauss(),GetDim())); +} + + +//--------------------------------------------------------------- +TInt +TTimeStampInfo +::GetNbGauss(EGeometrieElement theGeom) const +{ + TGeom2NbGauss::const_iterator anIter = myGeom2NbGauss.find(theGeom); + if(anIter == myGeom2NbGauss.end()) + return 1;//EXCEPTION(runtime_error,"TTimeStampInfo::GetNbGauss - myGeom2NbGauss.find(theGeom) fails"); + + return anIter->second; +} + + +//--------------------------------------------------------------- +// TGrilleInfo structure methods +//--------------------------------------------------------------- +const EGrilleType& +TGrilleInfo +::GetGrilleType() const +{ + return myGrilleType; +} + +EGrilleType +TGrilleInfo +::GetGrilleType() +{ + return myGrilleType; +} + +void +TGrilleInfo +::SetGrilleType(EGrilleType theGrilleType) +{ + myGrilleType = theGrilleType; +} + +const +TIndexes& +TGrilleInfo +::GetMapOfIndexes() const +{ + return myIndixes; +} + +TIndexes& +TGrilleInfo +::GetMapOfIndexes() +{ + return myIndixes; +} + +const +TFloatVector& +TGrilleInfo +::GetIndexes(TInt theAxisNumber) const +{ + TIndexes::const_iterator aIter=myIndixes.find(theAxisNumber); + if(aIter==myIndixes.end()) + EXCEPTION(std::runtime_error, "const TGrilleInfo::GetIndexes - myIndixes.find(theAxisNumber); fails"); + return aIter->second; +} + +TFloatVector& +TGrilleInfo +::GetIndexes(TInt theAxisNumber) +{ + TIndexes::iterator aIter=myIndixes.find(theAxisNumber); + if(aIter==myIndixes.end()) + EXCEPTION(std::runtime_error, "TGrilleInfo::GetIndexes - myIndixes.find(theAxisNumber="<second; +} + +TInt +TGrilleInfo +::GetNbIndexes(TInt theAxisNumber) +{ + const TFloatVector& aVector=GetIndexes(theAxisNumber); + return aVector.size(); +} + +TInt +TGrilleInfo +::GetNbNodes() +{ + TInt nbNodes=0; + TInt aDim = myMeshInfo->GetDim(); + for(int i=0;iGetGrilleStructure()[i]; + else + nbNodes = nbNodes*this->GetGrilleStructure()[i]; + + return nbNodes; +} + +TInt +TGrilleInfo +::GetNbCells() +{ + TInt nbCells=0; + TInt aDim = myMeshInfo->GetDim(); + for(int i=0;iGetGrilleStructure()[i]-1; + else + nbCells = nbCells*(this->GetGrilleStructure()[i]-1); + return nbCells; +} + +TInt +TGrilleInfo +::GetNbSubCells() +{ + TInt nb=0; + TInt aDim = myMeshInfo->GetDim(); + switch (aDim) { + case 3: + nb = + (myGrilleStructure[0] ) * (myGrilleStructure[1]-1) * (myGrilleStructure[2]-1) + + (myGrilleStructure[0]-1) * (myGrilleStructure[1] ) * (myGrilleStructure[2]-1) + + (myGrilleStructure[0]-1) * (myGrilleStructure[1]-1) * (myGrilleStructure[2] ); + break; + case 2: + nb = + (myGrilleStructure[0] ) * (myGrilleStructure[1]-1) + + (myGrilleStructure[0]-1) * (myGrilleStructure[1] ); + break; + } + return nb; +} + +EGeometrieElement +TGrilleInfo +::GetGeom() +{ + TInt aDim = myMeshInfo->GetDim(); + switch(aDim){ + case 1: + return eSEG2; + case 2: + return eQUAD4; + case 3: + return eHEXA8; + default: + return eNONE; + } +} + +EGeometrieElement +TGrilleInfo +::GetSubGeom() +{ + TInt aDim = myMeshInfo->GetDim(); + switch(aDim){ + case 2: + return eSEG2; + case 3: + return eQUAD4; + } + return eNONE; +} + +EEntiteMaillage +TGrilleInfo +::GetEntity() +{ + return eMAILLE; +} + +EEntiteMaillage +TGrilleInfo +::GetSubEntity() +{ + TInt aDim = myMeshInfo->GetDim(); + switch(aDim){ + case 2: + return eARETE; + case 3: + return eFACE; + } + return EEntiteMaillage(-1); +} + +const +TIntVector& +TGrilleInfo +::GetGrilleStructure() const +{ + return myGrilleStructure; +} + +TIntVector +TGrilleInfo +::GetGrilleStructure() +{ + return myGrilleStructure; +} + +void +TGrilleInfo +::SetGrilleStructure(TInt theAxis,TInt theNb) +{ + if(theAxis >= 0 && theAxis <=2 && theNb >= 0) + myGrilleStructure[theAxis]=theNb; +} + +const +TNodeCoord& +TGrilleInfo +::GetNodeCoord() const +{ + return myCoord; +} + +TNodeCoord& +TGrilleInfo +::GetNodeCoord() +{ + return myCoord; +} + +TNodeCoord +TGrilleInfo +::GetCoord(TInt theId) +{ + TNodeCoord aCoord; + TInt aDim = myMeshInfo->GetDim(); + TInt aNbNodes = this->GetNbNodes(); + aCoord.resize(aDim); + + if(theId >= aNbNodes) + EXCEPTION(std::runtime_error, "TGrilleInfo::GetCoord - theId out of range"); + + if(myGrilleType == eGRILLE_STANDARD){ + switch(aDim){ + case 3: + aCoord[2] = myCoord[aDim*theId+2]; + case 2: + aCoord[1] = myCoord[aDim*theId+1]; + case 1:{ + aCoord[0] = myCoord[aDim*theId]; + break; + } + } + } else { + + TFloatVector aVecX = this->GetIndexes(0); + TInt nbIndxX = this->GetNbIndexes(0); + + switch(aDim){ + case 1:{ + aCoord[0] = aVecX[theId]; + break; + } + case 2:{ + TFloatVector aVecY = this->GetIndexes(1); + TInt i,j,k; + i = j = k = 0; + i = theId % nbIndxX; + j = theId / nbIndxX; + if(myGrilleType == eGRILLE_CARTESIENNE){ + aCoord[0] = aVecX[i]; + aCoord[1] = aVecY[j]; + } else { // eGRILLE_POLAIRE (cylindrical) + aCoord[0] = aVecX[i] * cos(aVecY[j]); + aCoord[1] = aVecX[i] * sin(aVecY[j]); + } + break; + } + case 3:{ + TFloatVector aVecY = this->GetIndexes(1); + TInt nbIndxY = this->GetNbIndexes(1); + TFloatVector aVecZ = this->GetIndexes(2); + TInt i,j,k; + i = j = k = 0; + + i = theId % nbIndxX; + j = (theId / nbIndxX) % nbIndxY; + k = theId / (nbIndxX*nbIndxY); + + if(myGrilleType == eGRILLE_CARTESIENNE){ + aCoord[0] = aVecX[i]; + aCoord[1] = aVecY[j]; + aCoord[2] = aVecZ[k]; + } else { // eGRILLE_POLAIRE (cylindrical) + aCoord[0] = aVecX[i] * cos(aVecY[j]); + aCoord[1] = aVecX[i] * sin(aVecY[j]); + aCoord[2] = aVecZ[k]; + } + + break; + } + } + } + + return aCoord; +} + +TIntVector +TGrilleInfo +::GetConn(TInt theId, const bool isSub) +{ + TIntVector anIndexes; + TInt aDim = myMeshInfo->GetDim(); + + TInt idx; + TInt iMin, jMin, kMin, iMax, jMax, kMax; + TInt loc[3]; + + loc[0] = loc[1] = loc[2] = 0; + iMin = iMax = jMin = jMax = kMin = kMax = 0; + + switch(aDim) { + case 3: + { + TInt nbX = this->GetGrilleStructure()[0]; + TInt nbY = this->GetGrilleStructure()[1]; + TInt nbZ = this->GetGrilleStructure()[2]; + TInt d01 = nbX*nbY, dX = 1, dY = 1, dZ = 1; + if ( isSub ) + { + if ( theId < nbX * (nbY-1) * (nbZ-1)) + { // face is normal to X axis + dX = 0; + } + else if ( theId < nbX * (nbY-1) * (nbZ-1) + (nbX-1) * nbY * (nbZ-1)) + { // face is normal to Y axis + theId -= nbX * (nbY-1) * (nbZ-1); + dY = 0; + } + else + { + theId -= nbX * (nbY-1) * (nbZ-1) + (nbX-1) * nbY * (nbZ-1); + dZ = 0; + } + } + //else + { + iMin = theId % (nbX - dX); + jMin = (theId / (nbX - dX)) % (nbY - dY); + kMin = theId / ((nbX - dX) * (nbY - dY)); + iMax = iMin+dX; + jMax = jMin+dY; + kMax = kMin+dZ; + } + for (loc[2]=kMin; loc[2]<=kMax; loc[2]++) + for (loc[1]=jMin; loc[1]<=jMax; loc[1]++) + for (loc[0]=iMin; loc[0]<=iMax; loc[0]++) + { + idx = loc[0] + loc[1]*nbX + loc[2]*d01; + anIndexes.push_back(idx); + } + break; + } + case 2: + { + TInt nbX = this->GetGrilleStructure()[0]; + TInt nbY = this->GetGrilleStructure()[1]; + TInt dX = 1, dY = 1; + if ( isSub ) + { + if ( theId < nbX * (nbY-1)) + { // edge is normal to X axis + dX = 0; + } + else + { + theId -= nbX * (nbY-1); + dY = 0; + } + } + iMin = theId % (nbX-dX); + jMin = theId / (nbX-dX); + iMax = iMin+dX; + jMax = jMin+dY; + for (loc[1]=jMin; loc[1]<=jMax; loc[1]++) + for (loc[0]=iMin; loc[0]<=iMax; loc[0]++) + { + idx = loc[0] + loc[1]*nbX; + anIndexes.push_back(idx); + } + break; + } + case 1: + { + iMin = theId; + for (loc[0]=iMin; loc[0]<=iMin+1; loc[0]++) + { + idx = loc[0]; + anIndexes.push_back(idx); + } + break; + } + } + + return anIndexes; +} + +TInt +TGrilleInfo +::GetFamNumNode(TInt theId) const +{ + return myFamNumNode[theId]; +} + +void +TGrilleInfo +::SetFamNumNode(TInt theId,TInt theVal) +{ + myFamNumNode[theId] = theVal; +} + +TInt +TGrilleInfo +::GetFamNum(TInt theId) const +{ + return myFamNum[theId]; +} + +void +TGrilleInfo +::SetFamNum(TInt theId,TInt theVal) +{ + myFamNum[theId] = theVal; +} + +TInt +TGrilleInfo +::GetFamSubNum(TInt theId) const +{ + return myFamSubNum[theId]; +} + +void +TGrilleInfo +::SetFamSubNum(TInt theId,TInt theVal) +{ + myFamSubNum[theId] = theVal; +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/MED_Utilities.cpp b/src/3rdParty/salomesmesh/src/SMESH/MED_Utilities.cpp new file mode 100644 index 000000000000..d04b0576241e --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/MED_Utilities.cpp @@ -0,0 +1,113 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// +#include "MED_Utilities.hxx" +#include "MED_Common.hxx" + +using namespace std; + +#ifdef _DEBUG_ +static int MYDEBUG = 0; +#else +// static int MYDEBUG = 0; +#endif + + +int MED::PrefixPrinter::myCounter = 0; + +MED::PrefixPrinter::PrefixPrinter(bool theIsActive): + myIsActive(theIsActive) +{ + if(myIsActive) + myCounter++; + MSG(MYDEBUG,"MED::PrefixPrinter::PrefixPrinter(...)- "< + +#ifdef _DEBUG_ +static int MYDEBUG = 0; +static int MYVALUEDEBUG = 0; +#else +// static int MYDEBUG = 0; +// static int MYVALUEDEBUG = 0; +#endif + +namespace MED +{ + TLockProxy + ::TLockProxy(TWrapper* theWrapper): + myWrapper(theWrapper) + { +#if BOOST_VERSION >= 103500 + myWrapper->myMutex.lock(); +#else + boost::detail::thread::lock_ops::lock(myWrapper->myMutex); +#endif + INITMSG(MYDEBUG,"TLockProxy() - this -"<GetGroupName(iGroup); + INITMSG(MYDEBUG,"aGroupName = '"<myDim; + TInt aNbElem = anInfo->GetNbElem(); + INITMSG(MYDEBUG,"GetPNodeInfo: "); + { + INITMSG(MYDEBUG,"aCoords: "<myCoord; + for(TInt iElem = 0; iElem < aNbElem; iElem++){ + for(TInt iDim = 0, anId = iElem*aDim; iDim < aDim; iDim++, anId++){ + ADDMSG(MYVALUEDEBUG,aCoord[anId]<<","); + } + ADDMSG(MYVALUEDEBUG," "); + } + ADDMSG(MYDEBUG, std::endl); + + BEGMSG(MYVALUEDEBUG, "GetFamNum: "); + for(TInt iElem = 0; iElem < aNbElem; iElem++){ + ADDMSG(MYVALUEDEBUG,anInfo->GetFamNum(iElem)<<", "); + } + ADDMSG(MYVALUEDEBUG, std::endl); + + if(anInfo->IsElemNum()){ + BEGMSG(MYVALUEDEBUG,"GetElemNum: "); + for(TInt iElem = 0; iElem < aNbElem; iElem++){ + ADDMSG(MYVALUEDEBUG,anInfo->GetElemNum(iElem)<<", "); + } + ADDMSG(MYVALUEDEBUG, std::endl); + } + } + ADDMSG(MYDEBUG, std::endl); +#endif + + return anInfo; + } + + //---------------------------------------------------------------------------- + PPolygoneInfo + TWrapper + ::GetPPolygoneInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + EConnectivite theConnMode) + { + if(theMeshInfo->GetType() != eNON_STRUCTURE) + return PPolygoneInfo(); + + TInt aNbElem = GetNbPolygones(theMeshInfo,theEntity,theGeom,theConnMode); + TInt aConnSize = GetPolygoneConnSize(theMeshInfo,theEntity,theGeom,theConnMode); + PPolygoneInfo anInfo = CrPolygoneInfo(theMeshInfo,theEntity,theGeom,aNbElem,aConnSize,theConnMode); + GetPolygoneInfo(anInfo); + +#ifdef _DEBUG_ + INITMSG(MYDEBUG,"GetPPolygoneInfo"<< + " - theGeom = "<GetConnSlice(iElem); + TInt aConnDim = aConnSlice.size(); + for(TInt iConn = 0; iConn < aConnDim; iConn++){ + ADDMSG(MYVALUEDEBUG,aConnSlice[iConn]<<","); + } + ADDMSG(MYDEBUG," "); + } + ADDMSG(MYDEBUG, std::endl); +#endif + + return anInfo; + } + + //---------------------------------------------------------------------------- + PPolyedreInfo + TWrapper + ::GetPPolyedreInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + EConnectivite theConnMode) + { + if(theMeshInfo->GetType() != eNON_STRUCTURE) + return PPolyedreInfo(); + TInt aNbElem = GetNbPolyedres(theMeshInfo,theEntity,theGeom,theConnMode); + TInt aNbFaces, aConnSize; + GetPolyedreConnSize(theMeshInfo,aNbFaces,aConnSize,theConnMode); + PPolyedreInfo anInfo = CrPolyedreInfo(theMeshInfo,theEntity,theGeom,aNbElem,aNbFaces,aConnSize,theConnMode); + GetPolyedreInfo(anInfo); + +#ifdef _DEBUG_ + INITMSG(MYDEBUG,"GetPPolyedreInfo"<< + " - theGeom = "<GetConnSliceArr(iElem); + TInt aNbFaces = aConnSliceArr.size(); + ADDMSG(MYDEBUG,"{"); + for(TInt iFace = 0; iFace < aNbFaces; iFace++){ + TCConnSlice aConnSlice = aConnSliceArr[iFace]; + TInt aNbConn = aConnSlice.size(); + ADDMSG(MYDEBUG,"["); + for(TInt iConn = 0; iConn < aNbConn; iConn++){ + ADDMSG(MYVALUEDEBUG,aConnSlice[iConn]<<","); + } + ADDMSG(MYDEBUG,"] "); + } + ADDMSG(MYDEBUG,"} "); + } + ADDMSG(MYDEBUG, std::endl); +#endif + + return anInfo; + } + + //---------------------------------------------------------------------------- + PElemInfo + TWrapper + ::GetPElemInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + EConnectivite theConnMode, + TErr* theErr) + { + EMaillage aType = theMeshInfo->GetType(); + if(aType == eNON_STRUCTURE){ + switch(theGeom){ + case ePOINT1: + if(theEntity == eNOEUD) + return GetPNodeInfo(theMeshInfo,theErr); + return GetPCellInfo(theMeshInfo,theEntity,theGeom,theConnMode,theErr); + break; + case ePOLYGONE: + return GetPPolygoneInfo(theMeshInfo,theEntity,theGeom,theConnMode); + break; + case ePOLYEDRE: + return GetPPolyedreInfo(theMeshInfo,theEntity,theGeom,theConnMode); + break; + default: + return GetPCellInfo(theMeshInfo,theEntity,theGeom,theConnMode,theErr); + } + } else { + PGrilleInfo aGrille = GetPGrilleInfo(theMeshInfo); + + TInt nbElems; + EBooleen theIsElemNum = eFAUX; + // nodes + switch(theGeom){ + case ePOINT1: + nbElems = aGrille->GetNbNodes(); + theIsElemNum = eVRAI; + break; + case eSEG2: + case eQUAD4: + case eHEXA8: + nbElems = aGrille->GetNbCells(); + break; + default: + nbElems = 0; + } + + TIntVector aFamNum; + TIntVector aElemNum; + TStringVector aElemNames; + + PElemInfo aElemInfo; + + if(theGeom == ePOINT1){ + aElemInfo = CrElemInfo(theMeshInfo, + nbElems, + theIsElemNum); + MED::TElemInfo &aTElemInfo = *aElemInfo; + + // must be reimplemente in connection with mesh type eSTRUCTURE +// GetNumeration(aTElemInfo, +// nbElems, +// theEntity, +// theGeom, +// theErr); + + GetFamilies(aTElemInfo, + nbElems, + theEntity, + theGeom, + theErr); + + // must be reimplemente in connection with mesh type eSTRUCTURE +// GetNames(aTElemInfo, +// nbElems, +// theEntity, +// theGeom, +// theErr); + } else { + aElemInfo = CrElemInfo(theMeshInfo, + nbElems, + aFamNum, + aElemNum, + aElemNames); + } + + return aElemInfo; + } + return PElemInfo(); + } + + + //---------------------------------------------------------------------------- + PCellInfo + TWrapper + ::GetPCellInfo(const PMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + EConnectivite theConnMode, + TErr* theErr) + { + if(theMeshInfo->GetType() != eNON_STRUCTURE) + return PCellInfo(); + TInt aNbElem = GetNbCells(theMeshInfo,theEntity,theGeom,theConnMode); + PCellInfo anInfo = CrCellInfo(theMeshInfo,theEntity,theGeom,aNbElem,theConnMode); + GetCellInfo(anInfo,theErr); + +#ifdef _DEBUG_ + TInt aConnDim = anInfo->GetConnDim(); + INITMSG(MYDEBUG,"GetPCellInfo - theEntity = "<GetConnSlice(iElem); + for(TInt iConn = 0; iConn < aConnDim; iConn++){ + ADDMSG(MYVALUEDEBUG,aConnSlice[iConn]<<","); + } + ADDMSG(MYVALUEDEBUG," "); + } + ADDMSG(MYDEBUG, std::endl); + + BEGMSG(MYVALUEDEBUG,"GetPCellInfo - GetFamNum: "); + for(TInt iElem = 0; iElem < aNbElem; iElem++){ + ADDMSG(MYVALUEDEBUG,anInfo->GetFamNum(iElem)<<", "); + } + ADDMSG(MYVALUEDEBUG, std::endl); + + if(anInfo->IsElemNum()){ + BEGMSG(MYVALUEDEBUG,"GetPCellInfo - GetElemNum: "); + for(TInt iElem = 0; iElem < aNbElem; iElem++){ + ADDMSG(MYVALUEDEBUG,anInfo->GetElemNum(iElem)<<", "); + } + ADDMSG(MYVALUEDEBUG, std::endl); + } + ADDMSG(MYDEBUG, std::endl); +#endif + + return anInfo; + } + + //---------------------------------------------------------------------------- + //! Read a MEDWrapped representation of MED Balls from the MED file + PBallInfo + TWrapper + ::GetPBallInfo(const PMeshInfo& theMeshInfo) + { + TInt nbBalls = GetNbBalls(theMeshInfo); + if ( nbBalls < 1 ) return PBallInfo(); + + PBallInfo anInfo = CrBallInfo( theMeshInfo, nbBalls ); + GetBallInfo(anInfo); + + return anInfo; + } + //---------------------------------------------------------------------------- + PFieldInfo + TWrapper + ::GetPFieldInfo(const PMeshInfo& theMeshInfo, + TInt theId, + TErr* theErr) + { + TInt aNbComp = GetNbComp(theId); + PFieldInfo anInfo = CrFieldInfo(theMeshInfo,aNbComp); + GetFieldInfo(theId,*anInfo,theErr); + +#ifdef _DEBUG_ + INITMSG(MYDEBUG, + "GetPFieldInfo "<< + "- aName = '"<GetName()<<"'"<< + "; aType = "<GetType()<< + "; aNbComp = "<myGeom2NbGauss; + TGeom2NbGauss::const_iterator anIter = aGeom2NbGauss.begin(); + for(; anIter != aGeom2NbGauss.end(); anIter++){ + const EGeometrieElement& aGeom = anIter->first; + INITMSG(MYDEBUG,"aGeom = "<GetFieldInfo(); + return CrTimeStampValue(theTimeStampInfo, + aFieldInfo->GetType(), + theGeom2Profile, + theMode); + } + + //---------------------------------------------------------------------------- + PTimeStampValueBase + TWrapper + ::CrTimeStampValue(const PTimeStampInfo& theTimeStampInfo, + const PTimeStampValueBase& theInfo) + { + PFieldInfo aFieldInfo = theTimeStampInfo->GetFieldInfo(); + return CrTimeStampValue(theTimeStampInfo, + theInfo, + aFieldInfo->GetType()); + } + + //---------------------------------------------------------------------------- + template + void + Print(SharedPtr theTimeStampValue) + { + INITMSG(MYDEBUG,"Print - TimeStampValue\n"); + typename TimeStampValueType::TTGeom2Value& aGeom2Value = theTimeStampValue->myGeom2Value; + typename TimeStampValueType::TTGeom2Value::const_iterator anIter = aGeom2Value.begin(); + for(; anIter != aGeom2Value.end(); anIter++){ + const EGeometrieElement& aGeom = anIter->first; + const typename TimeStampValueType::TTMeshValue& aMeshValue = anIter->second; + TInt aNbElem = aMeshValue.myNbElem; + TInt aNbGauss = aMeshValue.myNbGauss; + TInt aNbComp = aMeshValue.myNbComp; + INITMSG(MYDEBUG,"aGeom = "<GetFieldInfo(); + PTimeStampValueBase anInfo = CrTimeStampValue(theTimeStampInfo, + aFieldInfo->GetType()); + GetTimeStampValue(anInfo, + theMKey2Profile, + theKey2Gauss, + theErr); +#ifdef _DEBUG_ + if(aFieldInfo->GetType() == eFLOAT64) + Print(anInfo); + else + Print(anInfo); +#endif + return anInfo; + } + + //---------------------------------------------------------------------------- + void + TWrapper + ::GetTimeStampVal(const PTimeStampVal& theVal, + const TMKey2Profile& theMKey2Profile, + const TKey2Gauss& theKey2Gauss, + TErr* theErr) + { + PTimeStampInfo aTimeStampInfo = theVal->GetTimeStampInfo(); + PFieldInfo aFieldInfo = aTimeStampInfo->GetFieldInfo(); + if(aFieldInfo->GetType() == eFLOAT64) + GetTimeStampValue(theVal, + theMKey2Profile, + theKey2Gauss, + theErr); + else{ + PTimeStampValueBase aVal = CrTimeStampValue(aTimeStampInfo, + theVal, + eINT); + GetTimeStampValue(aVal, + theMKey2Profile, + theKey2Gauss, + theErr); + CopyTimeStampValueBase(aVal, theVal); + } + } + + //---------------------------------------------------------------------------- + void + TWrapper + ::SetTimeStamp(const PTimeStampVal& theVal, + TErr* theErr) + { + PTimeStampInfo aTimeStampInfo = theVal->GetTimeStampInfo(); + PFieldInfo aFieldInfo = aTimeStampInfo->GetFieldInfo(); + if(aFieldInfo->GetType() == eFLOAT64) + SetTimeStampValue(theVal, theErr); + else{ + PTimeStampValueBase aVal = CrTimeStampValue(aTimeStampInfo, + eINT, + theVal->GetGeom2Profile(), + theVal->GetModeSwitch()); + CopyTimeStampValueBase(theVal, aVal); + SetTimeStampValue(aVal, theErr); + } + } + + //---------------------------------------------------------------------------- + PTimeStampVal + TWrapper + ::CrTimeStampVal(const PTimeStampInfo& theTimeStampInfo, + const TGeom2Profile& theGeom2Profile, + EModeSwitch theMode) + { + return CrTimeStampValue(theTimeStampInfo, + eFLOAT64, + theGeom2Profile, + theMode); + } + + //---------------------------------------------------------------------------- + PTimeStampVal + TWrapper + ::CrTimeStampVal(const PTimeStampInfo& theTimeStampInfo, + const PTimeStampVal& theInfo) + { + return CrTimeStampValue(theTimeStampInfo, + theInfo, + eFLOAT64); + } + + //---------------------------------------------------------------------------- + PTimeStampVal + TWrapper + ::GetPTimeStampVal(const PTimeStampInfo& theTimeStampInfo, + const TMKey2Profile& theMKey2Profile, + const TKey2Gauss& theKey2Gauss, + TErr* theErr) + { + PTimeStampVal anInfo = CrTimeStampVal(theTimeStampInfo); + GetTimeStampVal(anInfo, + theMKey2Profile, + theKey2Gauss, + theErr); + return anInfo; + } + + //---------------------------------------------------------------------------- + PGrilleInfo + TWrapper + ::GetPGrilleInfo(const PMeshInfo& theMeshInfo) + { + if(theMeshInfo->GetType() != eSTRUCTURE) + return PGrilleInfo(); + + EGrilleType type; + GetGrilleType(*theMeshInfo,type); + PGrilleInfo anInfo; + if(type == eGRILLE_STANDARD){ + const TInt nnoeuds = GetNbNodes(*theMeshInfo); + anInfo = CrGrilleInfo(theMeshInfo,type,nnoeuds); + } + else { + TIntVector aVec; + aVec.resize(theMeshInfo->GetDim()); + for(int aAxe=0;aAxeGetDim();aAxe++){ + ETable aATable; + switch(aAxe){ + case 0: + aATable = eCOOR_IND1; + break; + case 1: + aATable = eCOOR_IND2; + break; + case 2: + aATable = eCOOR_IND3; + break; + } + aVec[aAxe] = GetNbNodes(*theMeshInfo,aATable); + } + anInfo = CrGrilleInfo(theMeshInfo,type,aVec); + } + + GetGrilleInfo(anInfo); + anInfo->SetGrilleType(type); + +#ifdef _DEBUG_ + INITMSG(MYDEBUG,"GetPGrilleInfo: "); + { + TInt aNbElem = anInfo->GetNbNodes(); + BEGMSG(MYVALUEDEBUG,"GetFamNumNode: "); + for(TInt iElem = 0; iElem < aNbElem; iElem++){ + ADDMSG(MYVALUEDEBUG,anInfo->GetFamNumNode(iElem)<<", "); + } + TInt aNbCells = anInfo->GetNbCells(); + BEGMSG(MYVALUEDEBUG,"GetFamNum: "); + for(TInt iElem = 0; iElem < aNbCells; iElem++){ + ADDMSG(MYVALUEDEBUG,anInfo->GetFamNum(iElem)<<", "); + } + ADDMSG(MYVALUEDEBUG, std::endl); + BEGMSG(MYVALUEDEBUG,"GetCoordName: "); + for(TInt iElem = 0; iElem < theMeshInfo->GetDim(); iElem++){ + ADDMSG(MYVALUEDEBUG,anInfo->GetCoordName(iElem)<<", "); + } + ADDMSG(MYVALUEDEBUG, std::endl); + BEGMSG(MYVALUEDEBUG,"GetCoordUnit: "); + for(TInt iElem = 0; iElem < theMeshInfo->GetDim(); iElem++){ + ADDMSG(MYVALUEDEBUG,anInfo->GetCoordUnit(iElem)<<", "); + } + ADDMSG(MYVALUEDEBUG, std::endl); + + } +#endif + + return anInfo; + } + + //---------------------------------------------------------------------------- + PGrilleInfo + TWrapper + ::GetPGrilleInfo(const PMeshInfo& theMeshInfo, + const PGrilleInfo& theInfo) + { + PGrilleInfo anInfo = CrGrilleInfo(theMeshInfo,theInfo); + return anInfo; + } +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_0D_Algo.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_0D_Algo.cpp deleted file mode 100644 index 1342ea42ce01..000000000000 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_0D_Algo.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE -// -// Copyright (C) 2003-2007 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 -// -// SMESH SMESH : implementaion of SMESH idl descriptions -// File : SMESH_0D_Algo.cxx -// Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESH/SMESH_0D_Algo.cxx,v 1.2.2.1 2008/11/27 12:25:15 abd Exp $ -// -#include "SMESH_0D_Algo.hxx" -#include "SMESH_Gen.hxx" - -//============================================================================= -/*! - * - */ -//============================================================================= - -SMESH_0D_Algo::SMESH_0D_Algo(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_Algo(hypId, studyId, gen) -{ - _type = ALGO_0D; - gen->_map0D_Algo[hypId] = this; -} - -//============================================================================= -/*! - * - */ -//============================================================================= - -SMESH_0D_Algo::~SMESH_0D_Algo() -{ -} - diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_1D_Algo.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_1D_Algo.cpp deleted file mode 100644 index 8e8c065cf1cb..000000000000 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_1D_Algo.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE -// -// Copyright (C) 2003-2007 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 -// -// SMESH SMESH : implementaion of SMESH idl descriptions -// File : SMESH_1D_Algo.cxx -// Author : Paul RASCLE, EDF -// Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESH/SMESH_1D_Algo.cxx,v 1.8.2.1 2008/11/27 12:25:15 abd Exp $ -// -#include "SMESH_1D_Algo.hxx" -#include "SMESH_Gen.hxx" -#include "SMESH_subMesh.hxx" - -using namespace std; - -//============================================================================= -/*! - * - */ -//============================================================================= - -SMESH_1D_Algo::SMESH_1D_Algo(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_Algo(hypId, studyId, gen) -{ -// _compatibleHypothesis.push_back("hypothese_1D_bidon"); - _type = ALGO_1D; - gen->_map1D_Algo[hypId] = this; -} - -//============================================================================= -/*! - * - */ -//============================================================================= - -SMESH_1D_Algo::~SMESH_1D_Algo() -{ -} - diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_2D_Algo.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_2D_Algo.cpp deleted file mode 100644 index 525b3d60d7b5..000000000000 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_2D_Algo.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE -// -// Copyright (C) 2003-2007 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 -// -// SMESH SMESH : implementaion of SMESH idl descriptions -// File : SMESH_2D_Algo.cxx -// Author : Paul RASCLE, EDF -// Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESH/SMESH_2D_Algo.cxx,v 1.9.2.2 2008/11/27 12:25:15 abd Exp $ -// -#include "SMESH_2D_Algo.hxx" -#include "SMESH_Gen.hxx" - -#include "utilities.h" - -#include -#include -#include - -//============================================================================= -/*! - * - */ -//============================================================================= - -SMESH_2D_Algo::SMESH_2D_Algo(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_Algo(hypId, studyId, gen) -{ -// _compatibleHypothesis.push_back("hypothese_2D_bidon"); - _type = ALGO_2D; - gen->_map2D_Algo[hypId] = this; -} - -//============================================================================= -/*! - * - */ -//============================================================================= - -SMESH_2D_Algo::~SMESH_2D_Algo() -{ -} - -//============================================================================= -/*! - * - */ -//============================================================================= - -int SMESH_2D_Algo::NumberOfWires(const TopoDS_Shape& S) -{ - int i = 0; - for (TopExp_Explorer exp(S,TopAbs_WIRE); exp.More(); exp.Next()) - i++; - return i; -} - -//============================================================================= -/*! - * - */ -//============================================================================= - -int SMESH_2D_Algo::NumberOfPoints(SMESH_Mesh& aMesh, const TopoDS_Wire& W) -{ - int nbPoints = 0; - for (TopExp_Explorer exp(W,TopAbs_EDGE); exp.More(); exp.Next()) { - const TopoDS_Edge& E = TopoDS::Edge(exp.Current()); - int nb = aMesh.GetSubMesh(E)->GetSubMeshDS()->NbNodes(); - if(_quadraticMesh) - nb = nb/2; - nbPoints += nb + 1; // internal points plus 1 vertex of 2 (last point ?) - } - return nbPoints; -} - - diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_3D_Algo.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_3D_Algo.cpp deleted file mode 100644 index 641c5051865c..000000000000 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_3D_Algo.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE -// -// Copyright (C) 2003-2007 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 -// -// SMESH SMESH : implementaion of SMESH idl descriptions -// File : SMESH_3D_Algo.cxx -// Author : Paul RASCLE, EDF -// Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESH/SMESH_3D_Algo.cxx,v 1.9.2.1 2008/11/27 12:25:15 abd Exp $ -// -#include "SMESH_3D_Algo.hxx" -#include "SMESH_Gen.hxx" - -#include "utilities.h" - -using namespace std; - -//============================================================================= -/*! - * - */ -//============================================================================= - -SMESH_3D_Algo::SMESH_3D_Algo(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_Algo(hypId, studyId, gen) -{ -// _compatibleHypothesis.push_back("hypothese_3D_bidon"); - _type = ALGO_3D; - gen->_map3D_Algo[hypId] = this; -} - -//============================================================================= -/*! - * - */ -//============================================================================= - -SMESH_3D_Algo::~SMESH_3D_Algo() -{ -} - - diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Algo.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Algo.cpp index c44010450c5b..ece996d02cec 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Algo.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Algo.cpp @@ -1,41 +1,48 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : SMESH_Algo.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// #include "SMESH_Algo.hxx" -#include "SMESH_Comment.hxx" -#include "SMESH_Gen.hxx" -#include "SMESH_Mesh.hxx" -#include "SMESH_HypoFilter.hxx" -#include "SMDS_FacePosition.hxx" + #include "SMDS_EdgePosition.hxx" +#include "SMDS_FacePosition.hxx" #include "SMDS_MeshElement.hxx" #include "SMDS_MeshNode.hxx" +#include "SMDS_VolumeTool.hxx" #include "SMESHDS_Mesh.hxx" #include "SMESHDS_SubMesh.hxx" +#include "SMESH_Comment.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_HypoFilter.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MeshAlgos.hxx" +#include "SMESH_TypeDefs.hxx" +#include "SMESH_subMesh.hxx" + +#include #include #include @@ -44,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -61,9 +70,106 @@ #include "utilities.h" #include - +#include +#include "SMESH_ProxyMesh.hxx" +#include "SMESH_MesherHelper.hxx" +#include using namespace std; +//================================================================================ +/*! + * \brief Returns \a true if two algorithms (described by \a this and the given + * algo data) are compatible by their output and input types of elements. + */ +//================================================================================ + +bool SMESH_Algo::Features::IsCompatible( const SMESH_Algo::Features& algo2 ) const +{ + if ( _dim > algo2._dim ) return algo2.IsCompatible( *this ); + // algo2 is of highter dimension + if ( _outElemTypes.empty() || algo2._inElemTypes.empty() ) + return false; + bool compatible = true; + set::const_iterator myOutType = _outElemTypes.begin(); + for ( ; myOutType != _outElemTypes.end() && compatible; ++myOutType ) + compatible = algo2._inElemTypes.count( *myOutType ); + return compatible; +} + +//================================================================================ +/*! + * \brief Return Data of the algorithm + */ +//================================================================================ + + +const SMESH_Algo::Features& SMESH_Algo::GetFeatures( const std::string& algoType ) +{ + static map< string, SMESH_Algo::Features > theFeaturesByName; + if ( theFeaturesByName.empty() ) + { + // Read Plugin.xml files + vector< string > xmlPaths = SMESH_Gen::GetPluginXMLPaths(); + LDOMParser xmlParser; + for ( size_t iXML = 0; iXML < xmlPaths.size(); ++iXML ) + { + bool error = xmlParser.parse( xmlPaths[iXML].c_str() ); + if ( error ) + { + TCollection_AsciiString data; + INFOS( xmlParser.GetError(data) ); + continue; + } + // + // + LDOM_Document xmlDoc = xmlParser.getDocument(); + LDOM_NodeList algoNodeList = xmlDoc.getElementsByTagName( "algorithm" ); + for ( int i = 0; i < algoNodeList.getLength(); ++i ) + { + LDOM_Node algoNode = algoNodeList.item( i ); + LDOM_Element& algoElem = (LDOM_Element&) algoNode; + TCollection_AsciiString algoType = algoElem.getAttribute("type"); + TCollection_AsciiString input = algoElem.getAttribute("input"); + TCollection_AsciiString output = algoElem.getAttribute("output"); + TCollection_AsciiString dim = algoElem.getAttribute("dim"); + TCollection_AsciiString label = algoElem.getAttribute("label-id"); + if ( algoType.IsEmpty() ) continue; + + Features & data = theFeaturesByName[ algoType.ToCString() ]; + data._dim = dim.IntegerValue(); + data._label = label.ToCString(); + for ( int isInput = 0; isInput < 2; ++isInput ) + { + TCollection_AsciiString& typeStr = isInput ? input : output; + set& typeSet = isInput ? data._inElemTypes : data._outElemTypes; + int beg = 1, end; + while ( beg <= typeStr.Length() ) + { + while ( beg < typeStr.Length() && !isalpha( typeStr.Value( beg ) )) + ++beg; + end = beg; + while ( end < typeStr.Length() && isalpha( typeStr.Value( end + 1 ) )) + ++end; + if ( end > beg ) + { + TCollection_AsciiString typeName = typeStr.SubString( beg, end ); + if ( typeName == "EDGE" ) typeSet.insert( SMDSGeom_EDGE ); + else if ( typeName == "TRIA" ) typeSet.insert( SMDSGeom_TRIANGLE ); + else if ( typeName == "QUAD" ) typeSet.insert( SMDSGeom_QUADRANGLE ); + } + beg = end + 1; + } + } + } + } + } + return theFeaturesByName[ algoType ]; +} + + //============================================================================= /*! * @@ -73,11 +179,12 @@ using namespace std; SMESH_Algo::SMESH_Algo (int hypId, int studyId, SMESH_Gen * gen) : SMESH_Hypothesis(hypId, studyId, gen) { - gen->_mapAlgo[hypId] = this; - - _onlyUnaryInput = _requireDescretBoundary = _requireShape = true; - _quadraticMesh = false; + _compatibleAllHypFilter = _compatibleNoAuxHypFilter = NULL; + _onlyUnaryInput = _requireDiscreteBoundary = _requireShape = true; + _quadraticMesh = _supportSubmeshes = false; _error = COMPERR_OK; + for ( int i = 0; i < 4; ++i ) + _neededLowerHyps[ i ] = false; } //============================================================================= @@ -88,6 +195,39 @@ SMESH_Algo::SMESH_Algo (int hypId, int studyId, SMESH_Gen * gen) SMESH_Algo::~SMESH_Algo() { + delete _compatibleNoAuxHypFilter; + // delete _compatibleAllHypFilter; -- _compatibleNoAuxHypFilter does it!!! +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +SMESH_0D_Algo::SMESH_0D_Algo(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_Algo(hypId, studyId, gen) +{ + _shapeType = (1 << TopAbs_VERTEX); + _type = ALGO_0D; +} +SMESH_1D_Algo::SMESH_1D_Algo(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_Algo(hypId, studyId, gen) +{ + _shapeType = (1 << TopAbs_EDGE); + _type = ALGO_1D; +} +SMESH_2D_Algo::SMESH_2D_Algo(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_Algo(hypId, studyId, gen) +{ + _shapeType = (1 << TopAbs_FACE); + _type = ALGO_2D; +} +SMESH_3D_Algo::SMESH_3D_Algo(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_Algo(hypId, studyId, gen) +{ + _shapeType = (1 << TopAbs_SOLID); + _type = ALGO_3D; } //============================================================================= @@ -123,15 +263,15 @@ const vector < string > &SMESH_Algo::GetCompatibleHypothesis() const list & SMESH_Algo::GetUsedHypothesis(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, - const bool ignoreAuxiliary) + const bool ignoreAuxiliary) const { - _usedHypList.clear(); - SMESH_HypoFilter filter; - if ( InitCompatibleHypoFilter( filter, ignoreAuxiliary )) + SMESH_Algo* me = const_cast< SMESH_Algo* >( this ); + me->_usedHypList.clear(); + if ( const SMESH_HypoFilter* filter = GetCompatibleHypoFilter( ignoreAuxiliary )) { - aMesh.GetHypotheses( aShape, filter, _usedHypList, true ); + aMesh.GetHypotheses( aShape, *filter, me->_usedHypList, true ); if ( ignoreAuxiliary && _usedHypList.size() > 1 ) - _usedHypList.clear(); //only one compatible hypothesis allowed + me->_usedHypList.clear(); //only one compatible hypothesis allowed } return _usedHypList; } @@ -147,12 +287,12 @@ SMESH_Algo::GetUsedHypothesis(SMESH_Mesh & aMesh, const list & SMESH_Algo::GetAppliedHypothesis(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, - const bool ignoreAuxiliary) + const bool ignoreAuxiliary) const { - _appliedHypList.clear(); - SMESH_HypoFilter filter; - if ( InitCompatibleHypoFilter( filter, ignoreAuxiliary )) - aMesh.GetHypotheses( aShape, filter, _appliedHypList, false ); + SMESH_Algo* me = const_cast< SMESH_Algo* >( this ); + me->_appliedHypList.clear(); + if ( const SMESH_HypoFilter* filter = GetCompatibleHypoFilter( ignoreAuxiliary )) + aMesh.GetHypotheses( aShape, *filter, me->_appliedHypList, false ); return _appliedHypList; } @@ -166,123 +306,15 @@ SMESH_Algo::GetAppliedHypothesis(SMESH_Mesh & aMesh, double SMESH_Algo::EdgeLength(const TopoDS_Edge & E) { double UMin = 0, UMax = 0; - if (BRep_Tool::Degenerated(E)) - return 0; TopLoc_Location L; Handle(Geom_Curve) C = BRep_Tool::Curve(E, L, UMin, UMax); - GeomAdaptor_Curve AdaptCurve(C); + if ( C.IsNull() ) + return 0.; + GeomAdaptor_Curve AdaptCurve(C, UMin, UMax); //range is important for periodic curves double length = GCPnts_AbscissaPoint::Length(AdaptCurve, UMin, UMax); return length; } -//================================================================================ -/*! - * \brief Find out elements orientation on a geometrical face - * \param theFace - The face correctly oriented in the shape being meshed - * \param theMeshDS - The mesh data structure - * \retval bool - true if the face normal and the normal of first element - * in the correspoding submesh point in different directions - */ -//================================================================================ - -bool SMESH_Algo::IsReversedSubMesh (const TopoDS_Face& theFace, - SMESHDS_Mesh* theMeshDS) -{ - if ( theFace.IsNull() || !theMeshDS ) - return false; - - // find out orientation of a meshed face - int faceID = theMeshDS->ShapeToIndex( theFace ); - TopoDS_Shape aMeshedFace = theMeshDS->IndexToShape( faceID ); - bool isReversed = ( theFace.Orientation() != aMeshedFace.Orientation() ); - - const SMESHDS_SubMesh * aSubMeshDSFace = theMeshDS->MeshElements( faceID ); - if ( !aSubMeshDSFace ) - return isReversed; - - // find element with node located on face and get its normal - const SMDS_FacePosition* facePos = 0; - int vertexID = 0; - gp_Pnt nPnt[3]; - gp_Vec Ne; - bool normalOK = false; - SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements(); - while ( iteratorElem->more() ) // loop on elements on theFace - { - const SMDS_MeshElement* elem = iteratorElem->next(); - if ( elem && elem->NbNodes() > 2 ) { - SMDS_ElemIteratorPtr nodesIt = elem->nodesIterator(); - const SMDS_FacePosition* fPos = 0; - int i = 0, vID = 0; - while ( nodesIt->more() ) { // loop on nodes - const SMDS_MeshNode* node - = static_cast(nodesIt->next()); - if ( i == 3 ) i = 2; - nPnt[ i++ ].SetCoord( node->X(), node->Y(), node->Z() ); - // check position - const SMDS_PositionPtr& pos = node->GetPosition(); - if ( !pos ) continue; - if ( pos->GetTypeOfPosition() == SMDS_TOP_FACE ) { - fPos = dynamic_cast< const SMDS_FacePosition* >( pos.get() ); - } - else if ( pos->GetTypeOfPosition() == SMDS_TOP_VERTEX ) { - vID = pos->GetShapeId(); - } - } - if ( fPos || ( !normalOK && vID )) { - // compute normal - gp_Vec v01( nPnt[0], nPnt[1] ), v02( nPnt[0], nPnt[2] ); - if ( v01.SquareMagnitude() > RealSmall() && - v02.SquareMagnitude() > RealSmall() ) - { - Ne = v01 ^ v02; - normalOK = ( Ne.SquareMagnitude() > RealSmall() ); - } - // we need position on theFace or at least on vertex - if ( normalOK ) { - vertexID = vID; - if ((facePos = fPos)) - break; - } - } - } - } - if ( !normalOK ) - return isReversed; - - // node position on face - double u,v; - if ( facePos ) { - u = facePos->GetUParameter(); - v = facePos->GetVParameter(); - } - else if ( vertexID ) { - TopoDS_Shape V = theMeshDS->IndexToShape( vertexID ); - if ( V.IsNull() || V.ShapeType() != TopAbs_VERTEX ) - return isReversed; - gp_Pnt2d uv = BRep_Tool::Parameters( TopoDS::Vertex( V ), theFace ); - u = uv.X(); - v = uv.Y(); - } - else - { - return isReversed; - } - - // face normal at node position - TopLoc_Location loc; - Handle(Geom_Surface) surf = BRep_Tool::Surface( theFace, loc ); - if ( surf.IsNull() || surf->Continuity() < GeomAbs_C1 ) return isReversed; - gp_Vec d1u, d1v; - surf->D1( u, v, nPnt[0], d1u, d1v ); - gp_Vec Nf = (d1u ^ d1v).Transformed( loc ); - - if ( theFace.Orientation() == TopAbs_REVERSED ) - Nf.Reverse(); - - return Ne * Nf < 0.; -} - //================================================================================ /*! * \brief Just return false as the algorithm does not hold parameters values @@ -321,7 +353,7 @@ bool SMESH_Algo::GetNodeParamOnEdge(const SMESHDS_Mesh* theMesh, if ( !eSubMesh || !eSubMesh->GetElements()->more() ) return false; // edge is not meshed - int nbEdgeNodes = 0; + //int nbEdgeNodes = 0; set < double > paramSet; if ( eSubMesh ) { @@ -334,7 +366,7 @@ bool SMESH_Algo::GetNodeParamOnEdge(const SMESHDS_Mesh* theMesh, if ( pos->GetTypeOfPosition() != SMDS_TOP_EDGE ) return false; const SMDS_EdgePosition* epos = - static_cast(node->GetPosition().get()); + static_cast(node->GetPosition()); if ( !paramSet.insert( epos->GetUParameter() ).second ) return false; // equal parameters } @@ -372,7 +404,8 @@ bool SMESH_Algo::GetNodeParamOnEdge(const SMESHDS_Mesh* theMesh, bool SMESH_Algo::GetSortedNodesOnEdge(const SMESHDS_Mesh* theMesh, const TopoDS_Edge& theEdge, const bool ignoreMediumNodes, - map< double, const SMDS_MeshNode* > & theNodes) + map< double, const SMDS_MeshNode* > & theNodes, + const SMDSAbs_ElementType typeToCheck) { theNodes.clear(); @@ -380,7 +413,7 @@ bool SMESH_Algo::GetSortedNodesOnEdge(const SMESHDS_Mesh* theM return false; SMESHDS_SubMesh * eSubMesh = theMesh->MeshElements( theEdge ); - if ( !eSubMesh || !eSubMesh->GetElements()->more() ) + if ( !eSubMesh || ( eSubMesh->NbElements()==0 && eSubMesh->NbNodes() == 0)) return false; // edge is not meshed int nbNodes = 0; @@ -392,25 +425,22 @@ bool SMESH_Algo::GetSortedNodesOnEdge(const SMESHDS_Mesh* theM while ( nIt->more() ) { const SMDS_MeshNode* node = nIt->next(); - if ( ignoreMediumNodes ) { - SMDS_ElemIteratorPtr elemIt = node->GetInverseElementIterator(); - if ( elemIt->more() && elemIt->next()->IsMediumNode( node )) - continue; - } + if ( ignoreMediumNodes && SMESH_MesherHelper::IsMedium( node, typeToCheck )) + continue; const SMDS_PositionPtr& pos = node->GetPosition(); if ( pos->GetTypeOfPosition() != SMDS_TOP_EDGE ) return false; const SMDS_EdgePosition* epos = - static_cast(node->GetPosition().get()); - theNodes.insert( make_pair( epos->GetUParameter(), node )); + static_cast(node->GetPosition()); + theNodes.insert( theNodes.end(), make_pair( epos->GetUParameter(), node )); ++nbNodes; } } // add vertex nodes TopoDS_Vertex v1, v2; TopExp::Vertices(theEdge, v1, v2); - const SMDS_MeshNode* n1 = VertexNode( v1, (SMESHDS_Mesh*) theMesh ); - const SMDS_MeshNode* n2 = VertexNode( v2, (SMESHDS_Mesh*) theMesh ); + const SMDS_MeshNode* n1 = VertexNode( v1, eSubMesh, 0 ); + const SMDS_MeshNode* n2 = VertexNode( v2, eSubMesh, 0 ); Standard_Real f, l; BRep_Tool::Range(theEdge, f, l); if ( v1.Orientation() != TopAbs_FORWARD ) @@ -425,27 +455,35 @@ bool SMESH_Algo::GetSortedNodesOnEdge(const SMESHDS_Mesh* theM //================================================================================ /*! - * \brief Make filter recognize only compatible hypotheses - * \param theFilter - the filter to initialize - * \param ignoreAuxiliary - make filter ignore compatible auxiliary hypotheses + * \brief Returns the filter recognizing only compatible hypotheses + * \param ignoreAuxiliary - make filter ignore auxiliary hypotheses + * \retval SMESH_HypoFilter* - the filter that can be NULL */ //================================================================================ -bool SMESH_Algo::InitCompatibleHypoFilter( SMESH_HypoFilter & theFilter, - const bool ignoreAuxiliary) const +const SMESH_HypoFilter* +SMESH_Algo::GetCompatibleHypoFilter(const bool ignoreAuxiliary) const { if ( !_compatibleHypothesis.empty() ) { - theFilter.Init( theFilter.HasName( _compatibleHypothesis[0] )); - for ( int i = 1; i < _compatibleHypothesis.size(); ++i ) - theFilter.Or( theFilter.HasName( _compatibleHypothesis[ i ] )); - - if ( ignoreAuxiliary ) - theFilter.AndNot( theFilter.IsAuxiliary() ); - - return true; + if ( !_compatibleAllHypFilter ) + { + SMESH_HypoFilter* filter = new SMESH_HypoFilter(); + filter->Init( filter->HasName( _compatibleHypothesis[0] )); + for ( int i = 1; i < _compatibleHypothesis.size(); ++i ) + filter->Or( filter->HasName( _compatibleHypothesis[ i ] )); + + SMESH_HypoFilter* filterNoAux = new SMESH_HypoFilter( filter ); + filterNoAux->AndNot( filterNoAux->IsAuxiliary() ); + + // _compatibleNoAuxHypFilter will detele _compatibleAllHypFilter!!! + SMESH_Algo* me = const_cast< SMESH_Algo* >( this ); + me->_compatibleAllHypFilter = filter; + me->_compatibleNoAuxHypFilter = filterNoAux; + } + return ignoreAuxiliary ? _compatibleNoAuxHypFilter : _compatibleAllHypFilter; } - return false; + return 0; } //================================================================================ @@ -457,22 +495,31 @@ bool SMESH_Algo::InitCompatibleHypoFilter( SMESH_HypoFilter & theFilter, */ //================================================================================ -GeomAbs_Shape SMESH_Algo::Continuity(const TopoDS_Edge & E1, - const TopoDS_Edge & E2) +GeomAbs_Shape SMESH_Algo::Continuity(TopoDS_Edge E1, + TopoDS_Edge E2) { - TopoDS_Vertex V = TopExp::LastVertex (E1, true); - if ( !V.IsSame( TopExp::FirstVertex(E2, true ))) - if ( !TopExp::CommonVertex( E1, E2, V )) - return GeomAbs_C0; + //E1.Orientation(TopAbs_FORWARD), E2.Orientation(TopAbs_FORWARD); // avoid pb with internal edges + if (E1.Orientation() > TopAbs_REVERSED) // INTERNAL + E1.Orientation( TopAbs_FORWARD ); + if (E2.Orientation() > TopAbs_REVERSED) // INTERNAL + E2.Orientation( TopAbs_FORWARD ); + + TopoDS_Vertex V, VV1[2], VV2[2]; + TopExp::Vertices( E1, VV1[0], VV1[1], true ); + TopExp::Vertices( E2, VV2[0], VV2[1], true ); + if ( VV1[1].IsSame( VV2[0] )) { V = VV1[1]; } + else if ( VV1[0].IsSame( VV2[1] )) { V = VV1[0]; } + else if ( VV1[1].IsSame( VV2[1] )) { V = VV1[1]; E1.Reverse(); } + else if ( VV1[0].IsSame( VV2[0] )) { V = VV1[0]; E1.Reverse(); } + else { return GeomAbs_C0; } + Standard_Real u1 = BRep_Tool::Parameter( V, E1 ); Standard_Real u2 = BRep_Tool::Parameter( V, E2 ); BRepAdaptor_Curve C1( E1 ), C2( E2 ); Standard_Real tol = BRep_Tool::Tolerance( V ); Standard_Real angTol = 2e-3; try { -#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 OCC_CATCH_SIGNALS; -#endif return BRepLProp::Continuity(C1, C2, u1, u2, tol, angTol); } catch (Standard_Failure) { @@ -480,12 +527,78 @@ GeomAbs_Shape SMESH_Algo::Continuity(const TopoDS_Edge & E1, return GeomAbs_C0; } +//================================================================================ +/*! + * \brief Return true if an edge can be considered straight + */ +//================================================================================ + +bool SMESH_Algo::IsStraight( const TopoDS_Edge & E, + const bool degenResult) +{ + { + double f,l; + if ( BRep_Tool::Curve( E, f, l ).IsNull()) + return degenResult; + } + BRepAdaptor_Curve curve( E ); + switch( curve.GetType() ) + { + case GeomAbs_Line: + return true; + case GeomAbs_Circle: + case GeomAbs_Ellipse: + case GeomAbs_Hyperbola: + case GeomAbs_Parabola: + return false; + // case GeomAbs_BezierCurve: + // case GeomAbs_BSplineCurve: + // case GeomAbs_OtherCurve: + default:; + } + const double f = curve.FirstParameter(); + const double l = curve.LastParameter(); + const gp_Pnt pf = curve.Value( f ); + const gp_Pnt pl = curve.Value( l ); + const gp_Vec v1( pf, pl ); + const double v1Len = v1.Magnitude(); + if ( v1Len < std::numeric_limits< double >::min() ) + return false; // E seems closed + const double tol = Min( 10 * curve.Tolerance(), v1Len * 1e-2 ); + const double nbSamples = 7; + for ( int i = 0; i < nbSamples; ++i ) + { + const double r = ( i + 1 ) / nbSamples; + const gp_Pnt pi = curve.Value( f * r + l * ( 1 - r )); + const gp_Vec vi( pf, pi ); + const double h = 0.5 * v1.Crossed( vi ).Magnitude() / v1Len; + if ( h > tol ) + return false; + } + return true; +} + +//================================================================================ +/*! + * \brief Return true if an edge has no 3D curve + */ +//================================================================================ + +bool SMESH_Algo::isDegenerated( const TopoDS_Edge & E ) +{ + double f,l; + TopLoc_Location loc; + Handle(Geom_Curve) C = BRep_Tool::Curve( E, loc, f,l ); + return C.IsNull(); +} + //================================================================================ /*! * \brief Return the node built on a vertex * \param V - the vertex * \param meshDS - mesh * \retval const SMDS_MeshNode* - found node or NULL + * \sa SMESH_MesherHelper::GetSubShapeByNode( const SMDS_MeshNode*, SMESHDS_Mesh* ) */ //================================================================================ @@ -500,6 +613,200 @@ const SMDS_MeshNode* SMESH_Algo::VertexNode(const TopoDS_Vertex& V, return 0; } +//======================================================================= +/*! + * \brief Return the node built on a vertex. + * A node moved to other geometry by MergeNodes() is also returned. + * \param V - the vertex + * \param mesh - mesh + * \retval const SMDS_MeshNode* - found node or NULL + */ +//======================================================================= + +const SMDS_MeshNode* SMESH_Algo::VertexNode(const TopoDS_Vertex& V, + const SMESH_Mesh* mesh) +{ + const SMDS_MeshNode* node = VertexNode( V, mesh->GetMeshDS() ); + + if ( !node && mesh->HasModificationsToDiscard() ) + { + PShapeIteratorPtr edgeIt = SMESH_MesherHelper::GetAncestors( V, *mesh, TopAbs_EDGE ); + while ( const TopoDS_Shape* edge = edgeIt->next() ) + if ( SMESHDS_SubMesh* edgeSM = mesh->GetMeshDS()->MeshElements( *edge )) + if ( edgeSM->NbElements() > 0 ) + return VertexNode( V, edgeSM, mesh, /*checkV=*/false ); + } + return node; +} + +//======================================================================= +/*! + * \brief Return the node built on a vertex. + * A node moved to other geometry by MergeNodes() is also returned. + * \param V - the vertex + * \param edgeSM - sub-mesh of a meshed EDGE sharing the vertex + * \param checkV - if \c true, presence of a node on the vertex is checked + * \retval const SMDS_MeshNode* - found node or NULL + */ +//======================================================================= + +const SMDS_MeshNode* SMESH_Algo::VertexNode(const TopoDS_Vertex& V, + const SMESHDS_SubMesh* edgeSM, + const SMESH_Mesh* mesh, + const bool checkV) +{ + const SMDS_MeshNode* node = checkV ? VertexNode( V, edgeSM->GetParent() ) : 0; + + if ( !node && edgeSM ) + { + // find nodes not shared by mesh segments + typedef set< const SMDS_MeshNode* > TNodeSet; + typedef map< const SMDS_MeshNode*, const SMDS_MeshNode* > TNodeMap; + TNodeMap notSharedNodes; + TNodeSet otherShapeNodes; + vector< const SMDS_MeshNode* > segNodes(3); + SMDS_ElemIteratorPtr segIt = edgeSM->GetElements(); + while ( segIt->more() ) + { + const SMDS_MeshElement* seg = segIt->next(); + if ( seg->GetType() != SMDSAbs_Edge ) + return node; + segNodes.assign( seg->begin_nodes(), seg->end_nodes() ); + for ( int i = 0; i < 2; ++i ) + { + const SMDS_MeshNode* n1 = segNodes[i]; + const SMDS_MeshNode* n2 = segNodes[1-i]; + pair it2new = notSharedNodes.insert( make_pair( n1, n2 )); + if ( !it2new.second ) // n encounters twice + notSharedNodes.erase( it2new.first ); + if ( n1->getshapeId() != edgeSM->GetID() ) + otherShapeNodes.insert( n1 ); + } + } + if ( otherShapeNodes.size() == 1 && notSharedNodes.empty() ) // a closed EDGE + return *otherShapeNodes.begin(); + + if ( notSharedNodes.size() == 2 ) // two end nodes found + { + SMESHDS_Mesh* meshDS = edgeSM->GetParent(); + const TopoDS_Shape& E = meshDS->IndexToShape( edgeSM->GetID() ); + if ( E.IsNull() || E.ShapeType() != TopAbs_EDGE ) + return node; + const SMDS_MeshNode* n1 = notSharedNodes.begin ()->first; + const SMDS_MeshNode* n2 = notSharedNodes.rbegin()->first; + TopoDS_Shape S1 = SMESH_MesherHelper::GetSubShapeByNode( n1, meshDS ); + if ( S1.ShapeType() == TopAbs_VERTEX && SMESH_MesherHelper::IsSubShape( S1, E )) + return n2; + TopoDS_Shape S2 = SMESH_MesherHelper::GetSubShapeByNode( n2, meshDS ); + if ( S2.ShapeType() == TopAbs_VERTEX && SMESH_MesherHelper::IsSubShape( S2, E )) + return n1; + if ( edgeSM->NbElements() <= 2 || !mesh ) // one-two segments + { + gp_Pnt pV = BRep_Tool::Pnt( V ); + double dist1 = pV.SquareDistance( SMESH_TNodeXYZ( n1 )); + double dist2 = pV.SquareDistance( SMESH_TNodeXYZ( n2 )); + return dist1 < dist2 ? n1 : n2; + } + if ( mesh ) + { + SMESH_MesherHelper helper( const_cast( *mesh )); + const SMDS_MeshNode* n1i = notSharedNodes.begin ()->second; + const SMDS_MeshNode* n2i = notSharedNodes.rbegin()->second; + const TopoDS_Edge& edge = TopoDS::Edge( E ); + bool posOK = true; + double pos1 = helper.GetNodeU( edge, n1i, n2i, &posOK ); + double pos2 = helper.GetNodeU( edge, n2i, n1i, &posOK ); + double posV = BRep_Tool::Parameter( V, edge ); + if ( Abs( pos1 - posV ) < Abs( pos2 - posV )) return n1; + else return n2; + } + } + } + return node; +} + +//======================================================================= +//function : GetMeshError +//purpose : Finds topological errors of a sub-mesh +//WARNING : 1D check is NOT implemented so far +//======================================================================= + +SMESH_Algo::EMeshError SMESH_Algo::GetMeshError(SMESH_subMesh* subMesh) +{ + EMeshError err = MEr_OK; + + SMESHDS_SubMesh* smDS = subMesh->GetSubMeshDS(); + if ( !smDS ) + return MEr_EMPTY; + + switch ( subMesh->GetSubShape().ShapeType() ) + { + case TopAbs_FACE: { // ====================== 2D ===================== + + SMDS_ElemIteratorPtr fIt = smDS->GetElements(); + if ( !fIt->more() ) + return MEr_EMPTY; + + // We check that olny links on EDGEs encouter once, the rest links, twice + set< SMESH_TLink > links; + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + int nbNodes = f->NbCornerNodes(); // ignore medium nodes + for ( int i = 0; i < nbNodes; ++i ) + { + const SMDS_MeshNode* n1 = f->GetNode( i ); + const SMDS_MeshNode* n2 = f->GetNode(( i+1 ) % nbNodes); + std::pair< set< SMESH_TLink >::iterator, bool > it_added = + links.insert( SMESH_TLink( n1, n2 )); + if ( !it_added.second ) + // As we do NOT(!) check if mesh is manifold, we believe that a link can + // encounter once or twice only (not three times), we erase a link as soon + // as it encounters twice to speed up search in the map. + links.erase( it_added.first ); + } + } + // the links remaining in the should all be on EDGE + set< SMESH_TLink >::iterator linkIt = links.begin(); + for ( ; linkIt != links.end(); ++linkIt ) + { + const SMESH_TLink& link = *linkIt; + if ( link.node1()->GetPosition()->GetTypeOfPosition() > SMDS_TOP_EDGE || + link.node2()->GetPosition()->GetTypeOfPosition() > SMDS_TOP_EDGE ) + return MEr_HOLES; + } + // TODO: to check orientation + break; + } + case TopAbs_SOLID: { // ====================== 3D ===================== + + SMDS_ElemIteratorPtr vIt = smDS->GetElements(); + if ( !vIt->more() ) + return MEr_EMPTY; + + SMDS_VolumeTool vTool; + while ( !vIt->more() ) + { + if (!vTool.Set( vIt->next() )) + continue; // strange + + for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) + if ( vTool.IsFreeFace( iF )) + { + int nbN = vTool.NbFaceNodes( iF ); + const SMDS_MeshNode** nodes = vTool.GetFaceNodes( iF ); + for ( int i = 0; i < nbN; ++i ) + if ( nodes[i]->GetPosition()->GetTypeOfPosition() > SMDS_TOP_FACE ) + return MEr_HOLES; + } + } + break; + } + default:; + } + return err; +} + //================================================================================ /*! * \brief Sets event listener to submeshes if necessary @@ -541,6 +848,29 @@ bool SMESH_Algo::Compute(SMESH_Mesh & /*aMesh*/, SMESH_MesherHelper* /*aHelper*/ return error( COMPERR_BAD_INPUT_MESH, "Mesh built on shape expected"); } +//======================================================================= +//function : CancelCompute +//purpose : Sets _computeCanceled to true. It's usage depends on +// * implementation of a particular mesher. +//======================================================================= + +void SMESH_Algo::CancelCompute() +{ + _computeCanceled = true; + _error = COMPERR_CANCELED; +} + +//================================================================================ +/* + * If possible, returns progress of computation [0.,1.] + */ +//================================================================================ + +double SMESH_Algo::GetProgress() const +{ + return _progress; +} + //================================================================================ /*! * \brief store error and comment and then return ( error == COMPERR_OK ) @@ -588,7 +918,7 @@ SMESH_ComputeErrorPtr SMESH_Algo::GetComputeError() const //================================================================================ /*! - * \brief initialize compute error + * \brief initialize compute error before call of Compute() */ //================================================================================ @@ -601,6 +931,29 @@ void SMESH_Algo::InitComputeError() if ( (*elem)->GetID() < 1 ) delete *elem; _badInputElements.clear(); + + _computeCanceled = false; + _progressTic = 0; + _progress = 0.; +} + +//================================================================================ +/*! + * \brief Return compute progress by nb of calls of this method + */ +//================================================================================ + +double SMESH_Algo::GetProgressByTic() const +{ + int computeCost = 0; + for ( size_t i = 0; i < _smToCompute.size(); ++i ) + computeCost += _smToCompute[i]->GetComputeCost(); + + const_cast( this )->_progressTic++; + + double x = 5 * _progressTic; + x = ( x < computeCost ) ? ( x / computeCost ) : 1.; + return 0.9 * sin( x * M_PI / 2 ); } //================================================================================ @@ -616,3 +969,264 @@ void SMESH_Algo::addBadInputElement(const SMDS_MeshElement* elem) if ( elem ) _badInputElements.push_back( elem ); } + +//======================================================================= +//function : addBadInputElements +//purpose : store a bad input elements or nodes preventing computation +//======================================================================= + +void SMESH_Algo::addBadInputElements(const SMESHDS_SubMesh* sm, + const bool addNodes) +{ + if ( sm ) + { + if ( addNodes ) + { + SMDS_NodeIteratorPtr nIt = sm->GetNodes(); + while ( nIt->more() ) addBadInputElement( nIt->next() ); + } + else + { + SMDS_ElemIteratorPtr eIt = sm->GetElements(); + while ( eIt->more() ) addBadInputElement( eIt->next() ); + } + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +// int SMESH_Algo::NumberOfWires(const TopoDS_Shape& S) +// { +// int i = 0; +// for (TopExp_Explorer exp(S,TopAbs_WIRE); exp.More(); exp.Next()) +// i++; +// return i; +// } + +//============================================================================= +/*! + * + */ +//============================================================================= + +int SMESH_Algo::NumberOfPoints(SMESH_Mesh& aMesh, const TopoDS_Wire& W) +{ + int nbPoints = 0; + for (TopExp_Explorer exp(W,TopAbs_EDGE); exp.More(); exp.Next()) { + const TopoDS_Edge& E = TopoDS::Edge(exp.Current()); + int nb = aMesh.GetSubMesh(E)->GetSubMeshDS()->NbNodes(); + if(_quadraticMesh) + nb = nb/2; + nbPoints += nb + 1; // internal points plus 1 vertex of 2 (last point ?) + } + return nbPoints; +} + + +//================================================================================ +/*! + * Method in which an algorithm generating a structured mesh + * fixes positions of in-face nodes after there movement + * due to insertion of viscous layers. + */ +//================================================================================ + +bool SMESH_2D_Algo::FixInternalNodes(const SMESH_ProxyMesh& mesh, + const TopoDS_Face& face) +{ + const SMESHDS_SubMesh* smDS = mesh.GetSubMesh(face); + if ( !smDS || smDS->NbElements() < 1 ) + return false; + + SMESH_MesherHelper helper( *mesh.GetMesh() ); + + // get all faces from a proxy sub-mesh + typedef SMDS_StdIterator< const SMDS_MeshElement*, SMDS_ElemIteratorPtr > TIterator; + TIDSortedElemSet allFaces( TIterator( smDS->GetElements() ), TIterator() ); + TIDSortedElemSet avoidSet, firstRowQuads; + + // indices of nodes to pass to a neighbour quad using SMESH_MeshAlgos::FindFaceInSet() + int iN1, iN2; + + // get two first rows of nodes by passing through the first row of faces + vector< vector< const SMDS_MeshNode* > > nodeRows; + int iRow1 = 0, iRow2 = 1; + const SMDS_MeshElement* quad; + { + // look for a corner quadrangle and it's corner node + const SMDS_MeshElement* cornerQuad = 0; + int cornerNodeInd = -1; + SMDS_ElemIteratorPtr fIt = smDS->GetElements(); + while ( !cornerQuad && fIt->more() ) + { + cornerQuad = fIt->next(); + if ( cornerQuad->NbCornerNodes() != 4 ) + return false; + SMDS_NodeIteratorPtr nIt = cornerQuad->nodeIterator(); + for ( int i = 0; i < 4; ++i ) + { + int nbInverseQuads = 0; + SMDS_ElemIteratorPtr fIt = nIt->next()->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + nbInverseQuads += allFaces.count( fIt->next() ); + if ( nbInverseQuads == 1 ) + cornerNodeInd = i, i = 4; + } + if ( cornerNodeInd < 0 ) + cornerQuad = 0; + } + if ( !cornerQuad || cornerNodeInd < 0 ) + return false; + + iN1 = helper.WrapIndex( cornerNodeInd + 1, 4 ); + iN2 = helper.WrapIndex( cornerNodeInd + 2, 4 ); + int iN3 = helper.WrapIndex( cornerNodeInd + 3, 4 ); + nodeRows.resize(2); + nodeRows[iRow1].push_back( cornerQuad->GetNode( cornerNodeInd )); + nodeRows[iRow1].push_back( cornerQuad->GetNode( iN1 )); + nodeRows[iRow2].push_back( cornerQuad->GetNode( iN3 )); + nodeRows[iRow2].push_back( cornerQuad->GetNode( iN2 )); + firstRowQuads.insert( cornerQuad ); + + // pass through the rest quads in a face row + quad = cornerQuad; + while ( quad ) + { + avoidSet.clear(); + avoidSet.insert( quad ); + if (( quad = SMESH_MeshAlgos::FindFaceInSet( nodeRows[iRow1].back(), + nodeRows[iRow2].back(), + allFaces, avoidSet, &iN1, &iN2))) + { + nodeRows[iRow1].push_back( quad->GetNode( helper.WrapIndex( iN2 + 2, 4 ))); + nodeRows[iRow2].push_back( quad->GetNode( helper.WrapIndex( iN1 + 2, 4 ))); + if ( quad->NbCornerNodes() != 4 ) + return false; + } + } + if ( nodeRows[iRow1].size() < 3 ) + return true; // there is nothing to fix + } + + nodeRows.reserve( smDS->NbElements() / nodeRows[iRow1].size() ); + + // get the rest node rows + while ( true ) + { + ++iRow1, ++iRow2; + + // get the first quad in the next face row + if (( quad = SMESH_MeshAlgos::FindFaceInSet( nodeRows[iRow1][0], + nodeRows[iRow1][1], + allFaces, /*avoid=*/firstRowQuads, + &iN1, &iN2))) + { + if ( quad->NbCornerNodes() != 4 ) + return false; + nodeRows.resize( iRow2+1 ); + nodeRows[iRow2].push_back( quad->GetNode( helper.WrapIndex( iN2 + 2, 4 ))); + nodeRows[iRow2].push_back( quad->GetNode( helper.WrapIndex( iN1 + 2, 4 ))); + firstRowQuads.insert( quad ); + } + else + { + break; // no more rows + } + + // pass through the rest quads in a face row + while ( quad ) + { + avoidSet.clear(); + avoidSet.insert( quad ); + if (( quad = SMESH_MeshAlgos::FindFaceInSet( nodeRows[iRow1][ nodeRows[iRow2].size()-1 ], + nodeRows[iRow2].back(), + allFaces, avoidSet, &iN1, &iN2))) + { + if ( quad->NbCornerNodes() != 4 ) + return false; + nodeRows[iRow2].push_back( quad->GetNode( helper.WrapIndex( iN1 + 2, 4 ))); + } + } + if ( nodeRows[iRow1].size() != nodeRows[iRow2].size() ) + return false; + } + if ( nodeRows.size() < 3 ) + return true; // there is nothing to fix + + // get params of the first (bottom) and last (top) node rows + UVPtStructVec uvB( nodeRows[0].size() ), uvT( nodeRows[0].size() ); + for ( int isBot = 0; isBot < 2; ++isBot ) + { + UVPtStructVec & uvps = isBot ? uvB : uvT; + vector< const SMDS_MeshNode* >& nodes = nodeRows[ isBot ? 0 : nodeRows.size()-1 ]; + for ( size_t i = 0; i < nodes.size(); ++i ) + { + uvps[i].node = nodes[i]; + gp_XY uv = helper.GetNodeUV( face, uvps[i].node ); + uvps[i].u = uv.Coord(1); + uvps[i].v = uv.Coord(2); + uvps[i].x = 0; + } + // calculate x (normalized param) + for ( size_t i = 1; i < nodes.size(); ++i ) + uvps[i].x = uvps[i-1].x + SMESH_TNodeXYZ( uvps[i-1].node ).Distance( uvps[i].node ); + for ( size_t i = 1; i < nodes.size(); ++i ) + uvps[i].x /= uvps.back().x; + } + + // get params of the left and right node rows + UVPtStructVec uvL( nodeRows.size() ), uvR( nodeRows.size() ); + for ( int isLeft = 0; isLeft < 2; ++isLeft ) + { + UVPtStructVec & uvps = isLeft ? uvL : uvR; + const int iCol = isLeft ? 0 : nodeRows[0].size() - 1; + for ( size_t i = 0; i < nodeRows.size(); ++i ) + { + uvps[i].node = nodeRows[i][iCol]; + gp_XY uv = helper.GetNodeUV( face, uvps[i].node ); + uvps[i].u = uv.Coord(1); + uvps[i].v = uv.Coord(2); + uvps[i].y = 0; + } + // calculate y (normalized param) + for ( size_t i = 1; i < nodeRows.size(); ++i ) + uvps[i].y = uvps[i-1].y + SMESH_TNodeXYZ( uvps[i-1].node ).Distance( uvps[i].node ); + for ( size_t i = 1; i < nodeRows.size(); ++i ) + uvps[i].y /= uvps.back().y; + } + + // update node coordinates + SMESHDS_Mesh* meshDS = mesh.GetMeshDS(); + Handle(Geom_Surface) S = BRep_Tool::Surface( face ); + gp_XY a0 ( uvB.front().u, uvB.front().v ); + gp_XY a1 ( uvB.back().u, uvB.back().v ); + gp_XY a2 ( uvT.back().u, uvT.back().v ); + gp_XY a3 ( uvT.front().u, uvT.front().v ); + for ( size_t iRow = 1; iRow < nodeRows.size()-1; ++iRow ) + { + gp_XY p1 ( uvR[ iRow ].u, uvR[ iRow ].v ); + gp_XY p3 ( uvL[ iRow ].u, uvL[ iRow ].v ); + const double y0 = uvL[ iRow ].y; + const double y1 = uvR[ iRow ].y; + for ( size_t iCol = 1; iCol < nodeRows[0].size()-1; ++iCol ) + { + gp_XY p0 ( uvB[ iCol ].u, uvB[ iCol ].v ); + gp_XY p2 ( uvT[ iCol ].u, uvT[ iCol ].v ); + const double x0 = uvB[ iCol ].x; + const double x1 = uvT[ iCol ].x; + double x = (x0 + y0 * (x1 - x0)) / (1 - (y1 - y0) * (x1 - x0)); + double y = y0 + x * (y1 - y0); + gp_XY uv = helper.calcTFI( x, y, a0,a1,a2,a3, p0,p1,p2,p3 ); + gp_Pnt p = S->Value( uv.Coord(1), uv.Coord(2)); + const SMDS_MeshNode* n = nodeRows[iRow][iCol]; + meshDS->MoveNode( n, p.X(), p.Y(), p.Z() ); + if ( SMDS_FacePosition* pos = dynamic_cast< SMDS_FacePosition*>( n->GetPosition() )) + pos->SetParameters( uv.Coord(1), uv.Coord(2) ); + } + } + return true; +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Block.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Block.cpp index fd4edab3265c..b87928995d63 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Block.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Block.cpp @@ -1,30 +1,36 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : SMESH_Pattern.hxx // Created : Mon Aug 2 10:30:00 2004 // Author : Edward AGAPOV (eap) // #include "SMESH_Block.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMDS_MeshVolume.hxx" +#include "SMDS_VolumeTool.hxx" +#include "SMESH_MeshAlgos.hxx" + #include #include #include @@ -32,9 +38,12 @@ #include #include #include +#include #include #include +#include #include +#include #include #include #include @@ -52,12 +61,10 @@ #include #include -#include "SMDS_MeshNode.hxx" -#include "SMDS_MeshVolume.hxx" -#include "SMDS_VolumeTool.hxx" -#include "utilities.h" +#include #include +#include using namespace std; @@ -66,7 +73,7 @@ using namespace std; //================================================================================ /*! * \brief Set edge data - * \param edgeID - block subshape ID + * \param edgeID - block sub-shape ID * \param curve - edge geometry * \param isForward - is curve orientation coincides with edge orientation in the block */ @@ -86,7 +93,7 @@ void SMESH_Block::TEdge::Set( const int edgeID, Adaptor3d_Curve* curve, const bo //================================================================================ /*! * \brief Set coordinates of nodes at edge ends to work with mesh block - * \param edgeID - block subshape ID + * \param edgeID - block sub-shape ID * \param node1 - coordinates of node with lower ID * \param node2 - coordinates of node with upper ID */ @@ -142,7 +149,7 @@ SMESH_Block::TEdge::~TEdge() //================================================================================ /*! * \brief Set face data - * \param faceID - block subshape ID + * \param faceID - block sub-shape ID * \param S - face surface geometry * \param c2d - 4 pcurves in the order as returned by GetFaceEdgesIDs(faceID) * \param isForward - orientation of pcurves comparing with block edge direction @@ -179,7 +186,7 @@ void SMESH_Block::TFace::Set( const int faceID, //================================================================================ /*! * \brief Set face data to work with mesh block - * \param faceID - block subshape ID + * \param faceID - block sub-shape ID * \param edgeU0 - filled data of edge u0 = GetFaceEdgesIDs(faceID)[ 0 ] * \param edgeU1 - filled data of edge u1 = GetFaceEdgesIDs(faceID)[ 1 ] */ @@ -301,6 +308,60 @@ gp_XYZ SMESH_Block::TFace::Point( const gp_XYZ& theParams ) const return p; } + +namespace +{ + inline + bool isPntInTria( const gp_XY& p, const gp_XY& t0, const gp_XY& t1, const gp_XY& t2 ) + { + double bc0, bc1; + SMESH_MeshAlgos::GetBarycentricCoords( p, t0, t1, t2, bc0, bc1 ); + return ( bc0 >= 0. && bc1 >= 0. && bc0 + bc1 <= 1. ); + } + + inline + bool isPntInQuad( const gp_XY& p, + const gp_XY& q0, const gp_XY& q1, const gp_XY& q2, const gp_XY& q3 ) + { + const int in1 = isPntInTria( p, q0, q1, q2 ); + const int in2 = isPntInTria( p, q0, q2, q3 ); + return in1 + in2 == 1; + } +} + +//======================================================================= +//function : IsUVInQuad +//purpose : Checks if UV is in a quardilateral defined by 4 nornalized points +//======================================================================= + +bool SMESH_Block::TFace::IsUVInQuad( const gp_XY& uv, + const gp_XYZ& param0, const gp_XYZ& param1, + const gp_XYZ& param2, const gp_XYZ& param3 ) const +{ + gp_XY q0 = GetUV( param0 ); + gp_XY q1 = GetUV( param1 ); + gp_XY q2 = GetUV( param2 ); + gp_XY q3 = GetUV( param3 ); + return isPntInQuad( uv, q0,q1,q2,q3); +} + +//======================================================================= +//function : GetUVRange +//purpose : returns UV range of the face +//======================================================================= + +gp_XY SMESH_Block::TFace::GetUVRange() const +{ + if ( !myS ) return gp_XY(1.,1.); + + Bnd_B2d bb; + for ( int iE = 0; iE < 4; ++iE ) + { + //TColStd_Array1OfReal T(1, + } + return bb.CornerMax() - bb.CornerMin(); +} + //======================================================================= //function : GetShapeCoef //purpose : @@ -372,7 +433,7 @@ bool SMESH_Block::ShellPoint( const gp_XYZ& theParams, gp_XYZ& thePoint ) const //======================================================================= //function : ShellPoint //purpose : computes coordinates of a point in shell by points on sub-shapes; -// thePointOnShape[ subShapeID ] must be a point on a subShape +// thePointOnShape[ subShapeID ] must be a point on a sub-shape //======================================================================= bool SMESH_Block::ShellPoint(const gp_XYZ& theParams, @@ -382,8 +443,8 @@ bool SMESH_Block::ShellPoint(const gp_XYZ& theParams, if ( thePointOnShape.size() < ID_F1yz ) return false; - double x = theParams.X(), y = theParams.Y(), z = theParams.Z(); - double x1 = 1. - x, y1 = 1. - y, z1 = 1. - z; + const double x = theParams.X(), y = theParams.Y(), z = theParams.Z(); + const double x1 = 1. - x, y1 = 1. - y, z1 = 1. - z; const vector& p = thePointOnShape; thePoint = @@ -535,6 +596,7 @@ Standard_Boolean SMESH_Block::Values(const math_Vector& theXYZ, if ( mag > DBL_MIN ) dPi /= mag; drv[ iP - 1 ] = dPi; + // drv[ iP - 1 ] = dPi / 0.001; } for ( int iP = 0; iP < 3; iP++ ) { #if 1 @@ -579,7 +641,8 @@ Standard_Boolean SMESH_Block::Values(const math_Vector& theXYZ, bool SMESH_Block::computeParameters(const gp_Pnt& thePoint, gp_XYZ& theParams, - const gp_XYZ& theParamsHint) + const gp_XYZ& theParamsHint, + int theShapeID) { myPoint = thePoint.XYZ(); @@ -621,8 +684,11 @@ bool SMESH_Block::computeParameters(const gp_Pnt& thePoint, theParams = myParam; if ( myFaceIndex > 0 ) + { theParams.SetCoord( myFaceIndex, myFaceParam ); - + if ( distance() > loopTol ) + refineParametersOnFace( thePoint, theParams, theShapeID ); + } return true; } @@ -660,7 +726,7 @@ bool SMESH_Block::ComputeParameters(const gp_Pnt& thePoint, bool hasHint = ( 0 <= theParamsHint.X() && theParamsHint.X() <= 1 && 0 <= theParamsHint.Y() && theParamsHint.Y() <= 1 && - 0 <= theParamsHint.Y() && theParamsHint.Y() <= 1 ); + 0 <= theParamsHint.Z() && theParamsHint.Z() <= 1 ); if ( !hasHint && !myGridComputed ) { // define the first guess by thePoint projection on lines @@ -693,19 +759,20 @@ bool SMESH_Block::ComputeParameters(const gp_Pnt& thePoint, start.SetCoord( iParam, sumParam / 4.); } if ( needGrid ) { - // compute nodes of 3 x 3 x 3 grid + // compute nodes of 10 x 10 x 10 grid int iNode = 0; Bnd_Box box; - for ( double x = 0.25; x < 0.9; x += 0.25 ) - for ( double y = 0.25; y < 0.9; y += 0.25 ) - for ( double z = 0.25; z < 0.9; z += 0.25 ) { + for ( double x = 0.05; x < 1.; x += 0.1 ) + for ( double y = 0.05; y < 1.; y += 0.1 ) + for ( double z = 0.05; z < 1.; z += 0.1 ) { TxyzPair & prmPtn = my3x3x3GridNodes[ iNode++ ]; prmPtn.first.SetCoord( x, y, z ); ShellPoint( prmPtn.first, prmPtn.second ); box.Add( gp_Pnt( prmPtn.second )); } myGridComputed = true; - myTolerance = sqrt( box.SquareExtent() ) * 1e-5; + if ( myTolerance < 0 ) + myTolerance = sqrt( box.SquareExtent() ) * 1e-5; } } @@ -713,11 +780,17 @@ bool SMESH_Block::ComputeParameters(const gp_Pnt& thePoint, { start = theParamsHint; } - else if ( myGridComputed ) + if ( myGridComputed ) { double minDist = DBL_MAX; + if ( hasHint ) + { + gp_XYZ p; + if ( ShellPoint( start, p )) + minDist = thePoint.SquareDistance( p ); + } gp_XYZ* bestParam = 0; - for ( int iNode = 0; iNode < 27; iNode++ ) { + for ( int iNode = 0; iNode < 1000; iNode++ ) { TxyzPair & prmPtn = my3x3x3GridNodes[ iNode ]; double dist = ( thePoint.XYZ() - prmPtn.second ).SquareModulus(); if ( dist < minDist ) { @@ -725,7 +798,8 @@ bool SMESH_Block::ComputeParameters(const gp_Pnt& thePoint, bestParam = & prmPtn.first; } } - start = *bestParam; + if ( bestParam ) + start = *bestParam; } myFaceIndex = -1; @@ -763,7 +837,7 @@ bool SMESH_Block::ComputeParameters(const gp_Pnt& thePoint, if ( sqDist > sqDistance ) { // solution get worse if ( ++nbGetWorst > 2 ) - return computeParameters( thePoint, theParams, solution ); + return computeParameters( thePoint, theParams, solution, theShapeID ); } #ifdef DEBUG_PARAM_COMPUTE MESSAGE ( "PARAMS: ( " << params.X() <<" "<< params.Y() <<" "<< params.Z() <<" )" ); @@ -818,14 +892,449 @@ bool SMESH_Block::ComputeParameters(const gp_Pnt& thePoint, << " ------ NB IT: " << myNbIterations << ", SUM DIST: " << mySumDist ); #endif - theParams = solution; - if ( myFaceIndex > 0 ) theParams.SetCoord( myFaceIndex, myFaceParam ); + const double reachedDist = sqrt( sqDistance ); + // if ( reachedDist > 1000 * myTolerance && + // computeParameters( thePoint, theParams, solution ) && + // reachedDist > distance() ) + // return true; + + if ( reachedDist > 10 * myTolerance && + computeParameters( thePoint, theParams, solution, theShapeID ) && + reachedDist > distance() ) + return true; + + theParams = solution; + myValues[ SQUARE_DIST ] = sqDistance; + + if ( reachedDist > 10 * myTolerance && myFaceIndex > 0 ) + refineParametersOnFace( thePoint, theParams, theShapeID ); + return true; } +//================================================================================ +/*! + * \brief Find more precise solution + * \param [in] thePoint - the point + * \param [in,out] theParams - solution to precise + * \param [in] theFaceID - FACE ID + */ +//================================================================================ + +void SMESH_Block::refineParametersOnFace( const gp_Pnt& thePoint, + gp_XYZ& theParams, + int theFaceID ) +{ + // find UV of thePoint on the FACE + Standard_Real U,V; + + const TFace& tface = myFace[ theFaceID - ID_FirstF ]; + if ( !tface.Surface() ) return; + + Extrema_ExtPS extPS( thePoint, *tface.Surface(), + tface.Surface()->UResolution( myTolerance ), + tface.Surface()->VResolution( myTolerance )); + if ( !extPS.IsDone() || extPS.NbExt() < 1 ) + return; + + double minDist = 1e100; + for ( int i = 1; i <= extPS.NbExt(); ++i ) + if ( extPS.SquareDistance( i ) < minDist ) + { + minDist = extPS.SquareDistance( i ); + extPS.Point( i ).Parameter( U,V ); + } + if ( minDist > 100 * myTolerance * myTolerance ) + return; + + gp_XY uv(U,V); + if ( findUVByHalfDivision( thePoint, uv, tface, theParams)) + return; + + int nbGetWorstLimit = 20; + if ( findUVAround( thePoint, uv, tface, theParams, nbGetWorstLimit )) + return; + + double dist2, prevSolDist = distance(); + gp_XYZ sol = theParams; + for ( double delta = 1./10; delta > 0.001; delta /= 2.5, nbGetWorstLimit *= 2 ) + { + for ( double y = delta; y < 1.; y += delta ) + { + sol.SetCoord( tface.GetVInd(), y ); + for ( double x = delta; x < 1.; x += delta ) + { + sol.SetCoord( tface.GetUInd(), x ); + dist2 = thePoint.SquareDistance( tface.Point( sol )); + if ( dist2 < prevSolDist * prevSolDist ) + { + if ( findUVAround( thePoint, uv, tface, theParams, nbGetWorstLimit )) + return; + if ( distance() < 1000 * myTolerance ) + return; + prevSolDist = distance(); + } + } + } + } +} + +//================================================================================ +/*! + * \brief Finds parameters corresponding to a given UV of a given face using half-division + * \param [in] theUV - the UV to locate + * \param [in] tface - the face + * \param [in,out] theParams - the starting parameters to improve + * \return bool - \c true if found solution is within myTolerance + */ +//================================================================================ + +bool SMESH_Block::findUVByHalfDivision( const gp_Pnt& thePoint, + const gp_XY& theUV, + const SMESH_Block::TFace& tface, + gp_XYZ& theParams) +{ + int nbGetUV = 0; // just for statistics + + // find a range of parameters including the UV + + double xMin, xMax, yMin, yMax; + //#define _DEBUG_REFINE_ +#ifdef _DEBUG_REFINE_ + cout << "SMESH_Block::refineParametersOnFace(): dividing Starts at dist " << distance()<< endl; +#endif + double dx = 0.1, xSol = theParams.Coord( tface.GetUInd() ); + double dy = 0.1, ySol = theParams.Coord( tface.GetVInd() ); + gp_XYZ xXYZ( 0,0,0 ); xXYZ.SetCoord( tface.GetUInd(), 1 ); + gp_XYZ yXYZ( 0,0,0 ); yXYZ.SetCoord( tface.GetVInd(), 1 ); + gp_XYZ xy0,xy1,xy2,xy3; + bool isInQuad = false; + while ( !isInQuad ) + { + xMin = Max( 0., xSol - 0.5*dx ); xMax = Min( 1.0, xSol + 0.5*dx ); + yMin = Max( 0., ySol - 0.5*dy ); yMax = Min( 1.0, ySol + 0.5*dy ); + xy0.SetLinearForm( xMin, xXYZ, yMin, yXYZ ); + xy1.SetLinearForm( xMax, xXYZ, yMin, yXYZ ); + xy2.SetLinearForm( xMax, xXYZ, yMax, yXYZ ); + xy3.SetLinearForm( xMin, xXYZ, yMax, yXYZ ); + isInQuad = tface.IsUVInQuad( theUV, xy0,xy1,xy2,xy3 ); + nbGetUV += 4; + if ( !isInQuad ) + { + dx *= 1.2; + dy *= 1.2; + xSol = 0.5 * (xMax + xMin) ; + ySol = 0.5 * (yMax + yMin) ; + if ( xMin == 0. && yMin == 0. && xMax == 1. && yMax == 1. ) // avoid infinit loop + { +#ifdef _DEBUG_REFINE_ + cout << "SMESH_Block::refineParametersOnFace(): tface.IsUVInQuad() fails" << endl; + cout << " nbGetUV = " << nbGetUV << endl; +#endif + break; + } + } + } + + // refine solution using half-division technic + + gp_XYZ sol = theParams; + + const double paramTol = 0.001; + while ( dx > paramTol || dy > paramTol ) + { + // divide along X + bool xDivided = ( dx > paramTol ); + if ( xDivided ) + { + double xMid = 0.5 * ( xMin + xMax ); + gp_XYZ parMid1 = xMid * xXYZ + yMin * yXYZ; + gp_XYZ parMid2 = xMid * xXYZ + yMax * yXYZ; + nbGetUV += 4; + if ( tface.IsUVInQuad( theUV, xy0,parMid1,parMid2,xy3 )) + { + xMax = xMid; + xy1 = parMid1; xy2 = parMid2; + } + else if ( tface.IsUVInQuad( theUV, parMid1,xy1,xy2,parMid2 )) + { + nbGetUV += 4; + xMin = xMid; + xy0 = parMid1; xy3 = parMid2; + } + else + { + nbGetUV += 8; + xDivided = false; + } + dx = xMax - xMin; + } + // divide along Y + bool yDivided = ( dy > paramTol ); + if ( yDivided ) + { + double yMid = 0.5 * ( yMin + yMax ); + gp_XYZ parMid2 = xMax * xXYZ + yMid * yXYZ; + gp_XYZ parMid3 = xMin * xXYZ + yMid * yXYZ; + nbGetUV += 4; + if ( tface.IsUVInQuad( theUV, xy0,xy1,parMid2,parMid3 )) + { + yMax = yMid; + xy2 = parMid2; xy3 = parMid3; + } + else if ( tface.IsUVInQuad( theUV, parMid3,parMid2,xy2,xy3 )) + { + nbGetUV += 4; + yMin = yMid; + xy0 = parMid3; xy1 = parMid2; + } + else + { + nbGetUV += 8; + yDivided = false; + } + dy = yMax - yMin; + } + if ( !xDivided && !yDivided ) + { +#ifdef _DEBUG_REFINE_ + cout << "SMESH_Block::refineParametersOnFace(): nothing divided" << endl; + cout << " nbGetUV = " << nbGetUV << endl; +#endif + break; + } + + // evaluate reached distance to thePoint + sol.SetCoord( tface.GetUInd(), 0.5 * ( xMin + xMax )); + sol.SetCoord( tface.GetVInd(), 0.5 * ( yMin + yMax )); + if ( saveBetterSolution( sol, theParams, thePoint.SquareDistance( tface.Point( sol )))) + { +#ifdef _DEBUG_REFINE_ + cout << "SMESH_Block::refineParametersOnFace(): dividing suceeded" << endl; + cout << " nbGetUV = " << nbGetUV << endl; +#endif + return true; + } + } +#ifdef _DEBUG_REFINE_ + cout << "SMESH_Block::refineParametersOnFace(): dividing Ends at dist " << distance()<< endl; + cout << " nbGetUV = " << nbGetUV << endl; +#endif + + return false; +} + +//================================================================================ +/*! + * \brief Finds parameters corresponding to a given UV of a given face by searching + * around the starting solution + * \param [in] theUV - the UV to locate + * \param [in] tface - the face + * \param [in,out] theParams - the starting parameters to improve + * \param [in] nbGetWorstLimit - nb of steps from the starting solution w/o improvement + * to stop searching in this direction + * \return bool - \c true if found solution is within myTolerance + */ +//================================================================================ + +bool SMESH_Block::findUVAround( const gp_Pnt& thePoint, + const gp_XY& theUV, + const SMESH_Block::TFace& tface, + gp_XYZ& theParams, + int nbGetWorstLimit ) +{ +#ifdef _DEBUG_REFINE_ + cout << "SMESH_Block::refineParametersOnFace(): walk around Starts at dist " << distance()<< endl; + cout << " nbGetUV = " << (nbGetUV=0) << endl; +#endif + const double paramTol = 0.001; + const double dx = 0.01, dy = 0.01; + double xMin = theParams.Coord( tface.GetUInd() ), xMax; + double yMin = theParams.Coord( tface.GetVInd() ), yMax; + yMax = yMin; + if ( xMin + dx < 1. ) + xMax = xMin + dx; + else + xMax = 1, xMin = 1 - dx; + gp_XYZ sol = theParams; + sol.SetCoord( tface.GetUInd(), xMax ); + sol.SetCoord( tface.GetVInd(), yMax ); + //nbGetUV++; + if ( saveBetterSolution( sol, theParams, thePoint.SquareDistance( tface.Point( sol )))) + return true; + + int xMaxNbGetWorst = 0, xMinNbGetWorst = 0, yMaxNbGetWorst = 0, yMinNbGetWorst = 0; + double xMaxBestDist = 1e100, xMinBestDist = 1e100, yMaxBestDist = 1e100, yMinBestDist = 1e100; + double x, y, bestDist, dist; + while ( xMax - xMin < 1 || yMax - yMin < 1 ) + { + // walk along X + if ( yMin > 0. ) + { + bestDist = 1e100; + for ( x = Max(0.,xMin); x <= xMax+paramTol; x += dx ) + { + y = Max( 0., yMin - dy ); + sol.SetCoord( tface.GetUInd(), x ); + sol.SetCoord( tface.GetVInd(), y ); + //nbGetUV++; + dist = thePoint.SquareDistance( tface.Point( sol )); + bestDist = Min( dist, bestDist ); + if ( saveBetterSolution( sol, theParams, dist )) + return true; + sol.SetCoord( tface.GetUInd(), Min( 1., x + 0.5*dx )); + sol.SetCoord( tface.GetVInd(), y + 0.5*dy ); + //nbGetUV++; + dist = thePoint.SquareDistance( tface.Point( sol )); + bestDist = Min( dist, bestDist ); + if ( saveBetterSolution( sol, theParams, dist )) + return true; + } + yMin = Max(0., yMin-dy ); + yMinNbGetWorst += ( yMinBestDist < bestDist ); + yMinBestDist = Min( yMinBestDist, bestDist ); + if ( yMinNbGetWorst > nbGetWorstLimit ) + yMin = 0; + } + if ( yMax < 1. ) + { + bestDist = 1e100; + for ( x = Max(0.,xMin); x <= xMax+paramTol; x += dx ) + { + y = Min( 1., yMax + dy ); + sol.SetCoord( tface.GetUInd(), x ); + sol.SetCoord( tface.GetVInd(), y ); + //nbGetUV++; + dist = thePoint.SquareDistance( tface.Point( sol )); + bestDist = Min( dist, bestDist ); + if ( saveBetterSolution( sol, theParams, dist )) + return true; + sol.SetCoord( tface.GetUInd(), Min( 1., x + 0.5*dx )); + sol.SetCoord( tface.GetVInd(), y - 0.5*dy ); + //nbGetUV++; + dist = thePoint.SquareDistance( tface.Point( sol )); + bestDist = Min( dist, bestDist ); + if ( saveBetterSolution( sol, theParams, dist )) + return true; + } + yMax = Min(1., yMax+dy ); + yMaxNbGetWorst += ( yMaxBestDist < bestDist ); + yMaxBestDist = Min( yMaxBestDist, bestDist ); + if ( yMaxNbGetWorst > nbGetWorstLimit ) + yMax = 1; + } + // walk along Y + if ( xMin > 0. ) + { + bestDist = 1e100; + for ( y = Max(0.,yMin); y <= yMax+paramTol; y += dy ) + { + x = Max( 0., xMin - dx ); + sol.SetCoord( tface.GetUInd(), x ); + sol.SetCoord( tface.GetVInd(), y ); + //nbGetUV++; + dist = thePoint.SquareDistance( tface.Point( sol )); + bestDist = Min( dist, bestDist ); + if ( saveBetterSolution( sol, theParams, dist )) + return true; + sol.SetCoord( tface.GetUInd(), x + 0.5*dx ); + sol.SetCoord( tface.GetVInd(), Min( 1., y + 0.5*dy )); + //nbGetUV++; + dist = thePoint.SquareDistance( tface.Point( sol )); + bestDist = Min( dist, bestDist ); + if ( saveBetterSolution( sol, theParams, dist )) + return true; + } + xMin = Max(0., xMin-dx ); + xMinNbGetWorst += ( xMinBestDist < bestDist ); + xMinBestDist = Min( xMinBestDist, bestDist ); + if ( xMinNbGetWorst > nbGetWorstLimit ) + xMin = 0; + } + if ( xMax < 1. ) + { + bestDist = 1e100; + for ( y = Max(0.,yMin); y <= yMax+paramTol; y += dy ) + { + x = Min( 1., xMax + dx ); + sol.SetCoord( tface.GetUInd(), x ); + sol.SetCoord( tface.GetVInd(), y ); + //nbGetUV++; + dist = thePoint.SquareDistance( tface.Point( sol )); + bestDist = Min( dist, bestDist ); + if ( saveBetterSolution( sol, theParams, dist )) + return true; + sol.SetCoord( tface.GetUInd(), x - 0.5*dx); + sol.SetCoord( tface.GetVInd(), Min( 1., y + 0.5*dy )); + //nbGetUV++; + dist = thePoint.SquareDistance( tface.Point( sol )); + bestDist = Min( dist, bestDist ); + if ( saveBetterSolution( sol, theParams, dist )) + return true; + } + xMax = Min(1., xMax+dx ); + xMaxNbGetWorst += ( xMaxBestDist < bestDist ); + xMaxBestDist = Min( xMaxBestDist, bestDist ); + if ( xMaxNbGetWorst > nbGetWorstLimit ) + xMax = 1; + } + } +#ifdef _DEBUG_REFINE_ + cout << "SMESH_Block::refineParametersOnFace(): walk around failed at dist " << distance()<< endl; + //cout << " nbGetUV = " << nbGetUV << endl; +#endif + + return false; +} + +//================================================================================ +/*! + * \brief Store a solution if it's better than a previous one + * \param [in] theNewParams - a new solution + * \param [out] theParams - the parameters to store solution in + * \param [in] sqDistance - a square distance reached at theNewParams + * \return bool - true if the reached distance is within the tolerance + */ +//================================================================================ + +bool SMESH_Block::saveBetterSolution( const gp_XYZ& theNewParams, + gp_XYZ& theParams, + double sqDistance ) +{ + if ( myValues[ SQUARE_DIST ] > sqDistance ) + { + myValues[ SQUARE_DIST ] = sqDistance; + theParams = theNewParams; + if ( distance() <= myTolerance ) + return true; + } + return false; +} + +//======================================================================= +//function : SetTolerance +//purpose : set tolerance for ComputeParameters() +//======================================================================= + +void SMESH_Block::SetTolerance(const double tol) +{ + if ( tol > 0 ) + myTolerance = tol; +} + +//======================================================================= +//function : IsToleranceReached +//purpose : return true if solution found by ComputeParameters() is within the tolerance +//======================================================================= + +bool SMESH_Block::IsToleranceReached() const +{ + return distance() < myTolerance; +} + //======================================================================= //function : VertexParameters //purpose : return parameters of a vertex given by TShapeID @@ -952,29 +1461,45 @@ int SMESH_Block::GetShapeIDByParams ( const gp_XYZ& theCoord ) return id + 1; // shape ids start at 1 } -//======================================================================= -//function : GetOrderedEdges -//purpose : return nb wires and a list of oredered edges -//======================================================================= +//================================================================================ +/*! + * \brief Return number of wires and a list of oredered edges. + * \param theFace - the face to process + * \param theEdges - all ordered edges of theFace (outer edges go first). + * \param theNbEdgesInWires - nb of edges (== nb of vertices in closed wire) in each wire + * \param theFirstVertex - the vertex of the outer wire to set first in the returned + * list ( theFirstVertex may be NULL ) + * \param theShapeAnalysisAlgo - if true, ShapeAnalysis::OuterWire() is used to find + * the outer wire else BRepTools::OuterWire() is used. + * \retval int - nb of wires + * + * Always try to set a seam edge first. + * BRepTools::OuterWire() fails e.g. in the case of issue 0020184, + * ShapeAnalysis::OuterWire() fails in the case of issue 0020452 + */ +//================================================================================ int SMESH_Block::GetOrderedEdges (const TopoDS_Face& theFace, - TopoDS_Vertex theFirstVertex, list< TopoDS_Edge >& theEdges, - list< int > & theNbVertexInWires) + list< int > & theNbEdgesInWires, + TopoDS_Vertex theFirstVertex, + const bool theShapeAnalysisAlgo) { // put wires in a list, so that an outer wire comes first list aWireList; - //TopoDS_Wire anOuterWire = BRepTools::OuterWire( theFace ); ### issue 0020184 - TopoDS_Wire anOuterWire = ShapeAnalysis::OuterWire( theFace ); - //aWireList.push_back( anOuterWire ); ### issue 0020184 + TopoDS_Wire anOuterWire = + theShapeAnalysisAlgo ? ShapeAnalysis::OuterWire( theFace ) : BRepTools::OuterWire( theFace ); for ( TopoDS_Iterator wIt (theFace); wIt.More(); wIt.Next() ) - if ( !anOuterWire.IsSame( wIt.Value() )) - aWireList.push_back( TopoDS::Wire( wIt.Value() )); - else - aWireList.push_front( TopoDS::Wire( wIt.Value() ));// ### issue 0020184 + if ( wIt.Value().ShapeType() == TopAbs_WIRE ) // it can be internal vertex! + { + if ( !anOuterWire.IsSame( wIt.Value() )) + aWireList.push_back( TopoDS::Wire( wIt.Value() )); + else + aWireList.push_front( TopoDS::Wire( wIt.Value() )); + } // loop on edges of wires - theNbVertexInWires.clear(); + theNbEdgesInWires.clear(); list::iterator wlIt = aWireList.begin(); for ( ; wlIt != aWireList.end(); wlIt++ ) { @@ -983,10 +1508,16 @@ int SMESH_Block::GetOrderedEdges (const TopoDS_Face& theFace, for ( iE = 0; wExp.More(); wExp.Next(), iE++ ) { TopoDS_Edge edge = wExp.Current(); - edge = TopoDS::Edge( edge.Oriented( wExp.Orientation() )); + // commented for issue 0020557, other related ones: 0020526, PAL19080 + // edge = TopoDS::Edge( edge.Oriented( wExp.Orientation() )); theEdges.push_back( edge ); } - theNbVertexInWires.push_back( iE ); + if ( iE == 0 ) // wExp returns nothing if e.g. the wire contains one internal edge + { // Issue 0020676 + for ( TopoDS_Iterator e( *wlIt ); e.More(); e.Next(), ++iE ) + theEdges.push_back( TopoDS::Edge( e.Value() )); + } + theNbEdgesInWires.push_back( iE ); iE = 0; if ( wlIt == aWireList.begin() && theEdges.size() > 1 ) { // the outer wire // orient closed edges @@ -1024,7 +1555,7 @@ int SMESH_Block::GetOrderedEdges (const TopoDS_Face& theFace, theEdges.splice(theEdges.end(), theEdges, theEdges.begin(), ++theEdges.begin()); TopExp::Vertices( theEdges.front(), vv[0], vv[1], true ); - if ( iE++ > theNbVertexInWires.back() ) { + if ( iE++ > theNbEdgesInWires.back() ) { #ifdef _DEBUG_ gp_Pnt p = BRep_Tool::Pnt( theFirstVertex ); MESSAGE ( " : Warning : vertex "<< theFirstVertex.TShape().operator->() @@ -1268,8 +1799,11 @@ bool SMESH_Block::FindBlockShapes(const TopoDS_Shell& theShell, for ( ; eIt.More(); eIt.Next() ) { const TopoDS_Edge& e = TopoDS::Edge( eIt.Value() ); TopoDS_Vertex v = TopExp::FirstVertex( e ); - if ( v.IsSame( V000 )) + if ( v.IsSame( V000 )) { v = TopExp::LastVertex( e ); + if ( v.IsSame( V000 )) + return false; + } val = dir001 * gp_Vec( p000, BRep_Tool::Pnt( v )).Normalized(); if ( val > maxVal ) { V001 = v; @@ -1329,7 +1863,7 @@ bool SMESH_Block::FindBlockShapes(const TopoDS_Shell& theShell, // find bottom edges and veritices list< TopoDS_Edge > eList; list< int > nbVertexInWires; - GetOrderedEdges( TopoDS::Face( Fxy0 ), TopoDS::Vertex( V000 ), eList, nbVertexInWires ); + GetOrderedEdges( TopoDS::Face( Fxy0 ), eList, nbVertexInWires, TopoDS::Vertex( V000 ) ); if ( nbVertexInWires.size() != 1 || nbVertexInWires.front() != 4 ) { MESSAGE(" LoadBlockShapes() error "); return false; @@ -1351,7 +1885,7 @@ bool SMESH_Block::FindBlockShapes(const TopoDS_Shell& theShell, // find top edges and veritices eList.clear(); - GetOrderedEdges( TopoDS::Face( Fxy1 ), TopoDS::Vertex( V001 ), eList, nbVertexInWires ); + GetOrderedEdges( TopoDS::Face( Fxy1 ), eList, nbVertexInWires, TopoDS::Vertex( V001 ) ); if ( nbVertexInWires.size() != 1 || nbVertexInWires.front() != 4 ) { MESSAGE(" LoadBlockShapes() error "); return false; @@ -1482,7 +2016,7 @@ bool SMESH_Block::FindBlockShapes(const TopoDS_Shell& theShell, //================================================================================ /*! * \brief Initialize block geometry with shapes from theShapeIDMap - * \param theShapeIDMap - map of block subshapes + * \param theShapeIDMap - map of block sub-shapes * \retval bool - is a success */ //================================================================================ @@ -1531,11 +2065,11 @@ bool SMESH_Block::LoadBlockShapes(const TopTools_IndexedMapOfOrientedShape& theS * \brief Load face geometry * \param theFace - face * \param theFaceID - face in-block ID - * \param theShapeIDMap - map of block subshapes + * \param theShapeIDMap - map of block sub-shapes * \retval bool - is a success * * It is enough to compute params or coordinates on the face. - * Face subshapes must be loaded into theShapeIDMap before + * Face sub-shapes must be loaded into theShapeIDMap before */ //================================================================================ @@ -1567,7 +2101,7 @@ bool SMESH_Block::LoadFace(const TopoDS_Face& theFace, * \brief/ Insert theShape into theShapeIDMap with theShapeID * \param theShape - shape to insert * \param theShapeID - shape in-block ID - * \param theShapeIDMap - map of block subshapes + * \param theShapeIDMap - map of block sub-shapes */ //================================================================================ diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Gen.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Gen.cpp index 7effac165bb8..4c264d50ae52 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Gen.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Gen.cpp @@ -1,111 +1,107 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : SMESH_Gen.cxx // Author : Paul RASCLE, EDF // Module : SMESH +// + +//#define CHRONODEF #include "SMESH_Gen.hxx" -#include "SMESH_subMesh.hxx" -#include "SMESH_HypoFilter.hxx" -#include "SMESHDS_Document.hxx" + +#include "SMDS_Mesh.hxx" #include "SMDS_MeshElement.hxx" #include "SMDS_MeshNode.hxx" +#include "SMESHDS_Document.hxx" +#include "SMESH_HypoFilter.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_subMesh.hxx" #include "utilities.h" -//#include "OpUtil.hxx" -#include "SMESH_ExceptHandlers.hxx" +#include "OpUtil.hxx" +#include "Utils_ExceptHandlers.hxx" + +#include +#include + +#include "memoire.h" -#include -#include -#include -#include +#ifdef WIN32 + #include +#endif using namespace std; +//#include + + //============================================================================= /*! - * default constructor: + * Constructor */ //============================================================================= SMESH_Gen::SMESH_Gen() { - //MESSAGE("SMESH_Gen::SMESH_Gen"); - _localId = 0; - _hypId = 0; - _segmentation = 10; + MESSAGE("SMESH_Gen::SMESH_Gen"); + _localId = 0; + _hypId = 0; + _segmentation = _nbSegments = 10; + SMDS_Mesh::_meshList.clear(); + MESSAGE(SMDS_Mesh::_meshList.size()); + _compute_canceled = false; + //vtkDebugLeaks::SetExitError(0); } //============================================================================= /*! - * + * Destructor */ //============================================================================= SMESH_Gen::~SMESH_Gen() { - //MESSAGE("SMESH_Gen::~SMESH_Gen"); + MESSAGE("SMESH_Gen::~SMESH_Gen"); + std::map < int, StudyContextStruct * >::iterator i_sc = _mapStudyContext.begin(); + for ( ; i_sc != _mapStudyContext.end(); ++i_sc ) + { + delete i_sc->second->myDocument; + delete i_sc->second; + } } //============================================================================= /*! - * - */ -//============================================================================= - -/*SMESH_Hypothesis *SMESH_Gen::CreateHypothesis(const char *anHyp, int studyId) - throw(SALOME_Exception) -{ - - MESSAGE("CreateHypothesis("<GetID(); - myStudyContext->mapHypothesis[hypId] = myHypothesis; - SCRUTE(studyId); - SCRUTE(hypId); - - // store hypothesis in SMESHDS document - - myStudyContext->myDocument->AddHypothesis(myHypothesis); - return myHypothesis; -}*/ - -//============================================================================= -/*! - * + * Creates a mesh in a study. + * if (theIsEmbeddedMode) { mesh modification commands are not logged } */ //============================================================================= SMESH_Mesh* SMESH_Gen::CreateMesh(int theStudyId, bool theIsEmbeddedMode) - throw(SMESH_Exception) + throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); MESSAGE("SMESH_Gen::CreateMesh"); // Get studyContext, create it if it does'nt exist, with a SMESHDS_Document @@ -113,28 +109,30 @@ SMESH_Mesh* SMESH_Gen::CreateMesh(int theStudyId, bool theIsEmbeddedMode) // create a new SMESH_mesh object SMESH_Mesh *aMesh = new SMESH_Mesh(_localId++, - theStudyId, - this, - theIsEmbeddedMode, - aStudyContext->myDocument); - aStudyContext->mapMesh[_localId] = aMesh; + theStudyId, + this, + theIsEmbeddedMode, + aStudyContext->myDocument); + aStudyContext->mapMesh[_localId-1] = aMesh; return aMesh; } //============================================================================= -/*! +/* * Compute a mesh */ //============================================================================= bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, - const bool anUpward, - const ::MeshDimension aDim, - TSetOfInt* aShapesId) + const bool aShapeOnly /*=false*/, + const bool anUpward /*=false*/, + const ::MeshDimension aDim /*=::MeshDim_3D*/, + TSetOfInt* aShapesId /*=0*/) { MESSAGE("SMESH_Gen::Compute"); + MEMOSTAT; bool ret = true; @@ -142,52 +140,81 @@ bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, const bool includeSelf = true; const bool complexShapeFirst = true; + const int globalAlgoDim = 100; SMESH_subMeshIteratorPtr smIt; - if ( anUpward ) // is called from below code here + // Fix of Issue 22150. Due to !BLSURF->OnlyUnaryInput(), BLSURF computes edges + // that must be computed by Projection 1D-2D when Projection asks to compute + // one face only. + SMESH_subMesh::compute_event computeEvent = + aShapeOnly ? SMESH_subMesh::COMPUTE_SUBMESH : SMESH_subMesh::COMPUTE; + + if ( anUpward ) // is called from the below code in this method { - // ----------------------------------------------- - // mesh all the subshapes starting from vertices - // ----------------------------------------------- + // =============================================== + // Mesh all the sub-shapes starting from vertices + // =============================================== + smIt = sm->getDependsOnIterator(includeSelf, !complexShapeFirst); while ( smIt->more() ) { SMESH_subMesh* smToCompute = smIt->next(); // do not mesh vertices of a pseudo shape - const TopAbs_ShapeEnum aShType = smToCompute->GetSubShape().ShapeType(); - if ( !aMesh.HasShapeToMesh() && aShType == TopAbs_VERTEX ) + const TopoDS_Shape& shape = smToCompute->GetSubShape(); + const TopAbs_ShapeEnum shapeType = shape.ShapeType(); + if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX ) continue; // check for preview dimension limitations - if ( aShapesId && GetShapeDim( aShType ) > (int)aDim ) + if ( aShapesId && GetShapeDim( shapeType ) > (int)aDim ) { - // clear compute state to not show previous compute errors + // clear compute state not to show previous compute errors // if preview invoked less dimension less than previous smToCompute->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); - continue; + continue; } if (smToCompute->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE) - smToCompute->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + { + if (_compute_canceled) + return false; + setCurrentSubMesh( smToCompute ); + smToCompute->ComputeStateEngine( computeEvent ); + setCurrentSubMesh( NULL ); + } - // we check all the submeshes here and detect if any of them failed to compute - if (smToCompute->GetComputeState() == SMESH_subMesh::FAILED_TO_COMPUTE) + // we check all the sub-meshes here and detect if any of them failed to compute + if (smToCompute->GetComputeState() == SMESH_subMesh::FAILED_TO_COMPUTE && + ( shapeType != TopAbs_EDGE || !SMESH_Algo::isDegenerated( TopoDS::Edge( shape )))) ret = false; else if ( aShapesId ) - aShapesId->insert( smToCompute->GetId() ); + aShapesId->insert( smToCompute->GetId() ); } + //aMesh.GetMeshDS()->Modified(); return ret; } else { - // ----------------------------------------------------------------- - // apply algos that DO NOT require descretized boundaries and DO NOT - // support submeshes, starting from the most complex shapes - // and collect submeshes with algos that DO support submeshes - // ----------------------------------------------------------------- - list< SMESH_subMesh* > smWithAlgoSupportingSubmeshes; + // ================================================================ + // Apply algos that do NOT require discreteized boundaries + // ("all-dimensional") and do NOT support sub-meshes, starting from + // the most complex shapes and collect sub-meshes with algos that + // DO support sub-meshes + // ================================================================ + + list< SMESH_subMesh* > smWithAlgoSupportingSubmeshes[4]; // for each dim + + // map to sort sm with same dim algos according to dim of + // the shape the algo assigned to (issue 0021217). + // Other issues influenced the algo applying order: + // 21406, 21556, 21893, 20206 + multimap< int, SMESH_subMesh* > shDim2sm; + multimap< int, SMESH_subMesh* >::reverse_iterator shDim2smIt; + TopoDS_Shape algoShape; + int prevShapeDim = -1, aShapeDim; + smIt = sm->getDependsOnIterator(includeSelf, complexShapeFirst); while ( smIt->more() ) { @@ -196,97 +223,374 @@ bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, continue; const TopoDS_Shape& aSubShape = smToCompute->GetSubShape(); - const int aShapeDim = GetShapeDim( aSubShape ); + aShapeDim = GetShapeDim( aSubShape ); if ( aShapeDim < 1 ) break; // check for preview dimension limitations if ( aShapesId && aShapeDim > (int)aDim ) - continue; + continue; - SMESH_Algo* algo = GetAlgo( aMesh, aSubShape ); - if ( algo && !algo->NeedDescretBoundary() ) + SMESH_Algo* algo = GetAlgo( smToCompute, &algoShape ); + if ( algo && !algo->NeedDiscreteBoundary() ) { if ( algo->SupportSubmeshes() ) - smWithAlgoSupportingSubmeshes.push_back( smToCompute ); - else - { - smToCompute->ComputeStateEngine( SMESH_subMesh::COMPUTE ); - if ( aShapesId ) - aShapesId->insert( smToCompute->GetId() ); - } + { + // reload sub-meshes from shDim2sm into smWithAlgoSupportingSubmeshes + // so that more local algos to go first + if ( prevShapeDim != aShapeDim ) + { + prevShapeDim = aShapeDim; + for ( shDim2smIt = shDim2sm.rbegin(); shDim2smIt != shDim2sm.rend(); ++shDim2smIt ) + if ( shDim2smIt->first == globalAlgoDim ) + smWithAlgoSupportingSubmeshes[ aShapeDim ].push_back( shDim2smIt->second ); + else + smWithAlgoSupportingSubmeshes[ aShapeDim ].push_front( shDim2smIt->second ); + shDim2sm.clear(); + } + // add smToCompute to shDim2sm map + if ( algoShape.IsSame( aMesh.GetShapeToMesh() )) + { + aShapeDim = globalAlgoDim; // to compute last + } + else + { + aShapeDim = GetShapeDim( algoShape ); + if ( algoShape.ShapeType() == TopAbs_COMPOUND ) + { + TopoDS_Iterator it( algoShape ); + aShapeDim += GetShapeDim( it.Value() ); + } + } + shDim2sm.insert( make_pair( aShapeDim, smToCompute )); + } + else // Compute w/o support of sub-meshes + { + if (_compute_canceled) + return false; + setCurrentSubMesh( smToCompute ); + smToCompute->ComputeStateEngine( computeEvent ); + setCurrentSubMesh( NULL ); + if ( aShapesId ) + aShapesId->insert( smToCompute->GetId() ); + } + } + } + // reload sub-meshes from shDim2sm into smWithAlgoSupportingSubmeshes + for ( shDim2smIt = shDim2sm.rbegin(); shDim2smIt != shDim2sm.rend(); ++shDim2smIt ) + if ( shDim2smIt->first == globalAlgoDim ) + smWithAlgoSupportingSubmeshes[3].push_back( shDim2smIt->second ); + else + smWithAlgoSupportingSubmeshes[0].push_front( shDim2smIt->second ); + + // ====================================================== + // Apply all-dimensional algorithms supporing sub-meshes + // ====================================================== + + std::vector< SMESH_subMesh* > smVec; + for ( aShapeDim = 0; aShapeDim < 4; ++aShapeDim ) + { + // ------------------------------------------------ + // sort list of sub-meshes according to mesh order + // ------------------------------------------------ + smVec.assign( smWithAlgoSupportingSubmeshes[ aShapeDim ].begin(), + smWithAlgoSupportingSubmeshes[ aShapeDim ].end() ); + aMesh.SortByMeshOrder( smVec ); + + // ------------------------------------------------------------ + // compute sub-meshes with local uni-dimensional algos under + // sub-meshes with all-dimensional algos + // ------------------------------------------------------------ + // start from lower shapes + for ( size_t i = 0; i < smVec.size(); ++i ) + { + sm = smVec[i]; + + // get a shape the algo is assigned to + if ( !GetAlgo( sm, & algoShape )) + continue; // strange... + + // look for more local algos + smIt = sm->getDependsOnIterator(!includeSelf, !complexShapeFirst); + while ( smIt->more() ) + { + SMESH_subMesh* smToCompute = smIt->next(); + + const TopoDS_Shape& aSubShape = smToCompute->GetSubShape(); + const int aShapeDim = GetShapeDim( aSubShape ); + //if ( aSubShape.ShapeType() == TopAbs_VERTEX ) continue; + if ( aShapeDim < 1 ) continue; + + // check for preview dimension limitations + if ( aShapesId && GetShapeDim( aSubShape.ShapeType() ) > (int)aDim ) + continue; + + SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() ); + filter + .And( SMESH_HypoFilter::IsApplicableTo( aSubShape )) + .And( SMESH_HypoFilter::IsMoreLocalThan( algoShape, aMesh )); + + if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( smToCompute, filter, true)) + { + if ( ! subAlgo->NeedDiscreteBoundary() ) continue; + SMESH_Hypothesis::Hypothesis_Status status; + if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status )) + // mesh a lower smToCompute starting from vertices + Compute( aMesh, aSubShape, aShapeOnly, /*anUpward=*/true, aDim, aShapesId ); + } + } } + // -------------------------------- + // apply the all-dimensional algos + // -------------------------------- + for ( size_t i = 0; i < smVec.size(); ++i ) + { + sm = smVec[i]; + if ( sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE) + { + const TopAbs_ShapeEnum shapeType = sm->GetSubShape().ShapeType(); + // check for preview dimension limitations + if ( aShapesId && GetShapeDim( shapeType ) > (int)aDim ) + continue; + + if (_compute_canceled) + return false; + setCurrentSubMesh( sm ); + sm->ComputeStateEngine( computeEvent ); + setCurrentSubMesh( NULL ); + if ( aShapesId ) + aShapesId->insert( sm->GetId() ); + } + } + } // loop on shape dimensions + + // ----------------------------------------------- + // mesh the rest sub-shapes starting from vertices + // ----------------------------------------------- + ret = Compute( aMesh, aShape, aShapeOnly, /*anUpward=*/true, aDim, aShapesId ); + } + + MESSAGE( "VSR - SMESH_Gen::Compute() finished, OK = " << ret); + MEMOSTAT; + + SMESHDS_Mesh *myMesh = aMesh.GetMeshDS(); + MESSAGE("*** compactMesh after compute"); + myMesh->compactMesh(); + + // fix quadratic mesh by bending iternal links near concave boundary + if ( aShape.IsSame( aMesh.GetShapeToMesh() ) && + !aShapesId && // not preview + ret ) // everything is OK + { + SMESH_MesherHelper aHelper( aMesh ); + if ( aHelper.IsQuadraticMesh() != SMESH_MesherHelper::LINEAR ) + { + aHelper.FixQuadraticElements( sm->GetComputeError() ); } + } + return ret; +} + +//============================================================================= +/*! + * Prepare Compute a mesh + */ +//============================================================================= +void SMESH_Gen::PrepareCompute(SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape) +{ + _compute_canceled = false; + resetCurrentSubMesh(); +} + +//============================================================================= +/*! + * Cancel Compute a mesh + */ +//============================================================================= +void SMESH_Gen::CancelCompute(SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape) +{ + _compute_canceled = true; + if ( const SMESH_subMesh* sm = GetCurrentSubMesh() ) + { + const_cast< SMESH_subMesh* >( sm )->ComputeStateEngine( SMESH_subMesh::COMPUTE_CANCELED ); + } + resetCurrentSubMesh(); +} + +//================================================================================ +/*! + * \brief Returns a sub-mesh being currently computed + */ +//================================================================================ + +const SMESH_subMesh* SMESH_Gen::GetCurrentSubMesh() const +{ + return _sm_current.empty() ? 0 : _sm_current.back(); +} + +//================================================================================ +/*! + * \brief Sets a sub-mesh being currently computed. + * + * An algorithm can call Compute() for a sub-shape, hence we keep a stack of sub-meshes + */ +//================================================================================ + +void SMESH_Gen::setCurrentSubMesh(SMESH_subMesh* sm) +{ + if ( sm ) + _sm_current.push_back( sm ); + + else if ( !_sm_current.empty() ) + _sm_current.pop_back(); +} + +void SMESH_Gen::resetCurrentSubMesh() +{ + _sm_current.clear(); +} + +//============================================================================= +/*! + * Evaluate a mesh + */ +//============================================================================= + +bool SMESH_Gen::Evaluate(SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap, + const bool anUpward, + TSetOfInt* aShapesId) +{ + MESSAGE("SMESH_Gen::Evaluate"); + + bool ret = true; + + SMESH_subMesh *sm = aMesh.GetSubMesh(aShape); + + const bool includeSelf = true; + const bool complexShapeFirst = true; + SMESH_subMeshIteratorPtr smIt; + + if ( anUpward ) { // is called from below code here + // ----------------------------------------------- + // mesh all the sub-shapes starting from vertices + // ----------------------------------------------- + smIt = sm->getDependsOnIterator(includeSelf, !complexShapeFirst); + while ( smIt->more() ) { + SMESH_subMesh* smToCompute = smIt->next(); + + // do not mesh vertices of a pseudo shape + const TopAbs_ShapeEnum shapeType = smToCompute->GetSubShape().ShapeType(); + //if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX ) + // continue; + if ( !aMesh.HasShapeToMesh() ) { + if( shapeType == TopAbs_VERTEX || shapeType == TopAbs_WIRE || + shapeType == TopAbs_SHELL ) + continue; + } + + smToCompute->Evaluate(aResMap); + if( aShapesId ) + aShapesId->insert( smToCompute->GetId() ); + } + return ret; + } + else { + // ----------------------------------------------------------------- + // apply algos that DO NOT require Discreteized boundaries and DO NOT + // support sub-meshes, starting from the most complex shapes + // and collect sub-meshes with algos that DO support sub-meshes + // ----------------------------------------------------------------- + list< SMESH_subMesh* > smWithAlgoSupportingSubmeshes; + smIt = sm->getDependsOnIterator(includeSelf, complexShapeFirst); + while ( smIt->more() ) { + SMESH_subMesh* smToCompute = smIt->next(); + const TopoDS_Shape& aSubShape = smToCompute->GetSubShape(); + const int aShapeDim = GetShapeDim( aSubShape ); + if ( aShapeDim < 1 ) break; + + SMESH_Algo* algo = GetAlgo( smToCompute ); + if ( algo && !algo->NeedDiscreteBoundary() ) { + if ( algo->SupportSubmeshes() ) { + smWithAlgoSupportingSubmeshes.push_front( smToCompute ); + } + else { + smToCompute->Evaluate(aResMap); + if ( aShapesId ) + aShapesId->insert( smToCompute->GetId() ); + } + } + } + // ------------------------------------------------------------ - // compute submeshes under shapes with algos that DO NOT require - // descretized boundaries and DO support submeshes + // sort list of meshes according to mesh order + // ------------------------------------------------------------ + std::vector< SMESH_subMesh* > smVec( smWithAlgoSupportingSubmeshes.begin(), + smWithAlgoSupportingSubmeshes.end() ); + aMesh.SortByMeshOrder( smVec ); + + // ------------------------------------------------------------ + // compute sub-meshes under shapes with algos that DO NOT require + // Discreteized boundaries and DO support sub-meshes // ------------------------------------------------------------ - list< SMESH_subMesh* >::reverse_iterator subIt, subEnd; - subIt = smWithAlgoSupportingSubmeshes.rbegin(); - subEnd = smWithAlgoSupportingSubmeshes.rend(); // start from lower shapes - for ( ; subIt != subEnd; ++subIt ) + for ( size_t i = 0; i < smVec.size(); ++i ) { - sm = *subIt; + sm = smVec[i]; // get a shape the algo is assigned to TopoDS_Shape algoShape; - if ( !GetAlgo( aMesh, sm->GetSubShape(), & algoShape )) + if ( !GetAlgo( sm, & algoShape )) continue; // strange... // look for more local algos smIt = sm->getDependsOnIterator(!includeSelf, !complexShapeFirst); - while ( smIt->more() ) - { + while ( smIt->more() ) { SMESH_subMesh* smToCompute = smIt->next(); const TopoDS_Shape& aSubShape = smToCompute->GetSubShape(); - const int aShapeDim = GetShapeDim( aSubShape ); - //if ( aSubShape.ShapeType() == TopAbs_VERTEX ) continue; - if ( aShapeDim < 1 ) continue; - - // check for preview dimension limitations - if ( aShapesId && GetShapeDim( aSubShape.ShapeType() ) > (int)aDim ) - continue; - + const int aShapeDim = GetShapeDim( aSubShape ); + if ( aShapeDim < 1 ) continue; + SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() ); filter .And( SMESH_HypoFilter::IsApplicableTo( aSubShape )) - .And( SMESH_HypoFilter::IsMoreLocalThan( algoShape )); + .And( SMESH_HypoFilter::IsMoreLocalThan( algoShape, aMesh )); - if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( aSubShape, filter, true )) { + if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( smToCompute, filter, true )) + { + if ( ! subAlgo->NeedDiscreteBoundary() ) continue; SMESH_Hypothesis::Hypothesis_Status status; if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status )) // mesh a lower smToCompute starting from vertices - Compute( aMesh, aSubShape, /*anUpward=*/true, aDim, aShapesId ); + Evaluate( aMesh, aSubShape, aResMap, /*anUpward=*/true, aShapesId ); } } } // ---------------------------------------------------------- - // apply the algos that do not require descretized boundaries + // apply the algos that do not require Discreteized boundaries // ---------------------------------------------------------- - for ( subIt = smWithAlgoSupportingSubmeshes.rbegin(); subIt != subEnd; ++subIt ) - if ( sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE) - { - const TopAbs_ShapeEnum aShType = sm->GetSubShape().ShapeType(); - // check for preview dimension limitations - if ( aShapesId && GetShapeDim( aShType ) > (int)aDim ) - continue; - - sm->ComputeStateEngine( SMESH_subMesh::COMPUTE ); - if ( aShapesId ) - aShapesId->insert( sm->GetId() ); - } + for ( size_t i = 0; i < smVec.size(); ++i ) + { + sm = smVec[i]; + sm->Evaluate(aResMap); + if ( aShapesId ) + aShapesId->insert( sm->GetId() ); + } // ----------------------------------------------- - // mesh the rest subshapes starting from vertices + // mesh the rest sub-shapes starting from vertices // ----------------------------------------------- - ret = Compute( aMesh, aShape, /*anUpward=*/true, aDim, aShapesId ); + ret = Evaluate( aMesh, aShape, aResMap, /*anUpward=*/true, aShapesId ); } - MESSAGE( "VSR - SMESH_Gen::Compute() finished, OK = " << ret); + MESSAGE( "VSR - SMESH_Gen::Evaluate() finished, OK = " << ret); return ret; } + //======================================================================= //function : checkConformIgnoredAlgos //purpose : @@ -297,7 +601,7 @@ static bool checkConformIgnoredAlgos(SMESH_Mesh& aMesh, const SMESH_Algo* aGlobIgnoAlgo, const SMESH_Algo* aLocIgnoAlgo, bool & checkConform, - map& aCheckedMap, + set& aCheckedMap, list< SMESH_Gen::TAlgoStateError > & theErrors) { ASSERT( aSubMesh ); @@ -321,23 +625,29 @@ static bool checkConformIgnoredAlgos(SMESH_Mesh& aMesh, if ( aLocIgnoAlgo ) // algo is hidden by a local algo of upper dim { + theErrors.push_back( SMESH_Gen::TAlgoStateError() ); + theErrors.back().Set( SMESH_Hypothesis::HYP_HIDDEN_ALGO, algo, false ); INFOS( "Local <" << algo->GetName() << "> is hidden by local <" << aLocIgnoAlgo->GetName() << ">"); } else { - bool isGlobal = (aMesh.IsMainShape( aSubMesh->GetSubShape() )); - int dim = algo->GetDim(); + bool isGlobal = (aMesh.IsMainShape( aSubMesh->GetSubShape() )); + int dim = algo->GetDim(); int aMaxGlobIgnoDim = ( aGlobIgnoAlgo ? aGlobIgnoAlgo->GetDim() : -1 ); + bool isNeededDim = ( aGlobIgnoAlgo ? aGlobIgnoAlgo->NeedLowerHyps( dim ) : false ); - if ( dim < aMaxGlobIgnoDim ) + if (( dim < aMaxGlobIgnoDim && !isNeededDim ) && + ( isGlobal || !aGlobIgnoAlgo->SupportSubmeshes() )) { // algo is hidden by a global algo + theErrors.push_back( SMESH_Gen::TAlgoStateError() ); + theErrors.back().Set( SMESH_Hypothesis::HYP_HIDDEN_ALGO, algo, true ); INFOS( ( isGlobal ? "Global" : "Local" ) << " <" << algo->GetName() << "> is hidden by global <" << aGlobIgnoAlgo->GetName() << ">"); } - else if ( !algo->NeedDescretBoundary() && !isGlobal) + else if ( !algo->NeedDiscreteBoundary() && !isGlobal) { // local algo is not hidden and hides algos on sub-shapes if (checkConform && !aSubMesh->IsConform( algo )) @@ -351,20 +661,18 @@ static bool checkConformIgnoredAlgos(SMESH_Mesh& aMesh, theErrors.back().Set( SMESH_Hypothesis::HYP_NOTCONFORM, algo, false ); } - // sub-algos will be hidden by a local - const map& smMap = aSubMesh->DependsOn(); - map::const_reverse_iterator revItSub; + // sub-algos will be hidden by a local if does not support sub-meshes + if ( algo->SupportSubmeshes() ) + algo = 0; + SMESH_subMeshIteratorPtr revItSub = + aSubMesh->getDependsOnIterator( /*includeSelf=*/false, /*complexShapeFirst=*/true); bool checkConform2 = false; - for ( revItSub = smMap.rbegin(); revItSub != smMap.rend(); revItSub++) + while ( revItSub->more() ) { - checkConformIgnoredAlgos (aMesh, (*revItSub).second, aGlobIgnoAlgo, + SMESH_subMesh* sm = revItSub->next(); + checkConformIgnoredAlgos (aMesh, sm, aGlobIgnoAlgo, algo, checkConform2, aCheckedMap, theErrors); - int key = (*revItSub).first; - SMESH_subMesh* sm = (*revItSub).second; - if ( aCheckedMap.find( key ) == aCheckedMap.end() ) - { - aCheckedMap[ key ] = sm; - } + aCheckedMap.insert( sm ); } } } @@ -385,10 +693,18 @@ static bool checkMissing(SMESH_Gen* aGen, const int aTopAlgoDim, bool* globalChecked, const bool checkNoAlgo, - map& aCheckedMap, + set& aCheckedMap, list< SMESH_Gen::TAlgoStateError > & theErrors) { - if ( aSubMesh->GetSubShape().ShapeType() == TopAbs_VERTEX) + switch ( aSubMesh->GetSubShape().ShapeType() ) + { + case TopAbs_EDGE: + case TopAbs_FACE: + case TopAbs_SOLID: break; // check this sub-mesh, it can be meshed + default: + return true; // not meshable sub-mesh + } + if ( aCheckedMap.count( aSubMesh )) return true; //MESSAGE("=====checkMissing"); @@ -415,7 +731,7 @@ static bool checkMissing(SMESH_Gen* aGen, } case SMESH_subMesh::MISSING_HYP: { // notify if an algo missing hyp is attached to aSubMesh - algo = aGen->GetAlgo( aMesh, aSubMesh->GetSubShape() ); + algo = aSubMesh->GetAlgo(); ASSERT( algo ); bool IsGlobalHypothesis = aGen->IsGlobalHypothesis( algo, aMesh ); if (!IsGlobalHypothesis || !globalChecked[ algo->GetDim() ]) @@ -444,8 +760,15 @@ static bool checkMissing(SMESH_Gen* aGen, break; } case SMESH_subMesh::HYP_OK: - algo = aGen->GetAlgo( aMesh, aSubMesh->GetSubShape() ); + algo = aSubMesh->GetAlgo(); ret = true; + if (!algo->NeedDiscreteBoundary()) + { + SMESH_subMeshIteratorPtr itsub = aSubMesh->getDependsOnIterator( /*includeSelf=*/false, + /*complexShapeFirst=*/false); + while ( itsub->more() ) + aCheckedMap.insert( itsub->next() ); + } break; default: ASSERT(0); } @@ -455,18 +778,15 @@ static bool checkMissing(SMESH_Gen* aGen, ASSERT (algo); bool isTopLocalAlgo = ( aTopAlgoDim <= algo->GetDim() && !aGen->IsGlobalHypothesis( algo, aMesh )); - if (!algo->NeedDescretBoundary() || isTopLocalAlgo) + if (!algo->NeedDiscreteBoundary() || isTopLocalAlgo) { - bool checkNoAlgo2 = ( algo->NeedDescretBoundary() ); - const map& subMeshes = aSubMesh->DependsOn(); - map::const_iterator itsub; - for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++) + bool checkNoAlgo2 = ( algo->NeedDiscreteBoundary() ); + SMESH_subMeshIteratorPtr itsub = aSubMesh->getDependsOnIterator( /*includeSelf=*/false, + /*complexShapeFirst=*/true); + while ( itsub->more() ) { // sub-meshes should not be checked further more - int key = (*itsub).first; - SMESH_subMesh* sm = (*itsub).second; - if ( aCheckedMap.find( key ) == aCheckedMap.end() ) - aCheckedMap[ key ] = sm; + SMESH_subMesh* sm = itsub->next(); if (isTopLocalAlgo) { @@ -480,6 +800,7 @@ static bool checkMissing(SMESH_Gen* aGen, checkNoAlgo2 = false; } } + aCheckedMap.insert( sm ); } } return ret; @@ -513,9 +834,9 @@ bool SMESH_Gen::GetAlgoState(SMESH_Mesh& theMesh, bool ret = true; bool hasAlgo = false; - SMESH_subMesh* sm = theMesh.GetSubMesh(theShape); + SMESH_subMesh* sm = theMesh.GetSubMesh(theShape); const SMESHDS_Mesh* meshDS = theMesh.GetMeshDS(); - TopoDS_Shape mainShape = meshDS->ShapeToMesh(); + TopoDS_Shape mainShape = meshDS->ShapeToMesh(); // ----------------- // get global algos @@ -542,7 +863,7 @@ bool SMESH_Gen::GetAlgoState(SMESH_Mesh& theMesh, // -------------------------------------------------------- // info on algos that will be ignored because of ones that - // don't NeedDescretBoundary() attached to super-shapes, + // don't NeedDiscreteBoundary() attached to super-shapes, // check that a conform mesh will be produced // -------------------------------------------------------- @@ -553,46 +874,33 @@ bool SMESH_Gen::GetAlgoState(SMESH_Mesh& theMesh, for (dim = 3; dim > 0; dim--) { if (aGlobAlgoArr[ dim ] && - !aGlobAlgoArr[ dim ]->NeedDescretBoundary()) + !aGlobAlgoArr[ dim ]->NeedDiscreteBoundary() /*&& + !aGlobAlgoArr[ dim ]->SupportSubmeshes()*/ ) { aGlobIgnoAlgo = aGlobAlgoArr[ dim ]; break; } } - const map& smMap = sm->DependsOn(); - map::const_reverse_iterator revItSub = smMap.rbegin(); - map aCheckedMap; + set aCheckedSubs; bool checkConform = ( !theMesh.IsNotConformAllowed() ); - int aKey = 1; - SMESH_subMesh* smToCheck = sm; // loop on theShape and its sub-shapes - while ( smToCheck ) + SMESH_subMeshIteratorPtr revItSub = sm->getDependsOnIterator( /*includeSelf=*/true, + /*complexShapeFirst=*/true); + while ( revItSub->more() ) { + SMESH_subMesh* smToCheck = revItSub->next(); if ( smToCheck->GetSubShape().ShapeType() == TopAbs_VERTEX) break; - if ( aCheckedMap.find( aKey ) == aCheckedMap.end() ) + if ( aCheckedSubs.insert( smToCheck ).second ) // not yet checked if (!checkConformIgnoredAlgos (theMesh, smToCheck, aGlobIgnoAlgo, - 0, checkConform, aCheckedMap, theErrors)) + 0, checkConform, aCheckedSubs, theErrors)) ret = false; if ( smToCheck->GetAlgoState() != SMESH_subMesh::NO_ALGO ) hasAlgo = true; - - // next subMesh - if (revItSub != smMap.rend()) - { - aKey = (*revItSub).first; - smToCheck = (*revItSub).second; - revItSub++; - } - else - { - smToCheck = 0; - } - } // ---------------------------------------------------------------- @@ -612,43 +920,31 @@ bool SMESH_Gen::GetAlgoState(SMESH_Mesh& theMesh, break; } } - aCheckedMap.clear(); - smToCheck = sm; - revItSub = smMap.rbegin(); bool checkNoAlgo = theMesh.HasShapeToMesh() ? bool( aTopAlgoDim ) : false; bool globalChecked[] = { false, false, false, false }; // loop on theShape and its sub-shapes - while ( smToCheck ) + aCheckedSubs.clear(); + revItSub = sm->getDependsOnIterator( /*includeSelf=*/true, /*complexShapeFirst=*/true); + while ( revItSub->more() ) { + SMESH_subMesh* smToCheck = revItSub->next(); if ( smToCheck->GetSubShape().ShapeType() == TopAbs_VERTEX) break; - if ( aCheckedMap.find( aKey ) == aCheckedMap.end() ) - if (!checkMissing (this, theMesh, smToCheck, aTopAlgoDim, - globalChecked, checkNoAlgo, aCheckedMap, theErrors)) - { - ret = false; - if (smToCheck->GetAlgoState() == SMESH_subMesh::NO_ALGO ) - checkNoAlgo = false; - } - - // next subMesh - if (revItSub != smMap.rend()) + if (!checkMissing (this, theMesh, smToCheck, aTopAlgoDim, + globalChecked, checkNoAlgo, aCheckedSubs, theErrors)) { - aKey = (*revItSub).first; - smToCheck = (*revItSub).second; - revItSub++; + ret = false; + if (smToCheck->GetAlgoState() == SMESH_subMesh::NO_ALGO ) + checkNoAlgo = false; } - else - smToCheck = 0; } if ( !hasAlgo ) { ret = false; - INFOS( "None algorithm attached" ); theErrors.push_back( TAlgoStateError() ); - theErrors.back().Set( SMESH_Hypothesis::HYP_MISSING, 1, true ); + theErrors.back().Set( SMESH_Hypothesis::HYP_MISSING, theMesh.HasShapeToMesh() ? 1 : 3, true ); } return ret; @@ -665,9 +961,86 @@ bool SMESH_Gen::IsGlobalHypothesis(const SMESH_Hypothesis* theHyp, SMESH_Mesh& a return aMesh.GetHypothesis( aMesh.GetMeshDS()->ShapeToMesh(), filter, false ); } +//================================================================================ +/*! + * \brief Return paths to xml files of plugins + */ +//================================================================================ + +std::vector< std::string > SMESH_Gen::GetPluginXMLPaths() +{ + // Get paths to xml files of plugins + vector< string > xmlPaths; + string sep; + if ( const char* meshersList = getenv("SMESH_MeshersList") ) + { + string meshers = meshersList, plugin; + string::size_type from = 0, pos; + while ( from < meshers.size() ) + { + // cut off plugin name + pos = meshers.find( ':', from ); + if ( pos != string::npos ) + plugin = meshers.substr( from, pos-from ); + else + plugin = meshers.substr( from ), pos = meshers.size(); + from = pos + 1; + + // get PLUGIN_ROOT_DIR path + string rootDirVar, pluginSubDir = plugin; + if ( plugin == "StdMeshers" ) + rootDirVar = "SMESH", pluginSubDir = "smesh"; + else + for ( pos = 0; pos < plugin.size(); ++pos ) + rootDirVar += toupper( plugin[pos] ); + rootDirVar += "_ROOT_DIR"; + + const char* rootDir = getenv( rootDirVar.c_str() ); + if ( !rootDir || strlen(rootDir) == 0 ) + { + rootDirVar = plugin + "_ROOT_DIR"; // HexoticPLUGIN_ROOT_DIR + rootDir = getenv( rootDirVar.c_str() ); + if ( !rootDir || strlen(rootDir) == 0 ) continue; + } + + // get a separator from rootDir + for ( pos = strlen( rootDir )-1; pos >= 0 && sep.empty(); --pos ) + if ( rootDir[pos] == '/' || rootDir[pos] == '\\' ) + { + sep = rootDir[pos]; + break; + } +#ifdef WIN32 + if (sep.empty() ) sep = "\\"; +#else + if (sep.empty() ) sep = "/"; +#endif + + // get a path to resource file + string xmlPath = rootDir; + if ( xmlPath[ xmlPath.size()-1 ] != sep[0] ) + xmlPath += sep; + xmlPath += "share" + sep + "salome" + sep + "resources" + sep; + for ( pos = 0; pos < pluginSubDir.size(); ++pos ) + xmlPath += tolower( pluginSubDir[pos] ); + xmlPath += sep + plugin + ".xml"; + bool fileOK; +#ifdef WIN32 + fileOK = (GetFileAttributes(xmlPath.c_str()) != INVALID_FILE_ATTRIBUTES); +#else + fileOK = (access(xmlPath.c_str(), F_OK) == 0); +#endif + if ( fileOK ) + xmlPaths.push_back( xmlPath ); + } + } + + return xmlPaths; +} + //============================================================================= /*! - * + * Finds algo to mesh a shape. Optionally returns a shape the found algo is bound to */ //============================================================================= @@ -675,69 +1048,112 @@ SMESH_Algo *SMESH_Gen::GetAlgo(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, TopoDS_Shape* assignedTo) { - - SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() ); - filter.And( filter.IsApplicableTo( aShape )); - - return (SMESH_Algo*) aMesh.GetHypothesis( aShape, filter, true, assignedTo ); + return GetAlgo( aMesh.GetSubMesh( aShape ), assignedTo ); } //============================================================================= /*! - * + * Finds algo to mesh a sub-mesh. Optionally returns a shape the found algo is bound to */ //============================================================================= -StudyContextStruct *SMESH_Gen::GetStudyContext(int studyId) +SMESH_Algo *SMESH_Gen::GetAlgo(SMESH_subMesh * aSubMesh, + TopoDS_Shape* assignedTo) { - // Get studyContext, create it if it does'nt exist, with a SMESHDS_Document - - if (_mapStudyContext.find(studyId) == _mapStudyContext.end()) - { - _mapStudyContext[studyId] = new StudyContextStruct; - _mapStudyContext[studyId]->myDocument = new SMESHDS_Document(studyId); - } - StudyContextStruct *myStudyContext = _mapStudyContext[studyId]; -// ASSERT(_mapStudyContext.find(studyId) != _mapStudyContext.end()); - return myStudyContext; -} + if ( !aSubMesh ) return 0; + + const TopoDS_Shape & aShape = aSubMesh->GetSubShape(); + SMESH_Mesh& aMesh = *aSubMesh->GetFather(); -// //============================================================================= -// /*! -// * -// */ -// //============================================================================= + SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() ); + filter.And( filter.IsApplicableTo( aShape )); -// void SMESH_Gen::Save(int studyId, const char *aUrlOfFile) -// { -// } + typedef SMESH_Algo::Features AlgoData; -// //============================================================================= -// /*! -// * -// */ -// //============================================================================= + TopoDS_Shape assignedToShape; + SMESH_Algo* algo = + (SMESH_Algo*) aMesh.GetHypothesis( aSubMesh, filter, true, &assignedToShape ); -// void SMESH_Gen::Load(int studyId, const char *aUrlOfFile) -// { -// } + if ( algo && + aShape.ShapeType() == TopAbs_FACE && + !aShape.IsSame( assignedToShape ) && + SMESH_MesherHelper::NbAncestors( aShape, aMesh, TopAbs_SOLID ) > 1 ) + { + // Issue 0021559. If there is another 2D algo with different types of output + // elements that can be used to mesh aShape, and 3D algos on adjacent SOLIDs + // have different types of input elements, we choose a most appropriate 2D algo. + + // try to find a concurrent 2D algo + filter.AndNot( filter.Is( algo )); + TopoDS_Shape assignedToShape2; + SMESH_Algo* algo2 = + (SMESH_Algo*) aMesh.GetHypothesis( aSubMesh, filter, true, &assignedToShape2 ); + if ( algo2 && // algo found + !assignedToShape2.IsSame( aMesh.GetShapeToMesh() ) && // algo is local + ( SMESH_MesherHelper::GetGroupType( assignedToShape2 ) == // algo of the same level + SMESH_MesherHelper::GetGroupType( assignedToShape )) && + aMesh.IsOrderOK( aMesh.GetSubMesh( assignedToShape2 ), // no forced order + aMesh.GetSubMesh( assignedToShape ))) + { + // get algos on the adjacent SOLIDs + filter.Init( filter.IsAlgo() ).And( filter.HasDim( 3 )); + vector< SMESH_Algo* > algos3D; + PShapeIteratorPtr solidIt = SMESH_MesherHelper::GetAncestors( aShape, aMesh, + TopAbs_SOLID ); + while ( const TopoDS_Shape* solid = solidIt->next() ) + if ( SMESH_Algo* algo3D = (SMESH_Algo*) aMesh.GetHypothesis( *solid, filter, true )) + { + algos3D.push_back( algo3D ); + filter.AndNot( filter.HasName( algo3D->GetName() )); + } + // check compatibility of algos + if ( algos3D.size() > 1 ) + { + const AlgoData& algoData = algo->SMESH_Algo::GetFeatures(); + const AlgoData& algoData2 = algo2->SMESH_Algo::GetFeatures(); + const AlgoData& algoData3d0 = algos3D[0]->SMESH_Algo::GetFeatures(); + const AlgoData& algoData3d1 = algos3D[1]->SMESH_Algo::GetFeatures(); + if (( algoData2.IsCompatible( algoData3d0 ) && + algoData2.IsCompatible( algoData3d1 )) + && + !(algoData.IsCompatible( algoData3d0 ) && + algoData.IsCompatible( algoData3d1 ))) + algo = algo2; + } + } + } -// //============================================================================= -// /*! -// * -// */ -// //============================================================================= + if ( assignedTo && algo ) + * assignedTo = assignedToShape; -// void SMESH_Gen::Close(int studyId) -// { -// } + return algo; +} //============================================================================= /*! - * + * Returns StudyContextStruct for a study */ //============================================================================= +StudyContextStruct *SMESH_Gen::GetStudyContext(int studyId) +{ + // Get studyContext, create it if it does'nt exist, with a SMESHDS_Document + + if (_mapStudyContext.find(studyId) == _mapStudyContext.end()) + { + _mapStudyContext[studyId] = new StudyContextStruct; + _mapStudyContext[studyId]->myDocument = new SMESHDS_Document(studyId); + } + StudyContextStruct *myStudyContext = _mapStudyContext[studyId]; + return myStudyContext; +} + +//================================================================================ +/*! + * \brief Return shape dimension by TopAbs_ShapeEnum + */ +//================================================================================ + int SMESH_Gen::GetShapeDim(const TopAbs_ShapeEnum & aShapeType) { static vector dim; @@ -747,7 +1163,7 @@ int SMESH_Gen::GetShapeDim(const TopAbs_ShapeEnum & aShapeType) dim[ TopAbs_COMPOUND ] = MeshDim_3D; dim[ TopAbs_COMPSOLID ] = MeshDim_3D; dim[ TopAbs_SOLID ] = MeshDim_3D; - dim[ TopAbs_SHELL ] = MeshDim_3D; + dim[ TopAbs_SHELL ] = MeshDim_2D; dim[ TopAbs_FACE ] = MeshDim_2D; dim[ TopAbs_WIRE ] = MeshDim_1D; dim[ TopAbs_EDGE ] = MeshDim_1D; @@ -758,12 +1174,11 @@ int SMESH_Gen::GetShapeDim(const TopAbs_ShapeEnum & aShapeType) //============================================================================= /*! - * + * Genarate a new id unique withing this Gen */ //============================================================================= int SMESH_Gen::GetANewId() { - //MESSAGE("SMESH_Gen::GetANewId"); - return _hypId++; + return _hypId++; } diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Group.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Group.cpp index 71c6f5343ea3..1b45d64eea70 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Group.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Group.cpp @@ -1,34 +1,35 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : SMESH_Group.cxx // Author : Michael Sazonov (OCC) // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESH/SMESH_Group.cxx,v 1.7.2.1 2008/11/27 12:25:15 abd Exp $ // #include "SMESH_Group.hxx" #include "SMESH_Mesh.hxx" #include "SMESHDS_Group.hxx" #include "SMESHDS_GroupOnGeom.hxx" +#include "SMESHDS_GroupOnFilter.hxx" //============================================================================= /*! @@ -40,27 +41,58 @@ SMESH_Group::SMESH_Group (int theID, const SMESH_Mesh* theMesh, const SMDSAbs_ElementType theType, const char* theName, - const TopoDS_Shape& theShape) + const TopoDS_Shape& theShape, + const SMESH_PredicatePtr& thePredicate) : myName(theName) { - if ( theShape.IsNull() ) - myGroupDS = new SMESHDS_Group (theID, - const_cast(theMesh)->GetMeshDS(), - theType); - else + if ( !theShape.IsNull() ) myGroupDS = new SMESHDS_GroupOnGeom (theID, const_cast(theMesh)->GetMeshDS(), theType, theShape); + else if ( thePredicate ) + myGroupDS = new SMESHDS_GroupOnFilter (theID, + const_cast(theMesh)->GetMeshDS(), + theType, + thePredicate); + else + myGroupDS = new SMESHDS_Group (theID, + const_cast(theMesh)->GetMeshDS(), + theType); + myGroupDS->SetStoreName( theName ); +} + +//================================================================================ +/*! + * \brief Constructor accesible to SMESH_Mesh only + */ +//================================================================================ + +SMESH_Group::SMESH_Group (SMESHDS_GroupBase* groupDS): myGroupDS( groupDS ) +{ + if ( myGroupDS ) + myName = myGroupDS->GetStoreName(); } //============================================================================= /*! - * + * Destructor deletes myGroupDS */ //============================================================================= SMESH_Group::~SMESH_Group () { - delete myGroupDS; + delete myGroupDS; myGroupDS=0; +} + +//================================================================================ +/*! + * \brief Sets a new name + */ +//================================================================================ + +void SMESH_Group::SetName (const char* theName) +{ + myName = theName; + myGroupDS->SetStoreName( theName ); } diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_HypoFilter.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_HypoFilter.cpp index 13682ce488fd..fcebe63d36e8 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_HypoFilter.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_HypoFilter.cpp @@ -1,34 +1,38 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : SMESH_HypoFilter.cxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESH/SMESH_HypoFilter.cxx,v 1.6.2.2 2008/11/27 12:25:15 abd Exp $ // #include "SMESH_HypoFilter.hxx" +#include "SMESH_Gen.hxx" #include "SMESH_Hypothesis.hxx" +#include "SMESH_MesherHelper.hxx" #include "SMESH_subMesh.hxx" +#include + using namespace std; @@ -112,11 +116,39 @@ bool SMESH_HypoFilter::InstancePredicate::IsOk(const SMESH_Hypothesis* aHyp, //======================================================================= bool SMESH_HypoFilter::IsAssignedToPredicate::IsOk(const SMESH_Hypothesis* aHyp, - const TopoDS_Shape& aShape) const + const TopoDS_Shape& aShape) const { return ( !_mainShape.IsNull() && !aShape.IsNull() && _mainShape.IsSame( aShape )); } +//================================================================================ +/*! + * \brief Finds shapes preferable over _shape due to sub-mesh order + */ +//================================================================================ + +void SMESH_HypoFilter::IsMoreLocalThanPredicate::findPreferable() +{ + const int shapeID = _mesh.GetMeshDS()->ShapeToIndex( _shape ); + const TListOfListOfInt& listOfShapeIDList = _mesh.GetMeshOrder(); + TListOfListOfInt::const_iterator listsIt = listOfShapeIDList.begin(); + for ( ; listsIt != listOfShapeIDList.end(); ++listsIt ) + { + const TListOfInt& idList = *listsIt; + TListOfInt::const_iterator idIt = + std::find( idList.begin(), idList.end(), shapeID ); + if ( idIt != idList.end() && *idIt != idList.front() ) + { + for ( ; idIt != idList.end(); --idIt ) + { + const TopoDS_Shape& shape = _mesh.GetMeshDS()->IndexToShape( *idIt ); + if ( !shape.IsNull()) + _preferableShapes.Add( shape ); + } + } + } +} + //======================================================================= //function : IsMoreLocalThanPredicate::IsOk //purpose : @@ -125,7 +157,27 @@ bool SMESH_HypoFilter::IsAssignedToPredicate::IsOk(const SMESH_Hypothesis* aHyp, bool SMESH_HypoFilter::IsMoreLocalThanPredicate::IsOk(const SMESH_Hypothesis* aHyp, const TopoDS_Shape& aShape) const { - return ( aShape.ShapeType() > _shapeType ); + if ( aShape.IsSame( _mesh.GetShapeToMesh() ) || // aHyp is global + aShape.IsSame( _shape )) + return false; + + if ( SMESH_MesherHelper::IsSubShape( aShape, /*mainShape=*/_shape )) + return true; + + if ( aShape.ShapeType() == TopAbs_COMPOUND && + !SMESH_MesherHelper::IsSubShape( _shape, /*mainShape=*/aShape)) // issue 0020963 + { + for ( int type = TopAbs_SOLID; type < TopAbs_SHAPE; ++type ) + if ( aHyp->GetDim() == SMESH_Gen::GetShapeDim( TopAbs_ShapeEnum( type ))) + for ( TopExp_Explorer exp( aShape, TopAbs_ShapeEnum( type )); exp.More(); exp.Next()) + if ( SMESH_MesherHelper::IsSubShape( exp.Current(), /*mainShape=*/_shape )) + return true; + } + + if ( _preferableShapes.Contains( aShape )) + return true; // issue 21559, Mesh_6 + + return false; } //======================================================================= @@ -134,6 +186,7 @@ bool SMESH_HypoFilter::IsMoreLocalThanPredicate::IsOk(const SMESH_Hypothesis* aH //======================================================================= SMESH_HypoFilter::SMESH_HypoFilter() + : myNbPredicates(0) { } @@ -142,9 +195,10 @@ SMESH_HypoFilter::SMESH_HypoFilter() //purpose : //======================================================================= -SMESH_HypoFilter::SMESH_HypoFilter( SMESH_HypoPredicate* aPredicate, bool notNagate ) +SMESH_HypoFilter::SMESH_HypoFilter( SMESH_HypoPredicate* aPredicate, bool notNegate ) + : myNbPredicates(0) { - add( notNagate ? AND : AND_NOT, aPredicate ); + add( notNegate ? AND : AND_NOT, aPredicate ); } //======================================================================= @@ -277,9 +331,10 @@ SMESH_HypoPredicate* SMESH_HypoFilter::IsApplicableTo(const TopoDS_Shape& theSha //purpose : //======================================================================= -SMESH_HypoPredicate* SMESH_HypoFilter::IsMoreLocalThan(const TopoDS_Shape& theShape) +SMESH_HypoPredicate* SMESH_HypoFilter::IsMoreLocalThan(const TopoDS_Shape& theShape, + const SMESH_Mesh& theMesh) { - return new IsMoreLocalThanPredicate( theShape ); + return new IsMoreLocalThanPredicate( theShape, theMesh ); } //======================================================================= @@ -300,15 +355,14 @@ SMESH_HypoPredicate* SMESH_HypoFilter::HasType(const int theHypType) bool SMESH_HypoFilter::IsOk (const SMESH_Hypothesis* aHyp, const TopoDS_Shape& aShape) const { - if ( myPredicates.empty() ) + if ( IsEmpty() ) return true; - bool ok = ( myPredicates.front()->_logical_op <= AND_NOT ); - list::const_iterator pred = myPredicates.begin(); - for ( ; pred != myPredicates.end(); ++pred ) + bool ok = ( myPredicates[0]->_logical_op <= AND_NOT ); + for ( int i = 0; i < myNbPredicates; ++i ) { - bool ok2 = (*pred)->IsOk( aHyp, aShape ); - switch ( (*pred)->_logical_op ) { + bool ok2 = myPredicates[i]->IsOk( aHyp, aShape ); + switch ( myPredicates[i]->_logical_op ) { case AND: ok = ok && ok2; break; case AND_NOT: ok = ok && !ok2; break; case OR: ok = ok || ok2; break; @@ -324,14 +378,15 @@ bool SMESH_HypoFilter::IsOk (const SMESH_Hypothesis* aHyp, //purpose : //======================================================================= -SMESH_HypoFilter & SMESH_HypoFilter::Init ( SMESH_HypoPredicate* aPredicate, bool notNagate ) +SMESH_HypoFilter & SMESH_HypoFilter::Init ( SMESH_HypoPredicate* aPredicate, bool notNegate ) { - list::const_iterator pred = myPredicates.begin(); - for ( ; pred != myPredicates.end(); ++pred ) + SMESH_HypoPredicate** pred = &myPredicates[0]; + SMESH_HypoPredicate** end = &myPredicates[myNbPredicates]; + for ( ; pred != end; ++pred ) delete *pred; - myPredicates.clear(); + myNbPredicates = 0; - add( notNagate ? AND : AND_NOT, aPredicate ); + add( notNegate ? AND : AND_NOT, aPredicate ); return *this; } @@ -343,6 +398,12 @@ SMESH_HypoFilter & SMESH_HypoFilter::Init ( SMESH_HypoPredicate* aPredicate, bo SMESH_HypoFilter::~SMESH_HypoFilter() { - Init(0); + SMESH_HypoPredicate** pred = &myPredicates[0]; + SMESH_HypoPredicate** end = &myPredicates[myNbPredicates]; + for ( ; pred != end; ++pred ) + delete *pred; + myNbPredicates = 0; } + + diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Hypothesis.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Hypothesis.cpp index a3ed82fb1cda..62a37baf1b1a 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Hypothesis.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Hypothesis.cpp @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : SMESH_Hypothesis.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESH/SMESH_Hypothesis.cxx,v 1.10 2009/02/17 05:27:39 vsr Exp $ // #include "SMESH_Hypothesis.hxx" #include "SMESH_Gen.hxx" @@ -39,18 +39,17 @@ using namespace std; //============================================================================= SMESH_Hypothesis::SMESH_Hypothesis(int hypId, - int studyId, - SMESH_Gen* gen) : SMESHDS_Hypothesis(hypId) + int studyId, + SMESH_Gen* gen) : SMESHDS_Hypothesis(hypId) { - //MESSAGE("SMESH_Hypothesis::SMESH_Hypothesis"); - _gen = gen; - _studyId = studyId; - StudyContextStruct* myStudyContext = _gen->GetStudyContext(_studyId); - myStudyContext->mapHypothesis[_hypId] = this; - _type = PARAM_ALGO; - _shapeType = 0; // to be set by algo with TopAbs_Enum + _gen = gen; + _studyId = studyId; + _type = PARAM_ALGO; + _shapeType = 0; // to be set by algo with TopAbs_Enum _param_algo_dim = -1; // to be set by algo parameter _parameters = string(); + StudyContextStruct* myStudyContext = gen->GetStudyContext(_studyId); + myStudyContext->mapHypothesis[hypId] = this; } //============================================================================= @@ -62,6 +61,8 @@ SMESH_Hypothesis::SMESH_Hypothesis(int hypId, SMESH_Hypothesis::~SMESH_Hypothesis() { MESSAGE("SMESH_Hypothesis::~SMESH_Hypothesis"); + StudyContextStruct* myStudyContext = _gen->GetStudyContext(_studyId); + myStudyContext->mapHypothesis[_hypId] = 0; } //============================================================================= @@ -151,11 +152,24 @@ void SMESH_Hypothesis::SetLibName(const char* theLibName) _libName = string(theLibName); } -//============================================================================= -/*! - * - */ -//============================================================================= +//======================================================================= +//function : GetMeshByPersistentID +//purpose : Find a mesh with given persistent ID +//======================================================================= + +SMESH_Mesh* SMESH_Hypothesis::GetMeshByPersistentID(int id) +{ + StudyContextStruct* myStudyContext = _gen->GetStudyContext(_studyId); + map::iterator itm = itm = myStudyContext->mapMesh.begin(); + for ( ; itm != myStudyContext->mapMesh.end(); itm++) + { + SMESH_Mesh* mesh = (*itm).second; + if ( mesh->GetMeshDS()->GetPersistentId() == id ) + return mesh; + } + return 0; +} + void SMESH_Hypothesis::SetParameters(const char *theParameters) { string aNewParameters(theParameters); diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Mesh.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Mesh.cpp index e68056e18270..c7b9db890149 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Mesh.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Mesh.cpp @@ -1,57 +1,68 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMESH : implementaion of SMESH idl descriptions + // File : SMESH_Mesh.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESH/SMESH_Mesh.cxx,v 1.24.2.7 2008/11/27 12:25:15 abd Exp $ // #include "SMESH_Mesh.hxx" -#include "SMESH_subMesh.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMDS_MeshVolume.hxx" +#include "SMDS_SetIterator.hxx" +#include "SMESHDS_Document.hxx" +#include "SMESHDS_Group.hxx" +#include "SMESHDS_GroupOnGeom.hxx" +#include "SMESHDS_Script.hxx" +#include "SMESHDS_TSubMeshHolder.hxx" #include "SMESH_Gen.hxx" -#include "SMESH_Hypothesis.hxx" #include "SMESH_Group.hxx" #include "SMESH_HypoFilter.hxx" -#include "SMESHDS_Group.hxx" -#include "SMESHDS_Script.hxx" -#include "SMESHDS_GroupOnGeom.hxx" -#include "SMESHDS_Document.hxx" -#include "SMDS_MeshVolume.hxx" -#include "SMDS_SetIterator.hxx" +#include "SMESH_Hypothesis.hxx" +#include "SMESH_subMesh.hxx" #include "utilities.h" - +#include "SMESH_Exception.hxx" #include "DriverDAT_W_SMDS_Mesh.h" -#include "DriverUNV_W_SMDS_Mesh.h" +#include "DriverDAT_R_SMDS_Mesh.h" +#include "DriverGMF_Read.hxx" +#include "DriverGMF_Write.hxx" +#include "DriverMED_R_SMESHDS_Mesh.h" +#include "DriverMED_W_SMESHDS_Mesh.h" +#include "DriverSTL_R_SMDS_Mesh.h" #include "DriverSTL_W_SMDS_Mesh.h" - #include "DriverUNV_R_SMDS_Mesh.h" -#include "DriverSTL_R_SMDS_Mesh.h" -#include "DriverDAT_R_SMDS_Mesh.h" +#include "DriverUNV_W_SMDS_Mesh.h" +#ifdef WITH_CGNS +#include "DriverCGNS_Read.hxx" +#include "DriverCGNS_Write.hxx" +#endif + +#include #undef _Precision_HeaderFile #include #include #include +#include #include #include #include @@ -59,7 +70,21 @@ #include #include -#include "SMESH_ExceptHandlers.hxx" +#include "SMESH_TryCatch.hxx" // include after OCCT headers! + +#include "Utils_ExceptHandlers.hxx" + +#ifndef WIN32 +#include +#include +#else +#include +#endif + +using namespace std; + +// maximum stored group name length in MED file +#define MAX_MED_GROUP_NAME_LENGTH 80 #ifdef _DEBUG_ static int MYDEBUG = 0; @@ -67,12 +92,14 @@ static int MYDEBUG = 0; static int MYDEBUG = 0; #endif -using namespace std; - #define cSMESH_Hyp(h) static_cast(h) typedef SMESH_HypoFilter THypType; +class SMESH_Mesh::SubMeshHolder : public SMESHDS_TSubMeshHolder< SMESH_subMesh > +{ +}; + //============================================================================= /*! * @@ -80,34 +107,85 @@ typedef SMESH_HypoFilter THypType; //============================================================================= SMESH_Mesh::SMESH_Mesh(int theLocalId, - int theStudyId, - SMESH_Gen* theGen, - bool theIsEmbeddedMode, - SMESHDS_Document* theDocument): + int theStudyId, + SMESH_Gen* theGen, + bool theIsEmbeddedMode, + SMESHDS_Document* theDocument): _groupId( 0 ), _nbSubShapes( 0 ) { - //MESSAGE("SMESH_Mesh::SMESH_Mesh(int localId)"); + MESSAGE("SMESH_Mesh::SMESH_Mesh(int localId)"); _id = theLocalId; _studyId = theStudyId; _gen = theGen; _myDocument = theDocument; - _idDoc = theDocument->NewMesh(theIsEmbeddedMode); - _myMeshDS = theDocument->GetMesh(_idDoc); + _myMeshDS = theDocument->NewMesh(theIsEmbeddedMode,theLocalId); _isShapeToMesh = false; _isAutoColor = false; + _isModified = false; _shapeDiagonal = 0.0; + _callUp = NULL; _myMeshDS->ShapeToMesh( PseudoShape() ); + _subMeshHolder = new SubMeshHolder; +} + +//================================================================================ +/*! + * \brief Constructor of SMESH_Mesh being a base of some descendant class + */ +//================================================================================ + +SMESH_Mesh::SMESH_Mesh(): + _id(-1), + _studyId(-1), + _groupId( 0 ), + _nbSubShapes( 0 ), + _isShapeToMesh( false ), + _myDocument( 0 ), + _myMeshDS( 0 ), + _gen( 0 ), + _isAutoColor( false ), + _isModified( false ), + _shapeDiagonal( 0.0 ), + _callUp( 0 ) +{ + _subMeshHolder = new SubMeshHolder; +} + +namespace +{ +#ifndef WIN32 + void deleteMeshDS(SMESHDS_Mesh* meshDS) + { + //cout << "deleteMeshDS( " << meshDS << endl; + delete meshDS; + } +#else + static void* deleteMeshDS(void* meshDS) + { + //cout << "deleteMeshDS( " << meshDS << endl; + SMESHDS_Mesh* m = (SMESHDS_Mesh*)meshDS; + if(m) { + delete m; + } + return 0; + } +#endif } //============================================================================= /*! - * + * */ //============================================================================= SMESH_Mesh::~SMESH_Mesh() { - //INFOS("SMESH_Mesh::~SMESH_Mesh"); + MESSAGE("SMESH_Mesh::~SMESH_Mesh"); + + // avoid usual removal of elements while processing RemoveHypothesis( algo ) event + SMESHDS_SubMeshIteratorPtr smIt = _myMeshDS->SubMeshes(); + while ( smIt->more() ) + const_cast( smIt->next() )->Clear(); // issue 0020340: EDF 1022 SMESH : Crash with FindNodeClosestTo in a second new study // Notify event listeners at least that something happens @@ -115,12 +193,69 @@ SMESH_Mesh::~SMESH_Mesh() sm->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED ); // delete groups - std::map < int, SMESH_Group * >::iterator itg; + map < int, SMESH_Group * >::iterator itg; for (itg = _mapGroup.begin(); itg != _mapGroup.end(); itg++) { SMESH_Group *aGroup = (*itg).second; delete aGroup; } _mapGroup.clear(); + + // delete sub-meshes + delete _subMeshHolder; + + if ( _callUp) delete _callUp; + _callUp = 0; + + // remove self from studyContext + if ( _gen ) + { + StudyContextStruct * studyContext = _gen->GetStudyContext( _studyId ); + studyContext->mapMesh.erase( _id ); + } + if ( _myDocument ) + _myDocument->RemoveMesh( _id ); + _myDocument = 0; + + if ( _myMeshDS ) { + // delete _myMeshDS, in a thread in order not to block closing a study with large meshes +#ifndef WIN32 + boost::thread aThread(boost::bind( & deleteMeshDS, _myMeshDS )); +#else + pthread_t thread; + int result=pthread_create(&thread, NULL, deleteMeshDS, (void*)_myMeshDS); +#endif + } +} + +//================================================================================ +/*! + * \brief Return true if a mesh with given id exists + */ +//================================================================================ + +bool SMESH_Mesh::MeshExists( int meshId ) const +{ + return _myDocument ? bool( _myDocument->GetMesh( meshId )) : false; +} + +//================================================================================ +/*! + * \brief Return a mesh by id + */ +//================================================================================ + +SMESH_Mesh* SMESH_Mesh::FindMesh( int meshId ) const +{ + if ( _id == meshId ) + return (SMESH_Mesh*) this; + + if ( StudyContextStruct *aStudyContext = _gen->GetStudyContext( _studyId )) + { + std::map < int, SMESH_Mesh * >::iterator i_m = aStudyContext->mapMesh.find( meshId ); + if ( i_m != aStudyContext->mapMesh.end() ) + return i_m->second; + } + return NULL; } //============================================================================= @@ -136,20 +271,16 @@ void SMESH_Mesh::ShapeToMesh(const TopoDS_Shape & aShape) if ( !aShape.IsNull() && _isShapeToMesh ) { if ( aShape.ShapeType() != TopAbs_COMPOUND && // group contents is allowed to change _myMeshDS->ShapeToMesh().ShapeType() != TopAbs_COMPOUND ) - throw SMESH_Exception(LOCALIZED ("a shape to mesh has already been defined")); + throw SALOME_Exception(LOCALIZED ("a shape to mesh has already been defined")); } - // clear current data if ( !_myMeshDS->ShapeToMesh().IsNull() ) { // removal of a shape to mesh, delete objects referring to sub-shapes: // - sub-meshes - std::map ::iterator i_sm = _mapSubMesh.begin(); - for ( ; i_sm != _mapSubMesh.end(); ++i_sm ) - delete i_sm->second; - _mapSubMesh.clear(); + _subMeshHolder->DeleteAll(); // - groups on geometry - std::map ::iterator i_gr = _mapGroup.begin(); + map ::iterator i_gr = _mapGroup.begin(); while ( i_gr != _mapGroup.end() ) { if ( dynamic_cast( i_gr->second->GetGroupDS() )) { _myMeshDS->RemoveGroup( i_gr->second->GetGroupDS() ); @@ -164,6 +295,7 @@ void SMESH_Mesh::ShapeToMesh(const TopoDS_Shape & aShape) // clear SMESHDS TopoDS_Shape aNullShape; _myMeshDS->ShapeToMesh( aNullShape ); + _shapeDiagonal = 0.0; } @@ -174,14 +306,8 @@ void SMESH_Mesh::ShapeToMesh(const TopoDS_Shape & aShape) _isShapeToMesh = true; _nbSubShapes = _myMeshDS->MaxShapeIndex(); - // fill _mapAncestors - int desType, ancType; - for ( desType = TopAbs_VERTEX; desType > TopAbs_COMPOUND; desType-- ) - for ( ancType = desType - 1; ancType >= TopAbs_COMPOUND; ancType-- ) - TopExp::MapShapesAndAncestors ( aShape, - (TopAbs_ShapeEnum) desType, - (TopAbs_ShapeEnum) ancType, - _mapAncestors ); + // fill map of ancestors + fillAncestorsMap(aShape); } else { @@ -189,6 +315,7 @@ void SMESH_Mesh::ShapeToMesh(const TopoDS_Shape & aShape) _shapeDiagonal = 0.0; _myMeshDS->ShapeToMesh( PseudoShape() ); } + _isModified = false; } //======================================================================= @@ -229,8 +356,18 @@ double SMESH_Mesh::GetShapeDiagonalSize(const TopoDS_Shape & aShape) { if ( !aShape.IsNull() ) { Bnd_Box Box; - BRepBndLib::Add(aShape, Box); - return sqrt( Box.SquareExtent() ); + // avoid too long waiting on large shapes. PreciseBoundingBox() was added + // to assure same result which else depends on presence of triangulation (IPAL52557). + const int maxNbFaces = 4000; + int nbFaces = 0; + for ( TopExp_Explorer f( aShape, TopAbs_FACE ); f.More() && nbFaces < maxNbFaces; f.Next() ) + ++nbFaces; + if ( nbFaces < maxNbFaces ) + GEOMUtils::PreciseBoundingBox(aShape, Box); + else + BRepBndLib::Add( aShape, Box); + if ( !Box.IsVoid() ) + return sqrt( Box.SquareExtent() ); } return 0; } @@ -249,6 +386,18 @@ double SMESH_Mesh::GetShapeDiagonalSize() const return _shapeDiagonal; } +//================================================================================ +/*! + * \brief Load mesh from study file + */ +//================================================================================ + +void SMESH_Mesh::Load() +{ + if (_callUp) + _callUp->Load(); +} + //======================================================================= /*! * \brief Remove all nodes and elements @@ -257,59 +406,31 @@ double SMESH_Mesh::GetShapeDiagonalSize() const void SMESH_Mesh::Clear() { - // clear mesh data - _myMeshDS->ClearMesh(); + if ( HasShapeToMesh() ) // remove all nodes and elements + { + // clear mesh data + _myMeshDS->ClearMesh(); - // update compute state of submeshes - if ( SMESH_subMesh *sm = GetSubMeshContaining( GetShapeToMesh() ) ) { - SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true, - /*complexShapeFirst=*/false); - while ( smIt->more() ) { - sm = smIt->next(); + // update compute state of submeshes + if ( SMESH_subMesh *sm = GetSubMeshContaining( GetShapeToMesh() ) ) + { sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + sm->ComputeSubMeshStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); // for event listeners (issue 0020918) + sm->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN ); } } - -// // clear sub-meshes; get ready to re-compute as a side-effect - -// if ( SMESH_subMesh *sm = GetSubMeshContaining( GetShapeToMesh() ) ) -// { -// SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true, -// /*complexShapeFirst=*/false); -// while ( smIt->more() ) -// { -// sm = smIt->next(); -// TopAbs_ShapeEnum shapeType = sm->GetSubShape().ShapeType(); -// if ( shapeType == TopAbs_VERTEX || shapeType < TopAbs_SOLID ) -// // all other shapes depends on vertices so they are already cleaned -// sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); -// // to recompute even if failed -// sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); -// } -// } - -// // clear entities not on sub-meshes - -// SMDS_VolumeIteratorPtr vIt = _myMeshDS->volumesIterator(); -// while ( vIt->more() ) -// _myMeshDS->RemoveFreeElement( vIt->next(), 0 ); - -// SMDS_FaceIteratorPtr fIt = _myMeshDS->facesIterator(); -// while ( fIt->more() ) -// _myMeshDS->RemoveFreeElement( fIt->next(), 0 ); - -// SMDS_EdgeIteratorPtr eIt = _myMeshDS->edgesIterator(); -// while ( eIt->more() ) -// _myMeshDS->RemoveFreeElement( eIt->next(), 0 ); - -// SMDS_NodeIteratorPtr nIt = _myMeshDS->nodesIterator(); -// while ( nIt->more() ) { -// const SMDS_MeshNode * node = nIt->next(); -// if ( node->NbInverseElements() == 0 ) -// _myMeshDS->RemoveFreeNode( node, 0 ); -// else -// _myMeshDS->RemoveNode(node); -// } + else // remove only nodes/elements computed by algorithms + { + if ( SMESH_subMesh *sm = GetSubMeshContaining( GetShapeToMesh() ) ) + { + sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); + sm->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN ); + sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + sm->ComputeSubMeshStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + } + _isModified = false; } //======================================================================= @@ -324,14 +445,14 @@ void SMESH_Mesh::ClearSubMesh(const int theShapeId) if ( SMESH_subMesh *sm = GetSubMeshContaining( theShapeId ) ) { SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true, - /*complexShapeFirst=*/false); + /*complexShapeFirst=*/false); while ( smIt->more() ) { sm = smIt->next(); TopAbs_ShapeEnum shapeType = sm->GetSubShape().ShapeType(); if ( shapeType == TopAbs_VERTEX || shapeType < TopAbs_SOLID ) - // all other shapes depends on vertices so they are already cleaned - sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); + // all other shapes depends on vertices so they are already cleaned + sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); // to recompute even if failed sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); } @@ -347,7 +468,7 @@ int SMESH_Mesh::UNVToMesh(const char* theFileName) { if(MYDEBUG) MESSAGE("UNVToMesh - theFileName = "<InitSubGroupsIterator(); while (aGroup->MoreSubGroups()) { SMDS_MeshGroup* aSubGroup = (SMDS_MeshGroup*) aGroup->NextSubGroup(); - std::string aName = aGroupNames[aSubGroup]; + string aName = aGroupNames[aSubGroup]; int aId; SMESH_Group* aSMESHGroup = AddGroup( aSubGroup->GetType(), aName.c_str(), aId ); if ( aSMESHGroup ) { - if(MYDEBUG) MESSAGE("UNVToMesh - group added: "<( aSMESHGroup->GetGroupDS() ); - if ( aGroupDS ) { - aGroupDS->SetStoreName(aName.c_str()); - aSubGroup->InitIterator(); - const SMDS_MeshElement* aElement = 0; - while (aSubGroup->More()) { - aElement = aSubGroup->Next(); - if (aElement) { - aGroupDS->SMDSGroup().Add(aElement); - } - } - if (aElement) - aGroupDS->SetType(aElement->GetType()); - } + if(MYDEBUG) MESSAGE("UNVToMesh - group added: "<( aSMESHGroup->GetGroupDS() ); + if ( aGroupDS ) { + aGroupDS->SetStoreName(aName.c_str()); + aSubGroup->InitIterator(); + const SMDS_MeshElement* aElement = 0; + while (aSubGroup->More()) { + aElement = aSubGroup->Next(); + if (aElement) { + aGroupDS->SMDSGroup().Add(aElement); + } + } + if (aElement) + aGroupDS->SetType(aElement->GetType()); + } } } } @@ -395,13 +516,45 @@ int SMESH_Mesh::UNVToMesh(const char* theFileName) //======================================================================= //function : MEDToMesh -//purpose : +//purpose : //======================================================================= int SMESH_Mesh::MEDToMesh(const char* theFileName, const char* theMeshName) { - throw SMESH_Exception(LOCALIZED ("Not implemented ...")); - return 0; + if(MYDEBUG) MESSAGE("MEDToMesh - theFileName = "<NbNodes() = "<<_myMeshDS->NbNodes()); + MESSAGE("MEDToMesh - _myMeshDS->NbEdges() = "<<_myMeshDS->NbEdges()); + MESSAGE("MEDToMesh - _myMeshDS->NbFaces() = "<<_myMeshDS->NbFaces()); + MESSAGE("MEDToMesh - _myMeshDS->NbVolumes() = "<<_myMeshDS->NbVolumes()); + } + + // Reading groups (sub-meshes are out of scope of MED import functionality) + list aGroupNames = myReader.GetGroupNamesAndTypes(); + if(MYDEBUG) MESSAGE("MEDToMesh - Nb groups = "<::iterator name_type = aGroupNames.begin(); + for ( ; name_type != aGroupNames.end(); name_type++ ) { + SMESH_Group* aGroup = AddGroup( name_type->second, name_type->first.c_str(), anId ); + if ( aGroup ) { + if(MYDEBUG) MESSAGE("MEDToMesh - group added: "<first.c_str()); + SMESHDS_Group* aGroupDS = dynamic_cast( aGroup->GetGroupDS() ); + if ( aGroupDS ) { + aGroupDS->SetStoreName( name_type->first.c_str() ); + myReader.GetGroup( aGroupDS ); + } + } + } + return (int) status; } //======================================================================= @@ -413,7 +566,7 @@ int SMESH_Mesh::STLToMesh(const char* theFileName) { if(MYDEBUG) MESSAGE("STLToMesh - theFileName = "<clear(); + SMESH_subMesh *subMesh = GetSubMesh(aSubShape); if ( !subMesh || !subMesh->GetId()) return SMESH_Hypothesis::HYP_BAD_SUBSHAPE; - SMESHDS_SubMesh *subMeshDS = subMesh->GetSubMeshDS(); - if ( subMeshDS && subMeshDS->IsComplexSubmesh() ) // group of sub-shapes and maybe of not sub- - { - MESSAGE("AddHypothesis() to complex submesh"); - // return the worst but not fatal state of all group memebers - SMESH_Hypothesis::Hypothesis_Status aBestRet, aWorstNotFatal, ret; - aBestRet = SMESH_Hypothesis::HYP_BAD_DIM; - aWorstNotFatal = SMESH_Hypothesis::HYP_OK; - for ( TopoDS_Iterator itS ( aSubShape ); itS.More(); itS.Next()) - { - if ( !GetMeshDS()->ShapeToIndex( itS.Value() )) - continue; // not sub-shape - ret = AddHypothesis( itS.Value(), anHypId ); - if ( !SMESH_Hypothesis::IsStatusFatal( ret ) && ret > aWorstNotFatal ) - aWorstNotFatal = ret; - if ( ret < aBestRet ) - aBestRet = ret; - } - // bind hypotheses to a group just to know - SMESH_Hypothesis *anHyp = _gen->GetStudyContext(_studyId)->mapHypothesis[anHypId]; - GetMeshDS()->AddHypothesis( aSubShape, anHyp ); - - if ( SMESH_Hypothesis::IsStatusFatal( aBestRet )) - return aBestRet; - return aWorstNotFatal; - } - - StudyContextStruct *sc = _gen->GetStudyContext(_studyId); - if (sc->mapHypothesis.find(anHypId) == sc->mapHypothesis.end()) - { - if(MYDEBUG) MESSAGE("Hypothesis ID does not give an hypothesis"); - if(MYDEBUG) { - SCRUTE(_studyId); - SCRUTE(anHypId); - } - throw SMESH_Exception(LOCALIZED("hypothesis does not exist")); - } - - SMESH_Hypothesis *anHyp = sc->mapHypothesis[anHypId]; - MESSAGE( "SMESH_Mesh::AddHypothesis " << anHyp->GetName() ); + SMESH_Hypothesis *anHyp = GetHypothesis( anHypId ); + if ( !anHyp ) + throw SALOME_Exception(LOCALIZED("hypothesis does not exist")); bool isGlobalHyp = IsMainShape( aSubShape ); // NotConformAllowed can be only global if ( !isGlobalHyp ) { + // NOTE: this is not a correct way to check a name of hypothesis, + // there should be an attribute of hypothesis saying that it can/can't + // be global/local string hypName = anHyp->GetName(); if ( hypName == "NotConformAllowed" ) { @@ -525,25 +699,38 @@ SMESH_Hypothesis::Hypothesis_Status } } - // shape + // shape bool isAlgo = ( anHyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO ); - int event = isAlgo ? SMESH_subMesh::ADD_ALGO : SMESH_subMesh::ADD_HYP; + int event = isAlgo ? SMESH_subMesh::ADD_ALGO : SMESH_subMesh::ADD_HYP; SMESH_Hypothesis::Hypothesis_Status ret = subMesh->AlgoStateEngine(event, anHyp); - // subShapes - if (!SMESH_Hypothesis::IsStatusFatal(ret) && - anHyp->GetDim() <= SMESH_Gen::GetShapeDim(aSubShape)) // is added on father + if ( anError && SMESH_Hypothesis::IsStatusFatal(ret) && subMesh->GetComputeError() ) + *anError = subMesh->GetComputeError()->myComment; + + // sub-shapes + if ( !SMESH_Hypothesis::IsStatusFatal(ret) && + anHyp->GetDim() <= SMESH_Gen::GetShapeDim(aSubShape)) // is added on father { event = isAlgo ? SMESH_subMesh::ADD_FATHER_ALGO : SMESH_subMesh::ADD_FATHER_HYP; SMESH_Hypothesis::Hypothesis_Status ret2 = - subMesh->SubMeshesAlgoStateEngine(event, anHyp); + subMesh->SubMeshesAlgoStateEngine(event, anHyp, /*exitOnFatal=*/true); if (ret2 > ret) + { ret = ret2; + if ( SMESH_Hypothesis::IsStatusFatal( ret )) + { + if ( anError && subMesh->GetComputeError() ) + *anError = subMesh->GetComputeError()->myComment; + // remove anHyp + event = isAlgo ? SMESH_subMesh::REMOVE_ALGO : SMESH_subMesh::REMOVE_HYP; + subMesh->AlgoStateEngine(event, anHyp); + } + } - // check concurent hypotheses on ansestors + // check concurent hypotheses on ancestors if (ret < SMESH_Hypothesis::HYP_CONCURENT && !isGlobalHyp ) { SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false); @@ -559,9 +746,10 @@ SMESH_Hypothesis::Hypothesis_Status } } } + HasModificationsToDiscard(); // to reset _isModified flag if a mesh becomes empty if(MYDEBUG) subMesh->DumpAlgoState(true); - SCRUTE(ret); + if(MYDEBUG) SCRUTE(ret); return ret; } @@ -573,49 +761,26 @@ SMESH_Hypothesis::Hypothesis_Status SMESH_Hypothesis::Hypothesis_Status SMESH_Mesh::RemoveHypothesis(const TopoDS_Shape & aSubShape, - int anHypId)throw(SMESH_Exception) + int anHypId)throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); if(MYDEBUG) MESSAGE("SMESH_Mesh::RemoveHypothesis"); - SMESH_subMesh *subMesh = GetSubMesh(aSubShape); - SMESHDS_SubMesh *subMeshDS = subMesh->GetSubMeshDS(); - if ( subMeshDS && subMeshDS->IsComplexSubmesh() ) - { - // return the worst but not fatal state of all group memebers - SMESH_Hypothesis::Hypothesis_Status aBestRet, aWorstNotFatal, ret; - aBestRet = SMESH_Hypothesis::HYP_BAD_DIM; - aWorstNotFatal = SMESH_Hypothesis::HYP_OK; - for ( TopoDS_Iterator itS ( aSubShape ); itS.More(); itS.Next()) - { - if ( !GetMeshDS()->ShapeToIndex( itS.Value() )) - continue; // not sub-shape - ret = RemoveHypothesis( itS.Value(), anHypId ); - if ( !SMESH_Hypothesis::IsStatusFatal( ret ) && ret > aWorstNotFatal ) - aWorstNotFatal = ret; - if ( ret < aBestRet ) - aBestRet = ret; - } - SMESH_Hypothesis *anHyp = _gen->GetStudyContext(_studyId)->mapHypothesis[anHypId]; - GetMeshDS()->RemoveHypothesis( aSubShape, anHyp ); - - if ( SMESH_Hypothesis::IsStatusFatal( aBestRet )) - return aBestRet; - return aWorstNotFatal; - } - StudyContextStruct *sc = _gen->GetStudyContext(_studyId); if (sc->mapHypothesis.find(anHypId) == sc->mapHypothesis.end()) - throw SMESH_Exception(LOCALIZED("hypothesis does not exist")); + throw SALOME_Exception(LOCALIZED("hypothesis does not exist")); SMESH_Hypothesis *anHyp = sc->mapHypothesis[anHypId]; - int hypType = anHyp->GetType(); - if(MYDEBUG) SCRUTE(hypType); + if(MYDEBUG) { + SCRUTE(anHyp->GetType()); + } // shape - bool isAlgo = ( anHyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO ); - int event = isAlgo ? SMESH_subMesh::REMOVE_ALGO : SMESH_subMesh::REMOVE_HYP; + bool isAlgo = ( !anHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO ); + int event = isAlgo ? SMESH_subMesh::REMOVE_ALGO : SMESH_subMesh::REMOVE_HYP; + + SMESH_subMesh *subMesh = GetSubMesh(aSubShape); SMESH_Hypothesis::Hypothesis_Status ret = subMesh->AlgoStateEngine(event, anHyp); @@ -625,7 +790,7 @@ SMESH_Hypothesis::Hypothesis_Status subMesh->CheckConcurentHypothesis( anHyp->GetType() ) != SMESH_Hypothesis::HYP_OK) ret = SMESH_Hypothesis::HYP_CONCURENT; - // subShapes + // sub-shapes if (!SMESH_Hypothesis::IsStatusFatal(ret) && anHyp->GetDim() <= SMESH_Gen::GetShapeDim(aSubShape)) // is removed from father { @@ -636,7 +801,7 @@ SMESH_Hypothesis::Hypothesis_Status if (ret2 > ret) // more severe ret = ret2; - // check concurent hypotheses on ansestors + // check concurent hypotheses on ancestors if (ret < SMESH_Hypothesis::HYP_CONCURENT && !IsMainShape( aSubShape ) ) { SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false); @@ -652,7 +817,9 @@ SMESH_Hypothesis::Hypothesis_Status } } } - + + HasModificationsToDiscard(); // to reset _isModified flag if mesh become empty + if(MYDEBUG) subMesh->DumpAlgoState(true); if(MYDEBUG) SCRUTE(ret); return ret; @@ -664,11 +831,10 @@ SMESH_Hypothesis::Hypothesis_Status */ //============================================================================= -const std::list& +const list& SMESH_Mesh::GetHypothesisList(const TopoDS_Shape & aSubShape) const - throw(SMESH_Exception) + throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); return _myMeshDS->GetHypothesis(aSubShape); } @@ -688,9 +854,32 @@ const SMESH_Hypothesis * SMESH_Mesh::GetHypothesis(const TopoDS_Shape & aSubS const bool andAncestors, TopoDS_Shape* assignedTo) const { + return GetHypothesis( const_cast< SMESH_Mesh* >(this)->GetSubMesh( aSubShape ), + aFilter, andAncestors, assignedTo ); +} + +//======================================================================= +/*! + * \brief Return the hypothesis assigned to the shape of a sub-mesh + * \param aSubMesh - the sub-mesh to check + * \param aFilter - the hypothesis filter + * \param andAncestors - flag to check hypos assigned to ancestors of the shape + * \param assignedTo - to return the shape the found hypo is assigned to + * \retval SMESH_Hypothesis* - the first hypo passed through aFilter + */ +//======================================================================= + +const SMESH_Hypothesis * SMESH_Mesh::GetHypothesis(const SMESH_subMesh * aSubMesh, + const SMESH_HypoFilter& aFilter, + const bool andAncestors, + TopoDS_Shape* assignedTo) const +{ + if ( !aSubMesh ) return 0; + { - const std::list& hypList = _myMeshDS->GetHypothesis(aSubShape); - std::list::const_iterator hyp = hypList.begin(); + const TopoDS_Shape & aSubShape = aSubMesh->GetSubShape(); + const list& hypList = _myMeshDS->GetHypothesis(aSubShape); + list::const_iterator hyp = hypList.begin(); for ( ; hyp != hypList.end(); hyp++ ) { const SMESH_Hypothesis * h = cSMESH_Hyp( *hyp ); if ( aFilter.IsOk( h, aSubShape)) { @@ -701,15 +890,21 @@ const SMESH_Hypothesis * SMESH_Mesh::GetHypothesis(const TopoDS_Shape & aSubS } if ( andAncestors ) { - TopTools_ListIteratorOfListOfShape it( GetAncestors( aSubShape )); - for (; it.More(); it.Next() ) + // user sorted submeshes of ancestors, according to stored submesh priority + std::vector< SMESH_subMesh * > & ancestors = + const_cast< std::vector< SMESH_subMesh * > & > ( aSubMesh->GetAncestors() ); + SortByMeshOrder( ancestors ); + + vector::const_iterator smIt = ancestors.begin(); + for ( ; smIt != ancestors.end(); smIt++ ) { - const std::list& hypList = _myMeshDS->GetHypothesis(it.Value()); - std::list::const_iterator hyp = hypList.begin(); + const TopoDS_Shape& curSh = (*smIt)->GetSubShape(); + const list& hypList = _myMeshDS->GetHypothesis(curSh); + list::const_iterator hyp = hypList.begin(); for ( ; hyp != hypList.end(); hyp++ ) { const SMESH_Hypothesis * h = cSMESH_Hyp( *hyp ); - if (aFilter.IsOk( h, it.Value() )) { - if ( assignedTo ) *assignedTo = it.Value(); + if (aFilter.IsOk( h, curSh )) { + if ( assignedTo ) *assignedTo = curSh; return h; } } @@ -720,7 +915,7 @@ const SMESH_Hypothesis * SMESH_Mesh::GetHypothesis(const TopoDS_Shape & aSubS //================================================================================ /*! - * \brief Return hypothesis assigned to the shape + * \brief Return hypotheses assigned to the shape * \param aSubShape - the shape to check * \param aFilter - the hypothesis filter * \param aHypList - the list of the found hypotheses @@ -732,8 +927,32 @@ const SMESH_Hypothesis * SMESH_Mesh::GetHypothesis(const TopoDS_Shape & aSubS int SMESH_Mesh::GetHypotheses(const TopoDS_Shape & aSubShape, const SMESH_HypoFilter& aFilter, list & aHypList, - const bool andAncestors) const + const bool andAncestors, + list< TopoDS_Shape > * assignedTo/*=0*/) const +{ + return GetHypotheses( const_cast< SMESH_Mesh* >(this)->GetSubMesh( aSubShape ), + aFilter, aHypList, andAncestors, assignedTo ); +} + +//================================================================================ +/*! + * \brief Return hypotheses assigned to the shape of a sub-mesh + * \param aSubShape - the sub-mesh to check + * \param aFilter - the hypothesis filter + * \param aHypList - the list of the found hypotheses + * \param andAncestors - flag to check hypos assigned to ancestors of the shape + * \retval int - number of unique hypos in aHypList + */ +//================================================================================ + +int SMESH_Mesh::GetHypotheses(const SMESH_subMesh * aSubMesh, + const SMESH_HypoFilter& aFilter, + list & aHypList, + const bool andAncestors, + list< TopoDS_Shape > * assignedTo/*=0*/) const { + if ( !aSubMesh ) return 0; + set hypTypes; // to exclude same type hypos from the result list int nbHyps = 0; @@ -741,7 +960,7 @@ int SMESH_Mesh::GetHypotheses(const TopoDS_Shape & aSubShape, bool mainHypFound = false; // fill in hypTypes - std::list::const_iterator hyp; + list::const_iterator hyp; for ( hyp = aHypList.begin(); hyp != aHypList.end(); hyp++ ) { if ( hypTypes.insert( (*hyp)->GetName() ).second ) nbHyps++; @@ -751,53 +970,81 @@ int SMESH_Mesh::GetHypotheses(const TopoDS_Shape & aSubShape, // get hypos from aSubShape { - const std::list& hypList = _myMeshDS->GetHypothesis(aSubShape); + const TopoDS_Shape & aSubShape = aSubMesh->GetSubShape(); + const list& hypList = _myMeshDS->GetHypothesis(aSubShape); for ( hyp = hypList.begin(); hyp != hypList.end(); hyp++ ) - if ( aFilter.IsOk (cSMESH_Hyp( *hyp ), aSubShape) && - ( cSMESH_Hyp(*hyp)->IsAuxiliary() || !mainHypFound ) && - hypTypes.insert( (*hyp)->GetName() ).second ) + { + const SMESH_Hypothesis* h = cSMESH_Hyp( *hyp ); + if (( aFilter.IsOk( h, aSubShape )) && + ( h->IsAuxiliary() || !mainHypFound ) && + ( h->IsAuxiliary() || hypTypes.insert( h->GetName() ).second )) { aHypList.push_back( *hyp ); nbHyps++; - if ( !cSMESH_Hyp(*hyp)->IsAuxiliary() ) + if ( !h->IsAuxiliary() ) mainHypFound = true; + if ( assignedTo ) assignedTo->push_back( aSubShape ); } + } } // get hypos from ancestors of aSubShape if ( andAncestors ) { - TopTools_MapOfShape map; - TopTools_ListIteratorOfListOfShape it( GetAncestors( aSubShape )); - for (; it.More(); it.Next() ) + // user sorted submeshes of ancestors, according to stored submesh priority + std::vector< SMESH_subMesh * > & ancestors = + const_cast< std::vector< SMESH_subMesh * > & > ( aSubMesh->GetAncestors() ); + SortByMeshOrder( ancestors ); + + vector::const_iterator smIt = ancestors.begin(); + for ( ; smIt != ancestors.end(); smIt++ ) { - if ( !map.Add( it.Value() )) - continue; - const std::list& hypList = _myMeshDS->GetHypothesis(it.Value()); + const TopoDS_Shape& curSh = (*smIt)->GetSubShape(); + const list& hypList = _myMeshDS->GetHypothesis(curSh); for ( hyp = hypList.begin(); hyp != hypList.end(); hyp++ ) - if (aFilter.IsOk( cSMESH_Hyp( *hyp ), it.Value() ) && - ( cSMESH_Hyp(*hyp)->IsAuxiliary() || !mainHypFound ) && - hypTypes.insert( (*hyp)->GetName() ).second ) + { + const SMESH_Hypothesis* h = cSMESH_Hyp( *hyp ); + if (( aFilter.IsOk( h, curSh )) && + ( h->IsAuxiliary() || !mainHypFound ) && + ( h->IsAuxiliary() || hypTypes.insert( h->GetName() ).second )) { aHypList.push_back( *hyp ); nbHyps++; - if ( !cSMESH_Hyp(*hyp)->IsAuxiliary() ) + if ( !h->IsAuxiliary() ) mainHypFound = true; + if ( assignedTo ) assignedTo->push_back( curSh ); } + } } } return nbHyps; } +//================================================================================ +/*! + * \brief Return a hypothesis by its ID + */ +//================================================================================ + +SMESH_Hypothesis * SMESH_Mesh::GetHypothesis(const int anHypId) const +{ + StudyContextStruct *sc = _gen->GetStudyContext(_studyId); + if (sc->mapHypothesis.find(anHypId) == sc->mapHypothesis.end()) + return NULL; + + SMESH_Hypothesis *anHyp = sc->mapHypothesis[anHypId]; + return anHyp; +} + //============================================================================= /*! * */ //============================================================================= -const std::list & SMESH_Mesh::GetLog() throw(SMESH_Exception) +const list & SMESH_Mesh::GetLog() throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); if(MYDEBUG) MESSAGE("SMESH_Mesh::GetLog"); return _myMeshDS->GetScript()->GetCommands(); } @@ -807,9 +1054,9 @@ const std::list & SMESH_Mesh::GetLog() throw(SMESH_Exception) * */ //============================================================================= -void SMESH_Mesh::ClearLog() throw(SMESH_Exception) +void SMESH_Mesh::ClearLog() throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); if(MYDEBUG) MESSAGE("SMESH_Mesh::ClearLog"); _myMeshDS->GetScript()->Clear(); } @@ -821,30 +1068,46 @@ void SMESH_Mesh::ClearLog() throw(SMESH_Exception) //============================================================================= SMESH_subMesh *SMESH_Mesh::GetSubMesh(const TopoDS_Shape & aSubShape) - throw(SMESH_Exception) + throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); - SMESH_subMesh *aSubMesh; int index = _myMeshDS->ShapeToIndex(aSubShape); + if ( !index && aSubShape.IsNull() ) + return 0; // for submeshes on GEOM Group if (( !index || index > _nbSubShapes ) && aSubShape.ShapeType() == TopAbs_COMPOUND ) { TopoDS_Iterator it( aSubShape ); if ( it.More() ) + { index = _myMeshDS->AddCompoundSubmesh( aSubShape, it.Value().ShapeType() ); + // fill map of Ancestors + while ( _nbSubShapes < index ) + fillAncestorsMap( _myMeshDS->IndexToShape( ++_nbSubShapes )); + } } -// if ( !index ) -// return NULL; // neither sub-shape nor a group + // if ( !index ) + // return NULL; // neither sub-shape nor a group - map ::iterator i_sm = _mapSubMesh.find(index); - if ( i_sm != _mapSubMesh.end()) - { - aSubMesh = i_sm->second; - } - else + SMESH_subMesh* aSubMesh = _subMeshHolder->Get( index ); + if ( !aSubMesh ) { aSubMesh = new SMESH_subMesh(index, this, _myMeshDS, aSubShape); - _mapSubMesh[index] = aSubMesh; + _subMeshHolder->Add( index, aSubMesh ); + + // include non-computable sub-meshes in SMESH_subMesh::_ancestors of sub-submeshes + switch ( aSubShape.ShapeType() ) { + case TopAbs_COMPOUND: + case TopAbs_WIRE: + case TopAbs_SHELL: + for ( TopoDS_Iterator subIt( aSubShape ); subIt.More(); subIt.Next() ) + { + SMESH_subMesh* sm = GetSubMesh( subIt.Value() ); + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*inclideSelf=*/true); + while ( smIt->more() ) + smIt->next()->ClearAncestors(); + } + default:; + } } return aSubMesh; } @@ -857,19 +1120,12 @@ SMESH_subMesh *SMESH_Mesh::GetSubMesh(const TopoDS_Shape & aSubShape) //============================================================================= SMESH_subMesh *SMESH_Mesh::GetSubMeshContaining(const TopoDS_Shape & aSubShape) const - throw(SMESH_Exception) + throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); - SMESH_subMesh *aSubMesh = NULL; - int index = _myMeshDS->ShapeToIndex(aSubShape); - - map ::const_iterator i_sm = _mapSubMesh.find(index); - if ( i_sm != _mapSubMesh.end()) - aSubMesh = i_sm->second; - - return aSubMesh; + return GetSubMeshContaining( index ); } + //============================================================================= /*! * Get the SMESH_subMesh object implementation. Dont create it, return null @@ -878,48 +1134,62 @@ SMESH_subMesh *SMESH_Mesh::GetSubMeshContaining(const TopoDS_Shape & aSubShape) //============================================================================= SMESH_subMesh *SMESH_Mesh::GetSubMeshContaining(const int aShapeID) const -throw(SMESH_Exception) +throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); - - map ::const_iterator i_sm = _mapSubMesh.find(aShapeID); - if (i_sm == _mapSubMesh.end()) - return NULL; - return i_sm->second; + SMESH_subMesh *aSubMesh = _subMeshHolder->Get( aShapeID ); + + return aSubMesh; } + //================================================================================ /*! - * \brief Return submeshes of groups containing the given subshape + * \brief Return sub-meshes of groups containing the given sub-shape */ //================================================================================ -std::list +list SMESH_Mesh::GetGroupSubMeshesContaining(const TopoDS_Shape & aSubShape) const - throw(SMESH_Exception) + throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); - std::list found; + list found; SMESH_subMesh * subMesh = GetSubMeshContaining(aSubShape); if ( !subMesh ) return found; - // submeshes of groups have max IDs, so search from the map end - std::map::const_reverse_iterator i_sm; - for ( i_sm = _mapSubMesh.rbegin(); i_sm != _mapSubMesh.rend(); ++i_sm) { - SMESHDS_SubMesh * ds = i_sm->second->GetSubMeshDS(); + // sub-meshes of groups have max IDs, so search from the map end + SMESH_subMeshIteratorPtr smIt( _subMeshHolder->GetIterator( /*reverse=*/true ) ); + while ( smIt->more() ) { + SMESH_subMesh* sm = smIt->next(); + SMESHDS_SubMesh * ds = sm->GetSubMeshDS(); if ( ds && ds->IsComplexSubmesh() ) { - TopExp_Explorer exp( i_sm->second->GetSubShape(), aSubShape.ShapeType() ); - for ( ; exp.More(); exp.Next() ) { - if ( aSubShape.IsSame( exp.Current() )) { - found.push_back( i_sm->second ); - break; - } + if ( SMESH_MesherHelper::IsSubShape( aSubShape, sm->GetSubShape() )) + { + found.push_back( sm ); + //break; } } else { - break; + break; // the rest sub-meshes are not those of groups } } + + if ( found.empty() ) // maybe the main shape is a COMPOUND (issue 0021530) + { + if ( SMESH_subMesh * mainSM = GetSubMeshContaining(1) ) + if ( mainSM->GetSubShape().ShapeType() == TopAbs_COMPOUND ) + { + TopoDS_Iterator it( mainSM->GetSubShape() ); + if ( it.Value().ShapeType() == aSubShape.ShapeType() && + SMESH_MesherHelper::IsSubShape( aSubShape, mainSM->GetSubShape() )) + found.push_back( mainSM ); + } + } + else // issue 0023068 + { + if ( SMESH_subMesh * mainSM = GetSubMeshContaining(1) ) + if ( mainSM->GetSubShape().ShapeType() == TopAbs_COMPOUND ) + found.push_back( mainSM ); + } return found; } //======================================================================= @@ -936,9 +1206,7 @@ bool SMESH_Mesh::IsUsedHypothesis(SMESHDS_Hypothesis * anHyp, if ( !aSubMesh || !aSubMesh->IsApplicableHypotesis( hyp )) return false; - const TopoDS_Shape & aSubShape = const_cast( aSubMesh )->GetSubShape(); - - SMESH_Algo *algo = _gen->GetAlgo(*this, aSubShape ); + SMESH_Algo *algo = aSubMesh->GetAlgo(); // algorithm if (anHyp->GetType() > SMESHDS_Hypothesis::PARAM_ALGO) @@ -948,17 +1216,15 @@ bool SMESH_Mesh::IsUsedHypothesis(SMESHDS_Hypothesis * anHyp, if (algo) { // look trough hypotheses used by algo - SMESH_HypoFilter hypoKind; - if ( algo->InitCompatibleHypoFilter( hypoKind, !hyp->IsAuxiliary() )) { + const SMESH_HypoFilter* hypoKind; + if (( hypoKind = algo->GetCompatibleHypoFilter( !hyp->IsAuxiliary() ))) { list usedHyps; - if ( GetHypotheses( aSubShape, hypoKind, usedHyps, true )) + if ( GetHypotheses( aSubMesh, *hypoKind, usedHyps, true )) return ( find( usedHyps.begin(), usedHyps.end(), anHyp ) != usedHyps.end() ); } } - // look through all assigned hypotheses - //SMESH_HypoFilter filter( SMESH_HypoFilter::Is( hyp )); - return false; //GetHypothesis( aSubShape, filter, true ); + return false; } //============================================================================= @@ -967,22 +1233,20 @@ bool SMESH_Mesh::IsUsedHypothesis(SMESHDS_Hypothesis * anHyp, */ //============================================================================= -const list < SMESH_subMesh * >& -SMESH_Mesh::GetSubMeshUsingHypothesis(SMESHDS_Hypothesis * anHyp) - throw(SMESH_Exception) -{ - Unexpect aCatch(SmeshException); - if(MYDEBUG) MESSAGE("SMESH_Mesh::GetSubMeshUsingHypothesis"); - map < int, SMESH_subMesh * >::iterator itsm; - _subMeshesUsingHypothesisList.clear(); - for (itsm = _mapSubMesh.begin(); itsm != _mapSubMesh.end(); itsm++) - { - SMESH_subMesh *aSubMesh = (*itsm).second; - if ( IsUsedHypothesis ( anHyp, aSubMesh )) - _subMeshesUsingHypothesisList.push_back(aSubMesh); - } - return _subMeshesUsingHypothesisList; -} +// const list < SMESH_subMesh * >& +// SMESH_Mesh::GetSubMeshUsingHypothesis(SMESHDS_Hypothesis * anHyp) +// throw(SALOME_Exception) +// { +// _subMeshesUsingHypothesisList.clear(); +// SMESH_subMeshIteratorPtr smIt( _subMeshHolder->GetIterator() ); +// while ( smIt->more() ) +// { +// SMESH_subMesh* aSubMesh = smIt->next(); +// if ( IsUsedHypothesis ( anHyp, aSubMesh )) +// _subMeshesUsingHypothesisList.push_back( aSubMesh ); +// } +// return _subMeshesUsingHypothesisList; +// } //======================================================================= //function : NotifySubMeshesHypothesisModification @@ -991,50 +1255,62 @@ SMESH_Mesh::GetSubMeshUsingHypothesis(SMESHDS_Hypothesis * anHyp) void SMESH_Mesh::NotifySubMeshesHypothesisModification(const SMESH_Hypothesis* hyp) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); + + if ( !GetMeshDS()->IsUsedHypothesis( hyp )) + return; - const SMESH_Algo *foundAlgo = 0; - SMESH_HypoFilter algoKind, compatibleHypoKind; + if (_callUp) + _callUp->HypothesisModified(); + + SMESH_Algo *algo; + const SMESH_HypoFilter* compatibleHypoKind; list usedHyps; + // keep sub-meshes not to miss ones whose state can change due to notifying others + vector< SMESH_subMesh* > smToNotify; - map < int, SMESH_subMesh * >::iterator itsm; - for (itsm = _mapSubMesh.begin(); itsm != _mapSubMesh.end(); itsm++) + SMESH_subMeshIteratorPtr smIt( _subMeshHolder->GetIterator() ); + while ( smIt->more() ) { - SMESH_subMesh *aSubMesh = (*itsm).second; - if ( aSubMesh->IsApplicableHypotesis( hyp )) + SMESH_subMesh* aSubMesh = smIt->next(); + + // if aSubMesh meshing depends on hyp, + // we call aSubMesh->AlgoStateEngine( MODIF_HYP, hyp ) that causes either + // 1) clearing of already computed aSubMesh or + // 2) changing algo_state from MISSING_HYP to HYP_OK when parameters of hyp becomes valid, + // other possible changes are not interesting. (IPAL0052457 - assigning hyp performance pb) + if ( aSubMesh->GetComputeState() != SMESH_subMesh::COMPUTE_OK && + aSubMesh->GetComputeState() != SMESH_subMesh::FAILED_TO_COMPUTE && + aSubMesh->GetAlgoState() != SMESH_subMesh::MISSING_HYP && + !hyp->DataDependOnParams() ) + continue; + + const TopoDS_Shape & aSubShape = aSubMesh->GetSubShape(); + + if (( aSubMesh->IsApplicableHypotesis( hyp )) && + ( algo = aSubMesh->GetAlgo() ) && + ( compatibleHypoKind = algo->GetCompatibleHypoFilter( !hyp->IsAuxiliary() )) && + ( compatibleHypoKind->IsOk( hyp, aSubShape ))) { - const TopoDS_Shape & aSubShape = aSubMesh->GetSubShape(); - - if ( !foundAlgo ) // init filter for algo search - algoKind.Init( THypType::IsAlgo() ).And( THypType::IsApplicableTo( aSubShape )); - - const SMESH_Algo *algo = static_cast - ( GetHypothesis( aSubShape, algoKind, true )); - - if ( algo ) + // check if hyp is used by algo + usedHyps.clear(); + if ( GetHypotheses( aSubMesh, *compatibleHypoKind, usedHyps, true ) && + find( usedHyps.begin(), usedHyps.end(), hyp ) != usedHyps.end() ) { - bool sameAlgo = ( algo == foundAlgo ); - if ( !sameAlgo && foundAlgo ) - sameAlgo = ( strcmp( algo->GetName(), foundAlgo->GetName() ) == 0); - - if ( !sameAlgo ) { // init filter for used hypos search - if ( !algo->InitCompatibleHypoFilter( compatibleHypoKind, !hyp->IsAuxiliary() )) - continue; // algo does not use any hypothesis - foundAlgo = algo; - } - - // check if hyp is used by algo - usedHyps.clear(); - if ( GetHypotheses( aSubShape, compatibleHypoKind, usedHyps, true ) && - find( usedHyps.begin(), usedHyps.end(), hyp ) != usedHyps.end() ) - { - aSubMesh->AlgoStateEngine(SMESH_subMesh::MODIF_HYP, - const_cast< SMESH_Hypothesis*>( hyp )); - } + smToNotify.push_back( aSubMesh ); } } } + + for ( size_t i = 0; i < smToNotify.size(); ++i ) + { + smToNotify[i]->AlgoStateEngine(SMESH_subMesh::MODIF_HYP, + const_cast< SMESH_Hypothesis*>( hyp )); + } + + HasModificationsToDiscard(); // to reset _isModified flag if mesh becomes empty + GetMeshDS()->Modified(); } //============================================================================= @@ -1042,90 +1318,410 @@ void SMESH_Mesh::NotifySubMeshesHypothesisModification(const SMESH_Hypothesis* h * Auto color functionality */ //============================================================================= -void SMESH_Mesh::SetAutoColor(bool theAutoColor) throw(SMESH_Exception) +void SMESH_Mesh::SetAutoColor(bool theAutoColor) throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); _isAutoColor = theAutoColor; } -bool SMESH_Mesh::GetAutoColor() throw(SMESH_Exception) +bool SMESH_Mesh::GetAutoColor() throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); return _isAutoColor; } -//============================================================================= -/*! Export* methods. - * To store mesh contents on disk in different formats. +//======================================================================= +//function : SetIsModified +//purpose : Set the flag meaning that the mesh has been edited "manually" +//======================================================================= + +void SMESH_Mesh::SetIsModified(bool isModified) +{ + _isModified = isModified; + + if ( _isModified ) + // check if mesh becomes empty as result of modification + HasModificationsToDiscard(); +} + +//======================================================================= +//function : HasModificationsToDiscard +//purpose : Return true if the mesh has been edited since a total re-compute +// and those modifications may prevent successful partial re-compute. +// As a side effect reset _isModified flag if mesh is empty +//issue : 0020693 +//======================================================================= + +bool SMESH_Mesh::HasModificationsToDiscard() const +{ + if ( ! _isModified ) + return false; + + // return true if the next Compute() will be partial and + // existing but changed elements may prevent successful re-compute + bool hasComputed = false, hasNotComputed = false; + SMESH_subMeshIteratorPtr smIt( _subMeshHolder->GetIterator() ); + while ( smIt->more() ) + { + const SMESH_subMesh* aSubMesh = smIt->next(); + switch ( aSubMesh->GetSubShape().ShapeType() ) + { + case TopAbs_EDGE: + case TopAbs_FACE: + case TopAbs_SOLID: + if ( aSubMesh->IsMeshComputed() ) + hasComputed = true; + else + hasNotComputed = true; + if ( hasComputed && hasNotComputed) + return true; + } + } + if ( NbNodes() < 1 ) + const_cast(this)->_isModified = false; + + return false; +} + +//================================================================================ +/*! + * \brief Check if any groups of the same type have equal names */ -//============================================================================= +//================================================================================ bool SMESH_Mesh::HasDuplicatedGroupNamesMED() { - throw SMESH_Exception(LOCALIZED ("Not implemented ...")); - return 0; + //set aGroupNames; // Corrected for Mantis issue 0020028 + map< SMDSAbs_ElementType, set > aGroupNames; + for ( map::iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ ) + { + SMESH_Group* aGroup = it->second; + SMDSAbs_ElementType aType = aGroup->GetGroupDS()->GetType(); + string aGroupName = aGroup->GetName(); + aGroupName.resize(MAX_MED_GROUP_NAME_LENGTH); + if (!aGroupNames[aType].insert(aGroupName).second) + return true; + } + + return false; +} + +//================================================================================ +/*! + * \brief Export the mesh to a med file + * \param [in] file - name of the MED file + * \param [in] theMeshName - name of this mesh + * \param [in] theAutoGroups - boolean parameter for creating/not creating + * the groups Group_On_All_Nodes, Group_On_All_Faces, ... ; + * the typical use is auto_groups=false. + * \param [in] theVersion - defines the version of format of MED file, that will be created + * \param [in] meshPart - mesh data to export + * \param [in] theAutoDimension - if \c true, a space dimension of a MED mesh can be either + * - 1D if all mesh nodes lie on OX coordinate axis, or + * - 2D if all mesh nodes lie on XOY coordinate plane, or + * - 3D in the rest cases. + * If \a theAutoDimension is \c false, the space dimension is always 3. + * \return int - mesh index in the file + */ +//================================================================================ + +void SMESH_Mesh::ExportMED(const char * file, + const char* theMeshName, + bool theAutoGroups, + int theVersion, + const SMESHDS_Mesh* meshPart, + bool theAutoDimension, + bool theAddODOnVertices) + throw(SALOME_Exception) +{ + SMESH_TRY; + + DriverMED_W_SMESHDS_Mesh myWriter; + myWriter.SetFile ( file, MED::EVersion(theVersion) ); + myWriter.SetMesh ( meshPart ? (SMESHDS_Mesh*) meshPart : _myMeshDS ); + myWriter.SetAutoDimension( theAutoDimension ); + myWriter.AddODOnVertices ( theAddODOnVertices ); + if ( !theMeshName ) + myWriter.SetMeshId ( _id ); + else { + myWriter.SetMeshId ( -1 ); + myWriter.SetMeshName ( theMeshName ); + } + + if ( theAutoGroups ) { + myWriter.AddGroupOfNodes(); + myWriter.AddGroupOfEdges(); + myWriter.AddGroupOfFaces(); + myWriter.AddGroupOfVolumes(); + } + + // Pass groups to writer. Provide unique group names. + //set aGroupNames; // Corrected for Mantis issue 0020028 + if ( !meshPart ) + { + map< SMDSAbs_ElementType, set > aGroupNames; + char aString [256]; + int maxNbIter = 10000; // to guarantee cycle finish + for ( map::iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ ) { + SMESH_Group* aGroup = it->second; + SMESHDS_GroupBase* aGroupDS = aGroup->GetGroupDS(); + if ( aGroupDS ) { + SMDSAbs_ElementType aType = aGroupDS->GetType(); + string aGroupName0 = aGroup->GetName(); + aGroupName0.resize(MAX_MED_GROUP_NAME_LENGTH); + string aGroupName = aGroupName0; + for (int i = 1; !aGroupNames[aType].insert(aGroupName).second && i < maxNbIter; i++) { + sprintf(&aString[0], "GR_%d_%s", i, aGroupName0.c_str()); + aGroupName = aString; + aGroupName.resize(MAX_MED_GROUP_NAME_LENGTH); + } + aGroupDS->SetStoreName( aGroupName.c_str() ); + myWriter.AddGroup( aGroupDS ); + } + } + } + // Perform export + myWriter.Perform(); + + SMESH_CATCH( SMESH::throwSalomeEx ); } -void SMESH_Mesh::ExportMED(const char *file, - const char* theMeshName, - bool theAutoGroups, - int theVersion) - throw(SMESH_Exception) +//================================================================================ +/*! + * \brief Export the mesh to a SAUV file + */ +//================================================================================ + +void SMESH_Mesh::ExportSAUV(const char *file, + const char* theMeshName, + bool theAutoGroups) + throw(SALOME_Exception) { - throw SMESH_Exception(LOCALIZED ("Not implemented ...")); + std::string medfilename(file); + medfilename += ".med"; + std::string cmd; +#ifdef WIN32 + cmd = "%PYTHONBIN% "; +#else + cmd = "python "; +#endif + cmd += "-c \""; + cmd += "from medutilities import my_remove ; my_remove(r'" + medfilename + "')"; + cmd += "\""; + system(cmd.c_str()); + ExportMED(medfilename.c_str(), theMeshName, theAutoGroups, 1); +#ifdef WIN32 + cmd = "%PYTHONBIN% "; +#else + cmd = "python "; +#endif + cmd += "-c \""; + cmd += "from medutilities import convert ; convert(r'" + medfilename + "', 'MED', 'GIBI', 1, r'" + file + "')"; + cmd += "\""; + system(cmd.c_str()); +#ifdef WIN32 + cmd = "%PYTHONBIN% "; +#else + cmd = "python "; +#endif + cmd += "-c \""; + cmd += "from medutilities import my_remove ; my_remove(r'" + medfilename + "')"; + cmd += "\""; + system(cmd.c_str()); } -void SMESH_Mesh::ExportDAT(const char *file) throw(SMESH_Exception) +//================================================================================ +/*! + * \brief Export the mesh to a DAT file + */ +//================================================================================ + +void SMESH_Mesh::ExportDAT(const char * file, + const SMESHDS_Mesh* meshPart) throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); DriverDAT_W_SMDS_Mesh myWriter; - myWriter.SetFile(string(file)); - myWriter.SetMesh(_myMeshDS); - myWriter.SetMeshId(_idDoc); + myWriter.SetFile( file ); + myWriter.SetMesh( meshPart ? (SMESHDS_Mesh*) meshPart : _myMeshDS ); + myWriter.SetMeshId(_id); myWriter.Perform(); } -void SMESH_Mesh::ExportUNV(const char *file) throw(SMESH_Exception) +//================================================================================ +/*! + * \brief Export the mesh to an UNV file + */ +//================================================================================ + +void SMESH_Mesh::ExportUNV(const char * file, + const SMESHDS_Mesh* meshPart) throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); DriverUNV_W_SMDS_Mesh myWriter; - myWriter.SetFile(string(file)); - myWriter.SetMesh(_myMeshDS); - myWriter.SetMeshId(_idDoc); + myWriter.SetFile( file ); + myWriter.SetMesh( meshPart ? (SMESHDS_Mesh*) meshPart : _myMeshDS ); + myWriter.SetMeshId(_id); // myWriter.SetGroups(_mapGroup); - for ( std::map::iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ ) { - SMESH_Group* aGroup = it->second; - SMESHDS_GroupBase* aGroupDS = aGroup->GetGroupDS(); - if ( aGroupDS ) { - std::string aGroupName = aGroup->GetName(); - aGroupDS->SetStoreName( aGroupName.c_str() ); - myWriter.AddGroup( aGroupDS ); + if ( !meshPart ) + { + for ( map::iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ ) { + SMESH_Group* aGroup = it->second; + SMESHDS_GroupBase* aGroupDS = aGroup->GetGroupDS(); + if ( aGroupDS ) { + string aGroupName = aGroup->GetName(); + aGroupDS->SetStoreName( aGroupName.c_str() ); + myWriter.AddGroup( aGroupDS ); + } } } myWriter.Perform(); } -void SMESH_Mesh::ExportSTL(const char *file, const bool isascii) throw(SMESH_Exception) +//================================================================================ +/*! + * \brief Export the mesh to an STL file + */ +//================================================================================ + +void SMESH_Mesh::ExportSTL(const char * file, + const bool isascii, + const SMESHDS_Mesh* meshPart) throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); DriverSTL_W_SMDS_Mesh myWriter; - myWriter.SetFile(string(file)); + myWriter.SetFile( file ); myWriter.SetIsAscii( isascii ); - myWriter.SetMesh(_myMeshDS); - myWriter.SetMeshId(_idDoc); + myWriter.SetMesh( meshPart ? (SMESHDS_Mesh*) meshPart : _myMeshDS); + myWriter.SetMeshId(_id); + myWriter.Perform(); +} + +//================================================================================ +/*! + * \brief Export the mesh to the CGNS file + */ +//================================================================================ + +void SMESH_Mesh::ExportCGNS(const char * file, + const SMESHDS_Mesh* meshDS, + const char * meshName) +{ + int res = Driver_Mesh::DRS_FAIL; +#ifdef WITH_CGNS + DriverCGNS_Write myWriter; + myWriter.SetFile( file ); + myWriter.SetMesh( const_cast( meshDS )); + myWriter.SetMeshName( SMESH_Comment("Mesh_") << meshDS->GetPersistentId()); + if ( meshName && meshName[0] ) + myWriter.SetMeshName( meshName ); + res = myWriter.Perform(); +#endif + if ( res != Driver_Mesh::DRS_OK ) + throw SALOME_Exception("Export failed"); +} + +//================================================================================ +/*! + * \brief Export the mesh to a GMF file + */ +//================================================================================ + +void SMESH_Mesh::ExportGMF(const char * file, + const SMESHDS_Mesh* meshDS, + bool withRequiredGroups) +{ + DriverGMF_Write myWriter; + myWriter.SetFile( file ); + myWriter.SetMesh( const_cast( meshDS )); + myWriter.SetExportRequiredGroups( withRequiredGroups ); + myWriter.Perform(); } +//================================================================================ +/*! + * \brief Return a ratio of "compute cost" of computed sub-meshes to the whole + * "compute cost". + */ +//================================================================================ + +double SMESH_Mesh::GetComputeProgress() const +{ + double totalCost = 1e-100, computedCost = 0; + const SMESH_subMesh* curSM = _gen->GetCurrentSubMesh(); + + // get progress of a current algo + TColStd_MapOfInteger currentSubIds; + if ( curSM ) + if ( SMESH_Algo* algo = curSM->GetAlgo() ) + { + int algoNotDoneCost = 0, algoDoneCost = 0; + const std::vector& smToCompute = algo->SubMeshesToCompute(); + for ( size_t i = 0; i < smToCompute.size(); ++i ) + { + if ( smToCompute[i]->IsEmpty() ) + algoNotDoneCost += smToCompute[i]->GetComputeCost(); + else + algoDoneCost += smToCompute[i]->GetComputeCost(); + currentSubIds.Add( smToCompute[i]->GetId() ); + } + double rate = 0; + try + { + OCC_CATCH_SIGNALS; + rate = algo->GetProgress(); + } + catch (...) { +#ifdef _DEBUG_ + cerr << "Exception in " << algo->GetName() << "::GetProgress()" << endl; +#endif + } + if ( 0. < rate && rate < 1.001 ) + { + computedCost += rate * ( algoDoneCost + algoNotDoneCost ); + } + else + { + rate = algo->GetProgressByTic(); + computedCost += algoDoneCost + rate * algoNotDoneCost; + } + // cout << "rate: "<getDependsOnIterator(/*includeSelf=*/true); + while ( smIt->more() ) + { + const SMESH_subMesh* sm = smIt->next(); + const int smCost = sm->GetComputeCost(); + totalCost += smCost; + if ( !currentSubIds.Contains( sm->GetId() ) ) + { + if (( !sm->IsEmpty() ) || + ( sm->GetComputeState() == SMESH_subMesh::FAILED_TO_COMPUTE && + !sm->DependsOn( curSM ) )) + computedCost += smCost; + } + } + } + // cout << "Total: " << totalCost + // << " computed: " << computedCost << " progress: " << computedCost / totalCost + // << " nbElems: " << GetMeshDS()->GetMeshInfo().NbElements() << endl; + return computedCost / totalCost; +} + //================================================================================ /*! * \brief Return number of nodes in the mesh */ //================================================================================ -int SMESH_Mesh::NbNodes() throw(SMESH_Exception) +int SMESH_Mesh::NbNodes() const throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); return _myMeshDS->NbNodes(); } @@ -1135,9 +1731,21 @@ int SMESH_Mesh::NbNodes() throw(SMESH_Exception) */ //================================================================================ -int SMESH_Mesh::NbEdges(SMDSAbs_ElementOrder order) throw(SMESH_Exception) +int SMESH_Mesh::Nb0DElements() const throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); + return _myMeshDS->GetMeshInfo().Nb0DElements(); +} + +//================================================================================ +/*! + * \brief Return number of edges of given order in the mesh + */ +//================================================================================ + +int SMESH_Mesh::NbEdges(SMDSAbs_ElementOrder order) const throw(SALOME_Exception) +{ + Unexpect aCatch(SalomeException); return _myMeshDS->GetMeshInfo().NbEdges(order); } @@ -1147,9 +1755,9 @@ int SMESH_Mesh::NbEdges(SMDSAbs_ElementOrder order) throw(SMESH_Exception) */ //================================================================================ -int SMESH_Mesh::NbFaces(SMDSAbs_ElementOrder order) throw(SMESH_Exception) +int SMESH_Mesh::NbFaces(SMDSAbs_ElementOrder order) const throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); return _myMeshDS->GetMeshInfo().NbFaces(order); } @@ -1159,34 +1767,58 @@ int SMESH_Mesh::NbFaces(SMDSAbs_ElementOrder order) throw(SMESH_Exception) */ //================================================================================ -int SMESH_Mesh::NbTriangles(SMDSAbs_ElementOrder order) throw(SMESH_Exception) +int SMESH_Mesh::NbTriangles(SMDSAbs_ElementOrder order) const throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); return _myMeshDS->GetMeshInfo().NbTriangles(order); } +//================================================================================ +/*! + * \brief Return number of biquadratic triangles in the mesh + */ +//================================================================================ + +int SMESH_Mesh::NbBiQuadTriangles() const throw(SALOME_Exception) +{ + Unexpect aCatch(SalomeException); + return _myMeshDS->GetMeshInfo().NbBiQuadTriangles(); +} + //================================================================================ /*! * \brief Return the number nodes faces in the mesh */ //================================================================================ -int SMESH_Mesh::NbQuadrangles(SMDSAbs_ElementOrder order) throw(SMESH_Exception) +int SMESH_Mesh::NbQuadrangles(SMDSAbs_ElementOrder order) const throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); return _myMeshDS->GetMeshInfo().NbQuadrangles(order); } +//================================================================================ +/*! + * \brief Return number of biquadratic quadrangles in the mesh + */ +//================================================================================ + +int SMESH_Mesh::NbBiQuadQuadrangles() const throw(SALOME_Exception) +{ + Unexpect aCatch(SalomeException); + return _myMeshDS->GetMeshInfo().NbBiQuadQuadrangles(); +} + //================================================================================ /*! * \brief Return the number of polygonal faces in the mesh */ //================================================================================ -int SMESH_Mesh::NbPolygons() throw(SMESH_Exception) +int SMESH_Mesh::NbPolygons(SMDSAbs_ElementOrder order) const throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); - return _myMeshDS->GetMeshInfo().NbPolygons(); + Unexpect aCatch(SalomeException); + return _myMeshDS->GetMeshInfo().NbPolygons(order); } //================================================================================ @@ -1195,9 +1827,9 @@ int SMESH_Mesh::NbPolygons() throw(SMESH_Exception) */ //================================================================================ -int SMESH_Mesh::NbVolumes(SMDSAbs_ElementOrder order) throw(SMESH_Exception) +int SMESH_Mesh::NbVolumes(SMDSAbs_ElementOrder order) const throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); return _myMeshDS->GetMeshInfo().NbVolumes(order); } @@ -1207,9 +1839,9 @@ int SMESH_Mesh::NbVolumes(SMDSAbs_ElementOrder order) throw(SMESH_Exception) */ //================================================================================ -int SMESH_Mesh::NbTetras(SMDSAbs_ElementOrder order) throw(SMESH_Exception) +int SMESH_Mesh::NbTetras(SMDSAbs_ElementOrder order) const throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); return _myMeshDS->GetMeshInfo().NbTetras(order); } @@ -1219,21 +1851,33 @@ int SMESH_Mesh::NbTetras(SMDSAbs_ElementOrder order) throw(SMESH_Exception) */ //================================================================================ -int SMESH_Mesh::NbHexas(SMDSAbs_ElementOrder order) throw(SMESH_Exception) +int SMESH_Mesh::NbHexas(SMDSAbs_ElementOrder order) const throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); return _myMeshDS->GetMeshInfo().NbHexas(order); } +//================================================================================ +/*! + * \brief Return number of triquadratic hexahedrons in the mesh + */ +//================================================================================ + +int SMESH_Mesh::NbTriQuadraticHexas() const throw(SALOME_Exception) +{ + Unexpect aCatch(SalomeException); + return _myMeshDS->GetMeshInfo().NbTriQuadHexas(); +} + //================================================================================ /*! * \brief Return number of pyramids of given order in the mesh */ //================================================================================ -int SMESH_Mesh::NbPyramids(SMDSAbs_ElementOrder order) throw(SMESH_Exception) +int SMESH_Mesh::NbPyramids(SMDSAbs_ElementOrder order) const throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); return _myMeshDS->GetMeshInfo().NbPyramids(order); } @@ -1243,36 +1887,72 @@ int SMESH_Mesh::NbPyramids(SMDSAbs_ElementOrder order) throw(SMESH_Exception) */ //================================================================================ -int SMESH_Mesh::NbPrisms(SMDSAbs_ElementOrder order) throw(SMESH_Exception) +int SMESH_Mesh::NbPrisms(SMDSAbs_ElementOrder order) const throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); return _myMeshDS->GetMeshInfo().NbPrisms(order); } +//================================================================================ +/*! + * \brief Return number of hexagonal prisms in the mesh + */ +//================================================================================ + +int SMESH_Mesh::NbHexagonalPrisms() const throw(SALOME_Exception) +{ + Unexpect aCatch(SalomeException); + return _myMeshDS->GetMeshInfo().NbHexPrisms(); +} + //================================================================================ /*! * \brief Return number of polyhedrons in the mesh */ //================================================================================ -int SMESH_Mesh::NbPolyhedrons() throw(SMESH_Exception) +int SMESH_Mesh::NbPolyhedrons() const throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); return _myMeshDS->GetMeshInfo().NbPolyhedrons(); } +//================================================================================ +/*! + * \brief Return number of ball elements in the mesh + */ +//================================================================================ + +int SMESH_Mesh::NbBalls() const throw(SALOME_Exception) +{ + Unexpect aCatch(SalomeException); + return _myMeshDS->GetMeshInfo().NbBalls(); +} + //================================================================================ /*! * \brief Return number of submeshes in the mesh */ //================================================================================ -int SMESH_Mesh::NbSubMesh() throw(SMESH_Exception) +int SMESH_Mesh::NbSubMesh() const throw(SALOME_Exception) { - Unexpect aCatch(SmeshException); + Unexpect aCatch(SalomeException); return _myMeshDS->NbSubMesh(); } +//================================================================================ +/*! + * \brief Returns number of meshes in the Study, that is supposed to be + * equal to SMESHDS_Document::NbMeshes() + */ +//================================================================================ + +int SMESH_Mesh::NbMeshes() const // nb meshes in the Study +{ + return _myDocument->NbMeshes(); +} + //======================================================================= //function : IsNotConformAllowed //purpose : check if a hypothesis alowing notconform mesh is present @@ -1304,18 +1984,74 @@ bool SMESH_Mesh::IsMainShape(const TopoDS_Shape& theShape) const SMESH_Group* SMESH_Mesh::AddGroup (const SMDSAbs_ElementType theType, const char* theName, - int& theId, - const TopoDS_Shape& theShape) + int& theId, + const TopoDS_Shape& theShape, + const SMESH_PredicatePtr& thePredicate) { - if (_mapGroup.find(_groupId) != _mapGroup.end()) + if (_mapGroup.count(_groupId)) return NULL; theId = _groupId; - SMESH_Group* aGroup = new SMESH_Group (theId, this, theType, theName, theShape); + SMESH_Group* aGroup = new SMESH_Group (theId, this, theType, theName, theShape, thePredicate); GetMeshDS()->AddGroup( aGroup->GetGroupDS() ); _mapGroup[_groupId++] = aGroup; return aGroup; } +//================================================================================ +/*! + * \brief Creates a group based on an existing SMESHDS group. Group ID should be unique + */ +//================================================================================ + +SMESH_Group* SMESH_Mesh::AddGroup (SMESHDS_GroupBase* groupDS) throw(SALOME_Exception) +{ + if ( !groupDS ) + throw SALOME_Exception(LOCALIZED ("SMESH_Mesh::AddGroup(): NULL SMESHDS_GroupBase")); + + map ::iterator i_g = _mapGroup.find( groupDS->GetID() ); + if ( i_g != _mapGroup.end() && i_g->second ) + { + if ( i_g->second->GetGroupDS() == groupDS ) + return i_g->second; + else + throw SALOME_Exception(LOCALIZED ("SMESH_Mesh::AddGroup() wrong ID of SMESHDS_GroupBase")); + } + SMESH_Group* aGroup = new SMESH_Group (groupDS); + _mapGroup[ groupDS->GetID() ] = aGroup; + GetMeshDS()->AddGroup( aGroup->GetGroupDS() ); + + _groupId = 1 + _mapGroup.rbegin()->first; + + return aGroup; +} + + +//================================================================================ +/*! + * \brief Creates SMESH_Groups for not wrapped SMESHDS_Groups + * \retval bool - true if new SMESH_Groups have been created + * + */ +//================================================================================ + +bool SMESH_Mesh::SynchronizeGroups() +{ + int nbGroups = _mapGroup.size(); + const set& groups = _myMeshDS->GetGroups(); + set::const_iterator gIt = groups.begin(); + for ( ; gIt != groups.end(); ++gIt ) + { + SMESHDS_GroupBase* groupDS = (SMESHDS_GroupBase*) *gIt; + _groupId = groupDS->GetID(); + if ( !_mapGroup.count( _groupId )) + _mapGroup[_groupId] = new SMESH_Group( groupDS ); + } + if ( !_mapGroup.empty() ) + _groupId = _mapGroup.rbegin()->first + 1; + + return nbGroups < _mapGroup.size(); +} + //================================================================================ /*! * \brief Return iterator on all existing groups @@ -1348,15 +2084,27 @@ SMESH_Group* SMESH_Mesh::GetGroup (const int theGroupID) */ //============================================================================= -std::list SMESH_Mesh::GetGroupIds() const +list SMESH_Mesh::GetGroupIds() const { - std::list anIds; - for ( std::map::const_iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ ) + list anIds; + for ( map::const_iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ ) anIds.push_back( it->first ); return anIds; } +//================================================================================ +/*! + * \brief Set a caller of methods at level of CORBA API implementation. + * The set upCaller will be deleted by SMESH_Mesh + */ +//================================================================================ + +void SMESH_Mesh::SetCallUp( TCallUp* upCaller ) +{ + if ( _callUp ) delete _callUp; + _callUp = upCaller; +} //============================================================================= /*! @@ -1364,13 +2112,16 @@ std::list SMESH_Mesh::GetGroupIds() const */ //============================================================================= -void SMESH_Mesh::RemoveGroup (const int theGroupID) +bool SMESH_Mesh::RemoveGroup (const int theGroupID) { if (_mapGroup.find(theGroupID) == _mapGroup.end()) - return; + return false; GetMeshDS()->RemoveGroup( _mapGroup[theGroupID]->GetGroupDS() ); delete _mapGroup[theGroupID]; _mapGroup.erase (theGroupID); + if (_callUp) + _callUp->RemoveGroup( theGroupID ); + return true; } //======================================================================= @@ -1397,11 +2148,11 @@ ostream& SMESH_Mesh::Dump(ostream& save) { int clause = 0; save << "========================== Dump contents of mesh ==========================" << endl << endl; - save << ++clause << ") Total number of nodes: \t" << NbNodes() << endl; - save << ++clause << ") Total number of edges: \t" << NbEdges() << endl; - save << ++clause << ") Total number of faces: \t" << NbFaces() << endl; - save << ++clause << ") Total number of polygons:\t" << NbPolygons() << endl; - save << ++clause << ") Total number of volumes:\t" << NbVolumes() << endl; + save << ++clause << ") Total number of nodes: \t" << NbNodes() << endl; + save << ++clause << ") Total number of edges: \t" << NbEdges() << endl; + save << ++clause << ") Total number of faces: \t" << NbFaces() << endl; + save << ++clause << ") Total number of polygons: \t" << NbPolygons() << endl; + save << ++clause << ") Total number of volumes: \t" << NbVolumes() << endl; save << ++clause << ") Total number of polyhedrons:\t" << NbPolyhedrons() << endl << endl; for ( int isQuadratic = 0; isQuadratic < 2; ++isQuadratic ) { @@ -1416,7 +2167,7 @@ ostream& SMESH_Mesh::Dump(ostream& save) save << clause << ".1) Number of " << orderStr << " triangles: \t" << nb3 << endl; save << clause << ".2) Number of " << orderStr << " quadrangles:\t" << nb4 << endl; if ( nb3 + nb4 != NbFaces(order) ) { - std::map myFaceMap; + map myFaceMap; SMDS_FaceIteratorPtr itFaces=_myMeshDS->facesIterator(); while( itFaces->more( ) ) { int nbNodes = itFaces->next()->NbNodes(); @@ -1436,12 +2187,12 @@ ostream& SMESH_Mesh::Dump(ostream& save) int nb4 = NbTetras(order); int nb5 = NbPyramids(order); int nb6 = NbPrisms(order); - save << clause << ".1) Number of " << orderStr << " hexahedrons:\t" << nb8 << endl; + save << clause << ".1) Number of " << orderStr << " hexahedrons: \t" << nb8 << endl; save << clause << ".2) Number of " << orderStr << " tetrahedrons:\t" << nb4 << endl; save << clause << ".3) Number of " << orderStr << " prisms: \t" << nb6 << endl; - save << clause << ".4) Number of " << orderStr << " pyramids:\t" << nb5 << endl; + save << clause << ".4) Number of " << orderStr << " pyramids: \t" << nb5 << endl; if ( nb8 + nb4 + nb5 + nb6 != NbVolumes(order) ) { - std::map myVolumesMap; + map myVolumesMap; SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator(); while( itVolumes->more( ) ) { int nbNodes = itVolumes->next()->NbNodes(); @@ -1480,14 +2231,14 @@ SMDSAbs_ElementType SMESH_Mesh::GetElementType( const int id, const bool iselem SMESH_Group* SMESH_Mesh::ConvertToStandalone ( int theGroupID ) { SMESH_Group* aGroup = 0; - std::map < int, SMESH_Group * >::iterator itg = _mapGroup.find( theGroupID ); + map < int, SMESH_Group * >::iterator itg = _mapGroup.find( theGroupID ); if ( itg == _mapGroup.end() ) return aGroup; SMESH_Group* anOldGrp = (*itg).second; - SMESHDS_GroupBase* anOldGrpDS = anOldGrp->GetGroupDS(); - if ( !anOldGrp || !anOldGrpDS ) + if ( !anOldGrp || !anOldGrp->GetGroupDS() ) return aGroup; + SMESHDS_GroupBase* anOldGrpDS = anOldGrp->GetGroupDS(); // create new standalone group aGroup = new SMESH_Group (theGroupID, this, anOldGrpDS->GetType(), anOldGrp->GetName() ); @@ -1502,9 +2253,207 @@ SMESH_Group* SMESH_Mesh::ConvertToStandalone ( int theGroupID ) while ( anItr->more() ) aNewGrpDS->Add( (anItr->next())->GetID() ); + // set color + aNewGrpDS->SetColor( anOldGrpDS->GetColor() ); + // remove old group delete anOldGrp; return aGroup; } +//============================================================================= +/*! + * \brief remove submesh order from Mesh + */ +//============================================================================= + +void SMESH_Mesh::ClearMeshOrder() +{ + _mySubMeshOrder.clear(); +} + +//============================================================================= +/*! + * \brief remove submesh order from Mesh + */ +//============================================================================= + +void SMESH_Mesh::SetMeshOrder(const TListOfListOfInt& theOrder ) +{ + _mySubMeshOrder = theOrder; +} + +//============================================================================= +/*! + * \brief return submesh order if any + */ +//============================================================================= + +const TListOfListOfInt& SMESH_Mesh::GetMeshOrder() const +{ + return _mySubMeshOrder; +} + +//============================================================================= +/*! + * \brief fill _mapAncestors + */ +//============================================================================= + +void SMESH_Mesh::fillAncestorsMap(const TopoDS_Shape& theShape) +{ + int desType, ancType; + if ( !theShape.IsSame( GetShapeToMesh()) && theShape.ShapeType() == TopAbs_COMPOUND ) + { + // a geom group is added. Insert it into lists of ancestors before + // the first ancestor more complex than group members + TopoDS_Iterator subIt( theShape ); + if ( !subIt.More() ) return; + int memberType = subIt.Value().ShapeType(); + for ( desType = TopAbs_VERTEX; desType >= memberType; desType-- ) + for (TopExp_Explorer des( theShape, TopAbs_ShapeEnum( desType )); des.More(); des.Next()) + { + if ( !_mapAncestors.Contains( des.Current() )) continue;// issue 0020982 + TopTools_ListOfShape& ancList = _mapAncestors.ChangeFromKey( des.Current() ); + TopTools_ListIteratorOfListOfShape ancIt (ancList); + while ( ancIt.More() && ancIt.Value().ShapeType() >= memberType ) + ancIt.Next(); + if ( ancIt.More() ) ancList.InsertBefore( theShape, ancIt ); + else ancList.Append( theShape ); + } + } + else // else added for 52457: Addition of hypotheses is 8 time longer than meshing + { + for ( desType = TopAbs_VERTEX; desType > TopAbs_COMPOUND; desType-- ) + for ( ancType = desType - 1; ancType >= TopAbs_COMPOUND; ancType-- ) + TopExp::MapShapesAndAncestors ( theShape, + (TopAbs_ShapeEnum) desType, + (TopAbs_ShapeEnum) ancType, + _mapAncestors ); + } + // visit COMPOUNDs inside a COMPOUND that are not reachable by TopExp_Explorer + if ( theShape.ShapeType() == TopAbs_COMPOUND ) + { + TopoDS_Iterator sIt(theShape); + if ( sIt.More() && sIt.Value().ShapeType() == TopAbs_COMPOUND ) + for ( ; sIt.More(); sIt.Next() ) + if ( sIt.Value().ShapeType() == TopAbs_COMPOUND ) + fillAncestorsMap( sIt.Value() ); + } +} + +//============================================================================= +/*! + * \brief sort submeshes according to stored mesh order + * \param theListToSort in out list to be sorted + * \return FALSE if nothing sorted + */ +//============================================================================= + + bool SMESH_Mesh::SortByMeshOrder(std::vector& theListToSort) const +{ + if ( !_mySubMeshOrder.size() || theListToSort.size() < 2) + return true; + + bool res = false; + vector onlyOrderedList; + // collect all ordered submeshes in one list as pointers + // and get their positions within theListToSort + typedef vector::iterator TPosInList; + map< int, TPosInList > sortedPos; + TPosInList smBeg = theListToSort.begin(), smEnd = theListToSort.end(); + TListOfListOfInt::const_iterator listIdsIt = _mySubMeshOrder.begin(); + for( ; listIdsIt != _mySubMeshOrder.end(); listIdsIt++) + { + const TListOfInt& listOfId = *listIdsIt; + // convert sm ids to sm's + vector smVec; + TListOfInt::const_iterator idIt = listOfId.begin(); + for ( ; idIt != listOfId.end(); idIt++ ) { + if ( SMESH_subMesh * sm = GetSubMeshContaining( *idIt )) { + if ( sm->GetSubMeshDS() && sm->GetSubMeshDS()->IsComplexSubmesh() ) + { + SMESHDS_SubMeshIteratorPtr smdsIt = sm->GetSubMeshDS()->GetSubMeshIterator(); + while ( smdsIt->more() ) + { + const SMESHDS_SubMesh* smDS = smdsIt->next(); + if (( sm = GetSubMeshContaining( smDS->GetID() ))) + smVec.push_back( sm ); + } + } + else + { + smVec.push_back( sm ); + } + } + } + // find smVec items in theListToSort + for ( size_t i = 0; i < smVec.size(); ++i ) + { + TPosInList smPos = find( smBeg, smEnd, smVec[i] ); + if ( smPos != smEnd ) { + onlyOrderedList.push_back( smVec[i] ); + sortedPos[ distance( smBeg, smPos )] = smPos; + } + } + } + if (onlyOrderedList.size() < 2) + return res; + res = true; + + vector::iterator onlyBIt = onlyOrderedList.begin(); + vector::iterator onlyEIt = onlyOrderedList.end(); + + // iterate on ordered submeshes and insert them in detected positions + map< int, TPosInList >::iterator i_pos = sortedPos.begin(); + for ( ; onlyBIt != onlyEIt; ++onlyBIt, ++i_pos ) + *(i_pos->second) = *onlyBIt; + + return res; +} + +//================================================================================ +/*! + * \brief Return true if given order of sub-meshes is OK + */ +//================================================================================ + +bool SMESH_Mesh::IsOrderOK( const SMESH_subMesh* smBefore, + const SMESH_subMesh* smAfter ) const +{ + TListOfListOfInt::const_iterator listIdsIt = _mySubMeshOrder.begin(); + TListOfInt::const_iterator idBef, idAft; + for( ; listIdsIt != _mySubMeshOrder.end(); listIdsIt++) + { + const TListOfInt& listOfId = *listIdsIt; + idBef = std::find( listOfId.begin(), listOfId.end(), smBefore->GetId() ); + if ( idBef != listOfId.end() ) + idAft = std::find( listOfId.begin(), listOfId.end(), smAfter->GetId() ); + if ( idAft != listOfId.end () ) + return ( std::distance( listOfId.begin(), idBef ) < + std::distance( listOfId.begin(), idAft ) ); + } + return true; // no order imposed to given submeshes +} + +//============================================================================= +/*! + * \brief sort submeshes according to stored mesh order + * \param theListToSort in out list to be sorted + * \return FALSE if nothing sorted + */ +//============================================================================= + +void SMESH_Mesh::getAncestorsSubMeshes (const TopoDS_Shape& theSubShape, + std::vector< SMESH_subMesh* >& theSubMeshes) const +{ + theSubMeshes.clear(); + TopTools_ListIteratorOfListOfShape it( GetAncestors( theSubShape )); + for (; it.More(); it.Next() ) + if ( SMESH_subMesh* sm = GetSubMeshContaining( it.Value() )) + theSubMeshes.push_back(sm); + + // sort submeshes according to stored mesh order + SortByMeshOrder( theSubMeshes ); +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshAlgos.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshAlgos.cpp new file mode 100644 index 000000000000..b77ad457182b --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshAlgos.cpp @@ -0,0 +1,1667 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SMESH_MeshAlgos.hxx +// Created : Tue Apr 30 18:00:36 2013 +// Author : Edward AGAPOV (eap) + +// This file holds some low level algorithms extracted from SMESH_MeshEditor +// to make them accessible from Controls package + +#include "SMESH_MeshAlgos.hxx" + +#include "SMDS_FaceOfNodes.hxx" +#include "SMDS_LinearEdge.hxx" +#include "SMDS_Mesh.hxx" +#include "SMDS_PolygonalFaceOfNodes.hxx" +#include "SMDS_VolumeTool.hxx" +#include "SMESH_OctreeNode.hxx" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; + +//======================================================================= +/*! + * \brief Implementation of search for the node closest to point + */ +//======================================================================= + +struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher +{ + //--------------------------------------------------------------------- + /*! + * \brief Constructor + */ + SMESH_NodeSearcherImpl( const SMDS_Mesh* theMesh ) + { + myMesh = ( SMDS_Mesh* ) theMesh; + + TIDSortedNodeSet nodes; + if ( theMesh ) { + SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true); + while ( nIt->more() ) + nodes.insert( nodes.end(), nIt->next() ); + } + myOctreeNode = new SMESH_OctreeNode(nodes) ; + + // get max size of a leaf box + SMESH_OctreeNode* tree = myOctreeNode; + while ( !tree->isLeaf() ) + { + SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator(); + if ( cIt->more() ) + tree = cIt->next(); + } + myHalfLeafSize = tree->maxSize() / 2.; + } + + //--------------------------------------------------------------------- + /*! + * \brief Move node and update myOctreeNode accordingly + */ + void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt ) + { + myOctreeNode->UpdateByMoveNode( node, toPnt ); + myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() ); + } + + //--------------------------------------------------------------------- + /*! + * \brief Do it's job + */ + const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt ) + { + map dist2Nodes; + myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize ); + if ( !dist2Nodes.empty() ) + return dist2Nodes.begin()->second; + list nodes; + //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize ); + + double minSqDist = DBL_MAX; + if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt + { + // sort leafs by their distance from thePnt + typedef map< double, SMESH_OctreeNode* > TDistTreeMap; + TDistTreeMap treeMap; + list< SMESH_OctreeNode* > treeList; + list< SMESH_OctreeNode* >::iterator trIt; + treeList.push_back( myOctreeNode ); + + gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() ); + bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize ); + for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt) + { + SMESH_OctreeNode* tree = *trIt; + if ( !tree->isLeaf() ) // put children to the queue + { + if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue; + SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator(); + while ( cIt->more() ) + treeList.push_back( cIt->next() ); + } + else if ( tree->NbNodes() ) // put a tree to the treeMap + { + const Bnd_B3d& box = *tree->getBox(); + double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() )); + pair it_in = treeMap.insert( make_pair( sqDist, tree )); + if ( !it_in.second ) // not unique distance to box center + treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree )); + } + } + // find distance after which there is no sense to check tree's + double sqLimit = DBL_MAX; + TDistTreeMap::iterator sqDist_tree = treeMap.begin(); + if ( treeMap.size() > 5 ) { + SMESH_OctreeNode* closestTree = sqDist_tree->second; + const Bnd_B3d& box = *closestTree->getBox(); + double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() ); + sqLimit = limit * limit; + } + // get all nodes from trees + for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) { + if ( sqDist_tree->first > sqLimit ) + break; + SMESH_OctreeNode* tree = sqDist_tree->second; + tree->NodesAround( tree->GetNodeIterator()->next(), &nodes ); + } + } + // find closest among nodes + minSqDist = DBL_MAX; + const SMDS_MeshNode* closestNode = 0; + list::iterator nIt = nodes.begin(); + for ( ; nIt != nodes.end(); ++nIt ) { + double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) ); + if ( minSqDist > sqDist ) { + closestNode = *nIt; + minSqDist = sqDist; + } + } + return closestNode; + } + + //--------------------------------------------------------------------- + /*! + * \brief Finds nodes located within a tolerance near a point + */ + int FindNearPoint(const gp_Pnt& point, + const double tolerance, + std::vector< const SMDS_MeshNode* >& foundNodes) + { + myOctreeNode->NodesAround( point.Coord(), foundNodes, tolerance ); + return foundNodes.size(); + } + + //--------------------------------------------------------------------- + /*! + * \brief Destructor + */ + ~SMESH_NodeSearcherImpl() { delete myOctreeNode; } + + //--------------------------------------------------------------------- + /*! + * \brief Return the node tree + */ + const SMESH_OctreeNode* getTree() const { return myOctreeNode; } + +private: + SMESH_OctreeNode* myOctreeNode; + SMDS_Mesh* myMesh; + double myHalfLeafSize; // max size of a leaf box +}; + +// ======================================================================== +namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() +{ + const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree + const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152 + const double NodeRadius = 1e-9; // to enlarge bnd box of element + + //======================================================================= + /*! + * \brief Octal tree of bounding boxes of elements + */ + //======================================================================= + + class ElementBndBoxTree : public SMESH_Octree + { + public: + + ElementBndBoxTree(const SMDS_Mesh& mesh, + SMDSAbs_ElementType elemType, + SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), + double tolerance = NodeRadius ); + void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems ); + void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems); + void getElementsInSphere ( const gp_XYZ& center, + const double radius, TIDSortedElemSet& foundElems); + size_t getSize() { return std::max( _size, _elements.size() ); } + virtual ~ElementBndBoxTree(); + + protected: + ElementBndBoxTree():_size(0) {} + SMESH_Octree* newChild() const { return new ElementBndBoxTree; } + void buildChildrenData(); + Bnd_B3d* buildRootBox(); + private: + //!< Bounding box of element + struct ElementBox : public Bnd_B3d + { + const SMDS_MeshElement* _element; + int _refCount; // an ElementBox can be included in several tree branches + ElementBox(const SMDS_MeshElement* elem, double tolerance); + }; + vector< ElementBox* > _elements; + size_t _size; + }; + + //================================================================================ + /*! + * \brief ElementBndBoxTree creation + */ + //================================================================================ + + ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance) + :SMESH_Octree( new SMESH_TreeLimit( MaxLevel, /*minSize=*/0. )) + { + int nbElems = mesh.GetMeshInfo().NbElements( elemType ); + _elements.reserve( nbElems ); + + SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType ); + while ( elemIt->more() ) + _elements.push_back( new ElementBox( elemIt->next(),tolerance )); + + compute(); + } + + //================================================================================ + /*! + * \brief Destructor + */ + //================================================================================ + + ElementBndBoxTree::~ElementBndBoxTree() + { + for ( int i = 0; i < _elements.size(); ++i ) + if ( --_elements[i]->_refCount <= 0 ) + delete _elements[i]; + } + + //================================================================================ + /*! + * \brief Return the maximal box + */ + //================================================================================ + + Bnd_B3d* ElementBndBoxTree::buildRootBox() + { + Bnd_B3d* box = new Bnd_B3d; + for ( int i = 0; i < _elements.size(); ++i ) + box->Add( *_elements[i] ); + return box; + } + + //================================================================================ + /*! + * \brief Redistrubute element boxes among children + */ + //================================================================================ + + void ElementBndBoxTree::buildChildrenData() + { + for ( int i = 0; i < _elements.size(); ++i ) + { + for (int j = 0; j < 8; j++) + { + if ( !_elements[i]->IsOut( *myChildren[j]->getBox() )) + { + _elements[i]->_refCount++; + ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]); + } + } + _elements[i]->_refCount--; + } + _size = _elements.size(); + SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory + + for (int j = 0; j < 8; j++) + { + ElementBndBoxTree* child = static_cast( myChildren[j]); + if ( child->_elements.size() <= MaxNbElemsInLeaf ) + child->myIsLeaf = true; + + if ( child->_elements.capacity() - child->_elements.size() > 1000 ) + SMESHUtils::CompactVector( child->_elements ); + } + } + + //================================================================================ + /*! + * \brief Return elements which can include the point + */ + //================================================================================ + + void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point, + TIDSortedElemSet& foundElems) + { + if ( getBox()->IsOut( point.XYZ() )) + return; + + if ( isLeaf() ) + { + for ( int i = 0; i < _elements.size(); ++i ) + if ( !_elements[i]->IsOut( point.XYZ() )) + foundElems.insert( _elements[i]->_element ); + } + else + { + for (int i = 0; i < 8; i++) + ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems ); + } + } + + //================================================================================ + /*! + * \brief Return elements which can be intersected by the line + */ + //================================================================================ + + void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line, + TIDSortedElemSet& foundElems) + { + if ( getBox()->IsOut( line )) + return; + + if ( isLeaf() ) + { + for ( int i = 0; i < _elements.size(); ++i ) + if ( !_elements[i]->IsOut( line )) + foundElems.insert( _elements[i]->_element ); + } + else + { + for (int i = 0; i < 8; i++) + ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems ); + } + } + + //================================================================================ + /*! + * \brief Return elements from leaves intersecting the sphere + */ + //================================================================================ + + void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center, + const double radius, + TIDSortedElemSet& foundElems) + { + if ( getBox()->IsOut( center, radius )) + return; + + if ( isLeaf() ) + { + for ( int i = 0; i < _elements.size(); ++i ) + if ( !_elements[i]->IsOut( center, radius )) + foundElems.insert( _elements[i]->_element ); + } + else + { + for (int i = 0; i < 8; i++) + ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems ); + } + } + + //================================================================================ + /*! + * \brief Construct the element box + */ + //================================================================================ + + ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance) + { + _element = elem; + _refCount = 1; + SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); + while ( nIt->more() ) + Add( SMESH_TNodeXYZ( nIt->next() )); + Enlarge( tolerance ); + } + +} // namespace + +//======================================================================= +/*! + * \brief Implementation of search for the elements by point and + * of classification of point in 2D mesh + */ +//======================================================================= + +SMESH_ElementSearcher::~SMESH_ElementSearcher() +{ +} + +struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher +{ + SMDS_Mesh* _mesh; + SMDS_ElemIteratorPtr _meshPartIt; + ElementBndBoxTree* _ebbTree; + SMESH_NodeSearcherImpl* _nodeSearcher; + SMDSAbs_ElementType _elementType; + double _tolerance; + bool _outerFacesFound; + set _outerFaces; // empty means "no internal faces at all" + + SMESH_ElementSearcherImpl( SMDS_Mesh& mesh, + double tol=-1, + SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr()) + : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(tol),_outerFacesFound(false) {} + virtual ~SMESH_ElementSearcherImpl() + { + if ( _ebbTree ) delete _ebbTree; _ebbTree = 0; + if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0; + } + virtual int FindElementsByPoint(const gp_Pnt& point, + SMDSAbs_ElementType type, + vector< const SMDS_MeshElement* >& foundElements); + virtual TopAbs_State GetPointState(const gp_Pnt& point); + virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt& point, + SMDSAbs_ElementType type ); + + void GetElementsNearLine( const gp_Ax1& line, + SMDSAbs_ElementType type, + vector< const SMDS_MeshElement* >& foundElems); + double getTolerance(); + bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face, + const double tolerance, double & param); + void findOuterBoundary(const SMDS_MeshElement* anyOuterFace); + bool isOuterBoundary(const SMDS_MeshElement* face) const + { + return _outerFaces.empty() || _outerFaces.count(face); + } + struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState()) + { + const SMDS_MeshElement* _face; + gp_Vec _faceNorm; + bool _coincides; //!< the line lays in face plane + TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false) + : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {} + }; + struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary()) + { + SMESH_TLink _link; + TIDSortedElemSet _faces; + TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face) + : _link( n1, n2 ), _faces( &face, &face + 1) {} + }; +}; + +ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i) +{ + return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0) + << ", _coincides="<GetMeshInfo(); + + _tolerance = 0; + if ( _nodeSearcher && meshInfo.NbNodes() > 1 ) + { + double boxSize = _nodeSearcher->getTree()->maxSize(); + _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/; + } + else if ( _ebbTree && meshInfo.NbElements() > 0 ) + { + double boxSize = _ebbTree->maxSize(); + _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/; + } + if ( _tolerance == 0 ) + { + // define tolerance by size of a most complex element + int complexType = SMDSAbs_Volume; + while ( complexType > SMDSAbs_All && + meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 ) + --complexType; + if ( complexType == SMDSAbs_All ) return 0; // empty mesh + double elemSize; + if ( complexType == int( SMDSAbs_Node )) + { + SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator(); + elemSize = 1; + if ( meshInfo.NbNodes() > 2 ) + elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() ); + } + else + { + SMDS_ElemIteratorPtr elemIt = + _mesh->elementsIterator( SMDSAbs_ElementType( complexType )); + const SMDS_MeshElement* elem = elemIt->next(); + SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); + SMESH_TNodeXYZ n1( nodeIt->next() ); + elemSize = 0; + while ( nodeIt->more() ) + { + double dist = n1.Distance( static_cast( nodeIt->next() )); + elemSize = max( dist, elemSize ); + } + } + _tolerance = 1e-4 * elemSize; + } + } + return _tolerance; +} + +//================================================================================ +/*! + * \brief Find intersection of the line and an edge of face and return parameter on line + */ +//================================================================================ + +bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line, + const SMDS_MeshElement* face, + const double tol, + double & param) +{ + int nbInts = 0; + param = 0; + + GeomAPI_ExtremaCurveCurve anExtCC; + Handle(Geom_Curve) lineCurve = new Geom_Line( line ); + + int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes(); + for ( int i = 0; i < nbNodes && nbInts < 2; ++i ) + { + GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )), + SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); +// vejmarie ISSUE THERE +// anExtCC.Init( lineCurve, edge); + if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol) + { + Quantity_Parameter pl, pe; + anExtCC.LowerDistanceParameters( pl, pe ); + param += pl; + if ( ++nbInts == 2 ) + break; + } + } + if ( nbInts > 0 ) param /= nbInts; + return nbInts > 0; +} +//================================================================================ +/*! + * \brief Find all faces belonging to the outer boundary of mesh + */ +//================================================================================ + +void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace) +{ + if ( _outerFacesFound ) return; + + // Collect all outer faces by passing from one outer face to another via their links + // and BTW find out if there are internal faces at all. + + // checked links and links where outer boundary meets internal one + set< SMESH_TLink > visitedLinks, seamLinks; + + // links to treat with already visited faces sharing them + list < TFaceLink > startLinks; + + // load startLinks with the first outerFace + startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace)); + _outerFaces.insert( outerFace ); + + TIDSortedElemSet emptySet; + while ( !startLinks.empty() ) + { + const SMESH_TLink& link = startLinks.front()._link; + TIDSortedElemSet& faces = startLinks.front()._faces; + + outerFace = *faces.begin(); + // find other faces sharing the link + const SMDS_MeshElement* f; + while (( f = SMESH_MeshAlgos::FindFaceInSet(link.node1(), link.node2(), emptySet, faces ))) + faces.insert( f ); + + // select another outer face among the found + const SMDS_MeshElement* outerFace2 = 0; + if ( faces.size() == 2 ) + { + outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin()); + } + else if ( faces.size() > 2 ) + { + seamLinks.insert( link ); + + // link direction within the outerFace + gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()), + SMESH_TNodeXYZ( link.node2())); + int i1 = outerFace->GetNodeIndex( link.node1() ); + int i2 = outerFace->GetNodeIndex( link.node2() ); + bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 ); + if ( rev ) n1n2.Reverse(); + // outerFace normal + gp_XYZ ofNorm, fNorm; + if ( SMESH_MeshAlgos::FaceNormal( outerFace, ofNorm, /*normalized=*/false )) + { + // direction from the link inside outerFace + gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2; + // sort all other faces by angle with the dirInOF + map< double, const SMDS_MeshElement* > angle2Face; + set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin(); + for ( ; face != faces.end(); ++face ) + { + if ( !SMESH_MeshAlgos::FaceNormal( *face, fNorm, /*normalized=*/false )) + continue; + gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2; + double angle = dirInOF.AngleWithRef( dirInF, n1n2 ); + if ( angle < 0 ) angle += 2. * M_PI; + angle2Face.insert( make_pair( angle, *face )); + } + if ( !angle2Face.empty() ) + outerFace2 = angle2Face.begin()->second; + } + } + // store the found outer face and add its links to continue seaching from + if ( outerFace2 ) + { + _outerFaces.insert( outerFace ); + int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 ); + for ( int i = 0; i < nbNodes; ++i ) + { + SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes)); + if ( visitedLinks.insert( link2 ).second ) + startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 )); + } + } + startLinks.pop_front(); + } + _outerFacesFound = true; + + if ( !seamLinks.empty() ) + { + // There are internal boundaries touching the outher one, + // find all faces of internal boundaries in order to find + // faces of boundaries of holes, if any. + + } + else + { + _outerFaces.clear(); + } +} + +//======================================================================= +/*! + * \brief Find elements of given type where the given point is IN or ON. + * Returns nb of found elements and elements them-selves. + * + * 'ALL' type means elements of any type excluding nodes, balls and 0D elements + */ +//======================================================================= + +int SMESH_ElementSearcherImpl:: +FindElementsByPoint(const gp_Pnt& point, + SMDSAbs_ElementType type, + vector< const SMDS_MeshElement* >& foundElements) +{ + foundElements.clear(); + + double tolerance = getTolerance(); + + // ================================================================================= + if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement || type == SMDSAbs_Ball) + { + if ( !_nodeSearcher ) + _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh ); + + std::vector< const SMDS_MeshNode* > foundNodes; + _nodeSearcher->FindNearPoint( point, tolerance, foundNodes ); + + if ( type == SMDSAbs_Node ) + { + foundElements.assign( foundNodes.begin(), foundNodes.end() ); + } + else + { + for ( size_t i = 0; i < foundNodes.size(); ++i ) + { + SMDS_ElemIteratorPtr elemIt = foundNodes[i]->GetInverseElementIterator( type ); + while ( elemIt->more() ) + foundElements.push_back( elemIt->next() ); + } + } + } + // ================================================================================= + else // elements more complex than 0D + { + if ( !_ebbTree || _elementType != type ) + { + if ( _ebbTree ) delete _ebbTree; + _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance ); + } + TIDSortedElemSet suspectElems; + _ebbTree->getElementsNearPoint( point, suspectElems ); + TIDSortedElemSet::iterator elem = suspectElems.begin(); + for ( ; elem != suspectElems.end(); ++elem ) + if ( !SMESH_MeshAlgos::IsOut( *elem, point, tolerance )) + foundElements.push_back( *elem ); + } + return foundElements.size(); +} + +//======================================================================= +/*! + * \brief Find an element of given type most close to the given point + * + * WARNING: Only face search is implemeneted so far + */ +//======================================================================= + +const SMDS_MeshElement* +SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt& point, + SMDSAbs_ElementType type ) +{ + const SMDS_MeshElement* closestElem = 0; + + if ( type == SMDSAbs_Face || type == SMDSAbs_Volume ) + { + if ( !_ebbTree || _elementType != type ) + { + if ( _ebbTree ) delete _ebbTree; + _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt ); + } + TIDSortedElemSet suspectElems; + _ebbTree->getElementsNearPoint( point, suspectElems ); + + if ( suspectElems.empty() && _ebbTree->maxSize() > 0 ) + { + gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox()->CornerMin() + + _ebbTree->getBox()->CornerMax() ); + double radius = -1; + if ( _ebbTree->getBox()->IsOut( point.XYZ() )) + radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize(); + if ( radius < 0 ) + radius = _ebbTree->maxSize() / pow( 2., _ebbTree->getHeight()) / 2; + while ( suspectElems.empty() ) + { + _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems ); + radius *= 1.1; + } + } + double minDist = std::numeric_limits::max(); + multimap< double, const SMDS_MeshElement* > dist2face; + TIDSortedElemSet::iterator elem = suspectElems.begin(); + for ( ; elem != suspectElems.end(); ++elem ) + { + double dist = SMESH_MeshAlgos::GetDistance( *elem, point ); + if ( dist < minDist + 1e-10) + { + minDist = dist; + dist2face.insert( dist2face.begin(), make_pair( dist, *elem )); + } + } + if ( !dist2face.empty() ) + { + multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin(); + closestElem = d2f->second; + // if there are several elements at the same distance, select one + // with GC closest to the point + typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator; + double minDistToGC = 0; + for ( ++d2f; d2f != dist2face.end() && fabs( d2f->first - minDist ) < 1e-10; ++d2f ) + { + if ( minDistToGC == 0 ) + { + gp_XYZ gc(0,0,0); + gc = accumulate( TXyzIterator(closestElem->nodesIterator()), + TXyzIterator(), gc ) / closestElem->NbNodes(); + minDistToGC = point.SquareDistance( gc ); + } + gp_XYZ gc(0,0,0); + gc = accumulate( TXyzIterator( d2f->second->nodesIterator()), + TXyzIterator(), gc ) / d2f->second->NbNodes(); + double d = point.SquareDistance( gc ); + if ( d < minDistToGC ) + { + minDistToGC = d; + closestElem = d2f->second; + } + } + // cout << "FindClosestTo( " <GetID() << " DIST " << minDist << endl; + } + } + else + { + // NOT IMPLEMENTED SO FAR + } + return closestElem; +} + + +//================================================================================ +/*! + * \brief Classify the given point in the closed 2D mesh + */ +//================================================================================ + +TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) +{ + double tolerance = getTolerance(); + if ( !_ebbTree || _elementType != SMDSAbs_Face ) + { + if ( _ebbTree ) delete _ebbTree; + _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt ); + } + // Algo: analyse transition of a line starting at the point through mesh boundary; + // try three lines parallel to axis of the coordinate system and perform rough + // analysis. If solution is not clear perform thorough analysis. + + const int nbAxes = 3; + gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() }; + map< double, TInters > paramOnLine2TInters[ nbAxes ]; + list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line + multimap< int, int > nbInt2Axis; // to find the simplest case + for ( int axis = 0; axis < nbAxes; ++axis ) + { + gp_Ax1 lineAxis( point, axisDir[axis]); + gp_Lin line ( lineAxis ); + + TIDSortedElemSet suspectFaces; // faces possibly intersecting the line + _ebbTree->getElementsNearLine( lineAxis, suspectFaces ); + + // Intersect faces with the line + + map< double, TInters > & u2inters = paramOnLine2TInters[ axis ]; + TIDSortedElemSet::iterator face = suspectFaces.begin(); + for ( ; face != suspectFaces.end(); ++face ) + { + // get face plane + gp_XYZ fNorm; + if ( !SMESH_MeshAlgos::FaceNormal( *face, fNorm, /*normalized=*/false)) continue; + gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm ); + + // perform intersection + IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane )); + if ( !intersection.IsDone() ) + continue; + if ( intersection.IsInQuadric() ) + { + tangentInters[ axis ].push_back( TInters( *face, fNorm, true )); + } + else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 ) + { + gp_Pnt intersectionPoint = intersection.Point(1); + if ( !SMESH_MeshAlgos::IsOut( *face, intersectionPoint, tolerance )) + u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm ))); + } + } + // Analyse intersections roughly + + int nbInter = u2inters.size(); + if ( nbInter == 0 ) + return TopAbs_OUT; + + double f = u2inters.begin()->first, l = u2inters.rbegin()->first; + if ( nbInter == 1 ) // not closed mesh + return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN; + + if ( fabs( f ) < tolerance || fabs( l ) < tolerance ) + return TopAbs_ON; + + if ( (f<0) == (l<0) ) + return TopAbs_OUT; + + int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0)); + int nbIntAfterPoint = nbInter - nbIntBeforePoint; + if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 ) + return TopAbs_IN; + + nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis )); + + if ( _outerFacesFound ) break; // pass to thorough analysis + + } // three attempts - loop on CS axes + + // Analyse intersections thoroughly. + // We make two loops maximum, on the first one we only exclude touching intersections, + // on the second, if situation is still unclear, we gather and use information on + // position of faces (internal or outer). If faces position is already gathered, + // we make the second loop right away. + + for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo ) + { + multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin(); + for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis ) + { + int axis = nb_axis->second; + map< double, TInters > & u2inters = paramOnLine2TInters[ axis ]; + + gp_Ax1 lineAxis( point, axisDir[axis]); + gp_Lin line ( lineAxis ); + + // add tangent intersections to u2inters + double param; + list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin(); + for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt ) + if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param )) + u2inters.insert(make_pair( param, *tgtInt )); + tangentInters[ axis ].clear(); + + // Count intersections before and after the point excluding touching ones. + // If hasPositionInfo we count intersections of outer boundary only + + int nbIntBeforePoint = 0, nbIntAfterPoint = 0; + double f = numeric_limits::max(), l = -numeric_limits::max(); + map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1; + bool ok = ! u_int1->second._coincides; + while ( ok && u_int1 != u2inters.end() ) + { + double u = u_int1->first; + bool touchingInt = false; + if ( ++u_int2 != u2inters.end() ) + { + // skip intersections at the same point (if the line passes through edge or node) + int nbSamePnt = 0; + while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance ) + { + ++nbSamePnt; + ++u_int2; + } + + // skip tangent intersections + int nbTgt = 0; + const SMDS_MeshElement* prevFace = u_int1->second._face; + while ( ok && u_int2->second._coincides ) + { + if ( SMESH_MeshAlgos::GetCommonNodes(prevFace , u_int2->second._face).empty() ) + ok = false; + else + { + nbTgt++; + u_int2++; + ok = ( u_int2 != u2inters.end() ); + } + } + if ( !ok ) break; + + // skip intersections at the same point after tangent intersections + if ( nbTgt > 0 ) + { + double u2 = u_int2->first; + ++u_int2; + while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance ) + { + ++nbSamePnt; + ++u_int2; + } + } + // decide if we skipped a touching intersection + if ( nbSamePnt + nbTgt > 0 ) + { + double minDot = numeric_limits::max(), maxDot = -numeric_limits::max(); + map< double, TInters >::iterator u_int = u_int1; + for ( ; u_int != u_int2; ++u_int ) + { + if ( u_int->second._coincides ) continue; + double dot = u_int->second._faceNorm * line.Direction(); + if ( dot > maxDot ) maxDot = dot; + if ( dot < minDot ) minDot = dot; + } + touchingInt = ( minDot*maxDot < 0 ); + } + } + if ( !touchingInt ) + { + if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face )) + { + if ( u < 0 ) + ++nbIntBeforePoint; + else + ++nbIntAfterPoint; + } + if ( u < f ) f = u; + if ( u > l ) l = u; + } + + u_int1 = u_int2; // to next intersection + + } // loop on intersections with one line + + if ( ok ) + { + if ( fabs( f ) < tolerance || fabs( l ) < tolerance ) + return TopAbs_ON; + + if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0) + return TopAbs_OUT; + + if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh + return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN; + + if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 ) + return TopAbs_IN; + + if ( (f<0) == (l<0) ) + return TopAbs_OUT; + + if ( hasPositionInfo ) + return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT; + } + } // loop on intersections of the tree lines - thorough analysis + + if ( !hasPositionInfo ) + { + // gather info on faces position - is face in the outer boundary or not + map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ]; + findOuterBoundary( u2inters.begin()->second._face ); + } + + } // two attempts - with and w/o faces position info in the mesh + + return TopAbs_UNKNOWN; +} + +//======================================================================= +/*! + * \brief Return elements possibly intersecting the line + */ +//======================================================================= + +void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line, + SMDSAbs_ElementType type, + vector< const SMDS_MeshElement* >& foundElems) +{ + if ( !_ebbTree || _elementType != type ) + { + if ( _ebbTree ) delete _ebbTree; + _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt ); + } + TIDSortedElemSet suspectFaces; // elements possibly intersecting the line + _ebbTree->getElementsNearLine( line, suspectFaces ); + foundElems.assign( suspectFaces.begin(), suspectFaces.end()); +} + +//======================================================================= +/*! + * \brief Return true if the point is IN or ON of the element + */ +//======================================================================= + +bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol ) +{ + if ( element->GetType() == SMDSAbs_Volume) + { + return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol ); + } + + // get ordered nodes + + vector< SMESH_TNodeXYZ > xyz; + + SMDS_ElemIteratorPtr nodeIt = element->interlacedNodesElemIterator(); + while ( nodeIt->more() ) + { + SMESH_TNodeXYZ node = nodeIt->next(); + xyz.push_back( node ); + } + + int i, nbNodes = (int) xyz.size(); // central node of biquadratic is missing + + if ( element->GetType() == SMDSAbs_Face ) // -------------------------------------------------- + { + // compute face normal + gp_Vec faceNorm(0,0,0); + xyz.push_back( xyz.front() ); + for ( i = 0; i < nbNodes; ++i ) + { + gp_Vec edge1( xyz[i+1], xyz[i]); + gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] ); + faceNorm += edge1 ^ edge2; + } + double normSize = faceNorm.Magnitude(); + if ( normSize <= tol ) + { + // degenerated face: point is out if it is out of all face edges + for ( i = 0; i < nbNodes; ++i ) + { + SMDS_LinearEdge edge( xyz[i]._node, xyz[i+1]._node ); + if ( !IsOut( &edge, point, tol )) + return false; + } + return true; + } + faceNorm /= normSize; + + // check if the point lays on face plane + gp_Vec n2p( xyz[0], point ); + if ( fabs( n2p * faceNorm ) > tol ) + return true; // not on face plane + + // check if point is out of face boundary: + // define it by closest transition of a ray point->infinity through face boundary + // on the face plane. + // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool + // to find intersections of the ray with the boundary. + gp_Vec ray = n2p; + gp_Vec plnNorm = ray ^ faceNorm; + normSize = plnNorm.Magnitude(); + if ( normSize <= tol ) return false; // point coincides with the first node + plnNorm /= normSize; + // for each node of the face, compute its signed distance to the plane + vector dist( nbNodes + 1); + for ( i = 0; i < nbNodes; ++i ) + { + gp_Vec n2p( xyz[i], point ); + dist[i] = n2p * plnNorm; + } + dist.back() = dist.front(); + // find the closest intersection + int iClosest = -1; + double rClosest, distClosest = 1e100;; + gp_Pnt pClosest; + for ( i = 0; i < nbNodes; ++i ) + { + double r; + if ( fabs( dist[i]) < tol ) + r = 0.; + else if ( fabs( dist[i+1]) < tol ) + r = 1.; + else if ( dist[i] * dist[i+1] < 0 ) + r = dist[i] / ( dist[i] - dist[i+1] ); + else + continue; // no intersection + gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r; + gp_Vec p2int ( point, pInt); + if ( p2int * ray > -tol ) // right half-space + { + double intDist = p2int.SquareMagnitude(); + if ( intDist < distClosest ) + { + iClosest = i; + rClosest = r; + pClosest = pInt; + distClosest = intDist; + } + } + } + if ( iClosest < 0 ) + return true; // no intesections - out + + // analyse transition + gp_Vec edge( xyz[iClosest], xyz[iClosest+1] ); + gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face + gp_Vec p2int ( point, pClosest ); + bool out = (edgeNorm * p2int) < -tol; + if ( rClosest > 0. && rClosest < 1. ) // not node intersection + return out; + + // ray pass through a face node; analyze transition through an adjacent edge + gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ]; + gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ]; + gp_Vec edgeAdjacent( p1, p2 ); + gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm ); + bool out2 = (edgeNorm2 * p2int) < -tol; + + bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0; + return covexCorner ? (out || out2) : (out && out2); + } + if ( element->GetType() == SMDSAbs_Edge ) // -------------------------------------------------- + { + // point is out of edge if it is NOT ON any straight part of edge + // (we consider quadratic edge as being composed of two straight parts) + for ( i = 1; i < nbNodes; ++i ) + { + gp_Vec edge( xyz[i-1], xyz[i] ); + gp_Vec n1p ( xyz[i-1], point ); + double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge + if ( u <= 0. ) { + if ( n1p.SquareMagnitude() < tol * tol ) + return false; + continue; + } + if ( u >= 1. ) { + if ( point.SquareDistance( xyz[i] ) < tol * tol ) + return false; + continue; + } + gp_XYZ proj = ( 1. - u ) * xyz[i-1] + u * xyz[i]; // projection of the point on the edge + double dist2 = point.SquareDistance( proj ); + if ( dist2 > tol * tol ) + continue; + return false; // point is ON this part + } + return true; + } + // Node or 0D element ------------------------------------------------------------------------- + { + gp_Vec n2p ( xyz[0], point ); + return n2p.SquareMagnitude() <= tol * tol; + } + return true; +} + +//======================================================================= +namespace +{ + // Position of a point relative to a segment + // . . + // . LEFT . + // . . + // VERTEX 1 o----ON-----> VERTEX 2 + // . . + // . RIGHT . + // . . + enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8, + POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX }; + struct PointPos + { + PositionName _name; + int _index; // index of vertex or segment + + PointPos( PositionName n, int i=-1 ): _name(n), _index(i) {} + bool operator < (const PointPos& other ) const + { + if ( _name == other._name ) + return ( _index < 0 || other._index < 0 ) ? false : _index < other._index; + return _name < other._name; + } + }; + + //================================================================================ + /*! + * \brief Return of a point relative to a segment + * \param point2D - the point to analyze position of + * \param xyVec - end points of segments + * \param index0 - 0-based index of the first point of segment + * \param posToFindOut - flags of positions to detect + * \retval PointPos - point position + */ + //================================================================================ + + PointPos getPointPosition( const gp_XY& point2D, + const gp_XY* segEnds, + const int index0 = 0, + const int posToFindOut = POS_ALL) + { + const gp_XY& p1 = segEnds[ index0 ]; + const gp_XY& p2 = segEnds[ index0+1 ]; + const gp_XY grad = p2 - p1; + + if ( posToFindOut & POS_VERTEX ) + { + // check if the point2D is at "vertex 1" zone + gp_XY pp1[2] = { p1, gp_XY( p1.X() - grad.Y(), + p1.Y() + grad.X() ) }; + if ( getPointPosition( point2D, pp1, 0, POS_LEFT|POS_RIGHT )._name == POS_LEFT ) + return PointPos( POS_VERTEX, index0 ); + + // check if the point2D is at "vertex 2" zone + gp_XY pp2[2] = { p2, gp_XY( p2.X() - grad.Y(), + p2.Y() + grad.X() ) }; + if ( getPointPosition( point2D, pp2, 0, POS_LEFT|POS_RIGHT )._name == POS_RIGHT ) + return PointPos( POS_VERTEX, index0 + 1); + } + double edgeEquation = + ( point2D.X() - p1.X() ) * grad.Y() - ( point2D.Y() - p1.Y() ) * grad.X(); + return PointPos( edgeEquation < 0 ? POS_LEFT : POS_RIGHT, index0 ); + } +} + +//======================================================================= +/*! + * \brief Return minimal distance from a point to an element + * + * Currently we ignore non-planarity and 2nd order of face + */ +//======================================================================= + +double SMESH_MeshAlgos::GetDistance( const SMDS_MeshElement* elem, + const gp_Pnt& point ) +{ + switch ( elem->GetType() ) + { + case SMDSAbs_Volume: + return GetDistance( dynamic_cast( elem ), point); + case SMDSAbs_Face: + return GetDistance( dynamic_cast( elem ), point); + case SMDSAbs_Edge: + return GetDistance( dynamic_cast( elem ), point); + case SMDSAbs_Node: + return point.Distance( SMESH_TNodeXYZ( elem )); + } + return -1; +} + +//======================================================================= +/*! + * \brief Return minimal distance from a point to a face + * + * Currently we ignore non-planarity and 2nd order of face + */ +//======================================================================= + +double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face, + const gp_Pnt& point ) +{ + double badDistance = -1; + if ( !face ) return badDistance; + + // coordinates of nodes (medium nodes, if any, ignored) + typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator; + vector xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() ); + xyz.resize( face->NbCornerNodes()+1 ); + + // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis, + // and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane. + gp_Trsf trsf; + gp_Vec OZ ( xyz[0], xyz[1] ); + gp_Vec OX ( xyz[0], xyz[2] ); + if ( OZ.Magnitude() < std::numeric_limits::min() ) + { + if ( xyz.size() < 4 ) return badDistance; + OZ = gp_Vec ( xyz[0], xyz[2] ); + OX = gp_Vec ( xyz[0], xyz[3] ); + } + gp_Ax3 tgtCS; + try { + tgtCS = gp_Ax3( xyz[0], OZ, OX ); + } + catch ( Standard_Failure ) { + return badDistance; + } + trsf.SetTransformation( tgtCS ); + + // move all the nodes to 2D + vector xy( xyz.size() ); + for ( size_t i = 0;i < xyz.size()-1; ++i ) + { + gp_XYZ p3d = xyz[i]; + trsf.Transforms( p3d ); + xy[i].SetCoord( p3d.X(), p3d.Z() ); + } + xyz.back() = xyz.front(); + xy.back() = xy.front(); + + // // move the point in 2D + gp_XYZ tmpPnt = point.XYZ(); + trsf.Transforms( tmpPnt ); + gp_XY point2D( tmpPnt.X(), tmpPnt.Z() ); + + // loop on segments of the face to analyze point position ralative to the face + set< PointPos > pntPosSet; + for ( size_t i = 1; i < xy.size(); ++i ) + { + PointPos pos = getPointPosition( point2D, &xy[0], i-1 ); + pntPosSet.insert( pos ); + } + + // compute distance + PointPos pos = *pntPosSet.begin(); + // cout << "Face " << face->GetID() << " DIST: "; + switch ( pos._name ) + { + case POS_LEFT: { + // point is most close to a segment + gp_Vec p0p1( point, xyz[ pos._index ] ); + gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector + p1p2.Normalize(); + double projDist = p0p1 * p1p2; // distance projected to the segment + gp_Vec projVec = p1p2 * projDist; + gp_Vec distVec = p0p1 - projVec; + // cout << distVec.Magnitude() << ", SEG " << face->GetNode(pos._index)->GetID() + // << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl; + return distVec.Magnitude(); + } + case POS_RIGHT: { + // point is inside the face + double distToFacePlane = tmpPnt.Y(); + // cout << distToFacePlane << ", INSIDE " << endl; + return Abs( distToFacePlane ); + } + case POS_VERTEX: { + // point is most close to a node + gp_Vec distVec( point, xyz[ pos._index ]); + // cout << distVec.Magnitude() << " VERTEX " << face->GetNode(pos._index)->GetID() << endl; + return distVec.Magnitude(); + } + } + return badDistance; +} + +//======================================================================= +/*! + * \brief Return minimal distance from a point to an edge + */ +//======================================================================= + +double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* edge, const gp_Pnt& point ) +{ + throw SALOME_Exception(LOCALIZED("not implemented so far")); +} + +//======================================================================= +/*! + * \brief Return minimal distance from a point to a volume + * + * Currently we ignore non-planarity and 2nd order + */ +//======================================================================= + +double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point ) +{ + SMDS_VolumeTool vTool( volume ); + vTool.SetExternalNormal(); + const int iQ = volume->IsQuadratic() ? 2 : 1; + + double n[3], bc[3]; + double minDist = 1e100, dist; + for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) + { + // skip a facet with normal not "looking at" the point + if ( !vTool.GetFaceNormal( iF, n[0], n[1], n[2] ) || + !vTool.GetFaceBaryCenter( iF, bc[0], bc[1], bc[2] )) + continue; + gp_XYZ bcp = point.XYZ() - gp_XYZ( bc[0], bc[1], bc[2] ); + if ( gp_XYZ( n[0], n[1], n[2] ) * bcp < 1e-6 ) + continue; + + // find distance to a facet + const SMDS_MeshNode** nodes = vTool.GetFaceNodes( iF ); + switch ( vTool.NbFaceNodes( iF ) / iQ ) { + case 3: + { + SMDS_FaceOfNodes tmpFace( nodes[0], nodes[ 1*iQ ], nodes[ 2*iQ ] ); + dist = GetDistance( &tmpFace, point ); + break; + } + case 4: + { + SMDS_FaceOfNodes tmpFace( nodes[0], nodes[ 1*iQ ], nodes[ 2*iQ ], nodes[ 3*iQ ]); + dist = GetDistance( &tmpFace, point ); + break; + } + default: + vector nvec( nodes, nodes + vTool.NbFaceNodes( iF )); + SMDS_PolygonalFaceOfNodes tmpFace( nvec ); + dist = GetDistance( &tmpFace, point ); + } + minDist = Min( minDist, dist ); + } + return minDist; +} + +//================================================================================ +/*! + * \brief Returns barycentric coordinates of a point within a triangle. + * A not returned bc2 = 1. - bc0 - bc1. + * The point lies within the triangle if ( bc0 >= 0 && bc1 >= 0 && bc0+bc1 <= 1 ) + */ +//================================================================================ + +void SMESH_MeshAlgos::GetBarycentricCoords( const gp_XY& p, + const gp_XY& t0, + const gp_XY& t1, + const gp_XY& t2, + double & bc0, + double & bc1) +{ + const double // matrix 2x2 + T11 = t0.X()-t2.X(), T12 = t1.X()-t2.X(), + T21 = t0.Y()-t2.Y(), T22 = t1.Y()-t2.Y(); + const double Tdet = T11*T22 - T12*T21; // matrix determinant + if ( Abs( Tdet ) < std::numeric_limits::min() ) + { + bc0 = bc1 = 2.; + return; + } + // matrix inverse + const double t11 = T22, t12 = -T12, t21 = -T21, t22 = T11; + // vector + const double r11 = p.X()-t2.X(), r12 = p.Y()-t2.Y(); + // barycentric coordinates: mutiply matrix by vector + bc0 = (t11 * r11 + t12 * r12)/Tdet; + bc1 = (t21 * r11 + t22 * r12)/Tdet; +} + +//======================================================================= +//function : FindFaceInSet +//purpose : Return a face having linked nodes n1 and n2 and which is +// - not in avoidSet, +// - in elemSet provided that !elemSet.empty() +// i1 and i2 optionally returns indices of n1 and n2 +//======================================================================= + +const SMDS_MeshElement* +SMESH_MeshAlgos::FindFaceInSet(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const TIDSortedElemSet& elemSet, + const TIDSortedElemSet& avoidSet, + int* n1ind, + int* n2ind) + +{ + int i1, i2; + const SMDS_MeshElement* face = 0; + + SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face); + while ( invElemIt->more() && !face ) // loop on inverse faces of n1 + { + const SMDS_MeshElement* elem = invElemIt->next(); + if (avoidSet.count( elem )) + continue; + if ( !elemSet.empty() && !elemSet.count( elem )) + continue; + // index of n1 + i1 = elem->GetNodeIndex( n1 ); + // find a n2 linked to n1 + int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes(); + for ( int di = -1; di < 2 && !face; di += 2 ) + { + i2 = (i1+di+nbN) % nbN; + if ( elem->GetNode( i2 ) == n2 ) + face = elem; + } + if ( !face && elem->IsQuadratic()) + { + // analysis for quadratic elements using all nodes + SMDS_ElemIteratorPtr anIter = elem->interlacedNodesElemIterator(); + const SMDS_MeshNode* prevN = static_cast( anIter->next() ); + for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ ) + { + const SMDS_MeshNode* n = static_cast( anIter->next() ); + if ( n1 == prevN && n2 == n ) + { + face = elem; + } + else if ( n2 == prevN && n1 == n ) + { + face = elem; swap( i1, i2 ); + } + prevN = n; + } + } + } + if ( n1ind ) *n1ind = i1; + if ( n2ind ) *n2ind = i2; + return face; +} + +//================================================================================ +/*! + * \brief Calculate normal of a mesh face + */ +//================================================================================ + +bool SMESH_MeshAlgos::FaceNormal(const SMDS_MeshElement* F, gp_XYZ& normal, bool normalized) +{ + if ( !F || F->GetType() != SMDSAbs_Face ) + return false; + + normal.SetCoord(0,0,0); + int nbNodes = F->NbCornerNodes(); + for ( int i = 0; i < nbNodes-2; ++i ) + { + gp_XYZ p[3]; + for ( int n = 0; n < 3; ++n ) + { + const SMDS_MeshNode* node = F->GetNode( i + n ); + p[n].SetCoord( node->X(), node->Y(), node->Z() ); + } + normal += ( p[2] - p[1] ) ^ ( p[0] - p[1] ); + } + double size2 = normal.SquareModulus(); + bool ok = ( size2 > numeric_limits::min() * numeric_limits::min()); + if ( normalized && ok ) + normal /= sqrt( size2 ); + + return ok; +} + +//======================================================================= +//function : GetCommonNodes +//purpose : Return nodes common to two elements +//======================================================================= + +vector< const SMDS_MeshNode*> SMESH_MeshAlgos::GetCommonNodes(const SMDS_MeshElement* e1, + const SMDS_MeshElement* e2) +{ + vector< const SMDS_MeshNode*> common; + for ( int i = 0 ; i < e1->NbNodes(); ++i ) + if ( e2->GetNodeIndex( e1->GetNode( i )) >= 0 ) + common.push_back( e1->GetNode( i )); + return common; +} + +//======================================================================= +/*! + * \brief Return SMESH_NodeSearcher + */ +//======================================================================= + +SMESH_NodeSearcher* SMESH_MeshAlgos::GetNodeSearcher(SMDS_Mesh& mesh) +{ + return new SMESH_NodeSearcherImpl( &mesh ); +} + +//======================================================================= +/*! + * \brief Return SMESH_ElementSearcher + */ +//======================================================================= + +SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& mesh, + double tolerance) +{ + return new SMESH_ElementSearcherImpl( mesh, tolerance ); +} + +//======================================================================= +/*! + * \brief Return SMESH_ElementSearcher acting on a sub-set of elements + */ +//======================================================================= + +SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& mesh, + SMDS_ElemIteratorPtr elemIt, + double tolerance) +{ + return new SMESH_ElementSearcherImpl( mesh, tolerance, elemIt ); +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshEditor.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshEditor.cpp index 226b2ed8c07e..60edf865dcac 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshEditor.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshEditor.cpp @@ -1,72 +1,80 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMESH : idl implementation based on 'SMESH' unit's classes + // File : SMESH_MeshEditor.cxx // Created : Mon Apr 12 16:10:22 2004 // Author : Edward AGAPOV (eap) -// -#ifdef _MSC_VER -#define _USE_MATH_DEFINES -#endif // _MSC_VER -#include #include "SMESH_MeshEditor.hxx" #include "SMDS_FaceOfNodes.hxx" #include "SMDS_VolumeTool.hxx" #include "SMDS_EdgePosition.hxx" -#include "SMDS_PolyhedralVolumeOfNodes.hxx" #include "SMDS_FacePosition.hxx" #include "SMDS_SpacePosition.hxx" -#include "SMDS_QuadraticFaceOfNodes.hxx" #include "SMDS_MeshGroup.hxx" +#include "SMDS_LinearEdge.hxx" +#include "SMDS_Downward.hxx" +#include "SMDS_SetIterator.hxx" #include "SMESHDS_Group.hxx" #include "SMESHDS_Mesh.hxx" -#include "SMESH_subMesh.hxx" +#include "SMESH_Algo.hxx" #include "SMESH_ControlsDef.hxx" +#include "SMESH_Group.hxx" +#include "SMESH_MeshAlgos.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_OctreeNode.hxx" -#include "SMESH_Group.hxx" +#include "SMESH_subMesh.hxx" + +#include #include "utilities.h" +#include "chrono.hxx" +#include +#include +#include #include #include #include +#include #include #include #include #include #include -#include +#include #include +#include #include #include #include #include +#include #include #include +#include #include #include #include @@ -76,29 +84,36 @@ #include #include #include -#include + +#include #include #include +#include +#include +#include +#include -#ifndef PI -#define PI M_PI -#endif +#include + +#include +#include #define cast2Node(elem) static_cast( elem ) using namespace std; using namespace SMESH::Controls; -typedef map > TElemOfNodeListMap; -typedef map > TElemOfElemListMap; -//typedef map > TNodeOfNodeVecMap; -//typedef TNodeOfNodeVecMap::iterator TNodeOfNodeVecMapItr; -//typedef map > TElemOfVecOfMapNodesMap; - -struct TNodeXYZ : public gp_XYZ { - TNodeXYZ( const SMDS_MeshNode* n ):gp_XYZ( n->X(), n->Y(), n->Z() ) {} -}; +namespace +{ + template < class ELEM_SET > + SMDS_ElemIteratorPtr elemSetIterator( const ELEM_SET& elements ) + { + typedef SMDS_SetIterator + < SMDS_pElement, typename ELEM_SET::const_iterator> TSetIterator; + return SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() )); + } +} //======================================================================= //function : SMESH_MeshEditor @@ -110,6 +125,53 @@ SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh ) { } +//================================================================================ +/*! + * \brief Clears myLastCreatedNodes and myLastCreatedElems + */ +//================================================================================ + +void SMESH_MeshEditor::ClearLastCreated() +{ + myLastCreatedNodes.Clear(); + myLastCreatedElems.Clear(); +} + +//================================================================================ +/*! + * \brief Initializes members by an existing element + * \param [in] elem - the source element + * \param [in] basicOnly - if true, does not set additional data of Ball and Polyhedron + */ +//================================================================================ + +SMESH_MeshEditor::ElemFeatures& +SMESH_MeshEditor::ElemFeatures::Init( const SMDS_MeshElement* elem, bool basicOnly ) +{ + if ( elem ) + { + myType = elem->GetType(); + if ( myType == SMDSAbs_Face || myType == SMDSAbs_Volume ) + { + myIsPoly = elem->IsPoly(); + if ( myIsPoly ) + { + myIsQuad = elem->IsQuadratic(); + if ( myType == SMDSAbs_Volume && !basicOnly ) + { + vector quant = static_cast( elem )->GetQuantities(); + myPolyhedQuantities.swap( quant ); + } + } + } + else if ( myType == SMDSAbs_Ball && !basicOnly ) + { + myBallDiameter = static_cast(elem)->GetDiameter(); + } + } + return *this; +} + //======================================================================= /*! * \brief Add element @@ -118,106 +180,193 @@ SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh ) SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & node, - const SMDSAbs_ElementType type, - const bool isPoly, - const int ID) + const ElemFeatures& features) { SMDS_MeshElement* e = 0; int nbnode = node.size(); SMESHDS_Mesh* mesh = GetMeshDS(); - switch ( type ) { - case SMDSAbs_Edge: - if ( nbnode == 2 ) - if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID); - else e = mesh->AddEdge (node[0], node[1] ); - else if ( nbnode == 3 ) { - if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID); - else e = mesh->AddEdge (node[0], node[1], node[2] ); - } - break; + const int ID = features.myID; + + switch ( features.myType ) { case SMDSAbs_Face: - if ( !isPoly ) { - if (nbnode == 3) - if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID); - else e = mesh->AddFace (node[0], node[1], node[2] ); - else if (nbnode == 4) - if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID); - else e = mesh->AddFace (node[0], node[1], node[2], node[3] ); - else if (nbnode == 6) - if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], - node[4], node[5], ID); - else e = mesh->AddFace (node[0], node[1], node[2], node[3], - node[4], node[5] ); + if ( !features.myIsPoly ) { + if (nbnode == 3) { + if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID); + else e = mesh->AddFace (node[0], node[1], node[2] ); + } + else if (nbnode == 4) { + if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID); + else e = mesh->AddFace (node[0], node[1], node[2], node[3] ); + } + else if (nbnode == 6) { + if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], + node[4], node[5], ID); + else e = mesh->AddFace (node[0], node[1], node[2], node[3], + node[4], node[5] ); + } + else if (nbnode == 7) { + if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], + node[4], node[5], node[6], ID); + else e = mesh->AddFace (node[0], node[1], node[2], node[3], + node[4], node[5], node[6] ); + } else if (nbnode == 8) { - if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], - node[4], node[5], node[6], node[7], ID); - else e = mesh->AddFace (node[0], node[1], node[2], node[3], - node[4], node[5], node[6], node[7] ); + if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], ID); + else e = mesh->AddFace (node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7] ); } - } else { - if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID); - else e = mesh->AddPolygonalFace (node ); + else if (nbnode == 9) { + if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], node[8], ID); + else e = mesh->AddFace (node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], node[8] ); + } + } + else if ( !features.myIsQuad ) + { + if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID); + else e = mesh->AddPolygonalFace (node ); + } + else if ( nbnode % 2 == 0 ) // just a protection + { + if ( ID >= 1 ) e = mesh->AddQuadPolygonalFaceWithID(node, ID); + else e = mesh->AddQuadPolygonalFace (node ); } break; + case SMDSAbs_Volume: - if ( !isPoly ) { - if (nbnode == 4) - if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID); - else e = mesh->AddVolume (node[0], node[1], node[2], node[3] ); - else if (nbnode == 5) - if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], - node[4], ID); - else e = mesh->AddVolume (node[0], node[1], node[2], node[3], - node[4] ); - else if (nbnode == 6) - if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], - node[4], node[5], ID); - else e = mesh->AddVolume (node[0], node[1], node[2], node[3], - node[4], node[5] ); - else if (nbnode == 8) - if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], - node[4], node[5], node[6], node[7], ID); - else e = mesh->AddVolume (node[0], node[1], node[2], node[3], - node[4], node[5], node[6], node[7] ); - else if (nbnode == 10) - if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], - node[4], node[5], node[6], node[7], - node[8], node[9], ID); - else e = mesh->AddVolume (node[0], node[1], node[2], node[3], - node[4], node[5], node[6], node[7], - node[8], node[9] ); - else if (nbnode == 13) - if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], - node[4], node[5], node[6], node[7], - node[8], node[9], node[10],node[11], - node[12],ID); - else e = mesh->AddVolume (node[0], node[1], node[2], node[3], - node[4], node[5], node[6], node[7], - node[8], node[9], node[10],node[11], - node[12] ); - else if (nbnode == 15) - if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], - node[4], node[5], node[6], node[7], - node[8], node[9], node[10],node[11], - node[12],node[13],node[14],ID); - else e = mesh->AddVolume (node[0], node[1], node[2], node[3], - node[4], node[5], node[6], node[7], - node[8], node[9], node[10],node[11], - node[12],node[13],node[14] ); - else if (nbnode == 20) { - if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], - node[4], node[5], node[6], node[7], - node[8], node[9], node[10],node[11], - node[12],node[13],node[14],node[15], - node[16],node[17],node[18],node[19],ID); - else e = mesh->AddVolume (node[0], node[1], node[2], node[3], - node[4], node[5], node[6], node[7], - node[8], node[9], node[10],node[11], - node[12],node[13],node[14],node[15], - node[16],node[17],node[18],node[19] ); + if ( !features.myIsPoly ) { + if (nbnode == 4) { + if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID); + else e = mesh->AddVolume (node[0], node[1], node[2], node[3] ); + } + else if (nbnode == 5) { + if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], + node[4], ID); + else e = mesh->AddVolume (node[0], node[1], node[2], node[3], + node[4] ); + } + else if (nbnode == 6) { + if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], + node[4], node[5], ID); + else e = mesh->AddVolume (node[0], node[1], node[2], node[3], + node[4], node[5] ); + } + else if (nbnode == 8) { + if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], ID); + else e = mesh->AddVolume (node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7] ); + } + else if (nbnode == 10) { + if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], ID); + else e = mesh->AddVolume (node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9] ); + } + else if (nbnode == 12) { + if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], node[10], node[11], ID); + else e = mesh->AddVolume (node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], node[10], node[11] ); + } + else if (nbnode == 13) { + if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], node[10],node[11], + node[12],ID); + else e = mesh->AddVolume (node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], node[10],node[11], + node[12] ); + } + else if (nbnode == 15) { + if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], node[10],node[11], + node[12],node[13],node[14],ID); + else e = mesh->AddVolume (node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], node[10],node[11], + node[12],node[13],node[14] ); } + else if (nbnode == 20) { + if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], node[10],node[11], + node[12],node[13],node[14],node[15], + node[16],node[17],node[18],node[19],ID); + else e = mesh->AddVolume (node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], node[10],node[11], + node[12],node[13],node[14],node[15], + node[16],node[17],node[18],node[19] ); + } + else if (nbnode == 27) { + if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], node[10],node[11], + node[12],node[13],node[14],node[15], + node[16],node[17],node[18],node[19], + node[20],node[21],node[22],node[23], + node[24],node[25],node[26], ID); + else e = mesh->AddVolume (node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], node[10],node[11], + node[12],node[13],node[14],node[15], + node[16],node[17],node[18],node[19], + node[20],node[21],node[22],node[23], + node[24],node[25],node[26] ); + } + } + else if ( !features.myIsQuad ) + { + if ( ID >= 1 ) e = mesh->AddPolyhedralVolumeWithID(node, features.myPolyhedQuantities, ID); + else e = mesh->AddPolyhedralVolume (node, features.myPolyhedQuantities ); + } + else + { + // if ( ID >= 1 ) e = mesh->AddQuadPolyhedralVolumeWithID(node, features.myPolyhedQuantities,ID); + // else e = mesh->AddQuadPolyhedralVolume (node, features.myPolyhedQuantities ); + } + break; + + case SMDSAbs_Edge: + if ( nbnode == 2 ) { + if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID); + else e = mesh->AddEdge (node[0], node[1] ); } + else if ( nbnode == 3 ) { + if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID); + else e = mesh->AddEdge (node[0], node[1], node[2] ); + } + break; + + case SMDSAbs_0DElement: + if ( nbnode == 1 ) { + if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID); + else e = mesh->Add0DElement (node[0] ); + } + break; + + case SMDSAbs_Node: + if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID); + else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z() ); + break; + + case SMDSAbs_Ball: + if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], features.myBallDiameter, ID); + else e = mesh->AddBall (node[0], features.myBallDiameter ); + break; + + default:; } + if ( e ) myLastCreatedElems.Append( e ); return e; } @@ -227,10 +376,8 @@ SMESH_MeshEditor::AddElement(const vector & node, */ //======================================================================= -SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs, - const SMDSAbs_ElementType type, - const bool isPoly, - const int ID) +SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs, + const ElemFeatures& features) { vector nodes; nodes.reserve( nodeIDs.size() ); @@ -241,7 +388,7 @@ SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs else return 0; } - return AddElement( nodes, type, isPoly, ID ); + return AddElement( nodes, features ); } //======================================================================= @@ -250,8 +397,8 @@ SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs // Modify a compute state of sub-meshes which become empty //======================================================================= -bool SMESH_MeshEditor::Remove (const list< int >& theIDs, - const bool isNodes ) +int SMESH_MeshEditor::Remove (const list< int >& theIDs, + const bool isNodes ) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); @@ -259,6 +406,7 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs, SMESHDS_Mesh* aMesh = GetMeshDS(); set< SMESH_subMesh *> smmap; + int removed = 0; list::const_iterator it = theIDs.begin(); for ( ; it != theIDs.end(); it++ ) { const SMDS_MeshElement * elem; @@ -273,28 +421,29 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs, if ( isNodes ) { const SMDS_MeshNode* node = cast2Node( elem ); if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX ) - if ( int aShapeID = node->GetPosition()->GetShapeId() ) + if ( int aShapeID = node->getshapeId() ) if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) ) smmap.insert( sm ); } // Find sub-meshes to notify about modification -// SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); -// while ( nodeIt->more() ) { -// const SMDS_MeshNode* node = static_cast( nodeIt->next() ); -// const SMDS_PositionPtr& aPosition = node->GetPosition(); -// if ( aPosition.get() ) { -// if ( int aShapeID = aPosition->GetShapeId() ) { -// if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) ) -// smmap.insert( sm ); -// } -// } -// } + // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); + // while ( nodeIt->more() ) { + // const SMDS_MeshNode* node = static_cast( nodeIt->next() ); + // const SMDS_PositionPtr& aPosition = node->GetPosition(); + // if ( aPosition.get() ) { + // if ( int aShapeID = aPosition->GetShapeId() ) { + // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) ) + // smmap.insert( sm ); + // } + // } + // } // Do remove if ( isNodes ) aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem )); else aMesh->RemoveElement( elem ); + removed++; } // Notify sub-meshes about modification @@ -304,11 +453,58 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs, (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED ); } -// // Check if the whole mesh becomes empty -// if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) ) -// sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + // // Check if the whole mesh becomes empty + // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) ) + // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); - return true; + return removed; +} + +//================================================================================ +/*! + * \brief Create 0D elements on all nodes of the given object except those + * nodes on which a 0D element already exists. + * \param elements - Elements on whose nodes to create 0D elements; if empty, + * the all mesh is treated + * \param all0DElems - returns all 0D elements found or created on nodes of \a elements + */ +//================================================================================ + +void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements, + TIDSortedElemSet& all0DElems ) +{ + SMDS_ElemIteratorPtr elemIt; + vector< const SMDS_MeshElement* > allNodes; + if ( elements.empty() ) + { + allNodes.reserve( GetMeshDS()->NbNodes() ); + elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node ); + while ( elemIt->more() ) + allNodes.push_back( elemIt->next() ); + + elemIt = elemSetIterator( allNodes ); + } + else + { + elemIt = elemSetIterator( elements ); + } + + while ( elemIt->more() ) + { + const SMDS_MeshElement* e = elemIt->next(); + SMDS_ElemIteratorPtr nodeIt = e->nodesIterator(); + while ( nodeIt->more() ) + { + const SMDS_MeshNode* n = cast2Node( nodeIt->next() ); + SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement ); + if ( it0D->more() ) + all0DElems.insert( it0D->next() ); + else { + myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n )); + all0DElems.insert( myLastCreatedElems.Last() ); + } + } + } } //======================================================================= @@ -326,49 +522,56 @@ int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem) if ( aMesh->ShapeToMesh().IsNull() ) return 0; + int aShapeID = theElem->getshapeId(); + if ( aShapeID < 1 ) + return 0; + + if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID )) + if ( sm->Contains( theElem )) + return aShapeID; + if ( theElem->GetType() == SMDSAbs_Node ) { - const SMDS_PositionPtr& aPosition = - static_cast( theElem )->GetPosition(); - if ( aPosition.get() ) - return aPosition->GetShapeId(); - else - return 0; + MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() ); + } + else { + MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() ); } - TopoDS_Shape aShape; // the shape a node is on - SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); - while ( nodeIt->more() ) { - const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - const SMDS_PositionPtr& aPosition = node->GetPosition(); - if ( aPosition.get() ) { - int aShapeID = aPosition->GetShapeId(); - SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ); - if ( sm ) { - if ( sm->Contains( theElem )) - return aShapeID; - if ( aShape.IsNull() ) - aShape = aMesh->IndexToShape( aShapeID ); - } - else { - //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID ); + TopoDS_Shape aShape; // the shape a node of theElem is on + if ( theElem->GetType() != SMDSAbs_Node ) + { + SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); + while ( nodeIt->more() ) { + const SMDS_MeshNode* node = static_cast( nodeIt->next() ); + if ((aShapeID = node->getshapeId()) > 0) { + if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) { + if ( sm->Contains( theElem )) + return aShapeID; + if ( aShape.IsNull() ) + aShape = aMesh->IndexToShape( aShapeID ); + } } } } // None of nodes is on a proper shape, // find the shape among ancestors of aShape on which a node is - if ( aShape.IsNull() ) { - //MESSAGE ("::FindShape() - NONE node is on shape") - return 0; + if ( !aShape.IsNull() ) { + TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape )); + for ( ; ancIt.More(); ancIt.Next() ) { + SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() ); + if ( sm && sm->Contains( theElem )) + return aMesh->ShapeToIndex( ancIt.Value() ); + } } - TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape )); - for ( ; ancIt.More(); ancIt.Next() ) { - SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() ); - if ( sm && sm->Contains( theElem )) - return aMesh->ShapeToIndex( ancIt.Value() ); + else + { + SMESHDS_SubMeshIteratorPtr smIt = GetMeshDS()->SubMeshes(); + while ( const SMESHDS_SubMesh* sm = smIt->next() ) + if ( sm->Contains( theElem )) + return sm->GetID(); } - //MESSAGE ("::FindShape() - SHAPE NOT FOUND") return 0; } @@ -390,12 +593,12 @@ bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node, } //======================================================================= -//function : ShiftNodesQuadTria -//purpose : auxilary -// Shift nodes in the array corresponded to quadratic triangle +//function : shiftNodesQuadTria +//purpose : Shift nodes in the array corresponded to quadratic triangle // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3) //======================================================================= -static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[]) + +static void shiftNodesQuadTria(vector< const SMDS_MeshNode* >& aNodes) { const SMDS_MeshNode* nd1 = aNodes[0]; aNodes[0] = aNodes[1]; @@ -408,34 +611,42 @@ static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[]) } //======================================================================= -//function : GetNodesFromTwoTria -//purpose : auxilary -// Shift nodes in the array corresponded to quadratic triangle -// example: (0,1,2,3,4,5) -> (1,2,0,4,5,3) +//function : nbEdgeConnectivity +//purpose : return number of the edges connected with the theNode. +// if theEdges has connections with the other type of the +// elements, return -1 +//======================================================================= + +static int nbEdgeConnectivity(const SMDS_MeshNode* theNode) +{ + // SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(); + // int nb=0; + // while(elemIt->more()) { + // elemIt->next(); + // nb++; + // } + // return nb; + return theNode->NbInverseElements(); +} + +//======================================================================= +//function : getNodesFromTwoTria +//purpose : //======================================================================= -static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1, + +static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1, const SMDS_MeshElement * theTria2, - const SMDS_MeshNode* N1[], - const SMDS_MeshNode* N2[]) + vector< const SMDS_MeshNode*>& N1, + vector< const SMDS_MeshNode*>& N2) { - SMDS_ElemIteratorPtr it = theTria1->nodesIterator(); - int i=0; - while(i<6) { - N1[i] = static_cast( it->next() ); - i++; - } - if(it->more()) return false; - it = theTria2->nodesIterator(); - i=0; - while(i<6) { - N2[i] = static_cast( it->next() ); - i++; - } - if(it->more()) return false; + N1.assign( theTria1->begin_nodes(), theTria1->end_nodes() ); + if ( N1.size() < 6 ) return false; + N2.assign( theTria2->begin_nodes(), theTria2->end_nodes() ); + if ( N2.size() < 6 ) return false; int sames[3] = {-1,-1,-1}; int nbsames = 0; - int j; + int i, j; for(i=0; i<3; i++) { for(j=0; j<3; j++) { if(N1[i]==N2[j]) { @@ -447,18 +658,18 @@ static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1, } if(nbsames!=2) return false; if(sames[0]>-1) { - ShiftNodesQuadTria(N1); + shiftNodesQuadTria(N1); if(sames[1]>-1) { - ShiftNodesQuadTria(N1); + shiftNodesQuadTria(N1); } } i = sames[0] + sames[1] + sames[2]; for(; i<2; i++) { - ShiftNodesQuadTria(N2); + shiftNodesQuadTria(N2); } - // now we receive following N1 and N2 (using numeration as above image) + // now we receive following N1 and N2 (using numeration as in the image below) // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6) - // i.e. first nodes from both arrays determ new diagonal + // i.e. first nodes from both arrays form a new diagonal return true; } @@ -472,15 +683,19 @@ static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1, bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1, const SMDS_MeshElement * theTria2 ) { + MESSAGE("InverseDiag"); myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); if (!theTria1 || !theTria2) return false; - const SMDS_FaceOfNodes* F1 = dynamic_cast( theTria1 ); - const SMDS_FaceOfNodes* F2 = dynamic_cast( theTria2 ); - if (F1 && F2) { + const SMDS_VtkFace* F1 = dynamic_cast( theTria1 ); + if (!F1) return false; + const SMDS_VtkFace* F2 = dynamic_cast( theTria2 ); + if (!F2) return false; + if ((theTria1->GetEntityType() == SMDSEntity_Triangle) && + (theTria2->GetEntityType() == SMDSEntity_Triangle)) { // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ | @@ -489,7 +704,7 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1, // put nodes in array and find out indices of the same ones const SMDS_MeshNode* aNodes [6]; - int sameInd [] = { 0, 0, 0, 0, 0, 0 }; + int sameInd [] = { -1, -1, -1, -1, -1, -1 }; int i = 0; SMDS_ElemIteratorPtr it = theTria1->nodesIterator(); while ( it->more() ) { @@ -515,14 +730,15 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1, } // find indices of 1,2 and of A,B in theTria1 - int iA = 0, iB = 0, i1 = 0, i2 = 0; + int iA = -1, iB = 0, i1 = 0, i2 = 0; for ( i = 0; i < 6; i++ ) { - if ( sameInd [ i ] == 0 ) { + if ( sameInd [ i ] == -1 ) { if ( i < 3 ) i1 = i; else i2 = i; - } else if (i < 3) { - if ( iA ) iB = i; - else iA = i; + } + else if (i < 3) { + if ( iA >= 0) iB = i; + else iA = i; } } // nodes 1 and 2 should not be the same @@ -534,24 +750,20 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1, // theTria2: B->1 aNodes[ sameInd[ iB ]] = aNodes[ i1 ]; - //MESSAGE( theTria1 << theTria2 ); - GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 ); GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 ); - //MESSAGE( theTria1 << theTria2 ); - return true; } // end if(F1 && F2) // check case of quadratic faces - const SMDS_QuadraticFaceOfNodes* QF1 = - dynamic_cast (theTria1); - if(!QF1) return false; - const SMDS_QuadraticFaceOfNodes* QF2 = - dynamic_cast (theTria2); - if(!QF2) return false; + if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle && + theTria1->GetEntityType() != SMDSEntity_BiQuad_Triangle) + return false; + if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle&& + theTria2->GetEntityType() != SMDSEntity_BiQuad_Triangle) + return false; // 5 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9) @@ -563,32 +775,61 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1, // 4 +--+--+ 3 // 8 - const SMDS_MeshNode* N1 [6]; - const SMDS_MeshNode* N2 [6]; - if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2)) + vector< const SMDS_MeshNode* > N1; + vector< const SMDS_MeshNode* > N2; + if(!getNodesFromTwoTria(theTria1,theTria2,N1,N2)) return false; // now we receive following N1 and N2 (using numeration as above image) // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6) // i.e. first nodes from both arrays determ new diagonal - const SMDS_MeshNode* N1new [6]; - const SMDS_MeshNode* N2new [6]; - N1new[0] = N1[0]; - N1new[1] = N2[0]; - N1new[2] = N2[1]; - N1new[3] = N1[4]; - N1new[4] = N2[3]; - N1new[5] = N1[5]; - N2new[0] = N1[0]; - N2new[1] = N1[1]; - N2new[2] = N2[0]; - N2new[3] = N1[3]; - N2new[4] = N2[5]; - N2new[5] = N1[4]; - // replaces nodes in faces - GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 ); - GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 ); - + vector< const SMDS_MeshNode*> N1new( N1.size() ); + vector< const SMDS_MeshNode*> N2new( N2.size() ); + N1new.back() = N1.back(); // central node of biquadratic + N2new.back() = N2.back(); + N1new[0] = N1[0]; N2new[0] = N1[0]; + N1new[1] = N2[0]; N2new[1] = N1[1]; + N1new[2] = N2[1]; N2new[2] = N2[0]; + N1new[3] = N1[4]; N2new[3] = N1[3]; + N1new[4] = N2[3]; N2new[4] = N2[5]; + N1new[5] = N1[5]; N2new[5] = N1[4]; + // change nodes in faces + GetMeshDS()->ChangeElementNodes( theTria1, &N1new[0], N1new.size() ); + GetMeshDS()->ChangeElementNodes( theTria2, &N2new[0], N2new.size() ); + + // move the central node of biquadratic triangle + SMESH_MesherHelper helper( *GetMesh() ); + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + const SMDS_MeshElement* tria = is2nd ? theTria2 : theTria1; + vector< const SMDS_MeshNode*>& nodes = is2nd ? N2new : N1new; + if ( nodes.size() < 7 ) + continue; + helper.SetSubShape( tria->getshapeId() ); + const TopoDS_Face& F = TopoDS::Face( helper.GetSubShape() ); + gp_Pnt xyz; + if ( F.IsNull() ) + { + xyz = ( SMESH_TNodeXYZ( nodes[3] ) + + SMESH_TNodeXYZ( nodes[4] ) + + SMESH_TNodeXYZ( nodes[5] )) / 3.; + } + else + { + bool checkUV; + gp_XY uv = ( helper.GetNodeUV( F, nodes[3], nodes[2], &checkUV ) + + helper.GetNodeUV( F, nodes[4], nodes[0], &checkUV ) + + helper.GetNodeUV( F, nodes[5], nodes[1], &checkUV )) / 3.; + TopLoc_Location loc; + Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc); + xyz = S->Value( uv.X(), uv.Y() ); + xyz.Transform( loc ); + if ( nodes[6]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE && // set UV + nodes[6]->getshapeId() > 0 ) + GetMeshDS()->SetNodeOnFace( nodes[6], nodes[6]->getshapeId(), uv.X(), uv.Y() ); + } + GetMeshDS()->MoveNode( nodes[6], xyz.X(), xyz.Y(), xyz.Z() ); + } return true; } @@ -610,30 +851,28 @@ static bool findTriangles(const SMDS_MeshNode * theNode1, SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face); while (it->more()) { const SMDS_MeshElement* elem = it->next(); - if ( elem->NbNodes() == 3 ) + if ( elem->NbCornerNodes() == 3 ) emap.insert( elem ); } it = theNode2->GetInverseElementIterator(SMDSAbs_Face); while (it->more()) { const SMDS_MeshElement* elem = it->next(); - if ( emap.find( elem ) != emap.end() ) { - if ( theTria1 ) { - // theTria1 must be element with minimum ID - if( theTria1->GetID() < elem->GetID() ) { - theTria2 = elem; - } - else { - theTria2 = theTria1; - theTria1 = elem; - } - break; - } - else { + if ( emap.count( elem )) { + if ( !theTria1 ) + { theTria1 = elem; } + else + { + theTria2 = elem; + // theTria1 must be element with minimum ID + if ( theTria2->GetID() < theTria1->GetID() ) + std::swap( theTria2, theTria1 ); + return true; + } } } - return ( theTria1 && theTria2 ); + return false; } //======================================================================= @@ -655,11 +894,12 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1, if ( !findTriangles( theNode1, theNode2, tr1, tr2 )) return false; - const SMDS_FaceOfNodes* F1 = dynamic_cast( tr1 ); - //if (!F1) return false; - const SMDS_FaceOfNodes* F2 = dynamic_cast( tr2 ); - //if (!F2) return false; - if (F1 && F2) { + const SMDS_VtkFace* F1 = dynamic_cast( tr1 ); + if (!F1) return false; + const SMDS_VtkFace* F2 = dynamic_cast( tr2 ); + if (!F2) return false; + if ((tr1->GetEntityType() == SMDSEntity_Triangle) && + (tr2->GetEntityType() == SMDSEntity_Triangle)) { // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ | @@ -697,23 +937,13 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1, // tr2: B->1 aNodes2[ iB2 ] = aNodes1[ i1 ]; - //MESSAGE( tr1 << tr2 ); - GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 ); GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 ); - //MESSAGE( tr1 << tr2 ); - return true; } // check case of quadratic faces - const SMDS_QuadraticFaceOfNodes* QF1 = - dynamic_cast (tr1); - if(!QF1) return false; - const SMDS_QuadraticFaceOfNodes* QF2 = - dynamic_cast (tr2); - if(!QF2) return false; return InverseDiag(tr1,tr2); } @@ -787,34 +1017,39 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1, if ( !findTriangles( theNode1, theNode2, tr1, tr2 )) return false; - const SMDS_FaceOfNodes* F1 = dynamic_cast( tr1 ); - //if (!F1) return false; - const SMDS_FaceOfNodes* F2 = dynamic_cast( tr2 ); - //if (!F2) return false; - if (F1 && F2) { + const SMDS_VtkFace* F1 = dynamic_cast( tr1 ); + if (!F1) return false; + const SMDS_VtkFace* F2 = dynamic_cast( tr2 ); + if (!F2) return false; + SMESHDS_Mesh * aMesh = GetMeshDS(); + + if ((tr1->GetEntityType() == SMDSEntity_Triangle) && + (tr2->GetEntityType() == SMDSEntity_Triangle)) { const SMDS_MeshNode* aNodes [ 4 ]; if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 )) return false; - //MESSAGE( endl << tr1 << tr2 ); - - GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 ); - myLastCreatedElems.Append(tr1); - GetMeshDS()->RemoveElement( tr2 ); - - //MESSAGE( endl << tr1 ); + const SMDS_MeshElement* newElem = 0; + newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] ); + myLastCreatedElems.Append(newElem); + AddToSameGroups( newElem, tr1, aMesh ); + int aShapeId = tr1->getshapeId(); + if ( aShapeId ) + { + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + } + aMesh->RemoveElement( tr1 ); + aMesh->RemoveElement( tr2 ); return true; } // check case of quadratic faces - const SMDS_QuadraticFaceOfNodes* QF1 = - dynamic_cast (tr1); - if(!QF1) return false; - const SMDS_QuadraticFaceOfNodes* QF2 = - dynamic_cast (tr2); - if(!QF2) return false; + if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle) + return false; + if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle) + return false; // 5 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9) @@ -826,9 +1061,9 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1, // 4 +--+--+ 3 // 8 - const SMDS_MeshNode* N1 [6]; - const SMDS_MeshNode* N2 [6]; - if(!GetNodesFromTwoTria(tr1,tr2,N1,N2)) + vector< const SMDS_MeshNode* > N1; + vector< const SMDS_MeshNode* > N2; + if(!getNodesFromTwoTria(tr1,tr2,N1,N2)) return false; // now we receive following N1 and N2 (using numeration as above image) // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6) @@ -844,9 +1079,18 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1, aNodes[6] = N2[3]; aNodes[7] = N1[5]; - GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 ); - myLastCreatedElems.Append(tr1); - GetMeshDS()->RemoveElement( tr2 ); + const SMDS_MeshElement* newElem = 0; + newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3], + aNodes[4], aNodes[5], aNodes[6], aNodes[7]); + myLastCreatedElems.Append(newElem); + AddToSameGroups( newElem, tr1, aMesh ); + int aShapeId = tr1->getshapeId(); + if ( aShapeId ) + { + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + } + aMesh->RemoveElement( tr1 ); + aMesh->RemoveElement( tr2 ); // remove middle node (9) GetMeshDS()->RemoveNode( N1[4] ); @@ -861,6 +1105,7 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1, bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem) { + MESSAGE("Reorient"); myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); @@ -870,133 +1115,314 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem) if ( !it || !it->more() ) return false; - switch ( theElem->GetType() ) { + const SMDSAbs_ElementType type = theElem->GetType(); + if ( type < SMDSAbs_Edge || type > SMDSAbs_Volume ) + return false; - case SMDSAbs_Edge: - case SMDSAbs_Face: { - if(!theElem->IsQuadratic()) { - int i = theElem->NbNodes(); - vector aNodes( i ); - while ( it->more() ) - aNodes[ --i ]= static_cast( it->next() ); - return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() ); - } - else { - // quadratic elements - if(theElem->GetType()==SMDSAbs_Edge) { - vector aNodes(3); - aNodes[1]= static_cast( it->next() ); - aNodes[0]= static_cast( it->next() ); - aNodes[2]= static_cast( it->next() ); - return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 ); - } - else { - int nbn = theElem->NbNodes(); - vector aNodes(nbn); - aNodes[0]= static_cast( it->next() ); - int i=1; - for(; i( it->next() ); - } - for(i=0; i( it->next() ); - } - return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn ); - } + const SMDSAbs_EntityType geomType = theElem->GetEntityType(); + if ( geomType == SMDSEntity_Polyhedra ) // polyhedron + { + const SMDS_VtkVolume* aPolyedre = + dynamic_cast( theElem ); + if (!aPolyedre) { + MESSAGE("Warning: bad volumic element"); + return false; } - } - case SMDSAbs_Volume: { - if (theElem->IsPoly()) { - const SMDS_PolyhedralVolumeOfNodes* aPolyedre = - static_cast( theElem ); - if (!aPolyedre) { - MESSAGE("Warning: bad volumic element"); - return false; - } - - int nbFaces = aPolyedre->NbFaces(); - vector poly_nodes; - vector quantities (nbFaces); + const int nbFaces = aPolyedre->NbFaces(); + vector poly_nodes; + vector quantities (nbFaces); - // reverse each face of the polyedre - for (int iface = 1; iface <= nbFaces; iface++) { - int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface); - quantities[iface - 1] = nbFaceNodes; + // reverse each face of the polyedre + for (int iface = 1; iface <= nbFaces; iface++) { + int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface); + quantities[iface - 1] = nbFaceNodes; - for (inode = nbFaceNodes; inode >= 1; inode--) { - const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode); - poly_nodes.push_back(curNode); - } + for (inode = nbFaceNodes; inode >= 1; inode--) { + const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode); + poly_nodes.push_back(curNode); } - - return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities ); - - } - else { - SMDS_VolumeTool vTool; - if ( !vTool.Set( theElem )) - return false; - vTool.Inverse(); - return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() ); } + return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities ); } - default:; + else // other elements + { + vector nodes( theElem->begin_nodes(), theElem->end_nodes() ); + const std::vector& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType, nodes.size() ); + if ( interlace.empty() ) + { + std::reverse( nodes.begin(), nodes.end() ); // obsolete, just in case + } + else + { + SMDS_MeshCell::applyInterlace( interlace, nodes ); + } + return GetMeshDS()->ChangeElementNodes( theElem, &nodes[0], nodes.size() ); } - return false; } -//======================================================================= -//function : getBadRate -//purpose : -//======================================================================= +//================================================================================ +/*! + * \brief Reorient faces. + * \param theFaces - the faces to reorient. If empty the whole mesh is meant + * \param theDirection - desired direction of normal of \a theFace + * \param theFace - one of \a theFaces that sould be oriented according to + * \a theDirection and whose orientation defines orientation of other faces + * \return number of reoriented faces. + */ +//================================================================================ -static double getBadRate (const SMDS_MeshElement* theElem, - SMESH::Controls::NumericalFunctorPtr& theCrit) +int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces, + const gp_Dir& theDirection, + const SMDS_MeshElement * theFace) { - SMESH::Controls::TSequenceOfXYZ P; - if ( !theElem || !theCrit->GetPoints( theElem, P )) - return 1e100; - return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() ); - //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() ); -} + int nbReori = 0; + if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori; -//======================================================================= -//function : QuadToTri -//purpose : Cut quadrangles into triangles. -// theCrit is used to select a diagonal to cut -//======================================================================= + if ( theFaces.empty() ) + { + SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true); + while ( fIt->more() ) + theFaces.insert( theFaces.end(), fIt->next() ); + } -bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, - SMESH::Controls::NumericalFunctorPtr theCrit) -{ - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + // orient theFace according to theDirection + gp_XYZ normal; + SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false ); + if ( normal * theDirection.XYZ() < 0 ) + nbReori += Reorient( theFace ); - MESSAGE( "::QuadToTri()" ); + // Orient other faces - if ( !theCrit.get() ) - return false; + set< const SMDS_MeshElement* > startFaces, visitedFaces; + TIDSortedElemSet avoidSet; + set< SMESH_TLink > checkedLinks; + pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew; - SMESHDS_Mesh * aMesh = GetMeshDS(); + if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces + theFaces.erase( theFace ); + startFaces.insert( theFace ); - Handle(Geom_Surface) surface; - SMESH_MesherHelper helper( *GetMesh() ); + int nodeInd1, nodeInd2; + const SMDS_MeshElement* otherFace; + vector< const SMDS_MeshElement* > facesNearLink; + vector< std::pair< int, int > > nodeIndsOfFace; - TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() != SMDSAbs_Face ) - continue; - if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 )) + set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin(); + while ( !startFaces.empty() ) + { + startFace = startFaces.begin(); + theFace = *startFace; + startFaces.erase( startFace ); + if ( !visitedFaces.insert( theFace ).second ) continue; - // retrieve element nodes - const SMDS_MeshNode* aNodes [8]; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - int i = 0; - while ( itN->more() ) - aNodes[ i++ ] = static_cast( itN->next() ); + avoidSet.clear(); + avoidSet.insert(theFace); + + NLink link( theFace->GetNode( 0 ), (SMDS_MeshNode *) 0 ); + + const int nbNodes = theFace->NbCornerNodes(); + for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace + { + link.second = theFace->GetNode(( i+1 ) % nbNodes ); + linkIt_isNew = checkedLinks.insert( link ); + if ( !linkIt_isNew.second ) + { + // link has already been checked and won't be encountered more + // if the group (theFaces) is manifold + //checkedLinks.erase( linkIt_isNew.first ); + } + else + { + facesNearLink.clear(); + nodeIndsOfFace.clear(); + while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second, + theFaces, avoidSet, + &nodeInd1, &nodeInd2 ))) + if ( otherFace != theFace) + { + facesNearLink.push_back( otherFace ); + nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 )); + avoidSet.insert( otherFace ); + } + if ( facesNearLink.size() > 1 ) + { + // NON-MANIFOLD mesh shell ! + // select a face most co-directed with theFace, + // other faces won't be visited this time + gp_XYZ NF, NOF; + SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false ); + double proj, maxProj = -1; + for ( size_t i = 0; i < facesNearLink.size(); ++i ) { + SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false ); + if (( proj = Abs( NF * NOF )) > maxProj ) { + maxProj = proj; + otherFace = facesNearLink[i]; + nodeInd1 = nodeIndsOfFace[i].first; + nodeInd2 = nodeIndsOfFace[i].second; + } + } + // not to visit rejected faces + for ( size_t i = 0; i < facesNearLink.size(); ++i ) + if ( facesNearLink[i] != otherFace && theFaces.size() > 1 ) + visitedFaces.insert( facesNearLink[i] ); + } + else if ( facesNearLink.size() == 1 ) + { + otherFace = facesNearLink[0]; + nodeInd1 = nodeIndsOfFace.back().first; + nodeInd2 = nodeIndsOfFace.back().second; + } + if ( otherFace && otherFace != theFace) + { + // link must be reverse in otherFace if orientation ot otherFace + // is same as that of theFace + if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 ) + { + nbReori += Reorient( otherFace ); + } + startFaces.insert( otherFace ); + } + } + std::swap( link.first, link.second ); // reverse the link + } + } + return nbReori; +} + +//================================================================================ +/*! + * \brief Reorient faces basing on orientation of adjacent volumes. + * \param theFaces - faces to reorient. If empty, all mesh faces are treated. + * \param theVolumes - reference volumes. + * \param theOutsideNormal - to orient faces to have their normal + * pointing either \a outside or \a inside the adjacent volumes. + * \return number of reoriented faces. + */ +//================================================================================ + +int SMESH_MeshEditor::Reorient2DBy3D (TIDSortedElemSet & theFaces, + TIDSortedElemSet & theVolumes, + const bool theOutsideNormal) +{ + int nbReori = 0; + + SMDS_ElemIteratorPtr faceIt; + if ( theFaces.empty() ) + faceIt = GetMeshDS()->elementsIterator( SMDSAbs_Face ); + else + faceIt = elemSetIterator( theFaces ); + + vector< const SMDS_MeshNode* > faceNodes; + TIDSortedElemSet checkedVolumes; + set< const SMDS_MeshNode* > faceNodesSet; + SMDS_VolumeTool volumeTool; + + while ( faceIt->more() ) // loop on given faces + { + const SMDS_MeshElement* face = faceIt->next(); + if ( face->GetType() != SMDSAbs_Face ) + continue; + + const int nbCornersNodes = face->NbCornerNodes(); + faceNodes.assign( face->begin_nodes(), face->end_nodes() ); + + checkedVolumes.clear(); + SMDS_ElemIteratorPtr vIt = faceNodes[ 0 ]->GetInverseElementIterator( SMDSAbs_Volume ); + while ( vIt->more() ) + { + const SMDS_MeshElement* volume = vIt->next(); + + if ( !checkedVolumes.insert( volume ).second ) + continue; + if ( !theVolumes.empty() && !theVolumes.count( volume )) + continue; + + // is volume adjacent? + bool allNodesCommon = true; + for ( int iN = 1; iN < nbCornersNodes && allNodesCommon; ++iN ) + allNodesCommon = ( volume->GetNodeIndex( faceNodes[ iN ]) > -1 ); + if ( !allNodesCommon ) + continue; + + // get nodes of a corresponding volume facet + faceNodesSet.clear(); + faceNodesSet.insert( faceNodes.begin(), faceNodes.end() ); + volumeTool.Set( volume ); + int facetID = volumeTool.GetFaceIndex( faceNodesSet ); + if ( facetID < 0 ) continue; + volumeTool.SetExternalNormal(); + const SMDS_MeshNode** facetNodes = volumeTool.GetFaceNodes( facetID ); + + // compare order of faceNodes and facetNodes + const int iQ = 1 + ( nbCornersNodes < faceNodes.size() ); + int iNN[2]; + for ( int i = 0; i < 2; ++i ) + { + const SMDS_MeshNode* n = facetNodes[ i*iQ ]; + for ( int iN = 0; iN < nbCornersNodes; ++iN ) + if ( faceNodes[ iN ] == n ) + { + iNN[ i ] = iN; + break; + } + } + bool isOutside = Abs( iNN[0]-iNN[1] ) == 1 ? iNN[0] < iNN[1] : iNN[0] > iNN[1]; + if ( isOutside != theOutsideNormal ) + nbReori += Reorient( face ); + } + } // loop on given faces + + return nbReori; +} + +//======================================================================= +//function : getBadRate +//purpose : +//======================================================================= + +static double getBadRate (const SMDS_MeshElement* theElem, + SMESH::Controls::NumericalFunctorPtr& theCrit) +{ + SMESH::Controls::TSequenceOfXYZ P; + if ( !theElem || !theCrit->GetPoints( theElem, P )) + return 1e100; + return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() ); + //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() ); +} + +//======================================================================= +//function : QuadToTri +//purpose : Cut quadrangles into triangles. +// theCrit is used to select a diagonal to cut +//======================================================================= + +bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, + SMESH::Controls::NumericalFunctorPtr theCrit) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + if ( !theCrit.get() ) + return false; + + SMESHDS_Mesh * aMesh = GetMeshDS(); + + Handle(Geom_Surface) surface; + SMESH_MesherHelper helper( *GetMesh() ); + + TIDSortedElemSet::iterator itElem; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) + { + const SMDS_MeshElement* elem = *itElem; + if ( !elem || elem->GetType() != SMDSAbs_Face ) + continue; + if ( elem->NbCornerNodes() != 4 ) + continue; + + // retrieve element nodes + vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() ); // compare two sets of possible triangles double aBadRate1, aBadRate2; // to what extent a set is bad @@ -1008,115 +1434,196 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] ); aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit ); - int aShapeId = FindShape( elem ); - const SMDS_MeshElement* newElem = 0; - - if( !elem->IsQuadratic() ) { - - // split liner quadrangle + const int aShapeId = FindShape( elem ); + const SMDS_MeshElement* newElem1 = 0; + const SMDS_MeshElement* newElem2 = 0; + if ( !elem->IsQuadratic() ) // split liner quadrangle + { + // for MaxElementLength2D functor we return minimum diagonal for splitting, + // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4) if ( aBadRate1 <= aBadRate2 ) { // tr1 + tr2 is better - aMesh->ChangeElementNodes( elem, aNodes, 3 ); - newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] ); + newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] ); + newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] ); } else { // tr3 + tr4 is better - aMesh->ChangeElementNodes( elem, &aNodes[1], 3 ); - newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] ); + newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] ); + newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] ); } } - else { - - // split quadratic quadrangle + else // split quadratic quadrangle + { + helper.SetIsQuadratic( true ); + helper.SetIsBiQuadratic( aNodes.size() == 9 ); - // get surface elem is on - if ( aShapeId != helper.GetSubShapeID() ) { - surface.Nullify(); - TopoDS_Shape shape; - if ( aShapeId > 0 ) - shape = aMesh->IndexToShape( aShapeId ); - if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) { - TopoDS_Face face = TopoDS::Face( shape ); - surface = BRep_Tool::Surface( face ); - if ( !surface.IsNull() ) - helper.SetSubShape( shape ); - } - } - // get elem nodes - const SMDS_MeshNode* aNodes [8]; - const SMDS_MeshNode* inFaceNode = 0; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - int i = 0; - while ( itN->more() ) { - aNodes[ i++ ] = static_cast( itN->next() ); - if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() && - aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) - { - inFaceNode = aNodes[ i-1 ]; - } - } - // find middle point for (0,1,2,3) - // and create a node in this point; - gp_XYZ p( 0,0,0 ); - if ( surface.IsNull() ) { - for(i=0; i<4; i++) - p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() ); - p /= 4; - } - else { - TopoDS_Face face = TopoDS::Face( helper.GetSubShape() ); - gp_XY uv( 0,0 ); - for(i=0; i<4; i++) - uv += helper.GetNodeUV( face, aNodes[i], inFaceNode ); - uv /= 4.; - p = surface->Value( uv.X(), uv.Y() ).XYZ(); + helper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); + if ( aNodes.size() == 9 ) + { + helper.SetIsBiQuadratic( true ); + if ( aBadRate1 <= aBadRate2 ) + helper.AddTLinkNode( aNodes[0], aNodes[2], aNodes[8] ); + else + helper.AddTLinkNode( aNodes[1], aNodes[3], aNodes[8] ); } - const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() ); - myLastCreatedNodes.Append(newN); - // create a new element - const SMDS_MeshNode* N[6]; if ( aBadRate1 <= aBadRate2 ) { - N[0] = aNodes[0]; - N[1] = aNodes[1]; - N[2] = aNodes[2]; - N[3] = aNodes[4]; - N[4] = aNodes[5]; - N[5] = newN; - newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0], - aNodes[6], aNodes[7], newN ); + newElem1 = helper.AddFace( aNodes[2], aNodes[3], aNodes[0] ); + newElem2 = helper.AddFace( aNodes[2], aNodes[0], aNodes[1] ); } else { - N[0] = aNodes[1]; - N[1] = aNodes[2]; - N[2] = aNodes[3]; - N[3] = aNodes[5]; - N[4] = aNodes[6]; - N[5] = newN; - newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1], - aNodes[7], aNodes[4], newN ); + newElem1 = helper.AddFace( aNodes[3], aNodes[0], aNodes[1] ); + newElem2 = helper.AddFace( aNodes[3], aNodes[1], aNodes[2] ); } - aMesh->ChangeElementNodes( elem, N, 6 ); - } // quadratic case // care of a new element - myLastCreatedElems.Append(newElem); - AddToSameGroups( newElem, elem, aMesh ); + myLastCreatedElems.Append(newElem1); + myLastCreatedElems.Append(newElem2); + AddToSameGroups( newElem1, elem, aMesh ); + AddToSameGroups( newElem2, elem, aMesh ); // put a new triangle on the same shape if ( aShapeId ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); + aMesh->SetMeshElementOnShape( newElem1, aShapeId ); + aMesh->SetMeshElementOnShape( newElem2, aShapeId ); + + aMesh->RemoveElement( elem ); } return true; } +//======================================================================= +/*! + * \brief Split each of given quadrangles into 4 triangles. + * \param theElems - The faces to be splitted. If empty all faces are split. + */ +//======================================================================= + +void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + SMESH_MesherHelper helper( *GetMesh() ); + helper.SetElementsOnShape( true ); + + SMDS_ElemIteratorPtr faceIt; + if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face); + else faceIt = elemSetIterator( theElems ); + + bool checkUV; + gp_XY uv [9]; uv[8] = gp_XY(0,0); + gp_XYZ xyz[9]; + vector< const SMDS_MeshNode* > nodes; + SMESHDS_SubMesh* subMeshDS; + TopoDS_Face F; + Handle(Geom_Surface) surface; + TopLoc_Location loc; + + while ( faceIt->more() ) + { + const SMDS_MeshElement* quad = faceIt->next(); + if ( !quad || quad->NbCornerNodes() != 4 ) + continue; + + // get a surface the quad is on + + if ( quad->getshapeId() < 1 ) + { + F.Nullify(); + helper.SetSubShape( 0 ); + subMeshDS = 0; + } + else if ( quad->getshapeId() != helper.GetSubShapeID() ) + { + helper.SetSubShape( quad->getshapeId() ); + if ( !helper.GetSubShape().IsNull() && + helper.GetSubShape().ShapeType() == TopAbs_FACE ) + { + F = TopoDS::Face( helper.GetSubShape() ); + surface = BRep_Tool::Surface( F, loc ); + subMeshDS = GetMeshDS()->MeshElements( quad->getshapeId() ); + } + else + { + helper.SetSubShape( 0 ); + subMeshDS = 0; + } + } + + // create a central node + + const SMDS_MeshNode* nCentral; + nodes.assign( quad->begin_nodes(), quad->end_nodes() ); + + if ( nodes.size() == 9 ) + { + nCentral = nodes.back(); + } + else + { + size_t iN = 0; + if ( F.IsNull() ) + { + for ( ; iN < nodes.size(); ++iN ) + xyz[ iN ] = SMESH_TNodeXYZ( nodes[ iN ] ); + + for ( ; iN < 8; ++iN ) // mid-side points of a linear qudrangle + xyz[ iN ] = 0.5 * ( xyz[ iN - 4 ] + xyz[( iN - 3 )%4 ] ); + + xyz[ 8 ] = helper.calcTFI( 0.5, 0.5, + xyz[0], xyz[1], xyz[2], xyz[3], + xyz[4], xyz[5], xyz[6], xyz[7] ); + } + else + { + for ( ; iN < nodes.size(); ++iN ) + uv[ iN ] = helper.GetNodeUV( F, nodes[iN], nodes[(iN+2)%4], &checkUV ); + + for ( ; iN < 8; ++iN ) // UV of mid-side points of a linear qudrangle + uv[ iN ] = helper.GetMiddleUV( surface, uv[ iN - 4 ], uv[( iN - 3 )%4 ] ); + + uv[ 8 ] = helper.calcTFI( 0.5, 0.5, + uv[0], uv[1], uv[2], uv[3], + uv[4], uv[5], uv[6], uv[7] ); + + gp_Pnt p = surface->Value( uv[8].X(), uv[8].Y() ).Transformed( loc ); + xyz[ 8 ] = p.XYZ(); + } + + nCentral = helper.AddNode( xyz[8].X(), xyz[8].Y(), xyz[8].Z(), /*id=*/0, + uv[8].X(), uv[8].Y() ); + myLastCreatedNodes.Append( nCentral ); + } + + // create 4 triangles + + GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false ); + + helper.SetIsQuadratic ( nodes.size() > 4 ); + helper.SetIsBiQuadratic( nodes.size() == 9 ); + if ( helper.GetIsQuadratic() ) + helper.AddTLinks( static_cast< const SMDS_MeshFace*>( quad )); + + for ( int i = 0; i < 4; ++i ) + { + SMDS_MeshElement* tria = helper.AddFace( nodes[ i ], + nodes[(i+1)%4], + nCentral ); + ReplaceElemInGroups( tria, quad, GetMeshDS() ); + myLastCreatedElems.Append( tria ); + } + } +} + //======================================================================= //function : BestSplit //purpose : Find better diagonal for cutting. //======================================================================= + int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad, SMESH::Controls::NumericalFunctorPtr theCrit) { @@ -1149,7 +1656,8 @@ int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad, SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] ); SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] ); aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit ); - + // for MaxElementLength2D functor we return minimum diagonal for splitting, + // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4) if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better return 1; // diagonal 1-3 @@ -1158,4113 +1666,6197 @@ int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad, return -1; } -//======================================================================= -//function : AddToSameGroups -//purpose : add elemToAdd to the groups the elemInGroups belongs to -//======================================================================= - -void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd, - const SMDS_MeshElement* elemInGroups, - SMESHDS_Mesh * aMesh) +namespace { - const set& groups = aMesh->GetGroups(); - if (!groups.empty()) { - set::const_iterator grIt = groups.begin(); - for ( ; grIt != groups.end(); grIt++ ) { - SMESHDS_Group* group = dynamic_cast( *grIt ); - if ( group && group->Contains( elemInGroups )) - group->SMDSGroup().Add( elemToAdd ); - } - } -} + // Methods of splitting volumes into tetra - -//======================================================================= -//function : RemoveElemFromGroups -//purpose : Remove removeelem to the groups the elemInGroups belongs to -//======================================================================= -void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem, - SMESHDS_Mesh * aMesh) -{ - const set& groups = aMesh->GetGroups(); - if (!groups.empty()) - { - set::const_iterator GrIt = groups.begin(); - for (; GrIt != groups.end(); GrIt++) + const int theHexTo5_1[5*4+1] = { - SMESHDS_Group* grp = dynamic_cast(*GrIt); - if (!grp || grp->IsEmpty()) continue; - grp->SMDSGroup().Remove(removeelem); - } - } -} - -//======================================================================= -//function : ReplaceElemInGroups -//purpose : replace elemToRm by elemToAdd in the all groups -//======================================================================= + 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1 + }; + const int theHexTo5_2[5*4+1] = + { + 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1 + }; + const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 }; -void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm, - const SMDS_MeshElement* elemToAdd, - SMESHDS_Mesh * aMesh) -{ - const set& groups = aMesh->GetGroups(); - if (!groups.empty()) { - set::const_iterator grIt = groups.begin(); - for ( ; grIt != groups.end(); grIt++ ) { - SMESHDS_Group* group = dynamic_cast( *grIt ); - if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd ) - group->SMDSGroup().Add( elemToAdd ); - } - } -} + const int theHexTo6_1[6*4+1] = + { + 1, 5, 6, 0, 0, 1, 2, 6, 0, 4, 5, 6, 0, 4, 6, 7, 0, 2, 3, 6, 0, 3, 7, 6, -1 + }; + const int theHexTo6_2[6*4+1] = + { + 2, 6, 7, 1, 1, 2, 3, 7, 1, 5, 6, 7, 1, 5, 7, 4, 1, 3, 0, 7, 1, 0, 4, 7, -1 + }; + const int theHexTo6_3[6*4+1] = + { + 3, 7, 4, 2, 2, 3, 0, 4, 2, 6, 7, 4, 2, 6, 4, 5, 2, 0, 1, 4, 2, 1, 5, 4, -1 + }; + const int theHexTo6_4[6*4+1] = + { + 0, 4, 5, 3, 3, 0, 1, 5, 3, 7, 4, 5, 3, 7, 5, 6, 3, 1, 2, 5, 3, 2, 6, 5, -1 + }; + const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 }; -//======================================================================= -//function : QuadToTri -//purpose : Cut quadrangles into triangles. -// theCrit is used to select a diagonal to cut -//======================================================================= + const int thePyraTo2_1[2*4+1] = + { + 0, 1, 2, 4, 0, 2, 3, 4, -1 + }; + const int thePyraTo2_2[2*4+1] = + { + 1, 2, 3, 4, 1, 3, 0, 4, -1 + }; + const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 }; -bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, - const bool the13Diag) -{ - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + const int thePentaTo3_1[3*4+1] = + { + 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1 + }; + const int thePentaTo3_2[3*4+1] = + { + 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1 + }; + const int thePentaTo3_3[3*4+1] = + { + 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1 + }; + const int thePentaTo3_4[3*4+1] = + { + 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1 + }; + const int thePentaTo3_5[3*4+1] = + { + 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1 + }; + const int thePentaTo3_6[3*4+1] = + { + 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1 + }; + const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3, + thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 }; - MESSAGE( "::QuadToTri()" ); + // Methods of splitting hexahedron into prisms - SMESHDS_Mesh * aMesh = GetMeshDS(); + const int theHexTo4Prisms_BT[6*4+1] = // bottom-top + { + 0, 1, 8, 4, 5, 9, 1, 2, 8, 5, 6, 9, 2, 3, 8, 6, 7, 9, 3, 0, 8, 7, 4, 9, -1 + }; + const int theHexTo4Prisms_LR[6*4+1] = // left-right + { + 1, 0, 8, 2, 3, 9, 0, 4, 8, 3, 7, 9, 4, 5, 8, 7, 6, 9, 5, 1, 8, 6, 2, 9, -1 + }; + const int theHexTo4Prisms_FB[6*4+1] = // front-back + { + 0, 3, 9, 1, 2, 8, 3, 7, 9, 2, 6, 8, 7, 4, 9, 6, 5, 8, 4, 0, 9, 5, 1, 8, -1 + }; - Handle(Geom_Surface) surface; - SMESH_MesherHelper helper( *GetMesh() ); + const int theHexTo2Prisms_BT_1[6*2+1] = + { + 0, 1, 3, 4, 5, 7, 1, 2, 3, 5, 6, 7, -1 + }; + const int theHexTo2Prisms_BT_2[6*2+1] = + { + 0, 1, 2, 4, 5, 6, 0, 2, 3, 4, 6, 7, -1 + }; + const int* theHexTo2Prisms_BT[2] = { theHexTo2Prisms_BT_1, theHexTo2Prisms_BT_2 }; - TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() != SMDSAbs_Face ) - continue; - bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8; - if(!isquad) continue; + const int theHexTo2Prisms_LR_1[6*2+1] = + { + 1, 0, 4, 2, 3, 7, 1, 4, 5, 2, 7, 6, -1 + }; + const int theHexTo2Prisms_LR_2[6*2+1] = + { + 1, 0, 4, 2, 3, 7, 1, 4, 5, 2, 7, 6, -1 + }; + const int* theHexTo2Prisms_LR[2] = { theHexTo2Prisms_LR_1, theHexTo2Prisms_LR_2 }; - if(elem->NbNodes()==4) { - // retrieve element nodes - const SMDS_MeshNode* aNodes [4]; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - int i = 0; - while ( itN->more() ) - aNodes[ i++ ] = static_cast( itN->next() ); + const int theHexTo2Prisms_FB_1[6*2+1] = + { + 0, 3, 4, 1, 2, 5, 3, 7, 4, 2, 6, 5, -1 + }; + const int theHexTo2Prisms_FB_2[6*2+1] = + { + 0, 3, 7, 1, 2, 7, 0, 7, 4, 1, 6, 5, -1 + }; + const int* theHexTo2Prisms_FB[2] = { theHexTo2Prisms_FB_1, theHexTo2Prisms_FB_2 }; - int aShapeId = FindShape( elem ); - const SMDS_MeshElement* newElem = 0; - if ( the13Diag ) { - aMesh->ChangeElementNodes( elem, aNodes, 3 ); - newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] ); + + struct TTriangleFacet //!< stores indices of three nodes of tetra facet + { + int _n1, _n2, _n3; + TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {} + bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); } + bool hasAdjacentVol( const SMDS_MeshElement* elem, + const SMDSAbs_GeometryType geom = SMDSGeom_TETRA) const; + }; + struct TSplitMethod + { + int _nbSplits; + int _nbCorners; + const int* _connectivity; //!< foursomes of tetra connectivy finished by -1 + bool _baryNode; //!< additional node is to be created at cell barycenter + bool _ownConn; //!< to delete _connectivity in destructor + map _faceBaryNode; //!< map face index to node at BC of face + + TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false) + : _nbSplits(nbTet), _nbCorners(4), _connectivity(conn), _baryNode(addNode), _ownConn(false) {} + ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; } + bool hasFacet( const TTriangleFacet& facet ) const + { + if ( _nbCorners == 4 ) + { + const int* tetConn = _connectivity; + for ( ; tetConn[0] >= 0; tetConn += 4 ) + if (( facet.contains( tetConn[0] ) + + facet.contains( tetConn[1] ) + + facet.contains( tetConn[2] ) + + facet.contains( tetConn[3] )) == 3 ) + return true; } - else { - aMesh->ChangeElementNodes( elem, &aNodes[1], 3 ); - newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] ); + else // prism, _nbCorners == 6 + { + const int* prismConn = _connectivity; + for ( ; prismConn[0] >= 0; prismConn += 6 ) + { + if (( facet.contains( prismConn[0] ) && + facet.contains( prismConn[1] ) && + facet.contains( prismConn[2] )) + || + ( facet.contains( prismConn[3] ) && + facet.contains( prismConn[4] ) && + facet.contains( prismConn[5] ))) + return true; + } } - myLastCreatedElems.Append(newElem); - // put a new triangle on the same shape and add to the same groups - if ( aShapeId ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - AddToSameGroups( newElem, elem, aMesh ); + return false; } + }; - // Quadratic quadrangle + //======================================================================= + /*! + * \brief return TSplitMethod for the given element to split into tetrahedra + */ + //======================================================================= - if( elem->NbNodes()==8 && elem->IsQuadratic() ) { + TSplitMethod getTetraSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags) + { + const int iQ = vol.Element()->IsQuadratic() ? 2 : 1; - // get surface elem is on - int aShapeId = FindShape( elem ); - if ( aShapeId != helper.GetSubShapeID() ) { - surface.Nullify(); - TopoDS_Shape shape; - if ( aShapeId > 0 ) - shape = aMesh->IndexToShape( aShapeId ); - if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) { - TopoDS_Face face = TopoDS::Face( shape ); - surface = BRep_Tool::Surface( face ); - if ( !surface.IsNull() ) - helper.SetSubShape( shape ); - } - } + // at HEXA_TO_24 method, each face of volume is split into triangles each based on + // an edge and a face barycenter; tertaherdons are based on triangles and + // a volume barycenter + const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 ); - const SMDS_MeshNode* aNodes [8]; - const SMDS_MeshNode* inFaceNode = 0; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - int i = 0; - while ( itN->more() ) { - aNodes[ i++ ] = static_cast( itN->next() ); - if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() && - aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) + // Find out how adjacent volumes are split + + vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side + int hasAdjacentSplits = 0, maxTetConnSize = 0; + for ( int iF = 0; iF < vol.NbFaces(); ++iF ) + { + int nbNodes = vol.NbFaceNodes( iF ) / iQ; + maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2)); + if ( nbNodes < 4 ) continue; + + list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ]; + const int* nInd = vol.GetFaceNodesIndices( iF ); + if ( nbNodes == 4 ) + { + TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] ); + TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] ); + if ( t012.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t012 ); + else if ( t123.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t123 ); + } + else + { + int iCom = 0; // common node of triangle faces to split into + for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom ) { - inFaceNode = aNodes[ i-1 ]; + TTriangleFacet t012( nInd[ iQ * ( iCom )], + nInd[ iQ * ( (iCom+1)%nbNodes )], + nInd[ iQ * ( (iCom+2)%nbNodes )]); + TTriangleFacet t023( nInd[ iQ * ( iCom )], + nInd[ iQ * ( (iCom+2)%nbNodes )], + nInd[ iQ * ( (iCom+3)%nbNodes )]); + if ( t012.hasAdjacentVol( vol.Element() ) && t023.hasAdjacentVol( vol.Element() )) + { + triaSplits.push_back( t012 ); + triaSplits.push_back( t023 ); + break; + } } } + if ( !triaSplits.empty() ) + hasAdjacentSplits = true; + } - // find middle point for (0,1,2,3) - // and create a node in this point; - gp_XYZ p( 0,0,0 ); - if ( surface.IsNull() ) { - for(i=0; i<4; i++) - p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() ); - p /= 4; - } - else { - TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() ); - gp_XY uv( 0,0 ); - for(i=0; i<4; i++) - uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode ); - uv /= 4.; - p = surface->Value( uv.X(), uv.Y() ).XYZ(); - } - const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() ); - myLastCreatedNodes.Append(newN); + // Among variants of split method select one compliant with adjacent volumes - // create a new element - const SMDS_MeshElement* newElem = 0; - const SMDS_MeshNode* N[6]; - if ( the13Diag ) { - N[0] = aNodes[0]; - N[1] = aNodes[1]; - N[2] = aNodes[2]; - N[3] = aNodes[4]; - N[4] = aNodes[5]; - N[5] = newN; - newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0], - aNodes[6], aNodes[7], newN ); + TSplitMethod method; + if ( !vol.Element()->IsPoly() && !is24TetMode ) + { + int nbVariants = 2, nbTet = 0; + const int** connVariants = 0; + switch ( vol.Element()->GetEntityType() ) + { + case SMDSEntity_Hexa: + case SMDSEntity_Quad_Hexa: + case SMDSEntity_TriQuad_Hexa: + if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 ) + connVariants = theHexTo5, nbTet = 5; + else + connVariants = theHexTo6, nbTet = 6, nbVariants = 4; + break; + case SMDSEntity_Pyramid: + case SMDSEntity_Quad_Pyramid: + connVariants = thePyraTo2; nbTet = 2; + break; + case SMDSEntity_Penta: + case SMDSEntity_Quad_Penta: + connVariants = thePentaTo3; nbTet = 3; nbVariants = 6; + break; + default: + nbVariants = 0; + } + for ( int variant = 0; variant < nbVariants && method._nbSplits == 0; ++variant ) + { + // check method compliancy with adjacent tetras, + // all found splits must be among facets of tetras described by this method + method = TSplitMethod( nbTet, connVariants[variant] ); + if ( hasAdjacentSplits && method._nbSplits > 0 ) + { + bool facetCreated = true; + for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF ) + { + list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin(); + for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet ) + facetCreated = method.hasFacet( *facet ); + } + if ( !facetCreated ) + method = TSplitMethod(0); // incompatible method + } } - else { - N[0] = aNodes[1]; - N[1] = aNodes[2]; - N[2] = aNodes[3]; - N[3] = aNodes[5]; - N[4] = aNodes[6]; - N[5] = newN; - newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1], - aNodes[7], aNodes[4], newN ); - } - myLastCreatedElems.Append(newElem); - aMesh->ChangeElementNodes( elem, N, 6 ); - // put a new triangle on the same shape and add to the same groups - if ( aShapeId ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - AddToSameGroups( newElem, elem, aMesh ); } - } - - return true; -} + if ( method._nbSplits < 1 ) + { + // No standard method is applicable, use a generic solution: + // each facet of a volume is split into triangles and + // each of triangles and a volume barycenter form a tetrahedron. -//======================================================================= -//function : getAngle -//purpose : -//======================================================================= + const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa ); -double getAngle(const SMDS_MeshElement * tr1, - const SMDS_MeshElement * tr2, - const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2) -{ - double angle = 2*PI; // bad angle + int* connectivity = new int[ maxTetConnSize + 1 ]; + method._connectivity = connectivity; + method._ownConn = true; + method._baryNode = !isHex27; // to create central node or not - // get normals - SMESH::Controls::TSequenceOfXYZ P1, P2; - if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) || - !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 )) - return angle; - gp_Vec N1,N2; - if(!tr1->IsQuadratic()) - N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) ); - else - N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) ); - if ( N1.SquareMagnitude() <= gp::Resolution() ) - return angle; - if(!tr2->IsQuadratic()) - N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) ); - else - N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) ); - if ( N2.SquareMagnitude() <= gp::Resolution() ) - return angle; + int connSize = 0; + int baryCenInd = vol.NbNodes() - int( isHex27 ); + for ( int iF = 0; iF < vol.NbFaces(); ++iF ) + { + const int nbNodes = vol.NbFaceNodes( iF ) / iQ; + const int* nInd = vol.GetFaceNodesIndices( iF ); + // find common node of triangle facets of tetra to create + int iCommon = 0; // index in linear numeration + const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ]; + if ( !triaSplits.empty() ) + { + // by found facets + const TTriangleFacet* facet = &triaSplits.front(); + for ( ; iCommon < nbNodes-1 ; ++iCommon ) + if ( facet->contains( nInd[ iQ * iCommon ]) && + facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ])) + break; + } + else if ( nbNodes > 3 && !is24TetMode ) + { + // find the best method of splitting into triangles by aspect ratio + SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio); + map< double, int > badness2iCommon; + const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF ); + int nbVariants = ( nbNodes == 4 ? 2 : nbNodes ); + for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon ) + { + double badness = 0; + for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast ) + { + SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )], + nodes[ iQ*((iLast-1)%nbNodes)], + nodes[ iQ*((iLast )%nbNodes)]); + badness += getBadRate( &tria, aspectRatio ); + } + badness2iCommon.insert( make_pair( badness, iCommon )); + } + // use iCommon with lowest badness + iCommon = badness2iCommon.begin()->second; + } + if ( iCommon >= nbNodes ) + iCommon = 0; // something wrong - // find the first diagonal node n1 in the triangles: - // take in account a diagonal link orientation - const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 }; - for ( int t = 0; t < 2; t++ ) { - SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator(); - int i = 0, iDiag = -1; - while ( it->more()) { - const SMDS_MeshElement *n = it->next(); - if ( n == n1 || n == n2 ) { - if ( iDiag < 0) - iDiag = i; - else { - if ( i - iDiag == 1 ) - nFirst[ t ] = ( n == n1 ? n2 : n1 ); + // fill connectivity of tetrahedra based on a current face + int nbTet = nbNodes - 2; + if ( is24TetMode && nbNodes > 3 && triaSplits.empty()) + { + int faceBaryCenInd; + if ( isHex27 ) + { + faceBaryCenInd = vol.GetCenterNodeIndex( iF ); + method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ]; + } else - nFirst[ t ] = n; - break; + { + method._faceBaryNode[ iF ] = 0; + faceBaryCenInd = baryCenInd + method._faceBaryNode.size(); + } + nbTet = nbNodes; + for ( int i = 0; i < nbTet; ++i ) + { + int i1 = i, i2 = (i+1) % nbNodes; + if ( !vol.IsFaceExternal( iF )) swap( i1, i2 ); + connectivity[ connSize++ ] = nInd[ iQ * i1 ]; + connectivity[ connSize++ ] = nInd[ iQ * i2 ]; + connectivity[ connSize++ ] = faceBaryCenInd; + connectivity[ connSize++ ] = baryCenInd; + } } - } - i++; - } - } - if ( nFirst[ 0 ] == nFirst[ 1 ] ) - N2.Reverse(); + else + { + for ( int i = 0; i < nbTet; ++i ) + { + int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes; + if ( !vol.IsFaceExternal( iF )) swap( i1, i2 ); + connectivity[ connSize++ ] = nInd[ iQ * iCommon ]; + connectivity[ connSize++ ] = nInd[ iQ * i1 ]; + connectivity[ connSize++ ] = nInd[ iQ * i2 ]; + connectivity[ connSize++ ] = baryCenInd; + } + } + method._nbSplits += nbTet; - angle = N1.Angle( N2 ); - //SCRUTE( angle ); - return angle; -} + } // loop on volume faces -// ================================================= -// class generating a unique ID for a pair of nodes -// and able to return nodes by that ID -// ================================================= -class LinkID_Gen { - public: + connectivity[ connSize++ ] = -1; - LinkID_Gen( const SMESHDS_Mesh* theMesh ) - :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1) - {} + } // end of generic solution - long GetLinkID (const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2) const + return method; + } + //======================================================================= + /*! + * \brief return TSplitMethod to split haxhedron into prisms + */ + //======================================================================= + + TSplitMethod getPrismSplitMethod( SMDS_VolumeTool& vol, + const int methodFlags, + const int facetToSplit) { - return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID())); + // order of facets in HEX according to SMDS_VolumeTool::Hexa_F : + // B, T, L, B, R, F + const int iF = ( facetToSplit < 2 ) ? 0 : 1 + ( facetToSplit-2 ) % 2; // [0,1,2] + + if ( methodFlags == SMESH_MeshEditor::HEXA_TO_4_PRISMS ) + { + static TSplitMethod to4methods[4]; // order BT, LR, FB + if ( to4methods[iF]._nbSplits == 0 ) + { + switch ( iF ) { + case 0: + to4methods[iF]._connectivity = theHexTo4Prisms_BT; + to4methods[iF]._faceBaryNode[ 0 ] = 0; + to4methods[iF]._faceBaryNode[ 1 ] = 0; + break; + case 1: + to4methods[iF]._connectivity = theHexTo4Prisms_LR; + to4methods[iF]._faceBaryNode[ 2 ] = 0; + to4methods[iF]._faceBaryNode[ 4 ] = 0; + break; + case 2: + to4methods[iF]._connectivity = theHexTo4Prisms_FB; + to4methods[iF]._faceBaryNode[ 3 ] = 0; + to4methods[iF]._faceBaryNode[ 5 ] = 0; + break; + default: return to4methods[3]; + } + to4methods[iF]._nbSplits = 4; + to4methods[iF]._nbCorners = 6; + } + return to4methods[iF]; + } + // else if ( methodFlags == HEXA_TO_2_PRISMS ) + + TSplitMethod method; + + const int iQ = vol.Element()->IsQuadratic() ? 2 : 1; + + const int nbVariants = 2, nbSplits = 2; + const int** connVariants = 0; + switch ( iF ) { + case 0: connVariants = theHexTo2Prisms_BT; break; + case 1: connVariants = theHexTo2Prisms_LR; break; + case 2: connVariants = theHexTo2Prisms_FB; break; + default: return method; + } + + // look for prisms adjacent via facetToSplit and an opposite one + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit; + int nbNodes = vol.NbFaceNodes( iFacet ) / iQ; + if ( nbNodes != 4 ) return method; + + const int* nInd = vol.GetFaceNodesIndices( iFacet ); + TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] ); + TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] ); + TTriangleFacet* t; + if ( t012.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA )) + t = &t012; + else if ( t123.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA )) + t = &t123; + else + continue; + + // there are adjacent prism + for ( int variant = 0; variant < nbVariants; ++variant ) + { + // check method compliancy with adjacent prisms, + // the found prism facets must be among facets of prisms described by current method + method._nbSplits = nbSplits; + method._nbCorners = 6; + method._connectivity = connVariants[ variant ]; + if ( method.hasFacet( *t )) + return method; + } + } + + // No adjacent prisms. Select a variant with a best aspect ratio. + + double badness[2] = { 0, 0 }; + static SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio); + const SMDS_MeshNode** nodes = vol.GetNodes(); + for ( int variant = 0; variant < nbVariants; ++variant ) + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit; + const int* nInd = vol.GetFaceNodesIndices( iFacet ); + + method._connectivity = connVariants[ variant ]; + TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] ); + TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] ); + TTriangleFacet* t = ( method.hasFacet( t012 )) ? & t012 : & t123; + + SMDS_FaceOfNodes tria ( nodes[ t->_n1 ], + nodes[ t->_n2 ], + nodes[ t->_n3 ] ); + badness[ variant ] += getBadRate( &tria, aspectRatio ); + } + const int iBetter = ( badness[1] < badness[0] && badness[0]-badness[1] > 0.1 * badness[0] ); + + method._nbSplits = nbSplits; + method._nbCorners = 6; + method._connectivity = connVariants[ iBetter ]; + + return method; } - bool GetNodes (const long theLinkID, - const SMDS_MeshNode* & theNode1, - const SMDS_MeshNode* & theNode2) const + //================================================================================ + /*! + * \brief Check if there is a tetraherdon adjacent to the given element via this facet + */ + //================================================================================ + + bool TTriangleFacet::hasAdjacentVol( const SMDS_MeshElement* elem, + const SMDSAbs_GeometryType geom ) const { - theNode1 = myMesh->FindNode( theLinkID / myMaxID ); - if ( !theNode1 ) return false; - theNode2 = myMesh->FindNode( theLinkID % myMaxID ); - if ( !theNode2 ) return false; - return true; + // find the tetrahedron including the three nodes of facet + const SMDS_MeshNode* n1 = elem->GetNode(_n1); + const SMDS_MeshNode* n2 = elem->GetNode(_n2); + const SMDS_MeshNode* n3 = elem->GetNode(_n3); + SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume); + while ( volIt1->more() ) + { + const SMDS_MeshElement* v = volIt1->next(); + if ( v->GetGeomType() != geom ) + continue; + const int lastCornerInd = v->NbCornerNodes() - 1; + if ( v->IsQuadratic() && v->GetNodeIndex( n1 ) > lastCornerInd ) + continue; // medium node not allowed + const int ind2 = v->GetNodeIndex( n2 ); + if ( ind2 < 0 || lastCornerInd < ind2 ) + continue; + const int ind3 = v->GetNodeIndex( n3 ); + if ( ind3 < 0 || lastCornerInd < ind3 ) + continue; + return true; + } + return false; } - private: - LinkID_Gen(); - const SMESHDS_Mesh* myMesh; - long myMaxID; -}; + //======================================================================= + /*! + * \brief A key of a face of volume + */ + //======================================================================= + struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> > + { + TVolumeFaceKey( SMDS_VolumeTool& vol, int iF ) + { + TIDSortedNodeSet sortedNodes; + const int iQ = vol.Element()->IsQuadratic() ? 2 : 1; + int nbNodes = vol.NbFaceNodes( iF ); + const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF ); + for ( int i = 0; i < nbNodes; i += iQ ) + sortedNodes.insert( fNodes[i] ); + TIDSortedNodeSet::iterator n = sortedNodes.begin(); + first.first = (*(n++))->GetID(); + first.second = (*(n++))->GetID(); + second.first = (*(n++))->GetID(); + second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0; + } + }; +} // namespace //======================================================================= -//function : TriToQuad -//purpose : Fuse neighbour triangles into quadrangles. -// theCrit is used to select a neighbour to fuse with. -// theMaxAngle is a max angle between element normals at which -// fusion is still performed. +//function : SplitVolumes +//purpose : Split volume elements into tetrahedra or prisms. +// If facet ID < 0, element is split into tetrahedra, +// else a hexahedron is split into prisms so that the given facet is +// split into triangles //======================================================================= -bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, - SMESH::Controls::NumericalFunctorPtr theCrit, - const double theMaxAngle) +void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems, + const int theMethodFlags) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); - - MESSAGE( "::TriToQuad()" ); + SMDS_VolumeTool volTool; + SMESH_MesherHelper helper( *GetMesh()), fHelper(*GetMesh()); + fHelper.ToFixNodeParameters( true ); - if ( !theCrit.get() ) - return false; + SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1); + SMESHDS_SubMesh* fSubMesh = 0;//subMesh; - SMESHDS_Mesh * aMesh = GetMeshDS(); + SMESH_SequenceOfElemPtr newNodes, newElems; - // Prepare data for algo: build - // 1. map of elements with their linkIDs - // 2. map of linkIDs with their elements + // map face of volume to it's baricenrtic node + map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode; + double bc[3]; + vector splitVols; - map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl; - map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE; - map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi; - map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL; + TFacetOfElem::const_iterator elem2facet = theElems.begin(); + for ( ; elem2facet != theElems.end(); ++elem2facet ) + { + const SMDS_MeshElement* elem = elem2facet->first; + const int facetToSplit = elem2facet->second; + if ( elem->GetType() != SMDSAbs_Volume ) + continue; + const SMDSAbs_EntityType geomType = elem->GetEntityType(); + if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra ) + continue; - TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; - if(!elem || elem->GetType() != SMDSAbs_Face ) continue; - bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic()); - if(!IsTria) continue; + if ( !volTool.Set( elem, /*ignoreCentralNodes=*/false )) continue; // strange... - // retrieve element nodes - const SMDS_MeshNode* aNodes [4]; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - int i = 0; - while ( i<3 ) - aNodes[ i++ ] = cast2Node( itN->next() ); - aNodes[ 3 ] = aNodes[ 0 ]; + TSplitMethod splitMethod = ( facetToSplit < 0 ? + getTetraSplitMethod( volTool, theMethodFlags ) : + getPrismSplitMethod( volTool, theMethodFlags, facetToSplit )); + if ( splitMethod._nbSplits < 1 ) continue; - // fill maps - for ( i = 0; i < 3; i++ ) { - SMESH_TLink link( aNodes[i], aNodes[i+1] ); - // check if elements sharing a link can be fused - itLE = mapLi_listEl.find( link ); - if ( itLE != mapLi_listEl.end() ) { - if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link - continue; - const SMDS_MeshElement* elem2 = (*itLE).second.front(); - //if ( FindShape( elem ) != FindShape( elem2 )) - // continue; // do not fuse triangles laying on different shapes - if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle ) - continue; // avoid making badly shaped quads - (*itLE).second.push_back( elem ); - } - else { - mapLi_listEl[ link ].push_back( elem ); + // find submesh to add new tetras to + if ( !subMesh || !subMesh->Contains( elem )) + { + int shapeID = FindShape( elem ); + helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh + subMesh = GetMeshDS()->MeshElements( shapeID ); + } + int iQ; + if ( elem->IsQuadratic() ) + { + iQ = 2; + // add quadratic links to the helper + for ( int iF = 0; iF < volTool.NbFaces(); ++iF ) + { + const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF ); + int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 ); + for ( int iN = 0; iN < nbN; iN += iQ ) + helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] ); } - mapEl_setLi [ elem ].insert( link ); + helper.SetIsQuadratic( true ); } - } - // Clean the maps from the links shared by a sole element, ie - // links to which only one element is bound in mapLi_listEl + else + { + iQ = 1; + helper.SetIsQuadratic( false ); + } + vector nodes( volTool.GetNodes(), + volTool.GetNodes() + elem->NbNodes() ); + helper.SetElementsOnShape( true ); + if ( splitMethod._baryNode ) + { + // make a node at barycenter + volTool.GetBaryCenter( bc[0], bc[1], bc[2] ); + SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] ); + nodes.push_back( gcNode ); + newNodes.Append( gcNode ); + } + if ( !splitMethod._faceBaryNode.empty() ) + { + // make or find baricentric nodes of faces + map::iterator iF_n = splitMethod._faceBaryNode.begin(); + for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n ) + { + map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n = + volFace2BaryNode.insert + ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first; + if ( !f_n->second ) + { + volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] ); + newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] )); + } + nodes.push_back( iF_n->second = f_n->second ); + } + } + + // make new volumes + splitVols.resize( splitMethod._nbSplits ); // splits of a volume + const int* volConn = splitMethod._connectivity; + if ( splitMethod._nbCorners == 4 ) // tetra + for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners ) + newElems.Append( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ], + nodes[ volConn[1] ], + nodes[ volConn[2] ], + nodes[ volConn[3] ])); + else // prisms + for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners ) + newElems.Append( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ], + nodes[ volConn[1] ], + nodes[ volConn[2] ], + nodes[ volConn[3] ], + nodes[ volConn[4] ], + nodes[ volConn[5] ])); + + ReplaceElemInGroups( elem, splitVols, GetMeshDS() ); + + // Split faces on sides of the split volume + + const SMDS_MeshNode** volNodes = volTool.GetNodes(); + for ( int iF = 0; iF < volTool.NbFaces(); ++iF ) + { + const int nbNodes = volTool.NbFaceNodes( iF ) / iQ; + if ( nbNodes < 4 ) continue; + + // find an existing face + vector fNodes( volTool.GetFaceNodes( iF ), + volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF )); + while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face, + /*noMedium=*/false)) + { + // make triangles + helper.SetElementsOnShape( false ); + vector< const SMDS_MeshElement* > triangles; - for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) { - int nbElems = (*itLE).second.size(); - if ( nbElems < 2 ) { - const SMDS_MeshElement* elem = (*itLE).second.front(); - SMESH_TLink link = (*itLE).first; - mapEl_setLi[ elem ].erase( link ); - if ( mapEl_setLi[ elem ].empty() ) - mapEl_setLi.erase( elem ); + // find submesh to add new triangles in + if ( !fSubMesh || !fSubMesh->Contains( face )) + { + int shapeID = FindShape( face ); + fSubMesh = GetMeshDS()->MeshElements( shapeID ); + } + map::iterator iF_n = splitMethod._faceBaryNode.find(iF); + if ( iF_n != splitMethod._faceBaryNode.end() ) + { + const SMDS_MeshNode *baryNode = iF_n->second; + for ( int iN = 0; iN < nbNodes*iQ; iN += iQ ) + { + const SMDS_MeshNode* n1 = fNodes[iN]; + const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)]; + const SMDS_MeshNode *n3 = baryNode; + if ( !volTool.IsFaceExternal( iF )) + swap( n2, n3 ); + triangles.push_back( helper.AddFace( n1,n2,n3 )); + } + if ( fSubMesh ) // update position of the bary node on geometry + { + if ( subMesh ) + subMesh->RemoveNode( baryNode, false ); + GetMeshDS()->SetNodeOnFace( baryNode, fSubMesh->GetID() ); + const TopoDS_Shape& s = GetMeshDS()->IndexToShape( fSubMesh->GetID() ); + if ( !s.IsNull() && s.ShapeType() == TopAbs_FACE ) + { + fHelper.SetSubShape( s ); + gp_XY uv( 1e100, 1e100 ); + double distXYZ[4]; + if ( !fHelper.CheckNodeUV( TopoDS::Face( s ), baryNode, + uv, /*tol=*/1e-7, /*force=*/true, distXYZ ) && + uv.X() < 1e100 ) + { + // node is too far from the surface + GetMeshDS()->MoveNode( baryNode, distXYZ[1], distXYZ[2], distXYZ[3] ); + const_cast( baryNode )->SetPosition + ( SMDS_PositionPtr( new SMDS_FacePosition( uv.X(), uv.Y() ))); + } + } + } + } + else + { + // among possible triangles create ones discribed by split method + const int* nInd = volTool.GetFaceNodesIndices( iF ); + int nbVariants = ( nbNodes == 4 ? 2 : nbNodes ); + int iCom = 0; // common node of triangle faces to split into + list< TTriangleFacet > facets; + for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom ) + { + TTriangleFacet t012( nInd[ iQ * ( iCom )], + nInd[ iQ * ( (iCom+1)%nbNodes )], + nInd[ iQ * ( (iCom+2)%nbNodes )]); + TTriangleFacet t023( nInd[ iQ * ( iCom )], + nInd[ iQ * ( (iCom+2)%nbNodes )], + nInd[ iQ * ( (iCom+3)%nbNodes )]); + if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 )) + { + facets.push_back( t012 ); + facets.push_back( t023 ); + for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast ) + facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )], + nInd[ iQ * ((iLast-1)%nbNodes )], + nInd[ iQ * ((iLast )%nbNodes )])); + break; + } + } + list< TTriangleFacet >::iterator facet = facets.begin(); + if ( facet == facets.end() ) + break; + for ( ; facet != facets.end(); ++facet ) + { + if ( !volTool.IsFaceExternal( iF )) + swap( facet->_n2, facet->_n3 ); + triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ], + volNodes[ facet->_n2 ], + volNodes[ facet->_n3 ])); + } + } + for ( int i = 0; i < triangles.size(); ++i ) + { + if ( !triangles[i] ) continue; + if ( fSubMesh ) + fSubMesh->AddElement( triangles[i]); + newElems.Append( triangles[i] ); + } + ReplaceElemInGroups( face, triangles, GetMeshDS() ); + GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false ); + + } // while a face based on facet nodes exists + } // loop on volume faces to split them into triangles + + GetMeshDS()->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false ); + + if ( geomType == SMDSEntity_TriQuad_Hexa ) + { + // remove medium nodes that could become free + for ( int i = 20; i < volTool.NbNodes(); ++i ) + if ( volNodes[i]->NbInverseElements() == 0 ) + GetMeshDS()->RemoveNode( volNodes[i] ); } + } // loop on volumes to split + + myLastCreatedNodes = newNodes; + myLastCreatedElems = newElems; +} + +//======================================================================= +//function : GetHexaFacetsToSplit +//purpose : For hexahedra that will be split into prisms, finds facets to +// split into triangles. Only hexahedra adjacent to the one closest +// to theFacetNormal.Location() are returned. +//param [in,out] theHexas - the hexahedra +//param [in] theFacetNormal - facet normal +//param [out] theFacets - the hexahedra and found facet IDs +//======================================================================= + +void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas, + const gp_Ax1& theFacetNormal, + TFacetOfElem & theFacets) +{ + #define THIS_METHOD "SMESH_MeshEditor::GetHexaFacetsToSplit(): " + + // Find a hexa closest to the location of theFacetNormal + + const SMDS_MeshElement* startHex; + { + // get SMDS_ElemIteratorPtr on theHexas + typedef const SMDS_MeshElement* TValue; + typedef TIDSortedElemSet::iterator TSetIterator; + typedef SMDS::SimpleAccessor TAccesor; + typedef SMDS_MeshElement::GeomFilter TFilter; + typedef SMDS_SetIterator < TValue, TSetIterator, TAccesor, TFilter > TElemSetIter; + SMDS_ElemIteratorPtr elemIt = SMDS_ElemIteratorPtr + ( new TElemSetIter( theHexas.begin(), + theHexas.end(), + SMDS_MeshElement::GeomFilter( SMDSGeom_HEXA ))); + + SMESH_ElementSearcher* searcher = + SMESH_MeshAlgos::GetElementSearcher( *myMesh->GetMeshDS(), elemIt ); + + startHex = searcher->FindClosestTo( theFacetNormal.Location(), SMDSAbs_Volume ); + + delete searcher; + + if ( !startHex ) + throw SALOME_Exception( THIS_METHOD "startHex not found"); } - // Algo: fuse triangles into quadrangles + // Select a facet of startHex by theFacetNormal - while ( ! mapEl_setLi.empty() ) { - // Look for the start element: - // the element having the least nb of shared links - const SMDS_MeshElement* startElem = 0; - int minNbLinks = 4; - for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) { - int nbLinks = (*itEL).second.size(); - if ( nbLinks < minNbLinks ) { - startElem = (*itEL).first; - minNbLinks = nbLinks; - if ( minNbLinks == 1 ) - break; + SMDS_VolumeTool vTool( startHex ); + double norm[3], dot, maxDot = 0; + int facetID = -1; + for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) + if ( vTool.GetFaceNormal( iF, norm[0], norm[1], norm[2] )) + { + dot = Abs( theFacetNormal.Direction().Dot( gp_Dir( norm[0], norm[1], norm[2] ))); + if ( dot > maxDot ) + { + facetID = iF; + maxDot = dot; } } + if ( facetID < 0 ) + throw SALOME_Exception( THIS_METHOD "facet of startHex not found"); - // search elements to fuse starting from startElem or links of elements - // fused earlyer - startLinks - list< SMESH_TLink > startLinks; - while ( startElem || !startLinks.empty() ) { - while ( !startElem && !startLinks.empty() ) { - // Get an element to start, by a link - SMESH_TLink linkId = startLinks.front(); - startLinks.pop_front(); - itLE = mapLi_listEl.find( linkId ); - if ( itLE != mapLi_listEl.end() ) { - list< const SMDS_MeshElement* > & listElem = (*itLE).second; - list< const SMDS_MeshElement* >::iterator itE = listElem.begin(); - for ( ; itE != listElem.end() ; itE++ ) - if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() ) - startElem = (*itE); - mapLi_listEl.erase( itLE ); + // Fill theFacets starting from facetID of startHex + + // facets used for seach of volumes adjacent to already treated ones + typedef pair< TFacetOfElem::iterator, int > TElemFacets; + typedef map< TVolumeFaceKey, TElemFacets > TFacetMap; + TFacetMap facetsToCheck; + + set facetNodes; + const SMDS_MeshElement* curHex; + + const bool allHex = ( theHexas.size() == myMesh->NbHexas() ); + + while ( startHex ) + { + // move in two directions from startHex via facetID + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + curHex = startHex; + int curFacet = facetID; + if ( is2nd ) // do not treat startHex twice + { + vTool.Set( curHex ); + if ( vTool.IsFreeFace( curFacet, &curHex )) + { + curHex = 0; + } + else + { + vTool.GetFaceNodes( curFacet, facetNodes ); + vTool.Set( curHex ); + curFacet = vTool.GetFaceIndex( facetNodes ); } } + while ( curHex ) + { + // store a facet to split + if ( curHex->GetGeomType() != SMDSGeom_HEXA ) + { + theFacets.insert( make_pair( curHex, -1 )); + break; + } + if ( !allHex && !theHexas.count( curHex )) + break; - if ( startElem ) { - // Get candidates to be fused - const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0; - const SMESH_TLink *link12, *link13; - startElem = 0; - ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() ); - set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ]; - ASSERT( !setLi.empty() ); - set< SMESH_TLink >::iterator itLi; - for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ ) + pair< TFacetOfElem::iterator, bool > facetIt2isNew = + theFacets.insert( make_pair( curHex, curFacet )); + if ( !facetIt2isNew.second ) + break; + + // remember not-to-split facets in facetsToCheck + int oppFacet = vTool.GetOppFaceIndexOfHex( curFacet ); + for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) { - const SMESH_TLink & link = (*itLi); - itLE = mapLi_listEl.find( link ); - if ( itLE == mapLi_listEl.end() ) + if ( iF == curFacet && iF == oppFacet ) continue; - - const SMDS_MeshElement* elem = (*itLE).second.front(); - if ( elem == tr1 ) - elem = (*itLE).second.back(); - mapLi_listEl.erase( itLE ); - if ( mapEl_setLi.find( elem ) == mapEl_setLi.end()) - continue; - if ( tr2 ) { - tr3 = elem; - link13 = &link; - } - else { - tr2 = elem; - link12 = &link; - } - - // add other links of elem to list of links to re-start from - set< SMESH_TLink >& links = mapEl_setLi[ elem ]; - set< SMESH_TLink >::iterator it; - for ( it = links.begin(); it != links.end(); it++ ) { - const SMESH_TLink& link2 = (*it); - if ( link2 != link ) - startLinks.push_back( link2 ); - } + TVolumeFaceKey facetKey ( vTool, iF ); + TElemFacets elemFacet( facetIt2isNew.first, iF ); + pair< TFacetMap::iterator, bool > it2isnew = + facetsToCheck.insert( make_pair( facetKey, elemFacet )); + if ( !it2isnew.second ) + facetsToCheck.erase( it2isnew.first ); // adjacent hex already checked } - - // Get nodes of possible quadrangles - const SMDS_MeshNode *n12 [4], *n13 [4]; - bool Ok12 = false, Ok13 = false; - const SMDS_MeshNode *linkNode1, *linkNode2; - if(tr2) { - linkNode1 = link12->first; - linkNode2 = link12->second; - if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 )) - Ok12 = true; + // pass to a volume adjacent via oppFacet + if ( vTool.IsFreeFace( oppFacet, &curHex )) + { + curHex = 0; } - if(tr3) { - linkNode1 = link13->first; - linkNode2 = link13->second; - if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 )) - Ok13 = true; + else + { + // get a new curFacet + vTool.GetFaceNodes( oppFacet, facetNodes ); + vTool.Set( curHex ); + curFacet = vTool.GetFaceIndex( facetNodes, /*hint=*/curFacet ); } + } + } // move in two directions from startHex via facetID - // Choose a pair to fuse - if ( Ok12 && Ok13 ) { - SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] ); - SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] ); - double aBadRate12 = getBadRate( &quad12, theCrit ); - double aBadRate13 = getBadRate( &quad13, theCrit ); - if ( aBadRate13 < aBadRate12 ) - Ok12 = false; - else - Ok13 = false; - } + // Find a new startHex by facetsToCheck - // Make quadrangles - // and remove fused elems and removed links from the maps - mapEl_setLi.erase( tr1 ); - if ( Ok12 ) { - mapEl_setLi.erase( tr2 ); - mapLi_listEl.erase( *link12 ); - if(tr1->NbNodes()==3) { - if( tr1->GetID() < tr2->GetID() ) { - aMesh->ChangeElementNodes( tr1, n12, 4 ); - myLastCreatedElems.Append(tr1); - aMesh->RemoveElement( tr2 ); - } - else { - aMesh->ChangeElementNodes( tr2, n12, 4 ); - myLastCreatedElems.Append(tr2); - aMesh->RemoveElement( tr1); - } - } - else { - const SMDS_MeshNode* N1 [6]; - const SMDS_MeshNode* N2 [6]; - GetNodesFromTwoTria(tr1,tr2,N1,N2); - // now we receive following N1 and N2 (using numeration as above image) - // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6) - // i.e. first nodes from both arrays determ new diagonal - const SMDS_MeshNode* aNodes[8]; - aNodes[0] = N1[0]; - aNodes[1] = N1[1]; - aNodes[2] = N2[0]; - aNodes[3] = N2[1]; - aNodes[4] = N1[3]; - aNodes[5] = N2[5]; - aNodes[6] = N2[3]; - aNodes[7] = N1[5]; - if( tr1->GetID() < tr2->GetID() ) { - GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 ); - myLastCreatedElems.Append(tr1); - GetMeshDS()->RemoveElement( tr2 ); - } - else { - GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 ); - myLastCreatedElems.Append(tr2); - GetMeshDS()->RemoveElement( tr1 ); - } - // remove middle node (9) - GetMeshDS()->RemoveNode( N1[4] ); - } - } - else if ( Ok13 ) { - mapEl_setLi.erase( tr3 ); - mapLi_listEl.erase( *link13 ); - if(tr1->NbNodes()==3) { - if( tr1->GetID() < tr2->GetID() ) { - aMesh->ChangeElementNodes( tr1, n13, 4 ); - myLastCreatedElems.Append(tr1); - aMesh->RemoveElement( tr3 ); - } - else { - aMesh->ChangeElementNodes( tr3, n13, 4 ); - myLastCreatedElems.Append(tr3); - aMesh->RemoveElement( tr1 ); - } - } - else { - const SMDS_MeshNode* N1 [6]; - const SMDS_MeshNode* N2 [6]; - GetNodesFromTwoTria(tr1,tr3,N1,N2); - // now we receive following N1 and N2 (using numeration as above image) - // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6) - // i.e. first nodes from both arrays determ new diagonal - const SMDS_MeshNode* aNodes[8]; - aNodes[0] = N1[0]; - aNodes[1] = N1[1]; - aNodes[2] = N2[0]; - aNodes[3] = N2[1]; - aNodes[4] = N1[3]; - aNodes[5] = N2[5]; - aNodes[6] = N2[3]; - aNodes[7] = N1[5]; - if( tr1->GetID() < tr2->GetID() ) { - GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 ); - myLastCreatedElems.Append(tr1); - GetMeshDS()->RemoveElement( tr3 ); - } - else { - GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 ); - myLastCreatedElems.Append(tr3); - GetMeshDS()->RemoveElement( tr1 ); - } - // remove middle node (9) - GetMeshDS()->RemoveNode( N1[4] ); - } - } + startHex = 0; + facetID = -1; + TFacetMap::iterator fIt = facetsToCheck.begin(); + while ( !startHex && fIt != facetsToCheck.end() ) + { + const TElemFacets& elemFacets = fIt->second; + const SMDS_MeshElement* hex = elemFacets.first->first; + int splitFacet = elemFacets.first->second; + int lateralFacet = elemFacets.second; + facetsToCheck.erase( fIt ); + fIt = facetsToCheck.begin(); + + vTool.Set( hex ); + if ( vTool.IsFreeFace( lateralFacet, &curHex ) || + curHex->GetGeomType() != SMDSGeom_HEXA ) + continue; + if ( !allHex && !theHexas.count( curHex )) + continue; - // Next element to fuse: the rejected one - if ( tr3 ) - startElem = Ok12 ? tr3 : tr2; + startHex = curHex; - } // if ( startElem ) - } // while ( startElem || !startLinks.empty() ) - } // while ( ! mapEl_setLi.empty() ) + // find a facet of startHex to split - return true; -} + set lateralNodes; + vTool.GetFaceNodes( lateralFacet, lateralNodes ); + vTool.GetFaceNodes( splitFacet, facetNodes ); + int oppLateralFacet = vTool.GetOppFaceIndexOfHex( lateralFacet ); + vTool.Set( startHex ); + lateralFacet = vTool.GetFaceIndex( lateralNodes, oppLateralFacet ); + + // look for a facet of startHex having common nodes with facetNodes + // but not lateralFacet + for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) + { + if ( iF == lateralFacet ) + continue; + int nbCommonNodes = 0; + const SMDS_MeshNode** nn = vTool.GetFaceNodes( iF ); + for ( int iN = 0, nbN = vTool.NbFaceNodes( iF ); iN < nbN; ++iN ) + nbCommonNodes += facetNodes.count( nn[ iN ]); + if ( nbCommonNodes >= 2 ) + { + facetID = iF; + break; + } + } + if ( facetID < 0 ) + throw SALOME_Exception( THIS_METHOD "facet of a new startHex not found"); + } + } // while ( startHex ) -/*#define DUMPSO(txt) \ -// cout << txt << endl; -//============================================================================= -// -// -// -//============================================================================= -static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] ) + return; +} + +namespace { - if ( i1 == i2 ) - return; - int tmp = idNodes[ i1 ]; - idNodes[ i1 ] = idNodes[ i2 ]; - idNodes[ i2 ] = tmp; - gp_Pnt Ptmp = P[ i1 ]; - P[ i1 ] = P[ i2 ]; - P[ i2 ] = Ptmp; - DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")"); + //================================================================================ + /*! + * \brief Selects nodes of several elements according to a given interlace + * \param [in] srcNodes - nodes to select from + * \param [out] tgtNodesVec - array of nodes of several elements to fill in + * \param [in] interlace - indices of nodes for all elements + * \param [in] nbElems - nb of elements + * \param [in] nbNodes - nb of nodes in each element + * \param [in] mesh - the mesh + * \param [out] elemQueue - a list to push elements found by the selected nodes + * \param [in] type - type of elements to look for + */ + //================================================================================ + + void selectNodes( const vector< const SMDS_MeshNode* >& srcNodes, + vector< const SMDS_MeshNode* >* tgtNodesVec, + const int* interlace, + const int nbElems, + const int nbNodes, + SMESHDS_Mesh* mesh = 0, + list< const SMDS_MeshElement* >* elemQueue=0, + SMDSAbs_ElementType type=SMDSAbs_All) + { + for ( int iE = 0; iE < nbElems; ++iE ) + { + vector< const SMDS_MeshNode* >& elemNodes = tgtNodesVec[iE]; + const int* select = & interlace[iE*nbNodes]; + elemNodes.resize( nbNodes ); + for ( int iN = 0; iN < nbNodes; ++iN ) + elemNodes[iN] = srcNodes[ select[ iN ]]; + } + const SMDS_MeshElement* e; + if ( elemQueue ) + for ( int iE = 0; iE < nbElems; ++iE ) + if (( e = mesh->FindElement( tgtNodesVec[iE], type, /*noMedium=*/false))) + elemQueue->push_back( e ); + } } //======================================================================= -//function : SortQuadNodes -//purpose : Set 4 nodes of a quadrangle face in a good order. -// Swap 1<->2 or 2<->3 nodes and correspondingly return -// 1 or 2 else 0. +/* + * Split bi-quadratic elements into linear ones without creation of additional nodes + * - bi-quadratic triangle will be split into 3 linear quadrangles; + * - bi-quadratic quadrangle will be split into 4 linear quadrangles; + * - tri-quadratic hexahedron will be split into 8 linear hexahedra; + * Quadratic elements of lower dimension adjacent to the split bi-quadratic element + * will be split in order to keep the mesh conformal. + * \param elems - elements to split + */ //======================================================================= -int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh, - int idNodes[] ) +void SMESH_MeshEditor::SplitBiQuadraticIntoLinear(TIDSortedElemSet& theElems) { - gp_Pnt P[4]; - int i; - for ( i = 0; i < 4; i++ ) { - const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] ); - if ( !n ) return 0; - P[ i ].SetCoord( n->X(), n->Y(), n->Z() ); - } - - gp_Vec V1(P[0], P[1]); - gp_Vec V2(P[0], P[2]); - gp_Vec V3(P[0], P[3]); + vector< const SMDS_MeshNode* > elemNodes(27), subNodes[12], splitNodes[8]; + vector splitElems; + list< const SMDS_MeshElement* > elemQueue; + list< const SMDS_MeshElement* >::iterator elemIt; - gp_Vec Cross1 = V1 ^ V2; - gp_Vec Cross2 = V2 ^ V3; + SMESHDS_Mesh * mesh = GetMeshDS(); + ElemFeatures *elemType, hexaType(SMDSAbs_Volume), quadType(SMDSAbs_Face), segType(SMDSAbs_Edge); + int nbElems, nbNodes; - i = 0; - if (Cross1.Dot(Cross2) < 0) + TIDSortedElemSet::iterator elemSetIt = theElems.begin(); + for ( ; elemSetIt != theElems.end(); ++elemSetIt ) { - Cross1 = V2 ^ V1; - Cross2 = V1 ^ V3; + elemQueue.clear(); + elemQueue.push_back( *elemSetIt ); + for ( elemIt = elemQueue.begin(); elemIt != elemQueue.end(); ++elemIt ) + { + const SMDS_MeshElement* elem = *elemIt; + switch( elem->GetEntityType() ) + { + case SMDSEntity_TriQuad_Hexa: // HEX27 + { + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = nbNodes = 8; + elemType = & hexaType; + + // get nodes for new elements + static int vInd[8][8] = {{ 0,8,20,11, 16,21,26,24 }, + { 1,9,20,8, 17,22,26,21 }, + { 2,10,20,9, 18,23,26,22 }, + { 3,11,20,10, 19,24,26,23 }, + { 16,21,26,24, 4,12,25,15 }, + { 17,22,26,21, 5,13,25,12 }, + { 18,23,26,22, 6,14,25,13 }, + { 19,24,26,23, 7,15,25,14 }}; + selectNodes( elemNodes, & splitNodes[0], &vInd[0][0], nbElems, nbNodes ); + + // add boundary faces to elemQueue + static int fInd[6][9] = {{ 0,1,2,3, 8,9,10,11, 20 }, + { 4,5,6,7, 12,13,14,15, 25 }, + { 0,1,5,4, 8,17,12,16, 21 }, + { 1,2,6,5, 9,18,13,17, 22 }, + { 2,3,7,6, 10,19,14,18, 23 }, + { 3,0,4,7, 11,16,15,19, 24 }}; + selectNodes( elemNodes, & subNodes[0], &fInd[0][0], 6,9, mesh, &elemQueue, SMDSAbs_Face ); + + // add boundary segments to elemQueue + static int eInd[12][3] = {{ 0,1,8 }, { 1,2,9 }, { 2,3,10 }, { 3,0,11 }, + { 4,5,12}, { 5,6,13}, { 6,7,14 }, { 7,4,15 }, + { 0,4,16}, { 1,5,17}, { 2,6,18 }, { 3,7,19 }}; + selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 12,3, mesh, &elemQueue, SMDSAbs_Edge ); + break; + } + case SMDSEntity_BiQuad_Triangle: // TRIA7 + { + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = 3; + nbNodes = 4; + elemType = & quadType; + + // get nodes for new elements + static int fInd[3][4] = {{ 0,3,6,5 }, { 1,4,6,3 }, { 2,5,6,4 }}; + selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes ); + + // add boundary segments to elemQueue + static int eInd[3][3] = {{ 0,1,3 }, { 1,2,4 }, { 2,0,5 }}; + selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 3,3, mesh, &elemQueue, SMDSAbs_Edge ); + break; + } + case SMDSEntity_BiQuad_Quadrangle: // QUAD9 + { + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = 4; + nbNodes = 4; + elemType = & quadType; + + // get nodes for new elements + static int fInd[4][4] = {{ 0,4,8,7 }, { 1,5,8,4 }, { 2,6,8,5 }, { 3,7,8,6 }}; + selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes ); + + // add boundary segments to elemQueue + static int eInd[4][3] = {{ 0,1,4 }, { 1,2,5 }, { 2,3,6 }, { 3,0,7 }}; + selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 4,3, mesh, &elemQueue, SMDSAbs_Edge ); + break; + } + case SMDSEntity_Quad_Edge: + { + if ( elemIt == elemQueue.begin() ) + continue; // an elem is in theElems + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = 2; + nbNodes = 2; + elemType = & segType; + + // get nodes for new elements + static int eInd[2][2] = {{ 0,2 }, { 2,1 }}; + selectNodes( elemNodes, & splitNodes[0], &eInd[0][0], nbElems, nbNodes ); + break; + } + default: continue; + } // switch( elem->GetEntityType() ) - if (Cross1.Dot(Cross2) < 0) - i = 2; - else - i = 1; - swap ( i, i + 1, idNodes, P ); + // Create new elements -// for ( int ii = 0; ii < 4; ii++ ) { -// const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] ); -// DUMPSO( ii << "(" << idNodes[ii] <<") : "<X()<<" "<Y()<<" "<Z()); -// } + SMESHDS_SubMesh* subMesh = mesh->MeshElements( elem->getshapeId() ); + + splitElems.clear(); + + //elemType->SetID( elem->GetID() ); // create an elem with the same ID as a removed one + mesh->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false ); + //splitElems.push_back( AddElement( splitNodes[ 0 ], *elemType )); + //elemType->SetID( -1 ); + + for ( int iE = 0; iE < nbElems; ++iE ) + splitElems.push_back( AddElement( splitNodes[ iE ], *elemType )); + + + ReplaceElemInGroups( elem, splitElems, mesh ); + + if ( subMesh ) + for ( size_t i = 0; i < splitElems.size(); ++i ) + subMesh->AddElement( splitElems[i] ); + } } - return i; } //======================================================================= -//function : SortHexaNodes -//purpose : Set 8 nodes of a hexahedron in a good order. -// Return success status +//function : AddToSameGroups +//purpose : add elemToAdd to the groups the elemInGroups belongs to //======================================================================= -bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh, - int idNodes[] ) +void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd, + const SMDS_MeshElement* elemInGroups, + SMESHDS_Mesh * aMesh) { - gp_Pnt P[8]; - int i; - DUMPSO( "INPUT: ========================================"); - for ( i = 0; i < 8; i++ ) { - const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] ); - if ( !n ) return false; - P[ i ].SetCoord( n->X(), n->Y(), n->Z() ); - DUMPSO( i << "(" << idNodes[i] <<") : "<X()<<" "<Y()<<" "<Z()); + const set& groups = aMesh->GetGroups(); + if (!groups.empty()) { + set::const_iterator grIt = groups.begin(); + for ( ; grIt != groups.end(); grIt++ ) { + SMESHDS_Group* group = dynamic_cast( *grIt ); + if ( group && group->Contains( elemInGroups )) + group->SMDSGroup().Add( elemToAdd ); + } } - DUMPSO( "========================================"); - - - set faceNodes; // ids of bottom face nodes, to be found - set checkedId1; // ids of tried 2-nd nodes - Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane - const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane - int iMin, iLoop1 = 0; +} - // Loop to try the 2-nd nodes - while ( leastDist > DBL_MIN && ++iLoop1 < 8 ) +//======================================================================= +//function : RemoveElemFromGroups +//purpose : Remove removeelem to the groups the elemInGroups belongs to +//======================================================================= +void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem, + SMESHDS_Mesh * aMesh) +{ + const set& groups = aMesh->GetGroups(); + if (!groups.empty()) { - // Find not checked 2-nd node - for ( i = 1; i < 8; i++ ) - if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) { - int id1 = idNodes[i]; - swap ( 1, i, idNodes, P ); - checkedId1.insert ( id1 ); - break; - } + set::const_iterator GrIt = groups.begin(); + for (; GrIt != groups.end(); GrIt++) + { + SMESHDS_Group* grp = dynamic_cast(*GrIt); + if (!grp || grp->IsEmpty()) continue; + grp->SMDSGroup().Remove(removeelem); + } + } +} - // Find the 3-d node so that 1-2-3 triangle to be on a hexa face, - // ie that all but meybe one (id3 which is on the same face) nodes - // lay on the same side from the triangle plane. +//================================================================================ +/*! + * \brief Replace elemToRm by elemToAdd in the all groups + */ +//================================================================================ - bool manyInPlane = false; // more than 4 nodes lay in plane - int iLoop2 = 0; - while ( ++iLoop2 < 6 ) { - - // get 1-2-3 plane coeffs - Standard_Real A, B, C, D; - gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) ); - if ( N.SquareMagnitude() > gp::Resolution() ) - { - gp_Pln pln ( P[0], N ); - pln.Coefficients( A, B, C, D ); - - // find the node (iMin) closest to pln - Standard_Real dist[ 8 ], minDist = DBL_MAX; - set idInPln; - for ( i = 3; i < 8; i++ ) { - dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D; - if ( fabs( dist[i] ) < minDist ) { - minDist = fabs( dist[i] ); - iMin = i; - } - if ( fabs( dist[i] ) <= tol ) - idInPln.insert( idNodes[i] ); - } - - // there should not be more than 4 nodes in bottom plane - if ( idInPln.size() > 1 ) - { - DUMPSO( "### idInPln.size() = " << idInPln.size()); - // idInPlane does not contain the first 3 nodes - if ( manyInPlane || idInPln.size() == 5) - return false; // all nodes in one plane - manyInPlane = true; - - // set the 1-st node to be not in plane - for ( i = 3; i < 8; i++ ) { - if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) { - DUMPSO( "### Reset 0-th node"); - swap( 0, i, idNodes, P ); - break; - } - } - - // reset to re-check second nodes - leastDist = DBL_MAX; - faceNodes.clear(); - checkedId1.clear(); - iLoop1 = 0; - break; // from iLoop2; - } - - // check that the other 4 nodes are on the same side - bool sameSide = true; - bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.; - for ( i = 3; sameSide && i < 8; i++ ) { - if ( i != iMin ) - sameSide = ( isNeg == dist[i] <= 0.); - } - - // keep best solution - if ( sameSide && minDist < leastDist ) { - leastDist = minDist; - faceNodes.clear(); - faceNodes.insert( idNodes[ 1 ] ); - faceNodes.insert( idNodes[ 2 ] ); - faceNodes.insert( idNodes[ iMin ] ); - DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ] - << " leastDist = " << leastDist); - if ( leastDist <= DBL_MIN ) - break; - } - } - - // set next 3-d node to check - int iNext = 2 + iLoop2; - if ( iNext < 8 ) { - DUMPSO( "Try 2-nd"); - swap ( 2, iNext, idNodes, P ); - } - } // while ( iLoop2 < 6 ) - } // iLoop1 - - if ( faceNodes.empty() ) return false; - - // Put the faceNodes in proper places - for ( i = 4; i < 8; i++ ) { - if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) { - // find a place to put - int iTo = 1; - while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() ) - iTo++; - DUMPSO( "Set faceNodes"); - swap ( iTo, i, idNodes, P ); - } - } - - - // Set nodes of the found bottom face in good order - DUMPSO( " Found bottom face: "); - i = SortQuadNodes( theMesh, idNodes ); - if ( i ) { - gp_Pnt Ptmp = P[ i ]; - P[ i ] = P[ i+1 ]; - P[ i+1 ] = Ptmp; - } -// else -// for ( int ii = 0; ii < 4; ii++ ) { -// const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] ); -// DUMPSO( ii << "(" << idNodes[ii] <<") : "<X()<<" "<Y()<<" "<Z()); -// } - - // Gravity center of the top and bottom faces - gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.; - gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.; - - // Get direction from the bottom to the top face - gp_Vec upDir ( aGCb, aGCt ); - Standard_Real upDirSize = upDir.Magnitude(); - if ( upDirSize <= gp::Resolution() ) return false; - upDir / upDirSize; - - // Assure that the bottom face normal points up - gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) ); - Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) ); - if ( Nb.Dot( upDir ) < 0 ) { - DUMPSO( "Reverse bottom face"); - swap( 1, 3, idNodes, P ); - } - - // Find 5-th node - the one closest to the 1-st among the last 4 nodes. - Standard_Real minDist = DBL_MAX; - for ( i = 4; i < 8; i++ ) { - // projection of P[i] to the plane defined by P[0] and upDir - gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] )))); - Standard_Real sqDist = P[0].SquareDistance( Pp ); - if ( sqDist < minDist ) { - minDist = sqDist; - iMin = i; +void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm, + const SMDS_MeshElement* elemToAdd, + SMESHDS_Mesh * aMesh) +{ + const set& groups = aMesh->GetGroups(); + if (!groups.empty()) { + set::const_iterator grIt = groups.begin(); + for ( ; grIt != groups.end(); grIt++ ) { + SMESHDS_Group* group = dynamic_cast( *grIt ); + if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd ) + group->SMDSGroup().Add( elemToAdd ); } } - DUMPSO( "Set 4-th"); - swap ( 4, iMin, idNodes, P ); - - // Set nodes of the top face in good order - DUMPSO( "Sort top face"); - i = SortQuadNodes( theMesh, &idNodes[4] ); - if ( i ) { - i += 4; - gp_Pnt Ptmp = P[ i ]; - P[ i ] = P[ i+1 ]; - P[ i+1 ] = Ptmp; - } - - // Assure that direction of the top face normal is from the bottom face - gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) ); - Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) ); - if ( Nt.Dot( upDir ) < 0 ) { - DUMPSO( "Reverse top face"); - swap( 5, 7, idNodes, P ); - } - -// DUMPSO( "OUTPUT: ========================================"); -// for ( i = 0; i < 8; i++ ) { -// float *p = ugrid->GetPoint(idNodes[i]); -// DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]); -// } - - return true; -}*/ +} //================================================================================ /*! - * \brief Return nodes linked to the given one - * \param theNode - the node - * \param linkedNodes - the found nodes - * \param type - the type of elements to check - * - * Medium nodes are ignored + * \brief Replace elemToRm by elemToAdd in the all groups */ //================================================================================ -void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode, - TIDSortedElemSet & linkedNodes, - SMDSAbs_ElementType type ) +void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm, + const vector& elemToAdd, + SMESHDS_Mesh * aMesh) { - SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type); - while ( elemIt->more() ) + const set& groups = aMesh->GetGroups(); + if (!groups.empty()) { - const SMDS_MeshElement* elem = elemIt->next(); - SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); - if ( elem->GetType() == SMDSAbs_Volume ) - { - SMDS_VolumeTool vol( elem ); - while ( nodeIt->more() ) { - const SMDS_MeshNode* n = cast2Node( nodeIt->next() ); - if ( theNode != n && vol.IsLinked( theNode, n )) - linkedNodes.insert( n ); - } - } - else - { - for ( int i = 0; nodeIt->more(); ++i ) { - const SMDS_MeshNode* n = cast2Node( nodeIt->next() ); - if ( n == theNode ) { - int iBefore = i - 1; - int iAfter = i + 1; - if ( elem->IsQuadratic() ) { - int nb = elem->NbNodes() / 2; - iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb ); - iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb ); - } - linkedNodes.insert( elem->GetNodeWrap( iAfter )); - linkedNodes.insert( elem->GetNodeWrap( iBefore )); - } - } + set::const_iterator grIt = groups.begin(); + for ( ; grIt != groups.end(); grIt++ ) { + SMESHDS_Group* group = dynamic_cast( *grIt ); + if ( group && group->SMDSGroup().Remove( elemToRm ) ) + for ( int i = 0; i < elemToAdd.size(); ++i ) + group->SMDSGroup().Add( elemToAdd[ i ] ); } } } //======================================================================= -//function : laplacianSmooth -//purpose : pulls theNode toward the center of surrounding nodes directly -// connected to that node along an element edge +//function : QuadToTri +//purpose : Cut quadrangles into triangles. +// theCrit is used to select a diagonal to cut //======================================================================= -void laplacianSmooth(const SMDS_MeshNode* theNode, - const Handle(Geom_Surface)& theSurface, - map< const SMDS_MeshNode*, gp_XY* >& theUVMap) +bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, + const bool the13Diag) { - // find surrounding nodes + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); - TIDSortedElemSet nodeSet; - SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face ); + MESSAGE( "::QuadToTri()" ); - // compute new coodrs + SMESHDS_Mesh * aMesh = GetMeshDS(); - double coord[] = { 0., 0., 0. }; - TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin(); - for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) { - const SMDS_MeshNode* node = cast2Node(*nodeSetIt); - if ( theSurface.IsNull() ) { // smooth in 3D - coord[0] += node->X(); - coord[1] += node->Y(); - coord[2] += node->Z(); - } - else { // smooth in 2D - ASSERT( theUVMap.find( node ) != theUVMap.end() ); - gp_XY* uv = theUVMap[ node ]; - coord[0] += uv->X(); - coord[1] += uv->Y(); - } - } - int nbNodes = nodeSet.size(); - if ( !nbNodes ) - return; - coord[0] /= nbNodes; - coord[1] /= nbNodes; + Handle(Geom_Surface) surface; + SMESH_MesherHelper helper( *GetMesh() ); - if ( !theSurface.IsNull() ) { - ASSERT( theUVMap.find( theNode ) != theUVMap.end() ); - theUVMap[ theNode ]->SetCoord( coord[0], coord[1] ); - gp_Pnt p3d = theSurface->Value( coord[0], coord[1] ); - coord[0] = p3d.X(); - coord[1] = p3d.Y(); - coord[2] = p3d.Z(); - } - else - coord[2] /= nbNodes; + TIDSortedElemSet::iterator itElem; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + const SMDS_MeshElement* elem = *itElem; + if ( !elem || elem->GetType() != SMDSAbs_Face ) + continue; + bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8; + if(!isquad) continue; - // move node + if(elem->NbNodes()==4) { + // retrieve element nodes + const SMDS_MeshNode* aNodes [4]; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + int i = 0; + while ( itN->more() ) + aNodes[ i++ ] = static_cast( itN->next() ); - const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]); -} + int aShapeId = FindShape( elem ); + const SMDS_MeshElement* newElem1 = 0; + const SMDS_MeshElement* newElem2 = 0; + if ( the13Diag ) { + newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] ); + newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] ); + } + else { + newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] ); + newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] ); + } + myLastCreatedElems.Append(newElem1); + myLastCreatedElems.Append(newElem2); + // put a new triangle on the same shape and add to the same groups + if ( aShapeId ) + { + aMesh->SetMeshElementOnShape( newElem1, aShapeId ); + aMesh->SetMeshElementOnShape( newElem2, aShapeId ); + } + AddToSameGroups( newElem1, elem, aMesh ); + AddToSameGroups( newElem2, elem, aMesh ); + aMesh->RemoveElement( elem ); + } -//======================================================================= -//function : centroidalSmooth -//purpose : pulls theNode toward the element-area-weighted centroid of the -// surrounding elements -//======================================================================= + // Quadratic quadrangle -void centroidalSmooth(const SMDS_MeshNode* theNode, - const Handle(Geom_Surface)& theSurface, - map< const SMDS_MeshNode*, gp_XY* >& theUVMap) -{ - gp_XYZ aNewXYZ(0.,0.,0.); - SMESH::Controls::Area anAreaFunc; - double totalArea = 0.; - int nbElems = 0; + if( elem->NbNodes()==8 && elem->IsQuadratic() ) { - // compute new XYZ + // get surface elem is on + int aShapeId = FindShape( elem ); + if ( aShapeId != helper.GetSubShapeID() ) { + surface.Nullify(); + TopoDS_Shape shape; + if ( aShapeId > 0 ) + shape = aMesh->IndexToShape( aShapeId ); + if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) { + TopoDS_Face face = TopoDS::Face( shape ); + surface = BRep_Tool::Surface( face ); + if ( !surface.IsNull() ) + helper.SetSubShape( shape ); + } + } - SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face); - while ( elemIt->more() ) - { - const SMDS_MeshElement* elem = elemIt->next(); - nbElems++; + const SMDS_MeshNode* aNodes [8]; + const SMDS_MeshNode* inFaceNode = 0; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + int i = 0; + while ( itN->more() ) { + aNodes[ i++ ] = static_cast( itN->next() ); + if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() && + aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) + { + inFaceNode = aNodes[ i-1 ]; + } + } - gp_XYZ elemCenter(0.,0.,0.); - SMESH::Controls::TSequenceOfXYZ aNodePoints; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - int nn = elem->NbNodes(); - if(elem->IsQuadratic()) nn = nn/2; - int i=0; - //while ( itN->more() ) { - while ( i( itN->next() ); - i++; - gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() ); - aNodePoints.push_back( aP ); - if ( !theSurface.IsNull() ) { // smooth in 2D - ASSERT( theUVMap.find( aNode ) != theUVMap.end() ); - gp_XY* uv = theUVMap[ aNode ]; - aP.SetCoord( uv->X(), uv->Y(), 0. ); + // find middle point for (0,1,2,3) + // and create a node in this point; + gp_XYZ p( 0,0,0 ); + if ( surface.IsNull() ) { + for(i=0; i<4; i++) + p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() ); + p /= 4; } - elemCenter += aP; + else { + TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() ); + gp_XY uv( 0,0 ); + for(i=0; i<4; i++) + uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode ); + uv /= 4.; + p = surface->Value( uv.X(), uv.Y() ).XYZ(); + } + const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() ); + myLastCreatedNodes.Append(newN); + + // create a new element + const SMDS_MeshElement* newElem1 = 0; + const SMDS_MeshElement* newElem2 = 0; + if ( the13Diag ) { + newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0], + aNodes[6], aNodes[7], newN ); + newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1], + newN, aNodes[4], aNodes[5] ); + } + else { + newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1], + aNodes[7], aNodes[4], newN ); + newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2], + newN, aNodes[5], aNodes[6] ); + } + myLastCreatedElems.Append(newElem1); + myLastCreatedElems.Append(newElem2); + // put a new triangle on the same shape and add to the same groups + if ( aShapeId ) + { + aMesh->SetMeshElementOnShape( newElem1, aShapeId ); + aMesh->SetMeshElementOnShape( newElem2, aShapeId ); + } + AddToSameGroups( newElem1, elem, aMesh ); + AddToSameGroups( newElem2, elem, aMesh ); + aMesh->RemoveElement( elem ); } - double elemArea = anAreaFunc.GetValue( aNodePoints ); - totalArea += elemArea; - elemCenter /= nn; - aNewXYZ += elemCenter * elemArea; - } - aNewXYZ /= totalArea; - if ( !theSurface.IsNull() ) { - theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() ); - aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ(); } - // move node - - const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z()); + return true; } //======================================================================= -//function : getClosestUV -//purpose : return UV of closest projection +//function : getAngle +//purpose : //======================================================================= -static bool getClosestUV (Extrema_GenExtPS& projector, - const gp_Pnt& point, - gp_XY & result) +double getAngle(const SMDS_MeshElement * tr1, + const SMDS_MeshElement * tr2, + const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2) { - projector.Perform( point ); - if ( projector.IsDone() ) { - double u, v, minVal = DBL_MAX; - for ( int i = projector.NbExt(); i > 0; i-- ) -#if OCC_VERSION_HEX >= 0x060500 - if ( projector.SquareDistance( i ) < minVal ) { - minVal = projector.SquareDistance( i ); -#else - if ( projector.Value( i ) < minVal ) { - minVal = projector.Value( i ); -#endif - projector.Point( i ).Parameter( u, v ); + double angle = 2. * M_PI; // bad angle + + // get normals + SMESH::Controls::TSequenceOfXYZ P1, P2; + if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) || + !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 )) + return angle; + gp_Vec N1,N2; + if(!tr1->IsQuadratic()) + N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) ); + else + N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) ); + if ( N1.SquareMagnitude() <= gp::Resolution() ) + return angle; + if(!tr2->IsQuadratic()) + N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) ); + else + N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) ); + if ( N2.SquareMagnitude() <= gp::Resolution() ) + return angle; + + // find the first diagonal node n1 in the triangles: + // take in account a diagonal link orientation + const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 }; + for ( int t = 0; t < 2; t++ ) { + SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator(); + int i = 0, iDiag = -1; + while ( it->more()) { + const SMDS_MeshElement *n = it->next(); + if ( n == n1 || n == n2 ) { + if ( iDiag < 0) + iDiag = i; + else { + if ( i - iDiag == 1 ) + nFirst[ t ] = ( n == n1 ? n2 : n1 ); + else + nFirst[ t ] = n; + break; + } } - result.SetCoord( u, v ); - return true; + i++; + } } - return false; -} + if ( nFirst[ 0 ] == nFirst[ 1 ] ) + N2.Reverse(); -//======================================================================= -//function : Smooth -//purpose : Smooth theElements during theNbIterations or until a worst -// element has aspect ratio <= theTgtAspectRatio. -// Aspect Ratio varies in range [1.0, inf]. -// If theElements is empty, the whole mesh is smoothed. -// theFixedNodes contains additionally fixed nodes. Nodes built -// on edges and boundary nodes are always fixed. -//======================================================================= + angle = N1.Angle( N2 ); + //SCRUTE( angle ); + return angle; +} -void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, - set & theFixedNodes, - const SmoothMethod theSmoothMethod, - const int theNbIterations, - double theTgtAspectRatio, - const bool the2D) -{ - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); +// ================================================= +// class generating a unique ID for a pair of nodes +// and able to return nodes by that ID +// ================================================= +class LinkID_Gen { +public: - MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()"); + LinkID_Gen( const SMESHDS_Mesh* theMesh ) + :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1) + {} - if ( theTgtAspectRatio < 1.0 ) - theTgtAspectRatio = 1.0; + long GetLinkID (const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2) const + { + return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID())); + } - const double disttol = 1.e-16; + bool GetNodes (const long theLinkID, + const SMDS_MeshNode* & theNode1, + const SMDS_MeshNode* & theNode2) const + { + theNode1 = myMesh->FindNode( theLinkID / myMaxID ); + if ( !theNode1 ) return false; + theNode2 = myMesh->FindNode( theLinkID % myMaxID ); + if ( !theNode2 ) return false; + return true; + } - SMESH::Controls::AspectRatio aQualityFunc; +private: + LinkID_Gen(); + const SMESHDS_Mesh* myMesh; + long myMaxID; +}; - SMESHDS_Mesh* aMesh = GetMeshDS(); - if ( theElems.empty() ) { - // add all faces to theElems - SMDS_FaceIteratorPtr fIt = aMesh->facesIterator(); - while ( fIt->more() ) { - const SMDS_MeshElement* face = fIt->next(); - theElems.insert( face ); - } - } - // get all face ids theElems are on - set< int > faceIdSet; - TIDSortedElemSet::iterator itElem; - if ( the2D ) - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { - int fId = FindShape( *itElem ); - // check that corresponding submesh exists and a shape is face - if (fId && - faceIdSet.find( fId ) == faceIdSet.end() && - aMesh->MeshElements( fId )) { - TopoDS_Shape F = aMesh->IndexToShape( fId ); - if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE ) - faceIdSet.insert( fId ); - } - } - faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face +//======================================================================= +//function : TriToQuad +//purpose : Fuse neighbour triangles into quadrangles. +// theCrit is used to select a neighbour to fuse with. +// theMaxAngle is a max angle between element normals at which +// fusion is still performed. +//======================================================================= - // =============================================== - // smooth elements on each TopoDS_Face separately - // =============================================== +bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, + SMESH::Controls::NumericalFunctorPtr theCrit, + const double theMaxAngle) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); - set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end - for ( ; fId != faceIdSet.rend(); ++fId ) { - // get face surface and submesh - Handle(Geom_Surface) surface; - SMESHDS_SubMesh* faceSubMesh = 0; - TopoDS_Face face; - double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l; - double u1 = 0, u2 = 0, v1 = 0, v2 = 0; - bool isUPeriodic = false, isVPeriodic = false; - if ( *fId ) { - face = TopoDS::Face( aMesh->IndexToShape( *fId )); - surface = BRep_Tool::Surface( face ); - faceSubMesh = aMesh->MeshElements( *fId ); - fToler2 = BRep_Tool::Tolerance( face ); - fToler2 *= fToler2 * 10.; - isUPeriodic = surface->IsUPeriodic(); - if ( isUPeriodic ) - vPeriod = surface->UPeriod(); - isVPeriodic = surface->IsVPeriodic(); - if ( isVPeriodic ) - uPeriod = surface->VPeriod(); - surface->Bounds( u1, u2, v1, v2 ); - } - // --------------------------------------------------------- - // for elements on a face, find movable and fixed nodes and - // compute UV for them - // --------------------------------------------------------- - bool checkBoundaryNodes = false; - bool isQuadratic = false; - set setMovableNodes; - map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2; - list< gp_XY > listUV; // uvs the 2 uvMaps refer to - list< const SMDS_MeshElement* > elemsOnFace; + MESSAGE( "::TriToQuad()" ); - Extrema_GenExtPS projector; - GeomAdaptor_Surface surfAdaptor; - if ( !surface.IsNull() ) { - surfAdaptor.Load( surface ); - projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 ); - } - int nbElemOnFace = 0; - itElem = theElems.begin(); - // loop on not yet smoothed elements: look for elems on a face - while ( itElem != theElems.end() ) { - if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() ) - break; // all elements found + if ( !theCrit.get() ) + return false; - const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 || - ( faceSubMesh && !faceSubMesh->Contains( elem ))) { - ++itElem; - continue; - } - elemsOnFace.push_back( elem ); - theElems.erase( itElem++ ); - nbElemOnFace++; + SMESHDS_Mesh * aMesh = GetMeshDS(); - if ( !isQuadratic ) - isQuadratic = elem->IsQuadratic(); + // Prepare data for algo: build + // 1. map of elements with their linkIDs + // 2. map of linkIDs with their elements - // get movable nodes of elem - const SMDS_MeshNode* node; - SMDS_TypeOfPosition posType; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - int nn = 0, nbn = elem->NbNodes(); - if(elem->IsQuadratic()) - nbn = nbn/2; - while ( nn++ < nbn ) { - node = static_cast( itN->next() ); - const SMDS_PositionPtr& pos = node->GetPosition(); - posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE; - if (posType != SMDS_TOP_EDGE && - posType != SMDS_TOP_VERTEX && - theFixedNodes.find( node ) == theFixedNodes.end()) - { - // check if all faces around the node are on faceSubMesh - // because a node on edge may be bound to face - SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face); - bool all = true; - if ( faceSubMesh ) { - while ( eIt->more() && all ) { - const SMDS_MeshElement* e = eIt->next(); - all = faceSubMesh->Contains( e ); - } - } - if ( all ) - setMovableNodes.insert( node ); - else - checkBoundaryNodes = true; - } - if ( posType == SMDS_TOP_3DSPACE ) - checkBoundaryNodes = true; - } + map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl; + map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE; + map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi; + map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL; - if ( surface.IsNull() ) - continue; + TIDSortedElemSet::iterator itElem; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) + { + const SMDS_MeshElement* elem = *itElem; + if(!elem || elem->GetType() != SMDSAbs_Face ) continue; + bool IsTria = ( elem->NbCornerNodes()==3 ); + if (!IsTria) continue; - // get nodes to check UV - list< const SMDS_MeshNode* > uvCheckNodes; - itN = elem->nodesIterator(); - nn = 0; nbn = elem->NbNodes(); - if(elem->IsQuadratic()) - nbn = nbn/2; - while ( nn++ < nbn ) { - node = static_cast( itN->next() ); - if ( uvMap.find( node ) == uvMap.end() ) - uvCheckNodes.push_back( node ); - // add nodes of elems sharing node -// SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face); -// while ( eIt->more() ) { -// const SMDS_MeshElement* e = eIt->next(); -// if ( e != elem ) { -// SMDS_ElemIteratorPtr nIt = e->nodesIterator(); -// while ( nIt->more() ) { -// const SMDS_MeshNode* n = -// static_cast( nIt->next() ); -// if ( uvMap.find( n ) == uvMap.end() ) -// uvCheckNodes.push_back( n ); -// } -// } -// } + // retrieve element nodes + const SMDS_MeshNode* aNodes [4]; + SMDS_NodeIteratorPtr itN = elem->nodeIterator(); + int i = 0; + while ( i < 3 ) + aNodes[ i++ ] = itN->next(); + aNodes[ 3 ] = aNodes[ 0 ]; + + // fill maps + for ( i = 0; i < 3; i++ ) { + SMESH_TLink link( aNodes[i], aNodes[i+1] ); + // check if elements sharing a link can be fused + itLE = mapLi_listEl.find( link ); + if ( itLE != mapLi_listEl.end() ) { + if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link + continue; + const SMDS_MeshElement* elem2 = (*itLE).second.front(); + //if ( FindShape( elem ) != FindShape( elem2 )) + // continue; // do not fuse triangles laying on different shapes + if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle ) + continue; // avoid making badly shaped quads + (*itLE).second.push_back( elem ); } - // check UV on face - list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin(); - for ( ; n != uvCheckNodes.end(); ++n ) { - node = *n; - gp_XY uv( 0, 0 ); - const SMDS_PositionPtr& pos = node->GetPosition(); - posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE; - // get existing UV - switch ( posType ) { - case SMDS_TOP_FACE: { - SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get(); - uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() ); - break; - } - case SMDS_TOP_EDGE: { - TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() ); - Handle(Geom2d_Curve) pcurve; - if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE ) - pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l ); - if ( !pcurve.IsNull() ) { - double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter(); - uv = pcurve->Value( u ).XY(); - } - break; - } - case SMDS_TOP_VERTEX: { - TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() ); - if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX ) - uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY(); - break; - } - default:; - } - // check existing UV - bool project = true; - gp_Pnt pNode ( node->X(), node->Y(), node->Z() ); - double dist1 = DBL_MAX, dist2 = 0; - if ( posType != SMDS_TOP_3DSPACE ) { - dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() )); - project = dist1 > fToler2; - } - if ( project ) { // compute new UV - gp_XY newUV; - if ( !getClosestUV( projector, pNode, newUV )) { - MESSAGE("Node Projection Failed " << node); - } - else { - if ( isUPeriodic ) - newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 )); - if ( isVPeriodic ) - newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 )); - // check new UV - if ( posType != SMDS_TOP_3DSPACE ) - dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() )); - if ( dist2 < dist1 ) - uv = newUV; - } - } - // store UV in the map - listUV.push_back( uv ); - uvMap.insert( make_pair( node, &listUV.back() )); + else { + mapLi_listEl[ link ].push_back( elem ); } - } // loop on not yet smoothed elements + mapEl_setLi [ elem ].insert( link ); + } + } + // Clean the maps from the links shared by a sole element, ie + // links to which only one element is bound in mapLi_listEl - if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() ) - checkBoundaryNodes = true; + for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) { + int nbElems = (*itLE).second.size(); + if ( nbElems < 2 ) { + const SMDS_MeshElement* elem = (*itLE).second.front(); + SMESH_TLink link = (*itLE).first; + mapEl_setLi[ elem ].erase( link ); + if ( mapEl_setLi[ elem ].empty() ) + mapEl_setLi.erase( elem ); + } + } - // fix nodes on mesh boundary + // Algo: fuse triangles into quadrangles - if ( checkBoundaryNodes ) { - map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace - map< NLink, int >::iterator link_nb; - // put all elements links to linkNbMap - list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin(); - for ( ; elemIt != elemsOnFace.end(); ++elemIt ) { - const SMDS_MeshElement* elem = (*elemIt); - int nbn = elem->NbNodes(); - if(elem->IsQuadratic()) - nbn = nbn/2; - // loop on elem links: insert them in linkNbMap - const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn ); - for ( int iN = 0; iN < nbn; ++iN ) { - curNode = elem->GetNode( iN ); - NLink link; - if ( curNode < prevNode ) link = make_pair( curNode , prevNode ); - else link = make_pair( prevNode , curNode ); - prevNode = curNode; - link_nb = linkNbMap.find( link ); - if ( link_nb == linkNbMap.end() ) - linkNbMap.insert( make_pair ( link, 1 )); - else - link_nb->second++; - } - } - // remove nodes that are in links encountered only once from setMovableNodes - for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) { - if ( link_nb->second == 1 ) { - setMovableNodes.erase( link_nb->first.first ); - setMovableNodes.erase( link_nb->first.second ); - } + while ( ! mapEl_setLi.empty() ) { + // Look for the start element: + // the element having the least nb of shared links + const SMDS_MeshElement* startElem = 0; + int minNbLinks = 4; + for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) { + int nbLinks = (*itEL).second.size(); + if ( nbLinks < minNbLinks ) { + startElem = (*itEL).first; + minNbLinks = nbLinks; + if ( minNbLinks == 1 ) + break; } } - // ----------------------------------------------------- - // for nodes on seam edge, compute one more UV ( uvMap2 ); - // find movable nodes linked to nodes on seam and which - // are to be smoothed using the second UV ( uvMap2 ) - // ----------------------------------------------------- - - set nodesNearSeam; // to smooth using uvMap2 - if ( !surface.IsNull() ) { - TopExp_Explorer eExp( face, TopAbs_EDGE ); - for ( ; eExp.More(); eExp.Next() ) { - TopoDS_Edge edge = TopoDS::Edge( eExp.Current() ); - if ( !BRep_Tool::IsClosed( edge, face )) - continue; - SMESHDS_SubMesh* sm = aMesh->MeshElements( edge ); - if ( !sm ) continue; - // find out which parameter varies for a node on seam - double f,l; - gp_Pnt2d uv1, uv2; - Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l ); - if ( pcurve.IsNull() ) continue; - uv1 = pcurve->Value( f ); - edge.Reverse(); - pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l ); - if ( pcurve.IsNull() ) continue; - uv2 = pcurve->Value( f ); - int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2; - // assure uv1 < uv2 - if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) { - gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp; - } - // get nodes on seam and its vertices - list< const SMDS_MeshNode* > seamNodes; - SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes(); - while ( nSeamIt->more() ) { - const SMDS_MeshNode* node = nSeamIt->next(); - if ( !isQuadratic || !IsMedium( node )) - seamNodes.push_back( node ); - } - TopExp_Explorer vExp( edge, TopAbs_VERTEX ); - for ( ; vExp.More(); vExp.Next() ) { - sm = aMesh->MeshElements( vExp.Current() ); - if ( sm ) { - nSeamIt = sm->GetNodes(); - while ( nSeamIt->more() ) - seamNodes.push_back( nSeamIt->next() ); - } + // search elements to fuse starting from startElem or links of elements + // fused earlyer - startLinks + list< SMESH_TLink > startLinks; + while ( startElem || !startLinks.empty() ) { + while ( !startElem && !startLinks.empty() ) { + // Get an element to start, by a link + SMESH_TLink linkId = startLinks.front(); + startLinks.pop_front(); + itLE = mapLi_listEl.find( linkId ); + if ( itLE != mapLi_listEl.end() ) { + list< const SMDS_MeshElement* > & listElem = (*itLE).second; + list< const SMDS_MeshElement* >::iterator itE = listElem.begin(); + for ( ; itE != listElem.end() ; itE++ ) + if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() ) + startElem = (*itE); + mapLi_listEl.erase( itLE ); } - // loop on nodes on seam - list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin(); - for ( ; noSeIt != seamNodes.end(); ++noSeIt ) { - const SMDS_MeshNode* nSeam = *noSeIt; - map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam ); - if ( n_uv == uvMap.end() ) + } + + if ( startElem ) { + // Get candidates to be fused + const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0; + const SMESH_TLink *link12, *link13; + startElem = 0; + ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() ); + set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ]; + ASSERT( !setLi.empty() ); + set< SMESH_TLink >::iterator itLi; + for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ ) + { + const SMESH_TLink & link = (*itLi); + itLE = mapLi_listEl.find( link ); + if ( itLE == mapLi_listEl.end() ) continue; - // set the first UV - n_uv->second->SetCoord( iPar, uv1.Coord( iPar )); - // set the second UV - listUV.push_back( *n_uv->second ); - listUV.back().SetCoord( iPar, uv2.Coord( iPar )); - if ( uvMap2.empty() ) - uvMap2 = uvMap; // copy the uvMap contents - uvMap2[ nSeam ] = &listUV.back(); - // collect movable nodes linked to ones on seam in nodesNearSeam - SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face); - while ( eIt->more() ) { - const SMDS_MeshElement* e = eIt->next(); - int nbUseMap1 = 0, nbUseMap2 = 0; - SMDS_ElemIteratorPtr nIt = e->nodesIterator(); - int nn = 0, nbn = e->NbNodes(); - if(e->IsQuadratic()) nbn = nbn/2; - while ( nn++ < nbn ) - { - const SMDS_MeshNode* n = - static_cast( nIt->next() ); - if (n == nSeam || - setMovableNodes.find( n ) == setMovableNodes.end() ) - continue; - // add only nodes being closer to uv2 than to uv1 - gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ), - 0.5 * ( n->Y() + nSeam->Y() ), - 0.5 * ( n->Z() + nSeam->Z() )); - gp_XY uv; - getClosestUV( projector, pMid, uv ); - if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) { - nodesNearSeam.insert( n ); - nbUseMap2++; - } - else - nbUseMap1++; - } - // for centroidalSmooth all element nodes must - // be on one side of a seam - if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) { - SMDS_ElemIteratorPtr nIt = e->nodesIterator(); - nn = 0; - while ( nn++ < nbn ) { - const SMDS_MeshNode* n = - static_cast( nIt->next() ); - setMovableNodes.erase( n ); - } - } + const SMDS_MeshElement* elem = (*itLE).second.front(); + if ( elem == tr1 ) + elem = (*itLE).second.back(); + mapLi_listEl.erase( itLE ); + if ( mapEl_setLi.find( elem ) == mapEl_setLi.end()) + continue; + if ( tr2 ) { + tr3 = elem; + link13 = &link; + } + else { + tr2 = elem; + link12 = &link; } - } // loop on nodes on seam - } // loop on edge of a face - } // if ( !face.IsNull() ) - - if ( setMovableNodes.empty() ) { - MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!"); - continue; // goto next face - } - - // ------------- - // SMOOTHING // - // ------------- - - int it = -1; - double maxRatio = -1., maxDisplacement = -1.; - set::iterator nodeToMove; - for ( it = 0; it < theNbIterations; it++ ) { - maxDisplacement = 0.; - nodeToMove = setMovableNodes.begin(); - for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) { - const SMDS_MeshNode* node = (*nodeToMove); - gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() ); - - // smooth - bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() ); - if ( theSmoothMethod == LAPLACIAN ) - laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap ); - else - centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap ); - - // node displacement - gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() ); - Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus(); - if ( aDispl > maxDisplacement ) - maxDisplacement = aDispl; - } - // no node movement => exit - //if ( maxDisplacement < 1.e-16 ) { - if ( maxDisplacement < disttol ) { - MESSAGE("-- no node movement --"); - break; - } - // check elements quality - maxRatio = 0; - list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin(); - for ( ; elemIt != elemsOnFace.end(); ++elemIt ) { - const SMDS_MeshElement* elem = (*elemIt); - if ( !elem || elem->GetType() != SMDSAbs_Face ) - continue; - SMESH::Controls::TSequenceOfXYZ aPoints; - if ( aQualityFunc.GetPoints( elem, aPoints )) { - double aValue = aQualityFunc.GetValue( aPoints ); - if ( aValue > maxRatio ) - maxRatio = aValue; + // add other links of elem to list of links to re-start from + set< SMESH_TLink >& links = mapEl_setLi[ elem ]; + set< SMESH_TLink >::iterator it; + for ( it = links.begin(); it != links.end(); it++ ) { + const SMESH_TLink& link2 = (*it); + if ( link2 != link ) + startLinks.push_back( link2 ); + } } - } - if ( maxRatio <= theTgtAspectRatio ) { - MESSAGE("-- quality achived --"); - break; - } - if (it+1 == theNbIterations) { - MESSAGE("-- Iteration limit exceeded --"); - } - } // smoothing iterations - - MESSAGE(" Face id: " << *fId << - " Nb iterstions: " << it << - " Displacement: " << maxDisplacement << - " Aspect Ratio " << maxRatio); - - // --------------------------------------- - // new nodes positions are computed, - // record movement in DS and set new UV - // --------------------------------------- - nodeToMove = setMovableNodes.begin(); - for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) { - SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove); - aMesh->MoveNode( node, node->X(), node->Y(), node->Z() ); - map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node ); - if ( node_uv != uvMap.end() ) { - gp_XY* uv = node_uv->second; - node->SetPosition - ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() ))); - } - } - // move medium nodes of quadratic elements - if ( isQuadratic ) - { - SMESH_MesherHelper helper( *GetMesh() ); - if ( !face.IsNull() ) - helper.SetSubShape( face ); - list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin(); - for ( ; elemIt != elemsOnFace.end(); ++elemIt ) { - const SMDS_QuadraticFaceOfNodes* QF = - dynamic_cast (*elemIt); - if(QF) { - vector Ns; - Ns.reserve(QF->NbNodes()+1); - SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator(); - while ( anIter->more() ) - Ns.push_back( anIter->next() ); - Ns.push_back( Ns[0] ); - double x, y, z; - for(int i=0; iNbNodes(); i=i+2) { - if ( !surface.IsNull() ) { - gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] ); - gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] ); - gp_XY uv = ( uv1 + uv2 ) / 2.; - gp_Pnt xyz = surface->Value( uv.X(), uv.Y() ); - x = xyz.X(); y = xyz.Y(); z = xyz.Z(); - } - else { - x = (Ns[i]->X() + Ns[i+2]->X())/2; - y = (Ns[i]->Y() + Ns[i+2]->Y())/2; - z = (Ns[i]->Z() + Ns[i+2]->Z())/2; - } - if( fabs( Ns[i+1]->X() - x ) > disttol || - fabs( Ns[i+1]->Y() - y ) > disttol || - fabs( Ns[i+1]->Z() - z ) > disttol ) { - // we have to move i+1 node - aMesh->MoveNode( Ns[i+1], x, y, z ); - } - } + // Get nodes of possible quadrangles + const SMDS_MeshNode *n12 [4], *n13 [4]; + bool Ok12 = false, Ok13 = false; + const SMDS_MeshNode *linkNode1, *linkNode2; + if(tr2) { + linkNode1 = link12->first; + linkNode2 = link12->second; + if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 )) + Ok12 = true; + } + if(tr3) { + linkNode1 = link13->first; + linkNode2 = link13->second; + if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 )) + Ok13 = true; } - } - } - } // loop on face ids + // Choose a pair to fuse + if ( Ok12 && Ok13 ) { + SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] ); + SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] ); + double aBadRate12 = getBadRate( &quad12, theCrit ); + double aBadRate13 = getBadRate( &quad13, theCrit ); + if ( aBadRate13 < aBadRate12 ) + Ok12 = false; + else + Ok13 = false; + } -} - -//======================================================================= -//function : isReverse -//purpose : Return true if normal of prevNodes is not co-directied with -// gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]). -// iNotSame is where prevNodes and nextNodes are different -//======================================================================= + // Make quadrangles + // and remove fused elems and remove links from the maps + mapEl_setLi.erase( tr1 ); + if ( Ok12 ) + { + mapEl_setLi.erase( tr2 ); + mapLi_listEl.erase( *link12 ); + if ( tr1->NbNodes() == 3 ) + { + const SMDS_MeshElement* newElem = 0; + newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] ); + myLastCreatedElems.Append(newElem); + AddToSameGroups( newElem, tr1, aMesh ); + int aShapeId = tr1->getshapeId(); + if ( aShapeId ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + aMesh->RemoveElement( tr1 ); + aMesh->RemoveElement( tr2 ); + } + else { + vector< const SMDS_MeshNode* > N1; + vector< const SMDS_MeshNode* > N2; + getNodesFromTwoTria(tr1,tr2,N1,N2); + // now we receive following N1 and N2 (using numeration as in image in InverseDiag()) + // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6) + // i.e. first nodes from both arrays form a new diagonal + const SMDS_MeshNode* aNodes[8]; + aNodes[0] = N1[0]; + aNodes[1] = N1[1]; + aNodes[2] = N2[0]; + aNodes[3] = N2[1]; + aNodes[4] = N1[3]; + aNodes[5] = N2[5]; + aNodes[6] = N2[3]; + aNodes[7] = N1[5]; + const SMDS_MeshElement* newElem = 0; + if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic + newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3], + aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]); + else + newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3], + aNodes[4], aNodes[5], aNodes[6], aNodes[7]); + myLastCreatedElems.Append(newElem); + AddToSameGroups( newElem, tr1, aMesh ); + int aShapeId = tr1->getshapeId(); + if ( aShapeId ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + aMesh->RemoveElement( tr1 ); + aMesh->RemoveElement( tr2 ); + // remove middle node (9) + if ( N1[4]->NbInverseElements() == 0 ) + aMesh->RemoveNode( N1[4] ); + if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 ) + aMesh->RemoveNode( N1[6] ); + if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 ) + aMesh->RemoveNode( N2[6] ); + } + } + else if ( Ok13 ) + { + mapEl_setLi.erase( tr3 ); + mapLi_listEl.erase( *link13 ); + if ( tr1->NbNodes() == 3 ) { + const SMDS_MeshElement* newElem = 0; + newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] ); + myLastCreatedElems.Append(newElem); + AddToSameGroups( newElem, tr1, aMesh ); + int aShapeId = tr1->getshapeId(); + if ( aShapeId ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + aMesh->RemoveElement( tr1 ); + aMesh->RemoveElement( tr3 ); + } + else { + vector< const SMDS_MeshNode* > N1; + vector< const SMDS_MeshNode* > N2; + getNodesFromTwoTria(tr1,tr3,N1,N2); + // now we receive following N1 and N2 (using numeration as above image) + // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6) + // i.e. first nodes from both arrays form a new diagonal + const SMDS_MeshNode* aNodes[8]; + aNodes[0] = N1[0]; + aNodes[1] = N1[1]; + aNodes[2] = N2[0]; + aNodes[3] = N2[1]; + aNodes[4] = N1[3]; + aNodes[5] = N2[5]; + aNodes[6] = N2[3]; + aNodes[7] = N1[5]; + const SMDS_MeshElement* newElem = 0; + if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic + newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3], + aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]); + else + newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3], + aNodes[4], aNodes[5], aNodes[6], aNodes[7]); + myLastCreatedElems.Append(newElem); + AddToSameGroups( newElem, tr1, aMesh ); + int aShapeId = tr1->getshapeId(); + if ( aShapeId ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + aMesh->RemoveElement( tr1 ); + aMesh->RemoveElement( tr3 ); + // remove middle node (9) + if ( N1[4]->NbInverseElements() == 0 ) + aMesh->RemoveNode( N1[4] ); + if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 ) + aMesh->RemoveNode( N1[6] ); + if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 ) + aMesh->RemoveNode( N2[6] ); + } + } -static bool isReverse(vector prevNodes, - vector nextNodes, - const int nbNodes, - const int iNotSame) -{ - int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 ); - int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 ); + // Next element to fuse: the rejected one + if ( tr3 ) + startElem = Ok12 ? tr3 : tr2; - const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ]; - const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ]; - const SMDS_MeshNode* nP = prevNodes[ iNotSame ]; - const SMDS_MeshNode* nN = nextNodes[ iNotSame ]; + } // if ( startElem ) + } // while ( startElem || !startLinks.empty() ) + } // while ( ! mapEl_setLi.empty() ) - gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() ); - gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() ); - gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() ); - gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() ); + return true; +} - gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN ); - return (vA ^ vB) * vN < 0.0; +/*#define DUMPSO(txt) \ +// cout << txt << endl; +//============================================================================= +// +// +// +//============================================================================= +static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] ) +{ +if ( i1 == i2 ) +return; +int tmp = idNodes[ i1 ]; +idNodes[ i1 ] = idNodes[ i2 ]; +idNodes[ i2 ] = tmp; +gp_Pnt Ptmp = P[ i1 ]; +P[ i1 ] = P[ i2 ]; +P[ i2 ] = Ptmp; +DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")"); } //======================================================================= -/*! - * \brief Create elements by sweeping an element - * \param elem - element to sweep - * \param newNodesItVec - nodes generated from each node of the element - * \param newElems - generated elements - * \param nbSteps - number of sweeping steps - * \param srcElements - to append elem for each generated element - */ +//function : SortQuadNodes +//purpose : Set 4 nodes of a quadrangle face in a good order. +// Swap 1<->2 or 2<->3 nodes and correspondingly return +// 1 or 2 else 0. //======================================================================= -void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, - const vector & newNodesItVec, - list& newElems, - const int nbSteps, - SMESH_SequenceOfElemPtr& srcElements) +int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh, +int idNodes[] ) { - SMESHDS_Mesh* aMesh = GetMeshDS(); + gp_Pnt P[4]; + int i; + for ( i = 0; i < 4; i++ ) { + const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] ); + if ( !n ) return 0; + P[ i ].SetCoord( n->X(), n->Y(), n->Z() ); + } - // Loop on elem nodes: - // find new nodes and detect same nodes indices - int nbNodes = elem->NbNodes(); - vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes ); - vector prevNod( nbNodes ); - vector nextNod( nbNodes ); - vector midlNod( nbNodes ); + gp_Vec V1(P[0], P[1]); + gp_Vec V2(P[0], P[2]); + gp_Vec V3(P[0], P[3]); - int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0; - vector sames(nbNodes); - vector issimple(nbNodes); + gp_Vec Cross1 = V1 ^ V2; + gp_Vec Cross2 = V2 ^ V3; - for ( iNode = 0; iNode < nbNodes; iNode++ ) { - TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ]; - const SMDS_MeshNode* node = nnIt->first; - const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second; - if ( listNewNodes.empty() ) - return; + i = 0; + if (Cross1.Dot(Cross2) < 0) + { + Cross1 = V2 ^ V1; + Cross2 = V1 ^ V3; - issimple[iNode] = (listNewNodes.size()==nbSteps); + if (Cross1.Dot(Cross2) < 0) + i = 2; + else + i = 1; + swap ( i, i + 1, idNodes, P ); - itNN[ iNode ] = listNewNodes.begin(); - prevNod[ iNode ] = node; - nextNod[ iNode ] = listNewNodes.front(); -//cout<<"iNode="<GetID() ); - return; + // for ( int ii = 0; ii < 4; ii++ ) { + // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] ); + // DUMPSO( ii << "(" << idNodes[ii] <<") : "<X()<<" "<Y()<<" "<Z()); + // } } + return i; +} -// if( elem->IsQuadratic() && nbSame>0 ) { -// MESSAGE( "Can not rotate quadratic element " << elem->GetID() ); -// return; -// } +//======================================================================= +//function : SortHexaNodes +//purpose : Set 8 nodes of a hexahedron in a good order. +// Return success status +//======================================================================= - int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0; - if ( nbSame > 0 ) { - iBeforeSame = ( iSameNode == 0 ? nbNodes - 1 : iSameNode - 1 ); - iAfterSame = ( iSameNode + 1 == nbNodes ? 0 : iSameNode + 1 ); - iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 ); +bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh, + int idNodes[] ) +{ + gp_Pnt P[8]; + int i; + DUMPSO( "INPUT: ========================================"); + for ( i = 0; i < 8; i++ ) { + const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] ); + if ( !n ) return false; + P[ i ].SetCoord( n->X(), n->Y(), n->Z() ); + DUMPSO( i << "(" << idNodes[i] <<") : "<X()<<" "<Y()<<" "<Z()); } + DUMPSO( "========================================"); -//if(nbNodes==8) -//cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1] -// <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4] -// <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5] -// <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]< 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) { - //MESSAGE("Reversed elem " << elem ); - i0 = 2; - i2 = 0; - if ( nbSame > 0 ) - std::swap( iBeforeSame, iAfterSame ); - } + set faceNodes; // ids of bottom face nodes, to be found + set checkedId1; // ids of tried 2-nd nodes + Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane + const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane + int iMin, iLoop1 = 0; - // make new elements - for (int iStep = 0; iStep < nbSteps; iStep++ ) { - // get next nodes - for ( iNode = 0; iNode < nbNodes; iNode++ ) { - if(issimple[iNode]) { - nextNod[ iNode ] = *itNN[ iNode ]; - itNN[ iNode ]++; - } - else { - if( elem->GetType()==SMDSAbs_Node ) { - // we have to use two nodes - midlNod[ iNode ] = *itNN[ iNode ]; - itNN[ iNode ]++; - nextNod[ iNode ] = *itNN[ iNode ]; - itNN[ iNode ]++; - } - else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) { - // we have to use each second node - itNN[ iNode ]++; - nextNod[ iNode ] = *itNN[ iNode ]; - itNN[ iNode ]++; - } - else { - // we have to use two nodes - midlNod[ iNode ] = *itNN[ iNode ]; - itNN[ iNode ]++; - nextNod[ iNode ] = *itNN[ iNode ]; - itNN[ iNode ]++; - } - } - } - SMDS_MeshElement* aNewElem = 0; - if(!elem->IsPoly()) { - switch ( nbNodes ) { - case 0: - return; - case 1: { // NODE - if ( nbSame == 0 ) { - if(issimple[0]) - aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] ); - else - aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] ); - } - break; - } - case 2: { // EDGE - if ( nbSame == 0 ) - aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ], - nextNod[ 1 ], nextNod[ 0 ] ); - else - aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ], - nextNod[ iNotSameNode ] ); + // Loop to try the 2-nd nodes + + while ( leastDist > DBL_MIN && ++iLoop1 < 8 ) + { + // Find not checked 2-nd node + for ( i = 1; i < 8; i++ ) + if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) { + int id1 = idNodes[i]; + swap ( 1, i, idNodes, P ); + checkedId1.insert ( id1 ); break; } - case 3: { // TRIANGLE or quadratic edge - if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE + // Find the 3-d node so that 1-2-3 triangle to be on a hexa face, + // ie that all but meybe one (id3 which is on the same face) nodes + // lay on the same side from the triangle plane. - if ( nbSame == 0 ) // --- pentahedron - aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], - nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] ); + bool manyInPlane = false; // more than 4 nodes lay in plane + int iLoop2 = 0; + while ( ++iLoop2 < 6 ) { - else if ( nbSame == 1 ) // --- pyramid - aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ], - nextNod[ iAfterSame ], nextNod[ iBeforeSame ], - nextNod[ iSameNode ]); + // get 1-2-3 plane coeffs + Standard_Real A, B, C, D; + gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) ); + if ( N.SquareMagnitude() > gp::Resolution() ) + { + gp_Pln pln ( P[0], N ); + pln.Coefficients( A, B, C, D ); - else // 2 same nodes: --- tetrahedron - aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], - nextNod[ iNotSameNode ]); - } - else { // quadratic edge - if(nbSame==0) { // quadratic quadrangle - aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1], - midlNod[0], nextNod[2], midlNod[1], prevNod[2]); + // find the node (iMin) closest to pln + Standard_Real dist[ 8 ], minDist = DBL_MAX; + set idInPln; + for ( i = 3; i < 8; i++ ) { + dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D; + if ( fabs( dist[i] ) < minDist ) { + minDist = fabs( dist[i] ); + iMin = i; } - else if(nbSame==1) { // quadratic triangle - if(sames[0]==2) - return; // medium node on axis - else if(sames[0]==0) { - aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1], - nextNod[2], midlNod[1], prevNod[2]); - } - else { // sames[0]==1 - aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1], - midlNod[0], nextNod[2], prevNod[2]); + if ( fabs( dist[i] ) <= tol ) + idInPln.insert( idNodes[i] ); + } + + // there should not be more than 4 nodes in bottom plane + if ( idInPln.size() > 1 ) + { + DUMPSO( "### idInPln.size() = " << idInPln.size()); + // idInPlane does not contain the first 3 nodes + if ( manyInPlane || idInPln.size() == 5) + return false; // all nodes in one plane + manyInPlane = true; + + // set the 1-st node to be not in plane + for ( i = 3; i < 8; i++ ) { + if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) { + DUMPSO( "### Reset 0-th node"); + swap( 0, i, idNodes, P ); + break; } } - else - return; + + // reset to re-check second nodes + leastDist = DBL_MAX; + faceNodes.clear(); + checkedId1.clear(); + iLoop1 = 0; + break; // from iLoop2; } - break; - } - case 4: { // QUADRANGLE - if ( nbSame == 0 ) // --- hexahedron - aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ], - nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]); + // check that the other 4 nodes are on the same side + bool sameSide = true; + bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.; + for ( i = 3; sameSide && i < 8; i++ ) { + if ( i != iMin ) + sameSide = ( isNeg == dist[i] <= 0.); + } - else if ( nbSame == 1 ) { // --- pyramid + pentahedron - aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ], - nextNod[ iAfterSame ], nextNod[ iBeforeSame ], - nextNod[ iSameNode ]); - newElems.push_back( aNewElem ); - aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ], - prevNod[ iBeforeSame ], nextNod[ iAfterSame ], - nextNod[ iOpposSame ], nextNod[ iBeforeSame ] ); - } - else if ( nbSame == 2 ) { // pentahedron - if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) - // iBeforeSame is same too - aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ], - nextNod[ iOpposSame ], prevNod[ iSameNode ], - prevNod[ iAfterSame ], nextNod[ iAfterSame ]); - else - // iAfterSame is same too - aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ], - nextNod[ iBeforeSame ], prevNod[ iAfterSame ], - prevNod[ iOpposSame ], nextNod[ iOpposSame ]); - } - break; - } - case 6: { // quadratic triangle - // create pentahedron with 15 nodes - if(i0>0) { // reversed case - aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1], - nextNod[0], nextNod[2], nextNod[1], - prevNod[5], prevNod[4], prevNod[3], - nextNod[5], nextNod[4], nextNod[3], - midlNod[0], midlNod[2], midlNod[1]); - } - else { // not reversed case - aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], - nextNod[0], nextNod[1], nextNod[2], - prevNod[3], prevNod[4], prevNod[5], - nextNod[3], nextNod[4], nextNod[5], - midlNod[0], midlNod[1], midlNod[2]); - } - break; - } - case 8: { // quadratic quadrangle - // create hexahedron with 20 nodes - if(i0>0) { // reversed case - aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1], - nextNod[0], nextNod[3], nextNod[2], nextNod[1], - prevNod[7], prevNod[6], prevNod[5], prevNod[4], - nextNod[7], nextNod[6], nextNod[5], nextNod[4], - midlNod[0], midlNod[3], midlNod[2], midlNod[1]); - } - else { // not reversed case - aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3], - nextNod[0], nextNod[1], nextNod[2], nextNod[3], - prevNod[4], prevNod[5], prevNod[6], prevNod[7], - nextNod[4], nextNod[5], nextNod[6], nextNod[7], - midlNod[0], midlNod[1], midlNod[2], midlNod[3]); + // keep best solution + if ( sameSide && minDist < leastDist ) { + leastDist = minDist; + faceNodes.clear(); + faceNodes.insert( idNodes[ 1 ] ); + faceNodes.insert( idNodes[ 2 ] ); + faceNodes.insert( idNodes[ iMin ] ); + DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ] + << " leastDist = " << leastDist); + if ( leastDist <= DBL_MIN ) + break; } - break; - } - default: { - // realized for extrusion only - //vector polyedre_nodes (nbNodes*2 + 4*nbNodes); - //vector quantities (nbNodes + 2); - - //quantities[0] = nbNodes; // bottom of prism - //for (int inode = 0; inode < nbNodes; inode++) { - // polyedre_nodes[inode] = prevNod[inode]; - //} - - //quantities[1] = nbNodes; // top of prism - //for (int inode = 0; inode < nbNodes; inode++) { - // polyedre_nodes[nbNodes + inode] = nextNod[inode]; - //} - - //for (int iface = 0; iface < nbNodes; iface++) { - // quantities[iface + 2] = 4; - // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1; - // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface]; - // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface]; - // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface]; - // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface]; - //} - //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities); - break; } + + // set next 3-d node to check + int iNext = 2 + iLoop2; + if ( iNext < 8 ) { + DUMPSO( "Try 2-nd"); + swap ( 2, iNext, idNodes, P ); } + } // while ( iLoop2 < 6 ) + } // iLoop1 + + if ( faceNodes.empty() ) return false; + + // Put the faceNodes in proper places + for ( i = 4; i < 8; i++ ) { + if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) { + // find a place to put + int iTo = 1; + while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() ) + iTo++; + DUMPSO( "Set faceNodes"); + swap ( iTo, i, idNodes, P ); } + } - if(!aNewElem) { - // realized for extrusion only - vector polyedre_nodes (nbNodes*2 + 4*nbNodes); - vector quantities (nbNodes + 2); - quantities[0] = nbNodes; // bottom of prism - for (int inode = 0; inode < nbNodes; inode++) { - polyedre_nodes[inode] = prevNod[inode]; - } + // Set nodes of the found bottom face in good order + DUMPSO( " Found bottom face: "); + i = SortQuadNodes( theMesh, idNodes ); + if ( i ) { + gp_Pnt Ptmp = P[ i ]; + P[ i ] = P[ i+1 ]; + P[ i+1 ] = Ptmp; + } + // else + // for ( int ii = 0; ii < 4; ii++ ) { + // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] ); + // DUMPSO( ii << "(" << idNodes[ii] <<") : "<X()<<" "<Y()<<" "<Z()); + // } - quantities[1] = nbNodes; // top of prism - for (int inode = 0; inode < nbNodes; inode++) { - polyedre_nodes[nbNodes + inode] = nextNod[inode]; - } + // Gravity center of the top and bottom faces + gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.; + gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.; - for (int iface = 0; iface < nbNodes; iface++) { - quantities[iface + 2] = 4; - int inextface = (iface == nbNodes - 1) ? 0 : iface + 1; - polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface]; - polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface]; - polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface]; - polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface]; - } - aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities); - } + // Get direction from the bottom to the top face + gp_Vec upDir ( aGCb, aGCt ); + Standard_Real upDirSize = upDir.Magnitude(); + if ( upDirSize <= gp::Resolution() ) return false; + upDir / upDirSize; - if ( aNewElem ) { - newElems.push_back( aNewElem ); - myLastCreatedElems.Append(aNewElem); - srcElements.Append( elem ); + // Assure that the bottom face normal points up + gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) ); + Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) ); + if ( Nb.Dot( upDir ) < 0 ) { + DUMPSO( "Reverse bottom face"); + swap( 1, 3, idNodes, P ); + } + + // Find 5-th node - the one closest to the 1-st among the last 4 nodes. + Standard_Real minDist = DBL_MAX; + for ( i = 4; i < 8; i++ ) { + // projection of P[i] to the plane defined by P[0] and upDir + gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] )))); + Standard_Real sqDist = P[0].SquareDistance( Pp ); + if ( sqDist < minDist ) { + minDist = sqDist; + iMin = i; } + } + DUMPSO( "Set 4-th"); + swap ( 4, iMin, idNodes, P ); - // set new prev nodes - for ( iNode = 0; iNode < nbNodes; iNode++ ) - prevNod[ iNode ] = nextNod[ iNode ]; + // Set nodes of the top face in good order + DUMPSO( "Sort top face"); + i = SortQuadNodes( theMesh, &idNodes[4] ); + if ( i ) { + i += 4; + gp_Pnt Ptmp = P[ i ]; + P[ i ] = P[ i+1 ]; + P[ i+1 ] = Ptmp; + } - } // for steps -} + // Assure that direction of the top face normal is from the bottom face + gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) ); + Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) ); + if ( Nt.Dot( upDir ) < 0 ) { + DUMPSO( "Reverse top face"); + swap( 5, 7, idNodes, P ); + } -//======================================================================= + // DUMPSO( "OUTPUT: ========================================"); + // for ( i = 0; i < 8; i++ ) { + // float *p = ugrid->GetPoint(idNodes[i]); + // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]); + // } + + return true; +}*/ + +//================================================================================ /*! - * \brief Create 1D and 2D elements around swept elements - * \param mapNewNodes - source nodes and ones generated from them - * \param newElemsMap - source elements and ones generated from them - * \param elemNewNodesMap - nodes generated from each node of each element - * \param elemSet - all swept elements - * \param nbSteps - number of sweeping steps - * \param srcElements - to append elem for each generated element + * \brief Return nodes linked to the given one + * \param theNode - the node + * \param linkedNodes - the found nodes + * \param type - the type of elements to check + * + * Medium nodes are ignored */ -//======================================================================= +//================================================================================ -void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, - TElemOfElemListMap & newElemsMap, - TElemOfVecOfNnlmiMap & elemNewNodesMap, - TIDSortedElemSet& elemSet, - const int nbSteps, - SMESH_SequenceOfElemPtr& srcElements) +void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode, + TIDSortedElemSet & linkedNodes, + SMDSAbs_ElementType type ) { - ASSERT( newElemsMap.size() == elemNewNodesMap.size() ); - SMESHDS_Mesh* aMesh = GetMeshDS(); - - // Find nodes belonging to only one initial element - sweep them to get edges. + SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type); + while ( elemIt->more() ) + { + const SMDS_MeshElement* elem = elemIt->next(); + if(elem->GetType() == SMDSAbs_0DElement) + continue; - TNodeOfNodeListMapItr nList = mapNewNodes.begin(); - for ( ; nList != mapNewNodes.end(); nList++ ) { - const SMDS_MeshNode* node = - static_cast( nList->first ); - SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(); - int nbInitElems = 0; - const SMDS_MeshElement* el = 0; - SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only - while ( eIt->more() && nbInitElems < 2 ) { - el = eIt->next(); - SMDSAbs_ElementType type = el->GetType(); - if ( type == SMDSAbs_Volume || type < highType ) continue; - if ( type > highType ) { - nbInitElems = 0; - highType = type; + SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); + if ( elem->GetType() == SMDSAbs_Volume ) + { + SMDS_VolumeTool vol( elem ); + while ( nodeIt->more() ) { + const SMDS_MeshNode* n = cast2Node( nodeIt->next() ); + if ( theNode != n && vol.IsLinked( theNode, n )) + linkedNodes.insert( n ); } - if ( elemSet.find(el) != elemSet.end() ) - nbInitElems++; } - if ( nbInitElems < 2 ) { - bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node); - if(!NotCreateEdge) { - vector newNodesItVec( 1, nList ); - list newEdges; - sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements ); + else + { + for ( int i = 0; nodeIt->more(); ++i ) { + const SMDS_MeshNode* n = cast2Node( nodeIt->next() ); + if ( n == theNode ) { + int iBefore = i - 1; + int iAfter = i + 1; + if ( elem->IsQuadratic() ) { + int nb = elem->NbNodes() / 2; + iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb ); + iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb ); + } + linkedNodes.insert( elem->GetNodeWrap( iAfter )); + linkedNodes.insert( elem->GetNodeWrap( iBefore )); + } } } } +} - // Make a ceiling for each element ie an equal element of last new nodes. - // Find free links of faces - make edges and sweep them into faces. - - TElemOfElemListMap::iterator itElem = newElemsMap.begin(); - TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin(); - for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) { - const SMDS_MeshElement* elem = itElem->first; - vector& vecNewNodes = itElemNodes->second; - - if ( elem->GetType() == SMDSAbs_Edge ) { - // create a ceiling edge - if (!elem->IsQuadratic()) { - if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(), - vecNewNodes[ 1 ]->second.back())) { - myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), - vecNewNodes[ 1 ]->second.back())); - srcElements.Append( myLastCreatedElems.Last() ); - } - } - else { - if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(), - vecNewNodes[ 1 ]->second.back(), - vecNewNodes[ 2 ]->second.back())) { - myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), - vecNewNodes[ 1 ]->second.back(), - vecNewNodes[ 2 ]->second.back())); - srcElements.Append( myLastCreatedElems.Last() ); - } - } - } - if ( elem->GetType() != SMDSAbs_Face ) - continue; +//======================================================================= +//function : laplacianSmooth +//purpose : pulls theNode toward the center of surrounding nodes directly +// connected to that node along an element edge +//======================================================================= - if(itElem->second.size()==0) continue; +void laplacianSmooth(const SMDS_MeshNode* theNode, + const Handle(Geom_Surface)& theSurface, + map< const SMDS_MeshNode*, gp_XY* >& theUVMap) +{ + // find surrounding nodes - bool hasFreeLinks = false; + TIDSortedElemSet nodeSet; + SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face ); - TIDSortedElemSet avoidSet; - avoidSet.insert( elem ); + // compute new coodrs - set aFaceLastNodes; - int iNode, nbNodes = vecNewNodes.size(); - if(!elem->IsQuadratic()) { - // loop on the face nodes - for ( iNode = 0; iNode < nbNodes; iNode++ ) { - aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() ); - // look for free links of the face - int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1; - const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first; - const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first; - // check if a link is free - if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) { - hasFreeLinks = true; - // make an edge and a ceiling for a new edge - if ( !aMesh->FindEdge( n1, n2 )) { - myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge - srcElements.Append( myLastCreatedElems.Last() ); - } - n1 = vecNewNodes[ iNode ]->second.back(); - n2 = vecNewNodes[ iNext ]->second.back(); - if ( !aMesh->FindEdge( n1, n2 )) { - myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge - srcElements.Append( myLastCreatedElems.Last() ); - } - } - } + double coord[] = { 0., 0., 0. }; + TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin(); + for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) { + const SMDS_MeshNode* node = cast2Node(*nodeSetIt); + if ( theSurface.IsNull() ) { // smooth in 3D + coord[0] += node->X(); + coord[1] += node->Y(); + coord[2] += node->Z(); } - else { // elem is quadratic face - int nbn = nbNodes/2; - for ( iNode = 0; iNode < nbn; iNode++ ) { - aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() ); - int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1; - const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first; - const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first; - // check if a link is free - if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) { - hasFreeLinks = true; - // make an edge and a ceiling for a new edge - // find medium node - const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first; - if ( !aMesh->FindEdge( n1, n2, n3 )) { - myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge - srcElements.Append( myLastCreatedElems.Last() ); - } - n1 = vecNewNodes[ iNode ]->second.back(); - n2 = vecNewNodes[ iNext ]->second.back(); - n3 = vecNewNodes[ iNode+nbn ]->second.back(); - if ( !aMesh->FindEdge( n1, n2, n3 )) { - myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge - srcElements.Append( myLastCreatedElems.Last() ); - } - } - } - for ( iNode = nbn; iNode < 2*nbn; iNode++ ) { - aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() ); - } + else { // smooth in 2D + ASSERT( theUVMap.find( node ) != theUVMap.end() ); + gp_XY* uv = theUVMap[ node ]; + coord[0] += uv->X(); + coord[1] += uv->Y(); } + } + int nbNodes = nodeSet.size(); + if ( !nbNodes ) + return; + coord[0] /= nbNodes; + coord[1] /= nbNodes; - // sweep free links into faces + if ( !theSurface.IsNull() ) { + ASSERT( theUVMap.find( theNode ) != theUVMap.end() ); + theUVMap[ theNode ]->SetCoord( coord[0], coord[1] ); + gp_Pnt p3d = theSurface->Value( coord[0], coord[1] ); + coord[0] = p3d.X(); + coord[1] = p3d.Y(); + coord[2] = p3d.Z(); + } + else + coord[2] /= nbNodes; - if ( hasFreeLinks ) { - list & newVolumes = itElem->second; - int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps; + // move node - set initNodeSet, topNodeSet, faceNodeSet; - for ( iNode = 0; iNode < nbNodes; iNode++ ) { - initNodeSet.insert( vecNewNodes[ iNode ]->first ); - topNodeSet .insert( vecNewNodes[ iNode ]->second.back() ); - } - for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) { - list::iterator v = newVolumes.begin(); - iVol = 0; - while ( iVol++ < volNb ) v++; - // find indices of free faces of a volume and their source edges - list< int > freeInd; - list< const SMDS_MeshElement* > srcEdges; // source edges of free faces - SMDS_VolumeTool vTool( *v ); - int iF, nbF = vTool.NbFaces(); - for ( iF = 0; iF < nbF; iF ++ ) { - if (vTool.IsFreeFace( iF ) && - vTool.GetFaceNodes( iF, faceNodeSet ) && - initNodeSet != faceNodeSet) // except an initial face - { - if ( nbSteps == 1 && faceNodeSet == topNodeSet ) - continue; - freeInd.push_back( iF ); - // find source edge of a free face iF - vector commonNodes; // shared by the initial and free faces - commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory - std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(), - initNodeSet.begin(), initNodeSet.end(), - commonNodes.begin()); - if ( (*v)->IsQuadratic() ) - srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2])); - else - srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1])); -#ifdef _DEBUG_ - if ( !srcEdges.back() ) - { - cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #" - << iF << " of volume #" << vTool.ID() << endl; - } -#endif - } - } - if ( freeInd.empty() ) - continue; + const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]); +} - // create faces for all steps; - // if such a face has been already created by sweep of edge, - // assure that its orientation is OK - for ( int iStep = 0; iStep < nbSteps; iStep++ ) { - vTool.Set( *v ); - vTool.SetExternalNormal(); - list< int >::iterator ind = freeInd.begin(); - list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin(); - for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces - { - const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind ); - int nbn = vTool.NbFaceNodes( *ind ); - switch ( nbn ) { - case 3: { ///// triangle - const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]); - if ( !f ) - myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] )); - else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) - aMesh->ChangeElementNodes( f, nodes, nbn ); - break; - } - case 4: { ///// quadrangle - const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]); - if ( !f ) - myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] )); - else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) - aMesh->ChangeElementNodes( f, nodes, nbn ); - break; - } - default: - if( (*v)->IsQuadratic() ) { - if(nbn==6) { /////// quadratic triangle - const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], - nodes[1], nodes[3], nodes[5] ); - if ( !f ) - myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], - nodes[1], nodes[3], nodes[5])); - else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) - aMesh->ChangeElementNodes( f, nodes, nbn ); - } - else { /////// quadratic quadrangle - const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6], - nodes[1], nodes[3], nodes[5], nodes[7] ); - if ( !f ) - myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6], - nodes[1], nodes[3], nodes[5], nodes[7])); - else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) - aMesh->ChangeElementNodes( f, nodes, nbn ); - } - } - else { //////// polygon - vector polygon_nodes ( nodes, &nodes[nbn] ); - const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes ); - if ( !f ) - myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes)); - else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) - aMesh->ChangeElementNodes( f, nodes, nbn ); - } - } - while ( srcElements.Length() < myLastCreatedElems.Length() ) - srcElements.Append( *srcEdge ); +//======================================================================= +//function : centroidalSmooth +//purpose : pulls theNode toward the element-area-weighted centroid of the +// surrounding elements +//======================================================================= - } // loop on free faces +void centroidalSmooth(const SMDS_MeshNode* theNode, + const Handle(Geom_Surface)& theSurface, + map< const SMDS_MeshNode*, gp_XY* >& theUVMap) +{ + gp_XYZ aNewXYZ(0.,0.,0.); + SMESH::Controls::Area anAreaFunc; + double totalArea = 0.; + int nbElems = 0; - // go to the next volume - iVol = 0; - while ( iVol++ < nbVolumesByStep ) v++; - } + // compute new XYZ + + SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face); + while ( elemIt->more() ) + { + const SMDS_MeshElement* elem = elemIt->next(); + nbElems++; + + gp_XYZ elemCenter(0.,0.,0.); + SMESH::Controls::TSequenceOfXYZ aNodePoints; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + int nn = elem->NbNodes(); + if(elem->IsQuadratic()) nn = nn/2; + int i=0; + //while ( itN->more() ) { + while ( i( itN->next() ); + i++; + gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() ); + aNodePoints.push_back( aP ); + if ( !theSurface.IsNull() ) { // smooth in 2D + ASSERT( theUVMap.find( aNode ) != theUVMap.end() ); + gp_XY* uv = theUVMap[ aNode ]; + aP.SetCoord( uv->X(), uv->Y(), 0. ); } - } // sweep free links into faces + elemCenter += aP; + } + double elemArea = anAreaFunc.GetValue( aNodePoints ); + totalArea += elemArea; + elemCenter /= nn; + aNewXYZ += elemCenter * elemArea; + } + aNewXYZ /= totalArea; + if ( !theSurface.IsNull() ) { + theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() ); + aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ(); + } - // Make a ceiling face with a normal external to a volume + // move node - SMDS_VolumeTool lastVol( itElem->second.back() ); + const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z()); +} - int iF = lastVol.GetFaceIndex( aFaceLastNodes ); - if ( iF >= 0 ) { - lastVol.SetExternalNormal(); - const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF ); - int nbn = lastVol.NbFaceNodes( iF ); - switch ( nbn ) { - case 3: - if (!hasFreeLinks || - !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ])) - myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] )); - break; - case 4: - if (!hasFreeLinks || - !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ])) - myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] )); - break; - default: - if(itElem->second.back()->IsQuadratic()) { - if(nbn==6) { - if (!hasFreeLinks || - !aMesh->FindFace(nodes[0], nodes[2], nodes[4], - nodes[1], nodes[3], nodes[5]) ) { - myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], - nodes[1], nodes[3], nodes[5])); - } - } - else { // nbn==8 - if (!hasFreeLinks || - !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6], - nodes[1], nodes[3], nodes[5], nodes[7]) ) - myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6], - nodes[1], nodes[3], nodes[5], nodes[7])); - } - } - else { - vector polygon_nodes ( nodes, &nodes[nbn] ); - if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes)) - myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes)); - } - } // switch +//======================================================================= +//function : getClosestUV +//purpose : return UV of closest projection +//======================================================================= - while ( srcElements.Length() < myLastCreatedElems.Length() ) - srcElements.Append( myLastCreatedElems.Last() ); - } - } // loop on swept elements +static bool getClosestUV (Extrema_GenExtPS& projector, + const gp_Pnt& point, + gp_XY & result) +{ + projector.Perform( point ); + if ( projector.IsDone() ) { + double u, v, minVal = DBL_MAX; + for ( int i = projector.NbExt(); i > 0; i-- ) + if ( projector.SquareDistance( i ) < minVal ) { + minVal = projector.SquareDistance( i ); + projector.Point( i ).Parameter( u, v ); + } + result.SetCoord( u, v ); + return true; + } + return false; } //======================================================================= -//function : RotationSweep -//purpose : +//function : Smooth +//purpose : Smooth theElements during theNbIterations or until a worst +// element has aspect ratio <= theTgtAspectRatio. +// Aspect Ratio varies in range [1.0, inf]. +// If theElements is empty, the whole mesh is smoothed. +// theFixedNodes contains additionally fixed nodes. Nodes built +// on edges and boundary nodes are always fixed. //======================================================================= -SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, - const gp_Ax1& theAxis, - const double theAngle, - const int theNbSteps, - const double theTol, - const bool theMakeGroups, - const bool theMakeWalls) +void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, + set & theFixedNodes, + const SmoothMethod theSmoothMethod, + const int theNbIterations, + double theTgtAspectRatio, + const bool the2D) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); - // source elements for each generated one - SMESH_SequenceOfElemPtr srcElems, srcNodes; + MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()"); - MESSAGE( "RotationSweep()"); - gp_Trsf aTrsf; - aTrsf.SetRotation( theAxis, theAngle ); - gp_Trsf aTrsf2; - aTrsf2.SetRotation( theAxis, theAngle/2. ); + if ( theTgtAspectRatio < 1.0 ) + theTgtAspectRatio = 1.0; - gp_Lin aLine( theAxis ); - double aSqTol = theTol * theTol; + const double disttol = 1.e-16; - SMESHDS_Mesh* aMesh = GetMeshDS(); + SMESH::Controls::AspectRatio aQualityFunc; - TNodeOfNodeListMap mapNewNodes; - TElemOfVecOfNnlmiMap mapElemNewNodes; - TElemOfElemListMap newElemsMap; + SMESHDS_Mesh* aMesh = GetMeshDS(); - // loop on theElems + if ( theElems.empty() ) { + // add all faces to theElems + SMDS_FaceIteratorPtr fIt = aMesh->facesIterator(); + while ( fIt->more() ) { + const SMDS_MeshElement* face = fIt->next(); + theElems.insert( theElems.end(), face ); + } + } + // get all face ids theElems are on + set< int > faceIdSet; TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() == SMDSAbs_Volume ) - continue; - vector & newNodesItVec = mapElemNewNodes[ elem ]; - newNodesItVec.reserve( elem->NbNodes() ); - - // loop on elem nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { - // check if a node has been already sweeped - const SMDS_MeshNode* node = cast2Node( itN->next() ); - TNodeOfNodeListMapItr nIt = mapNewNodes.find( node ); - if ( nIt == mapNewNodes.end() ) { - nIt = mapNewNodes.insert( make_pair( node, list() )).first; - list& listNewNodes = nIt->second; - - // make new nodes - gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); - double coord[3]; - aXYZ.Coord( coord[0], coord[1], coord[2] ); - bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol ); - const SMDS_MeshNode * newNode = node; - for ( int i = 0; i < theNbSteps; i++ ) { - if ( !isOnAxis ) { - if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { - // create two nodes - aTrsf2.Transforms( coord[0], coord[1], coord[2] ); - //aTrsf.Transforms( coord[0], coord[1], coord[2] ); - newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - aTrsf2.Transforms( coord[0], coord[1], coord[2] ); - //aTrsf.Transforms( coord[0], coord[1], coord[2] ); - } - else { - aTrsf.Transforms( coord[0], coord[1], coord[2] ); - } - newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - } - listNewNodes.push_back( newNode ); - } - } - else { - // if current elem is quadratic and current node is not medium - // we have to check - may be it is needed to insert additional nodes - if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { - list< const SMDS_MeshNode* > & listNewNodes = nIt->second; - if(listNewNodes.size()==theNbSteps) { - listNewNodes.clear(); - // make new nodes - gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); - double coord[3]; - aXYZ.Coord( coord[0], coord[1], coord[2] ); - const SMDS_MeshNode * newNode = node; - for(int i = 0; iAddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - listNewNodes.push_back( newNode ); - srcNodes.Append( node ); - aTrsf2.Transforms( coord[0], coord[1], coord[2] ); - newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - } - } - } + if ( the2D ) + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + int fId = FindShape( *itElem ); + // check that corresponding submesh exists and a shape is face + if (fId && + faceIdSet.find( fId ) == faceIdSet.end() && + aMesh->MeshElements( fId )) { + TopoDS_Shape F = aMesh->IndexToShape( fId ); + if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE ) + faceIdSet.insert( fId ); } - newNodesItVec.push_back( nIt ); } - // make new elements - sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems ); - } - - if ( theMakeWalls ) - makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems ); - - PGroupIDs newGroupIDs; - if ( theMakeGroups ) - newGroupIDs = generateGroups( srcNodes, srcElems, "rotated"); - - return newGroupIDs; -} - + faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face -//======================================================================= -//function : CreateNode -//purpose : -//======================================================================= -const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x, - const double y, - const double z, - const double tolnode, - SMESH_SequenceOfNode& aNodes) -{ - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + // =============================================== + // smooth elements on each TopoDS_Face separately + // =============================================== - gp_Pnt P1(x,y,z); - SMESHDS_Mesh * aMesh = myMesh->GetMeshDS(); + SMESH_MesherHelper helper( *GetMesh() ); - // try to search in sequence of existing nodes - // if aNodes.Length()>0 we 'nave to use given sequence - // else - use all nodes of mesh - if(aNodes.Length()>0) { - int i; - for(i=1; i<=aNodes.Length(); i++) { - gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z()); - if(P1.Distance(P2)nodesIterator(); - while(itn->more()) { - const SMDS_MeshNode* aN = static_cast (itn->next()); - gp_Pnt P2(aN->X(),aN->Y(),aN->Z()); - if(P1.Distance(P2)::reverse_iterator fId = faceIdSet.rbegin(); // treat 0 fId at the end + for ( ; fId != faceIdSet.rend(); ++fId ) + { + // get face surface and submesh + Handle(Geom_Surface) surface; + SMESHDS_SubMesh* faceSubMesh = 0; + TopoDS_Face face; + double fToler2 = 0, f,l; + double u1 = 0, u2 = 0, v1 = 0, v2 = 0; + bool isUPeriodic = false, isVPeriodic = false; + if ( *fId ) + { + face = TopoDS::Face( aMesh->IndexToShape( *fId )); + surface = BRep_Tool::Surface( face ); + faceSubMesh = aMesh->MeshElements( *fId ); + fToler2 = BRep_Tool::Tolerance( face ); + fToler2 *= fToler2 * 10.; + isUPeriodic = surface->IsUPeriodic(); + if ( isUPeriodic ) + surface->UPeriod(); + isVPeriodic = surface->IsVPeriodic(); + if ( isVPeriodic ) + surface->VPeriod(); + surface->Bounds( u1, u2, v1, v2 ); + helper.SetSubShape( face ); } - } - - // create new node and return it - const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z); - myLastCreatedNodes.Append(NewNode); - return NewNode; -} + // --------------------------------------------------------- + // for elements on a face, find movable and fixed nodes and + // compute UV for them + // --------------------------------------------------------- + bool checkBoundaryNodes = false; + bool isQuadratic = false; + set setMovableNodes; + map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2; + list< gp_XY > listUV; // uvs the 2 uvMaps refer to + list< const SMDS_MeshElement* > elemsOnFace; + Extrema_GenExtPS projector; + GeomAdaptor_Surface surfAdaptor; + if ( !surface.IsNull() ) { + surfAdaptor.Load( surface ); + projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 ); + } + int nbElemOnFace = 0; + itElem = theElems.begin(); + // loop on not yet smoothed elements: look for elems on a face + while ( itElem != theElems.end() ) + { + if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() ) + break; // all elements found -//======================================================================= -//function : ExtrusionSweep -//purpose : -//======================================================================= + const SMDS_MeshElement* elem = *itElem; + if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 || + ( faceSubMesh && !faceSubMesh->Contains( elem ))) { + ++itElem; + continue; + } + elemsOnFace.push_back( elem ); + theElems.erase( itElem++ ); + nbElemOnFace++; -SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, - const gp_Vec& theStep, - const int theNbSteps, - TElemOfElemListMap& newElemsMap, - const bool theMakeGroups, - const int theFlags, - const double theTolerance) -{ - ExtrusParam aParams; - aParams.myDir = gp_Dir(theStep); - aParams.myNodes.Clear(); - aParams.mySteps = new TColStd_HSequenceOfReal; - int i; - for(i=1; i<=theNbSteps; i++) - aParams.mySteps->Append(theStep.Magnitude()); + if ( !isQuadratic ) + isQuadratic = elem->IsQuadratic(); - return - ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance); -} + // get movable nodes of elem + const SMDS_MeshNode* node; + SMDS_TypeOfPosition posType; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + int nn = 0, nbn = elem->NbNodes(); + if(elem->IsQuadratic()) + nbn = nbn/2; + while ( nn++ < nbn ) { + node = static_cast( itN->next() ); + const SMDS_PositionPtr& pos = node->GetPosition(); + posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE; + if (posType != SMDS_TOP_EDGE && + posType != SMDS_TOP_VERTEX && + theFixedNodes.find( node ) == theFixedNodes.end()) + { + // check if all faces around the node are on faceSubMesh + // because a node on edge may be bound to face + SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face); + bool all = true; + if ( faceSubMesh ) { + while ( eIt->more() && all ) { + const SMDS_MeshElement* e = eIt->next(); + all = faceSubMesh->Contains( e ); + } + } + if ( all ) + setMovableNodes.insert( node ); + else + checkBoundaryNodes = true; + } + if ( posType == SMDS_TOP_3DSPACE ) + checkBoundaryNodes = true; + } + if ( surface.IsNull() ) + continue; -//======================================================================= -//function : ExtrusionSweep -//purpose : -//======================================================================= + // get nodes to check UV + list< const SMDS_MeshNode* > uvCheckNodes; + const SMDS_MeshNode* nodeInFace = 0; + itN = elem->nodesIterator(); + nn = 0; nbn = elem->NbNodes(); + if(elem->IsQuadratic()) + nbn = nbn/2; + while ( nn++ < nbn ) { + node = static_cast( itN->next() ); + if ( node->GetPosition()->GetDim() == 2 ) + nodeInFace = node; + if ( uvMap.find( node ) == uvMap.end() ) + uvCheckNodes.push_back( node ); + // add nodes of elems sharing node + // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face); + // while ( eIt->more() ) { + // const SMDS_MeshElement* e = eIt->next(); + // if ( e != elem ) { + // SMDS_ElemIteratorPtr nIt = e->nodesIterator(); + // while ( nIt->more() ) { + // const SMDS_MeshNode* n = + // static_cast( nIt->next() ); + // if ( uvMap.find( n ) == uvMap.end() ) + // uvCheckNodes.push_back( n ); + // } + // } + // } + } + // check UV on face + list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin(); + for ( ; n != uvCheckNodes.end(); ++n ) { + node = *n; + gp_XY uv( 0, 0 ); + const SMDS_PositionPtr& pos = node->GetPosition(); + posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE; + // get existing UV + if ( pos ) + { + bool toCheck = true; + uv = helper.GetNodeUV( face, node, nodeInFace, &toCheck ); + } + // compute not existing UV + bool project = ( posType == SMDS_TOP_3DSPACE ); + // double dist1 = DBL_MAX, dist2 = 0; + // if ( posType != SMDS_TOP_3DSPACE ) { + // dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() )); + // project = dist1 > fToler2; + // } + if ( project ) { // compute new UV + gp_XY newUV; + gp_Pnt pNode = SMESH_TNodeXYZ( node ); + if ( !getClosestUV( projector, pNode, newUV )) { + MESSAGE("Node Projection Failed " << node); + } + else { + if ( isUPeriodic ) + newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 )); + if ( isVPeriodic ) + newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 )); + // check new UV + // if ( posType != SMDS_TOP_3DSPACE ) + // dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() )); + // if ( dist2 < dist1 ) + uv = newUV; + } + } + // store UV in the map + listUV.push_back( uv ); + uvMap.insert( make_pair( node, &listUV.back() )); + } + } // loop on not yet smoothed elements -SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, - ExtrusParam& theParams, - TElemOfElemListMap& newElemsMap, - const bool theMakeGroups, - const int theFlags, - const double theTolerance) -{ - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() ) + checkBoundaryNodes = true; - // source elements for each generated one - SMESH_SequenceOfElemPtr srcElems, srcNodes; + // fix nodes on mesh boundary - SMESHDS_Mesh* aMesh = GetMeshDS(); + if ( checkBoundaryNodes ) { + map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace + map< SMESH_TLink, int >::iterator link_nb; + // put all elements links to linkNbMap + list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin(); + for ( ; elemIt != elemsOnFace.end(); ++elemIt ) { + const SMDS_MeshElement* elem = (*elemIt); + int nbn = elem->NbCornerNodes(); + // loop on elem links: insert them in linkNbMap + for ( int iN = 0; iN < nbn; ++iN ) { + const SMDS_MeshNode* n1 = elem->GetNode( iN ); + const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn); + SMESH_TLink link( n1, n2 ); + link_nb = linkNbMap.insert( make_pair( link, 0 )).first; + link_nb->second++; + } + } + // remove nodes that are in links encountered only once from setMovableNodes + for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) { + if ( link_nb->second == 1 ) { + setMovableNodes.erase( link_nb->first.node1() ); + setMovableNodes.erase( link_nb->first.node2() ); + } + } + } - int nbsteps = theParams.mySteps->Length(); + // ----------------------------------------------------- + // for nodes on seam edge, compute one more UV ( uvMap2 ); + // find movable nodes linked to nodes on seam and which + // are to be smoothed using the second UV ( uvMap2 ) + // ----------------------------------------------------- - TNodeOfNodeListMap mapNewNodes; - //TNodeOfNodeVecMap mapNewNodes; - TElemOfVecOfNnlmiMap mapElemNewNodes; - //TElemOfVecOfMapNodesMap mapElemNewNodes; - - // loop on theElems - TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { - // check element type - const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() == SMDSAbs_Volume ) - continue; - - vector & newNodesItVec = mapElemNewNodes[ elem ]; - //vector & newNodesItVec = mapElemNewNodes[ elem ]; - newNodesItVec.reserve( elem->NbNodes() ); + set nodesNearSeam; // to smooth using uvMap2 + if ( !surface.IsNull() ) { + TopExp_Explorer eExp( face, TopAbs_EDGE ); + for ( ; eExp.More(); eExp.Next() ) { + TopoDS_Edge edge = TopoDS::Edge( eExp.Current() ); + if ( !BRep_Tool::IsClosed( edge, face )) + continue; + SMESHDS_SubMesh* sm = aMesh->MeshElements( edge ); + if ( !sm ) continue; + // find out which parameter varies for a node on seam + double f,l; + gp_Pnt2d uv1, uv2; + Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l ); + if ( pcurve.IsNull() ) continue; + uv1 = pcurve->Value( f ); + edge.Reverse(); + pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l ); + if ( pcurve.IsNull() ) continue; + uv2 = pcurve->Value( f ); + int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2; + // assure uv1 < uv2 + if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) + std::swap( uv1, uv2 ); + // get nodes on seam and its vertices + list< const SMDS_MeshNode* > seamNodes; + SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes(); + while ( nSeamIt->more() ) { + const SMDS_MeshNode* node = nSeamIt->next(); + if ( !isQuadratic || !IsMedium( node )) + seamNodes.push_back( node ); + } + TopExp_Explorer vExp( edge, TopAbs_VERTEX ); + for ( ; vExp.More(); vExp.Next() ) { + sm = aMesh->MeshElements( vExp.Current() ); + if ( sm ) { + nSeamIt = sm->GetNodes(); + while ( nSeamIt->more() ) + seamNodes.push_back( nSeamIt->next() ); + } + } + // loop on nodes on seam + list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin(); + for ( ; noSeIt != seamNodes.end(); ++noSeIt ) { + const SMDS_MeshNode* nSeam = *noSeIt; + map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam ); + if ( n_uv == uvMap.end() ) + continue; + // set the first UV + n_uv->second->SetCoord( iPar, uv1.Coord( iPar )); + // set the second UV + listUV.push_back( *n_uv->second ); + listUV.back().SetCoord( iPar, uv2.Coord( iPar )); + if ( uvMap2.empty() ) + uvMap2 = uvMap; // copy the uvMap contents + uvMap2[ nSeam ] = &listUV.back(); - // loop on elem nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { - // check if a node has been already sweeped - const SMDS_MeshNode* node = cast2Node( itN->next() ); - TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node ); - //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node ); - if ( nIt == mapNewNodes.end() ) { - nIt = mapNewNodes.insert( make_pair( node, list() )).first; - //nIt = mapNewNodes.insert( make_pair( node, vector() )).first; - list& listNewNodes = nIt->second; - //vector& vecNewNodes = nIt->second; - //vecNewNodes.reserve(nbsteps); - - // make new nodes - double coord[] = { node->X(), node->Y(), node->Z() }; - //int nbsteps = theParams.mySteps->Length(); - for ( int i = 0; i < nbsteps; i++ ) { - if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { - // create additional node - double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.; - double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.; - double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.; - if( theFlags & EXTRUSION_FLAG_SEW ) { - const SMDS_MeshNode * newNode = CreateNode(x, y, z, - theTolerance, theParams.myNodes); - listNewNodes.push_back( newNode ); + // collect movable nodes linked to ones on seam in nodesNearSeam + SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face); + while ( eIt->more() ) { + const SMDS_MeshElement* e = eIt->next(); + int nbUseMap1 = 0, nbUseMap2 = 0; + SMDS_ElemIteratorPtr nIt = e->nodesIterator(); + int nn = 0, nbn = e->NbNodes(); + if(e->IsQuadratic()) nbn = nbn/2; + while ( nn++ < nbn ) + { + const SMDS_MeshNode* n = + static_cast( nIt->next() ); + if (n == nSeam || + setMovableNodes.find( n ) == setMovableNodes.end() ) + continue; + // add only nodes being closer to uv2 than to uv1 + // gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ), + // 0.5 * ( n->Y() + nSeam->Y() ), + // 0.5 * ( n->Z() + nSeam->Z() )); + // gp_XY uv; + // getClosestUV( projector, pMid, uv ); + double x = uvMap[ n ]->Coord( iPar ); + if ( Abs( uv1.Coord( iPar ) - x ) > + Abs( uv2.Coord( iPar ) - x )) { + nodesNearSeam.insert( n ); + nbUseMap2++; + } + else + nbUseMap1++; } - else { - const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); + // for centroidalSmooth all element nodes must + // be on one side of a seam + if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) { + SMDS_ElemIteratorPtr nIt = e->nodesIterator(); + nn = 0; + while ( nn++ < nbn ) { + const SMDS_MeshNode* n = + static_cast( nIt->next() ); + setMovableNodes.erase( n ); + } } } - //aTrsf.Transforms( coord[0], coord[1], coord[2] ); - coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1); - coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1); - coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1); - if( theFlags & EXTRUSION_FLAG_SEW ) { - const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2], - theTolerance, theParams.myNodes); - listNewNodes.push_back( newNode ); - //vecNewNodes[i]=newNode; - } - else { - const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - //vecNewNodes[i]=newNode; - } + } // loop on nodes on seam + } // loop on edge of a face + } // if ( !face.IsNull() ) + + if ( setMovableNodes.empty() ) { + MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!"); + continue; // goto next face + } + + // ------------- + // SMOOTHING // + // ------------- + + int it = -1; + double maxRatio = -1., maxDisplacement = -1.; + set::iterator nodeToMove; + for ( it = 0; it < theNbIterations; it++ ) { + maxDisplacement = 0.; + nodeToMove = setMovableNodes.begin(); + for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) { + const SMDS_MeshNode* node = (*nodeToMove); + gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() ); + + // smooth + bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() ); + if ( theSmoothMethod == LAPLACIAN ) + laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap ); + else + centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap ); + + // node displacement + gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() ); + Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus(); + if ( aDispl > maxDisplacement ) + maxDisplacement = aDispl; + } + // no node movement => exit + //if ( maxDisplacement < 1.e-16 ) { + if ( maxDisplacement < disttol ) { + MESSAGE("-- no node movement --"); + break; + } + + // check elements quality + maxRatio = 0; + list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin(); + for ( ; elemIt != elemsOnFace.end(); ++elemIt ) { + const SMDS_MeshElement* elem = (*elemIt); + if ( !elem || elem->GetType() != SMDSAbs_Face ) + continue; + SMESH::Controls::TSequenceOfXYZ aPoints; + if ( aQualityFunc.GetPoints( elem, aPoints )) { + double aValue = aQualityFunc.GetValue( aPoints ); + if ( aValue > maxRatio ) + maxRatio = aValue; } } - else { - // if current elem is quadratic and current node is not medium - // we have to check - may be it is needed to insert additional nodes - if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { - list< const SMDS_MeshNode* > & listNewNodes = nIt->second; - if(listNewNodes.size()==nbsteps) { - listNewNodes.clear(); - double coord[] = { node->X(), node->Y(), node->Z() }; - for ( int i = 0; i < nbsteps; i++ ) { - double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1); - double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1); - double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1); - if( theFlags & EXTRUSION_FLAG_SEW ) { - const SMDS_MeshNode * newNode = CreateNode(x, y, z, - theTolerance, theParams.myNodes); - listNewNodes.push_back( newNode ); - } - else { - const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - } - coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1); - coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1); - coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1); - if( theFlags & EXTRUSION_FLAG_SEW ) { - const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2], - theTolerance, theParams.myNodes); - listNewNodes.push_back( newNode ); - } - else { - const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - } + if ( maxRatio <= theTgtAspectRatio ) { + MESSAGE("-- quality achived --"); + break; + } + if (it+1 == theNbIterations) { + MESSAGE("-- Iteration limit exceeded --"); + } + } // smoothing iterations + + MESSAGE(" Face id: " << *fId << + " Nb iterstions: " << it << + " Displacement: " << maxDisplacement << + " Aspect Ratio " << maxRatio); + + // --------------------------------------- + // new nodes positions are computed, + // record movement in DS and set new UV + // --------------------------------------- + nodeToMove = setMovableNodes.begin(); + for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) { + SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove); + aMesh->MoveNode( node, node->X(), node->Y(), node->Z() ); + map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node ); + if ( node_uv != uvMap.end() ) { + gp_XY* uv = node_uv->second; + node->SetPosition + ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() ))); + } + } + + // move medium nodes of quadratic elements + if ( isQuadratic ) + { + vector nodes; + bool checkUV; + list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin(); + for ( ; elemIt != elemsOnFace.end(); ++elemIt ) + { + const SMDS_MeshElement* QF = *elemIt; + if ( QF->IsQuadratic() ) + { + nodes.assign( SMDS_MeshElement::iterator( QF->interlacedNodesElemIterator() ), + SMDS_MeshElement::iterator() ); + nodes.push_back( nodes[0] ); + gp_Pnt xyz; + for (size_t i = 1; i < nodes.size(); i += 2 ) // i points to a medium node + { + if ( !surface.IsNull() ) + { + gp_XY uv1 = helper.GetNodeUV( face, nodes[i-1], nodes[i+1], &checkUV ); + gp_XY uv2 = helper.GetNodeUV( face, nodes[i+1], nodes[i-1], &checkUV ); + gp_XY uv = helper.GetMiddleUV( surface, uv1, uv2 ); + xyz = surface->Value( uv.X(), uv.Y() ); } + else { + xyz = 0.5 * ( SMESH_TNodeXYZ( nodes[i-1] ) + SMESH_TNodeXYZ( nodes[i+1] )); + } + if (( SMESH_TNodeXYZ( nodes[i] ) - xyz.XYZ() ).Modulus() > disttol ) + // we have to move a medium node + aMesh->MoveNode( nodes[i], xyz.X(), xyz.Y(), xyz.Z() ); } } } - newNodesItVec.push_back( nIt ); } - // make new elements - sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems ); - } - if( theFlags & EXTRUSION_FLAG_BOUNDARY ) { - makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems ); - } - PGroupIDs newGroupIDs; - if ( theMakeGroups ) - newGroupIDs = generateGroups( srcNodes, srcElems, "extruded"); + } // loop on face ids - return newGroupIDs; } +namespace +{ + //======================================================================= + //function : isReverse + //purpose : Return true if normal of prevNodes is not co-directied with + // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]). + // iNotSame is where prevNodes and nextNodes are different. + // If result is true then future volume orientation is OK + //======================================================================= + + bool isReverse(const SMDS_MeshElement* face, + const vector& prevNodes, + const vector& nextNodes, + const int iNotSame) + { -//======================================================================= -//class : SMESH_MeshEditor_PathPoint -//purpose : auxiliary class -//======================================================================= -class SMESH_MeshEditor_PathPoint { -public: - SMESH_MeshEditor_PathPoint() { - myPnt.SetCoord(99., 99., 99.); - myTgt.SetCoord(1.,0.,0.); - myAngle=0.; - myPrm=0.; - } - void SetPnt(const gp_Pnt& aP3D){ - myPnt=aP3D; - } - void SetTangent(const gp_Dir& aTgt){ - myTgt=aTgt; - } - void SetAngle(const double& aBeta){ - myAngle=aBeta; - } - void SetParameter(const double& aPrm){ - myPrm=aPrm; - } - const gp_Pnt& Pnt()const{ - return myPnt; - } - const gp_Dir& Tangent()const{ - return myTgt; - } - double Angle()const{ - return myAngle; - } - double Parameter()const{ - return myPrm; + SMESH_TNodeXYZ pP = prevNodes[ iNotSame ]; + SMESH_TNodeXYZ pN = nextNodes[ iNotSame ]; + gp_XYZ extrDir( pN - pP ), faceNorm; + SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false ); + + return faceNorm * extrDir < 0.0; } -protected: - gp_Pnt myPnt; - gp_Dir myTgt; - double myAngle; - double myPrm; -}; + //================================================================================ + /*! + * \brief Assure that theElemSets[0] holds elements, not nodes + */ + //================================================================================ + + void setElemsFirst( TIDSortedElemSet theElemSets[2] ) + { + if ( !theElemSets[0].empty() && + (*theElemSets[0].begin())->GetType() == SMDSAbs_Node ) + { + std::swap( theElemSets[0], theElemSets[1] ); + } + else if ( !theElemSets[1].empty() && + (*theElemSets[1].begin())->GetType() != SMDSAbs_Node ) + { + std::swap( theElemSets[0], theElemSets[1] ); + } + } +} //======================================================================= -//function : ExtrusionAlongTrack -//purpose : +/*! + * \brief Create elements by sweeping an element + * \param elem - element to sweep + * \param newNodesItVec - nodes generated from each node of the element + * \param newElems - generated elements + * \param nbSteps - number of sweeping steps + * \param srcElements - to append elem for each generated element + */ //======================================================================= -SMESH_MeshEditor::Extrusion_Error - SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, - SMESH_subMesh* theTrack, - const SMDS_MeshNode* theN1, - const bool theHasAngles, - list& theAngles, - const bool theHasRefPoint, - const gp_Pnt& theRefPoint, - const bool theMakeGroups) -{ - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); - - // source elements for each generated one - SMESH_SequenceOfElemPtr srcElems, srcNodes; - - int j, aNbTP, aNbE, aNb; - double aT1, aT2, aT, aAngle, aX, aY, aZ; - std::list aPrms; - std::list::iterator aItD; - TIDSortedElemSet::iterator itElem; - - Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2; - gp_Pnt aP3D, aV0; - gp_Vec aVec; - gp_XYZ aGC; - Handle(Geom_Curve) aC3D; - TopoDS_Edge aTrackEdge; - TopoDS_Vertex aV1, aV2; - - SMDS_ElemIteratorPtr aItE; - SMDS_NodeIteratorPtr aItN; - SMDSAbs_ElementType aTypeE; - - TNodeOfNodeListMap mapNewNodes; - TElemOfVecOfNnlmiMap mapElemNewNodes; - TElemOfElemListMap newElemsMap; - - aTolVec=1.e-7; - aTolVec2=aTolVec*aTolVec; - - // 1. Check data - aNbE = theElements.size(); - // nothing to do - if ( !aNbE ) - return EXTR_NO_ELEMENTS; - - // 1.1 Track Pattern - ASSERT( theTrack ); - - SMESHDS_SubMesh* pSubMeshDS=theTrack->GetSubMeshDS(); - - aItE = pSubMeshDS->GetElements(); - while ( aItE->more() ) { - const SMDS_MeshElement* pE = aItE->next(); - aTypeE = pE->GetType(); - // Pattern must contain links only - if ( aTypeE != SMDSAbs_Edge ) - return EXTR_PATH_NOT_EDGE; - } - - const TopoDS_Shape& aS = theTrack->GetSubShape(); - // Sub shape for the Pattern must be an Edge - if ( aS.ShapeType() != TopAbs_EDGE ) - return EXTR_BAD_PATH_SHAPE; - - aTrackEdge = TopoDS::Edge( aS ); - // the Edge must not be degenerated - if ( BRep_Tool::Degenerated( aTrackEdge ) ) - return EXTR_BAD_PATH_SHAPE; - TopExp::Vertices( aTrackEdge, aV1, aV2 ); - aT1=BRep_Tool::Parameter( aV1, aTrackEdge ); - aT2=BRep_Tool::Parameter( aV2, aTrackEdge ); - - aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes(); - const SMDS_MeshNode* aN1 = aItN->next(); +void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, + const vector & newNodesItVec, + list& newElems, + const int nbSteps, + SMESH_SequenceOfElemPtr& srcElements) +{ + //MESSAGE("sweepElement " << nbSteps); + SMESHDS_Mesh* aMesh = GetMeshDS(); - aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes(); - const SMDS_MeshNode* aN2 = aItN->next(); + const int nbNodes = elem->NbNodes(); + const int nbCorners = elem->NbCornerNodes(); + SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of + polyhedron creation !!! */ + // Loop on elem nodes: + // find new nodes and detect same nodes indices + vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes ); + vector prevNod( nbNodes ); + vector nextNod( nbNodes ); + vector midlNod( nbNodes ); - // starting node must be aN1 or aN2 - if ( !( aN1 == theN1 || aN2 == theN1 ) ) - return EXTR_BAD_STARTING_NODE; + int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0; + vector sames(nbNodes); + vector isSingleNode(nbNodes); - aNbTP = pSubMeshDS->NbNodes() + 2; + for ( iNode = 0; iNode < nbNodes; iNode++ ) { + TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ]; + const SMDS_MeshNode* node = nnIt->first; + const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second; + if ( listNewNodes.empty() ) + return; - // 1.2. Angles - vector aAngles( aNbTP ); + itNN [ iNode ] = listNewNodes.begin(); + prevNod[ iNode ] = node; + nextNod[ iNode ] = listNewNodes.front(); - for ( j=0; j < aNbTP; ++j ) { - aAngles[j] = 0.; - } + isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or + corner node of linear */ + if ( prevNod[ iNode ] != nextNod [ iNode ]) + nbDouble += !isSingleNode[iNode]; - if ( theHasAngles ) { - aItD = theAngles.begin(); - for ( j=1; (aItD != theAngles.end()) && (jGetNodes(); - while ( aItN->more() ) { - const SMDS_MeshNode* pNode = aItN->next(); - const SMDS_EdgePosition* pEPos = - static_cast( pNode->GetPosition().get() ); - aT = pEPos->GetUParameter(); - aPrms.push_back( aT ); + if ( nbSame == nbNodes || nbSame > 2) { + MESSAGE( " Too many same nodes of element " << elem->GetID() ); + return; } - // sort parameters - aPrms.sort(); - if ( aN1 == theN1 ) { - if ( aT1 > aT2 ) { - aPrms.reverse(); + if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode )) + { + // fix nodes order to have bottom normal external + if ( baseType == SMDSEntity_Polygon ) + { + std::reverse( itNN.begin(), itNN.end() ); + std::reverse( prevNod.begin(), prevNod.end() ); + std::reverse( midlNod.begin(), midlNod.end() ); + std::reverse( nextNod.begin(), nextNod.end() ); + std::reverse( isSingleNode.begin(), isSingleNode.end() ); + } + else + { + const vector& ind = SMDS_MeshCell::reverseSmdsOrder( baseType, nbNodes ); + SMDS_MeshCell::applyInterlace( ind, itNN ); + SMDS_MeshCell::applyInterlace( ind, prevNod ); + SMDS_MeshCell::applyInterlace( ind, nextNod ); + SMDS_MeshCell::applyInterlace( ind, midlNod ); + SMDS_MeshCell::applyInterlace( ind, isSingleNode ); + if ( nbSame > 0 ) + { + sames[nbSame] = iNotSameNode; + for ( int j = 0; j <= nbSame; ++j ) + for ( size_t i = 0; i < ind.size(); ++i ) + if ( ind[i] == sames[j] ) + { + sames[j] = i; + break; + } + iNotSameNode = sames[nbSame]; + } } } - else { - if ( aT2 > aT1 ) { - aPrms.reverse(); + else if ( elem->GetType() == SMDSAbs_Edge ) + { + // orient a new face same as adjacent one + int i1, i2; + const SMDS_MeshElement* e; + TIDSortedElemSet dummy; + if (( e = SMESH_MeshAlgos::FindFaceInSet( nextNod[0], prevNod[0], dummy,dummy, &i1, &i2 )) || + ( e = SMESH_MeshAlgos::FindFaceInSet( prevNod[1], nextNod[1], dummy,dummy, &i1, &i2 )) || + ( e = SMESH_MeshAlgos::FindFaceInSet( prevNod[0], prevNod[1], dummy,dummy, &i1, &i2 ))) + { + // there is an adjacent face, check order of nodes in it + bool sameOrder = ( Abs( i2 - i1 ) == 1 ) ? ( i2 > i1 ) : ( i2 < i1 ); + if ( sameOrder ) + { + std::swap( itNN[0], itNN[1] ); + std::swap( prevNod[0], prevNod[1] ); + std::swap( nextNod[0], nextNod[1] ); + + std::swap( isSingleNode[0], isSingleNode[1] ); + if ( nbSame > 0 ) + sames[0] = 1 - sames[0]; + iNotSameNode = 1 - iNotSameNode; + } } } - // 3. Path Points - SMESH_MeshEditor_PathPoint aPP; - vector aPPs( aNbTP ); - // - aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 ); - // - aItD = aPrms.begin(); - for ( j=0; aItD != aPrms.end(); ++aItD, ++j ) { - aT = *aItD; - aC3D->D1( aT, aP3D, aVec ); - aL2 = aVec.SquareMagnitude(); - if ( aL2 < aTolVec2 ) - return EXTR_CANT_GET_TANGENT; - - gp_Dir aTgt( aVec ); - aAngle = aAngles[j]; - - aPP.SetPnt( aP3D ); - aPP.SetTangent( aTgt ); - aPP.SetAngle( aAngle ); - aPP.SetParameter( aT ); - aPPs[j]=aPP; + int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0; + if ( nbSame > 0 ) { + iSameNode = sames[ nbSame-1 ]; + iBeforeSame = ( iSameNode + nbCorners - 1 ) % nbCorners; + iAfterSame = ( iSameNode + 1 ) % nbCorners; + iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 ); } - // 3. Center of rotation aV0 - aV0 = theRefPoint; - if ( !theHasRefPoint ) { - aNb = 0; - aGC.SetCoord( 0.,0.,0. ); - - itElem = theElements.begin(); - for ( ; itElem != theElements.end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; - - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { - const SMDS_MeshNode* node = static_cast( itN->next() ); - aX = node->X(); - aY = node->Y(); - aZ = node->Z(); - - if ( mapNewNodes.find( node ) == mapNewNodes.end() ) { - list aLNx; - mapNewNodes[node] = aLNx; - // - gp_XYZ aXYZ( aX, aY, aZ ); - aGC += aXYZ; - ++aNb; - } - } - } - aGC /= aNb; - aV0.SetXYZ( aGC ); - } // if (!theHasRefPoint) { - mapNewNodes.clear(); - - // 4. Processing the elements - SMESHDS_Mesh* aMesh = GetMeshDS(); - - for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) { - // check element type - const SMDS_MeshElement* elem = *itElem; - aTypeE = elem->GetType(); - if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) ) - continue; - - vector & newNodesItVec = mapElemNewNodes[ elem ]; - newNodesItVec.reserve( elem->NbNodes() ); + if ( baseType == SMDSEntity_Polygon ) + { + if ( nbNodes == 3 ) baseType = SMDSEntity_Triangle; + else if ( nbNodes == 4 ) baseType = SMDSEntity_Quadrangle; + } + else if ( baseType == SMDSEntity_Quad_Polygon ) + { + if ( nbNodes == 6 ) baseType = SMDSEntity_Quad_Triangle; + else if ( nbNodes == 8 ) baseType = SMDSEntity_Quad_Quadrangle; + } - // loop on elem nodes - int nodeIndex = -1; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) + // make new elements + for (int iStep = 0; iStep < nbSteps; iStep++ ) + { + // get next nodes + for ( iNode = 0; iNode < nbNodes; iNode++ ) { - ++nodeIndex; - // check if a node has been already processed - const SMDS_MeshNode* node = - static_cast( itN->next() ); - TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node ); - if ( nIt == mapNewNodes.end() ) { - nIt = mapNewNodes.insert( make_pair( node, list() )).first; - list& listNewNodes = nIt->second; + midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++; + nextNod[ iNode ] = *itNN[ iNode ]++; + } - // make new nodes - aX = node->X(); aY = node->Y(); aZ = node->Z(); - - Standard_Real aAngle1x, aAngleT1T0, aTolAng; - gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x; - gp_Ax1 anAx1, anAxT1T0; - gp_Dir aDT1x, aDT0x, aDT1T0; - - aTolAng=1.e-4; - - aV0x = aV0; - aPN0.SetCoord(aX, aY, aZ); - - const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0]; - aP0x = aPP0.Pnt(); - aDT0x= aPP0.Tangent(); - - for ( j = 1; j < aNbTP; ++j ) { - const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j]; - aP1x = aPP1.Pnt(); - aDT1x = aPP1.Tangent(); - aAngle1x = aPP1.Angle(); - - gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0; - // Translation - gp_Vec aV01x( aP0x, aP1x ); - aTrsf.SetTranslation( aV01x ); - - // traslated point - aV1x = aV0x.Transformed( aTrsf ); - aPN1 = aPN0.Transformed( aTrsf ); - - // rotation 1 [ T1,T0 ] - aAngleT1T0=-aDT1x.Angle( aDT0x ); - if (fabs(aAngleT1T0) > aTolAng) { - aDT1T0=aDT1x^aDT0x; - anAxT1T0.SetLocation( aV1x ); - anAxT1T0.SetDirection( aDT1T0 ); - aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 ); - - aPN1 = aPN1.Transformed( aTrsfRotT1T0 ); - } - - // rotation 2 - if ( theHasAngles ) { - anAx1.SetLocation( aV1x ); - anAx1.SetDirection( aDT1x ); - aTrsfRot.SetRotation( anAx1, aAngle1x ); - - aPN1 = aPN1.Transformed( aTrsfRot ); - } - - // make new node - if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { - // create additional node - double x = ( aPN1.X() + aPN0.X() )/2.; - double y = ( aPN1.Y() + aPN0.Y() )/2.; - double z = ( aPN1.Z() + aPN0.Z() )/2.; - const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); + SMDS_MeshElement* aNewElem = 0; + /*if(!elem->IsPoly())*/ { + switch ( baseType ) { + case SMDSEntity_0D: + case SMDSEntity_Node: { // sweep NODE + if ( nbSame == 0 ) { + if ( isSingleNode[0] ) + aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] ); + else + aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] ); + } + else + return; + break; + } + case SMDSEntity_Edge: { // sweep EDGE + if ( nbDouble == 0 ) + { + if ( nbSame == 0 ) // ---> quadrangle + aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ], + nextNod[ 1 ], nextNod[ 0 ] ); + else // ---> triangle + aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ], + nextNod[ iNotSameNode ] ); + } + else // ---> polygon + { + vector poly_nodes; + poly_nodes.push_back( prevNod[0] ); + poly_nodes.push_back( prevNod[1] ); + if ( prevNod[1] != nextNod[1] ) + { + if ( midlNod[1]) poly_nodes.push_back( midlNod[1]); + poly_nodes.push_back( nextNod[1] ); } - aX = aPN1.X(); - aY = aPN1.Y(); - aZ = aPN1.Z(); - const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - - aPN0 = aPN1; - aP0x = aP1x; - aV0x = aV1x; - aDT0x = aDT1x; - } + if ( prevNod[0] != nextNod[0] ) + { + poly_nodes.push_back( nextNod[0] ); + if ( midlNod[0]) poly_nodes.push_back( midlNod[0]); + } + switch ( poly_nodes.size() ) { + case 3: + aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]); + break; + case 4: + aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], + poly_nodes[ 2 ], poly_nodes[ 3 ]); + break; + default: + aNewElem = aMesh->AddPolygonalFace (poly_nodes); + } + } + break; } + case SMDSEntity_Triangle: // TRIANGLE ---> + { + if ( nbDouble > 0 ) break; + if ( nbSame == 0 ) // ---> pentahedron + aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], + nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] ); + + else if ( nbSame == 1 ) // ---> pyramid + aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ], + nextNod[ iAfterSame ], nextNod[ iBeforeSame ], + nextNod[ iSameNode ]); - else { - // if current elem is quadratic and current node is not medium - // we have to check - may be it is needed to insert additional nodes - if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { - list< const SMDS_MeshNode* > & listNewNodes = nIt->second; - if(listNewNodes.size()==aNbTP-1) { - vector aNodes(2*(aNbTP-1)); - gp_XYZ P(node->X(), node->Y(), node->Z()); - list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin(); - int i; - for(i=0; iX() + P.X() )/2.; - double y = ( N->Y() + P.Y() )/2.; - double z = ( N->Z() + P.Z() )/2.; - const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z); - srcNodes.Append( node ); - myLastCreatedNodes.Append(newN); - aNodes[2*i] = newN; - aNodes[2*i+1] = N; - P = gp_XYZ(N->X(),N->Y(),N->Z()); + else // 2 same nodes: ---> tetrahedron + aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], + nextNod[ iNotSameNode ]); + break; + } + case SMDSEntity_Quad_Edge: // sweep quadratic EDGE ---> + { + if ( nbSame == 2 ) + return; + if ( nbDouble+nbSame == 2 ) + { + if(nbSame==0) { // ---> quadratic quadrangle + aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0], + prevNod[2], midlNod[1], nextNod[2], midlNod[0]); } - listNewNodes.clear(); - for(i=0; i<2*(aNbTP-1); i++) { - listNewNodes.push_back(aNodes[i]); + else { //(nbSame==1) // ---> quadratic triangle + if(sames[0]==2) { + return; // medium node on axis + } + else if(sames[0]==0) + aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], + prevNod[2], midlNod[1], nextNod[2] ); + else // sames[0]==1 + aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[0], + prevNod[2], nextNod[2], midlNod[0]); + } + } + else if ( nbDouble == 3 ) + { + if ( nbSame == 0 ) { // ---> bi-quadratic quadrangle + aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0], + prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]); } } + else + return; + break; } - } + case SMDSEntity_Quadrangle: { // sweep QUADRANGLE ---> + if ( nbDouble > 0 ) break; - newNodesItVec.push_back( nIt ); - } - // make new elements - //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], - // newNodesItVec[0]->second.size(), myLastCreatedElems ); - sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems ); - } + if ( nbSame == 0 ) // ---> hexahedron + aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ], + nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]); - makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems ); + else if ( nbSame == 1 ) { // ---> pyramid + pentahedron + aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ], + nextNod[ iAfterSame ], nextNod[ iBeforeSame ], + nextNod[ iSameNode ]); + newElems.push_back( aNewElem ); + aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ], + prevNod[ iBeforeSame ], nextNod[ iAfterSame ], + nextNod[ iOpposSame ], nextNod[ iBeforeSame ] ); + } + else if ( nbSame == 2 ) { // ---> pentahedron + if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) + // iBeforeSame is same too + aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ], + nextNod[ iOpposSame ], prevNod[ iSameNode ], + prevNod[ iAfterSame ], nextNod[ iAfterSame ]); + else + // iAfterSame is same too + aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ], + nextNod[ iBeforeSame ], prevNod[ iAfterSame ], + prevNod[ iOpposSame ], nextNod[ iOpposSame ]); + } + break; + } + case SMDSEntity_Quad_Triangle: // sweep (Bi)Quadratic TRIANGLE ---> + case SMDSEntity_BiQuad_Triangle: /* ??? */ { + if ( nbDouble+nbSame != 3 ) break; + if(nbSame==0) { + // ---> pentahedron with 15 nodes + aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], + nextNod[0], nextNod[1], nextNod[2], + prevNod[3], prevNod[4], prevNod[5], + nextNod[3], nextNod[4], nextNod[5], + midlNod[0], midlNod[1], midlNod[2]); + } + else if(nbSame==1) { + // ---> 2d order pyramid of 13 nodes + int apex = iSameNode; + int i0 = ( apex + 1 ) % nbCorners; + int i1 = ( apex - 1 + nbCorners ) % nbCorners; + int i0a = apex + 3; + int i1a = i1 + 3; + int i01 = i0 + 3; + aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0], + nextNod[i0], nextNod[i1], prevNod[apex], + prevNod[i01], midlNod[i0], + nextNod[i01], midlNod[i1], + prevNod[i1a], prevNod[i0a], + nextNod[i0a], nextNod[i1a]); + } + else if(nbSame==2) { + // ---> 2d order tetrahedron of 10 nodes + int n1 = iNotSameNode; + int n2 = ( n1 + 1 ) % nbCorners; + int n3 = ( n1 + nbCorners - 1 ) % nbCorners; + int n12 = n1 + 3; + int n23 = n2 + 3; + int n31 = n3 + 3; + aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1], + prevNod[n12], prevNod[n23], prevNod[n31], + midlNod[n1], nextNod[n12], nextNod[n31]); + } + break; + } + case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE ---> + if( nbSame == 0 ) { + if ( nbDouble != 4 ) break; + // ---> hexahedron with 20 nodes + aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3], + nextNod[0], nextNod[1], nextNod[2], nextNod[3], + prevNod[4], prevNod[5], prevNod[6], prevNod[7], + nextNod[4], nextNod[5], nextNod[6], nextNod[7], + midlNod[0], midlNod[1], midlNod[2], midlNod[3]); + } + else if(nbSame==1) { + // ---> pyramid + pentahedron - can not be created since it is needed + // additional middle node at the center of face + //INFOS( " Sweep for face " << elem->GetID() << " can not be created" ); + return; + } + else if( nbSame == 2 ) { + if ( nbDouble != 2 ) break; + // ---> 2d order Pentahedron with 15 nodes + int n1,n2,n4,n5; + if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) { + // iBeforeSame is same too + n1 = iBeforeSame; + n2 = iOpposSame; + n4 = iSameNode; + n5 = iAfterSame; + } + else { + // iAfterSame is same too + n1 = iSameNode; + n2 = iBeforeSame; + n4 = iAfterSame; + n5 = iOpposSame; + } + int n12 = n2 + 4; + int n45 = n4 + 4; + int n14 = n1 + 4; + int n25 = n5 + 4; + aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2], + prevNod[n4], prevNod[n5], nextNod[n5], + prevNod[n12], midlNod[n2], nextNod[n12], + prevNod[n45], midlNod[n5], nextNod[n45], + prevNod[n14], prevNod[n25], nextNod[n25]); + } + break; + } + case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE ---> - if ( theMakeGroups ) - generateGroups( srcNodes, srcElems, "extruded"); + if( nbSame == 0 && nbDouble == 9 ) { + // ---> tri-quadratic hexahedron with 27 nodes + aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3], + nextNod[0], nextNod[1], nextNod[2], nextNod[3], + prevNod[4], prevNod[5], prevNod[6], prevNod[7], + nextNod[4], nextNod[5], nextNod[6], nextNod[7], + midlNod[0], midlNod[1], midlNod[2], midlNod[3], + prevNod[8], // bottom center + midlNod[4], midlNod[5], midlNod[6], midlNod[7], + nextNod[8], // top center + midlNod[8]);// elem center + } + else + { + return; + } + break; + } + case SMDSEntity_Polygon: { // sweep POLYGON - return EXTR_OK; -} + if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) { + // ---> hexagonal prism + aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], + prevNod[3], prevNod[4], prevNod[5], + nextNod[0], nextNod[1], nextNod[2], + nextNod[3], nextNod[4], nextNod[5]); + } + break; + } + case SMDSEntity_Ball: + return; -//======================================================================= -//function : Transform -//purpose : -//======================================================================= + default: + break; + } // switch ( baseType ) + } // scope -SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, - const gp_Trsf& theTrsf, - const bool theCopy, - const bool theMakeGroups, - SMESH_Mesh* theTargetMesh) -{ - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism + { + if ( baseType != SMDSEntity_Polygon ) + { + const std::vector& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType,nbNodes); + SMDS_MeshCell::applyInterlace( ind, prevNod ); + SMDS_MeshCell::applyInterlace( ind, nextNod ); + SMDS_MeshCell::applyInterlace( ind, midlNod ); + SMDS_MeshCell::applyInterlace( ind, itNN ); + SMDS_MeshCell::applyInterlace( ind, isSingleNode ); + baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!! + } + vector polyedre_nodes (nbNodes*2 + 4*nbNodes); + vector quantities (nbNodes + 2); + polyedre_nodes.clear(); + quantities.clear(); + + // bottom of prism + for (int inode = 0; inode < nbNodes; inode++) + polyedre_nodes.push_back( prevNod[inode] ); + quantities.push_back( nbNodes ); + + // top of prism + polyedre_nodes.push_back( nextNod[0] ); + for (int inode = nbNodes; inode-1; --inode ) + polyedre_nodes.push_back( nextNod[inode-1] ); + quantities.push_back( nbNodes ); + + // side faces + // 3--6--2 + // | | + // 7 5 + // | | + // 0--4--1 + const int iQuad = elem->IsQuadratic(); + for (int iface = 0; iface < nbNodes; iface += 1+iQuad ) + { + const int prevNbNodes = polyedre_nodes.size(); // to detect degenerated face + int inextface = (iface+1+iQuad) % nbNodes; + int imid = (iface+1) % nbNodes; + polyedre_nodes.push_back( prevNod[inextface] ); // 0 + if ( iQuad ) polyedre_nodes.push_back( prevNod[imid] ); // 4 + polyedre_nodes.push_back( prevNod[iface] ); // 1 + if ( prevNod[iface] != nextNod[iface] ) // 1 != 2 + { + if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]); // 5 + polyedre_nodes.push_back( nextNod[iface] ); // 2 + } + if ( iQuad ) polyedre_nodes.push_back( nextNod[imid] ); // 6 + if ( prevNod[inextface] != nextNod[inextface] ) // 0 != 3 + { + polyedre_nodes.push_back( nextNod[inextface] ); // 3 + if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);// 7 + } + const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes; + if ( nbFaceNodes > 2 ) + quantities.push_back( nbFaceNodes ); + else // degenerated face + polyedre_nodes.resize( prevNbNodes ); + } + aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities); - bool needReverse = false; - string groupPostfix; - switch ( theTrsf.Form() ) { - case gp_PntMirror: - case gp_Ax1Mirror: - case gp_Ax2Mirror: - needReverse = true; - groupPostfix = "mirrored"; - break; - case gp_Rotation: - groupPostfix = "rotated"; - break; - case gp_Translation: - groupPostfix = "translated"; - break; - case gp_Scale: - groupPostfix = "scaled"; - break; - default: - needReverse = false; - groupPostfix = "transformed"; - } + } // try to create a polyherdal prism - SMESH_MeshEditor targetMeshEditor( theTargetMesh ); - SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0; - SMESHDS_Mesh* aMesh = GetMeshDS(); - + if ( aNewElem ) { + newElems.push_back( aNewElem ); + myLastCreatedElems.Append(aNewElem); + srcElements.Append( elem ); + } - // map old node to new one - TNodeNodeMap nodeMap; + // set new prev nodes + for ( iNode = 0; iNode < nbNodes; iNode++ ) + prevNod[ iNode ] = nextNod[ iNode ]; - // elements sharing moved nodes; those of them which have all - // nodes mirrored but are not in theElems are to be reversed - TIDSortedElemSet inverseElemSet; + } // loop on steps +} - // source elements for each generated one - SMESH_SequenceOfElemPtr srcElems, srcNodes; +//======================================================================= +/*! + * \brief Create 1D and 2D elements around swept elements + * \param mapNewNodes - source nodes and ones generated from them + * \param newElemsMap - source elements and ones generated from them + * \param elemNewNodesMap - nodes generated from each node of each element + * \param elemSet - all swept elements + * \param nbSteps - number of sweeping steps + * \param srcElements - to append elem for each generated element + */ +//======================================================================= - // loop on theElems - TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; - if ( !elem ) - continue; +void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, + TTElemOfElemListMap & newElemsMap, + TElemOfVecOfNnlmiMap & elemNewNodesMap, + TIDSortedElemSet& elemSet, + const int nbSteps, + SMESH_SequenceOfElemPtr& srcElements) +{ + ASSERT( newElemsMap.size() == elemNewNodesMap.size() ); + SMESHDS_Mesh* aMesh = GetMeshDS(); - // loop on elem nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { + // Find nodes belonging to only one initial element - sweep them into edges. - // check if a node has been already transformed - const SMDS_MeshNode* node = cast2Node( itN->next() ); - pair n2n_isnew = - nodeMap.insert( make_pair ( node, node )); - if ( !n2n_isnew.second ) + TNodeOfNodeListMapItr nList = mapNewNodes.begin(); + for ( ; nList != mapNewNodes.end(); nList++ ) + { + const SMDS_MeshNode* node = + static_cast( nList->first ); + if ( newElemsMap.count( node )) + continue; // node was extruded into edge + SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(); + int nbInitElems = 0; + const SMDS_MeshElement* el = 0; + SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only + while ( eIt->more() && nbInitElems < 2 ) { + const SMDS_MeshElement* e = eIt->next(); + SMDSAbs_ElementType type = e->GetType(); + if ( type == SMDSAbs_Volume || + type < highType || + !elemSet.count(e)) continue; - - double coord[3]; - coord[0] = node->X(); - coord[1] = node->Y(); - coord[2] = node->Z(); - theTrsf.Transforms( coord[0], coord[1], coord[2] ); - if ( theTargetMesh ) { - const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] ); - n2n_isnew.first->second = newNode; - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - } - else if ( theCopy ) { - const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - n2n_isnew.first->second = newNode; - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - } - else { - aMesh->MoveNode( node, coord[0], coord[1], coord[2] ); - // node position on shape becomes invalid - const_cast< SMDS_MeshNode* > ( node )->SetPosition - ( SMDS_SpacePosition::originSpacePosition() ); + if ( type > highType ) { + nbInitElems = 0; + highType = type; } - - // keep inverse elements - if ( !theCopy && !theTargetMesh && needReverse ) { - SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator(); - while ( invElemIt->more() ) { - const SMDS_MeshElement* iel = invElemIt->next(); - inverseElemSet.insert( iel ); - } + el = e; + ++nbInitElems; + } + if ( nbInitElems == 1 ) { + bool NotCreateEdge = el && el->IsMediumNode(node); + if(!NotCreateEdge) { + vector newNodesItVec( 1, nList ); + list newEdges; + sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements ); } } } - // either create new elements or reverse mirrored ones - if ( !theCopy && !needReverse && !theTargetMesh ) - return PGroupIDs(); - - TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin(); - for ( ; invElemIt != inverseElemSet.end(); invElemIt++ ) - theElems.insert( *invElemIt ); - - // replicate or reverse elements + // Make a ceiling for each element ie an equal element of last new nodes. + // Find free links of faces - make edges and sweep them into faces. - enum { - REV_TETRA = 0, // = nbNodes - 4 - REV_PYRAMID = 1, // = nbNodes - 4 - REV_PENTA = 2, // = nbNodes - 4 - REV_FACE = 3, - REV_HEXA = 4, // = nbNodes - 4 - FORWARD = 5 - }; - int index[][8] = { - { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA - { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID - { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA - { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE - { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA - { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD - }; + ElemFeatures polyFace( SMDSAbs_Face, /*isPoly=*/true ), anyFace; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) + TTElemOfElemListMap::iterator itElem = newElemsMap.begin(); + TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin(); + for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) { - const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() == SMDSAbs_Node ) - continue; + const SMDS_MeshElement* elem = itElem->first; + vector& vecNewNodes = itElemNodes->second; - int nbNodes = elem->NbNodes(); - int elemType = elem->GetType(); + if(itElem->second.size()==0) continue; - if (elem->IsPoly()) { - // Polygon or Polyhedral Volume - switch ( elemType ) { - case SMDSAbs_Face: - { - vector poly_nodes (nbNodes); - int iNode = 0; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while (itN->more()) { - const SMDS_MeshNode* node = - static_cast(itN->next()); - TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node); - if (nodeMapIt == nodeMap.end()) - break; // not all nodes transformed - if (needReverse) { - // reverse mirrored faces and volumes - poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second; - } else { - poly_nodes[iNode] = (*nodeMapIt).second; - } - iNode++; - } - if ( iNode != nbNodes ) - continue; // not all nodes transformed + const bool isQuadratic = elem->IsQuadratic(); - if ( theTargetMesh ) { - myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes)); - srcElems.Append( elem ); - } - else if ( theCopy ) { - myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes)); - srcElems.Append( elem ); - } - else { - aMesh->ChangePolygonNodes(elem, poly_nodes); - } + if ( elem->GetType() == SMDSAbs_Edge ) { + // create a ceiling edge + if ( !isQuadratic ) { + if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(), + vecNewNodes[ 1 ]->second.back())) { + myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), + vecNewNodes[ 1 ]->second.back())); + srcElements.Append( elem ); } - break; - case SMDSAbs_Volume: - { - // ATTENTION: Reversing is not yet done!!! - const SMDS_PolyhedralVolumeOfNodes* aPolyedre = - dynamic_cast( elem ); - if (!aPolyedre) { - MESSAGE("Warning: bad volumic element"); - continue; - } + } + else { + if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(), + vecNewNodes[ 1 ]->second.back(), + vecNewNodes[ 2 ]->second.back())) { + myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), + vecNewNodes[ 1 ]->second.back(), + vecNewNodes[ 2 ]->second.back())); + srcElements.Append( elem ); + } + } + } + if ( elem->GetType() != SMDSAbs_Face ) + continue; - vector poly_nodes; - vector quantities; + bool hasFreeLinks = false; - bool allTransformed = true; - int nbFaces = aPolyedre->NbFaces(); - for (int iface = 1; iface <= nbFaces && allTransformed; iface++) { - int nbFaceNodes = aPolyedre->NbFaceNodes(iface); - for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) { - const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode); - TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node); - if (nodeMapIt == nodeMap.end()) { - allTransformed = false; // not all nodes transformed - } else { - poly_nodes.push_back((*nodeMapIt).second); - } - } - quantities.push_back(nbFaceNodes); - } - if ( !allTransformed ) - continue; // not all nodes transformed + TIDSortedElemSet avoidSet; + avoidSet.insert( elem ); - if ( theTargetMesh ) { - myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities)); - srcElems.Append( elem ); - } - else if ( theCopy ) { - myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities)); - srcElems.Append( elem ); + set aFaceLastNodes; + int iNode, nbNodes = vecNewNodes.size(); + if ( !isQuadratic ) { + // loop on the face nodes + for ( iNode = 0; iNode < nbNodes; iNode++ ) { + aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() ); + // look for free links of the face + int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1; + const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first; + const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first; + // check if a link n1-n2 is free + if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet )) { + hasFreeLinks = true; + // make a new edge and a ceiling for a new edge + const SMDS_MeshElement* edge; + if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) { + myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge + srcElements.Append( myLastCreatedElems.Last() ); } - else { - aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); + n1 = vecNewNodes[ iNode ]->second.back(); + n2 = vecNewNodes[ iNext ]->second.back(); + if ( !aMesh->FindEdge( n1, n2 )) { + myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling + srcElements.Append( edge ); } } - break; - default:; - } - continue; - } - - // Regular elements - int* i = index[ FORWARD ]; - if ( needReverse && nbNodes > 2) { // reverse mirrored faces and volumes - if ( elemType == SMDSAbs_Face ) - i = index[ REV_FACE ]; - else - i = index[ nbNodes - 4 ]; + } } - - if(elem->IsQuadratic()) { - static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; - i = anIds; - if(needReverse) { - if(nbNodes==3) { // quadratic edge - static int anIds[] = {1,0,2}; - i = anIds; - } - else if(nbNodes==6) { // quadratic triangle - static int anIds[] = {0,2,1,5,4,3}; - i = anIds; - } - else if(nbNodes==8) { // quadratic quadrangle - static int anIds[] = {0,3,2,1,7,6,5,4}; - i = anIds; - } - else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes - static int anIds[] = {0,2,1,3,6,5,4,7,9,8}; - i = anIds; - } - else if(nbNodes==13) { // quadratic pyramid of 13 nodes - static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10}; - i = anIds; - } - else if(nbNodes==15) { // quadratic pentahedron with 15 nodes - static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13}; - i = anIds; - } - else { // nbNodes==20 - quadratic hexahedron with 20 nodes - static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17}; - i = anIds; + else { // elem is quadratic face + int nbn = nbNodes/2; + for ( iNode = 0; iNode < nbn; iNode++ ) { + aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() ); + int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1; + const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first; + const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first; + const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first; + // check if a link is free + if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet ) && + ! SMESH_MeshAlgos::FindFaceInSet ( n1, n3, elemSet, avoidSet ) && + ! SMESH_MeshAlgos::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) { + hasFreeLinks = true; + // make an edge and a ceiling for a new edge + // find medium node + if ( !aMesh->FindEdge( n1, n2, n3 )) { + myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge + srcElements.Append( elem ); + } + n1 = vecNewNodes[ iNode ]->second.back(); + n2 = vecNewNodes[ iNext ]->second.back(); + n3 = vecNewNodes[ iNode+nbn ]->second.back(); + if ( !aMesh->FindEdge( n1, n2, n3 )) { + myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge + srcElements.Append( elem ); + } } } + for ( iNode = nbn; iNode < nbNodes; iNode++ ) { + aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() ); + } } - // find transformed nodes - vector nodes(nbNodes); - int iNode = 0; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { - const SMDS_MeshNode* node = - static_cast( itN->next() ); - TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node ); - if ( nodeMapIt == nodeMap.end() ) - break; // not all nodes transformed - nodes[ i [ iNode++ ]] = (*nodeMapIt).second; - } - if ( iNode != nbNodes ) - continue; // not all nodes transformed - - if ( theTargetMesh ) { - if ( SMDS_MeshElement* copy = - targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) { - myLastCreatedElems.Append( copy ); - srcElems.Append( elem ); + // sweep free links into faces + + if ( hasFreeLinks ) { + list & newVolumes = itElem->second; + int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps; + + set initNodeSet, topNodeSet, faceNodeSet; + set initNodeSetNoCenter/*, topNodeSetNoCenter*/; + for ( iNode = 0; iNode < nbNodes; iNode++ ) { + initNodeSet.insert( vecNewNodes[ iNode ]->first ); + topNodeSet .insert( vecNewNodes[ iNode ]->second.back() ); } - } - else if ( theCopy ) { - if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) { - myLastCreatedElems.Append( copy ); - srcElems.Append( elem ); + if ( isQuadratic && nbNodes % 2 ) { // node set for the case of a biquadratic + initNodeSetNoCenter = initNodeSet; // swept face and a not biquadratic volume + initNodeSetNoCenter.erase( vecNewNodes.back()->first ); } - } - else { - // reverse element as it was reversed by transformation - if ( nbNodes > 2 ) - aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes ); - } - } + for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) { + list::iterator v = newVolumes.begin(); + std::advance( v, volNb ); + // find indices of free faces of a volume and their source edges + list< int > freeInd; + list< const SMDS_MeshElement* > srcEdges; // source edges of free faces + SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false ); + int iF, nbF = vTool.NbFaces(); + for ( iF = 0; iF < nbF; iF ++ ) { + if (vTool.IsFreeFace( iF ) && + vTool.GetFaceNodes( iF, faceNodeSet ) && + initNodeSet != faceNodeSet) // except an initial face + { + if ( nbSteps == 1 && faceNodeSet == topNodeSet ) + continue; + if ( faceNodeSet == initNodeSetNoCenter ) + continue; + freeInd.push_back( iF ); + // find source edge of a free face iF + vector commonNodes; // shared by the initial and free faces + vector::iterator lastCommom; + commonNodes.resize( nbNodes, 0 ); + lastCommom = std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(), + initNodeSet.begin(), initNodeSet.end(), + commonNodes.begin()); + if ( std::distance( commonNodes.begin(), lastCommom ) == 3 ) + srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2])); + else + srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1])); +#ifdef _DEBUG_ + if ( !srcEdges.back() ) + { + cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #" + << iF << " of volume #" << vTool.ID() << endl; + } +#endif + } + } + if ( freeInd.empty() ) + continue; - PGroupIDs newGroupIDs; + // create wall faces for all steps; + // if such a face has been already created by sweep of edge, + // assure that its orientation is OK + for ( int iStep = 0; iStep < nbSteps; iStep++ ) + { + vTool.Set( *v, /*ignoreCentralNodes=*/false ); + vTool.SetExternalNormal(); + const int nextShift = vTool.IsForward() ? +1 : -1; + list< int >::iterator ind = freeInd.begin(); + list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin(); + for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces + { + const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind ); + int nbn = vTool.NbFaceNodes( *ind ); + const SMDS_MeshElement * f = 0; + if ( nbn == 3 ) ///// triangle + { + f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]); + if ( !f || + nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift )) + { + const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ], + nodes[ 1 ], + nodes[ 1 + nextShift ] }; + if ( f ) + aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); + else + myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ], + newOrder[ 2 ] )); + } + } + else if ( nbn == 4 ) ///// quadrangle + { + f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]); + if ( !f || + nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift )) + { + const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ], + nodes[ 2 ], nodes[ 2+nextShift ] }; + if ( f ) + aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); + else + myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ], + newOrder[ 2 ], newOrder[ 3 ])); + } + } + else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle + { + f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] ); + if ( !f || + nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift )) + { + const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift], + nodes[2], + nodes[2 + 2*nextShift], + nodes[3 - 2*nextShift], + nodes[3], + nodes[3 + 2*nextShift]}; + if ( f ) + aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); + else + myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], + newOrder[ 1 ], + newOrder[ 2 ], + newOrder[ 3 ], + newOrder[ 4 ], + newOrder[ 5 ] )); + } + } + else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle + { + f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6], + nodes[1], nodes[3], nodes[5], nodes[7] ); + if ( !f || + nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift )) + { + const SMDS_MeshNode* newOrder[8] = { nodes[0], + nodes[4 - 2*nextShift], + nodes[4], + nodes[4 + 2*nextShift], + nodes[1], + nodes[5 - 2*nextShift], + nodes[5], + nodes[5 + 2*nextShift] }; + if ( f ) + aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); + else + myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ], + newOrder[ 2 ], newOrder[ 3 ], + newOrder[ 4 ], newOrder[ 5 ], + newOrder[ 6 ], newOrder[ 7 ])); + } + } + else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle + { + f = aMesh->FindElement( vector( nodes, nodes+nbn ), + SMDSAbs_Face, /*noMedium=*/false); + if ( !f || + nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift )) + { + const SMDS_MeshNode* newOrder[9] = { nodes[0], + nodes[4 - 2*nextShift], + nodes[4], + nodes[4 + 2*nextShift], + nodes[1], + nodes[5 - 2*nextShift], + nodes[5], + nodes[5 + 2*nextShift], + nodes[8] }; + if ( f ) + aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); + else + myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ], + newOrder[ 2 ], newOrder[ 3 ], + newOrder[ 4 ], newOrder[ 5 ], + newOrder[ 6 ], newOrder[ 7 ], + newOrder[ 8 ])); + } + } + else //////// polygon + { + vector polygon_nodes ( nodes, nodes+nbn ); + const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes ); + if ( !f || + nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift )) + { + if ( !vTool.IsForward() ) + std::reverse( polygon_nodes.begin(), polygon_nodes.end()); + if ( f ) + aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn ); + else + AddElement( polygon_nodes, polyFace.SetQuad( (*v)->IsQuadratic() )); + } + } - if ( (theMakeGroups && theCopy) || - (theMakeGroups && theTargetMesh) ) - newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh ); + while ( srcElements.Length() < myLastCreatedElems.Length() ) + srcElements.Append( *srcEdge ); - return newGroupIDs; + } // loop on free faces + + // go to the next volume + iVol = 0; + while ( iVol++ < nbVolumesByStep ) v++; + + } // loop on steps + } // loop on volumes of one step + } // sweep free links into faces + + // Make a ceiling face with a normal external to a volume + + // use SMDS_VolumeTool to get a correctly ordered nodes of a ceiling face + SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false ); + int iF = lastVol.GetFaceIndex( aFaceLastNodes ); + + if ( iF < 0 && isQuadratic && nbNodes % 2 ) { // remove a central node of biquadratic + aFaceLastNodes.erase( vecNewNodes.back()->second.back() ); + iF = lastVol.GetFaceIndex( aFaceLastNodes ); + } + if ( iF >= 0 ) + { + lastVol.SetExternalNormal(); + const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF ); + const int nbn = lastVol.NbFaceNodes( iF ); + vector nodeVec( nodes, nodes+nbn ); + if ( !hasFreeLinks || + !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) ) + { + const vector& interlace = + SMDS_MeshCell::interlacedSmdsOrder( elem->GetEntityType(), nbn ); + SMDS_MeshCell::applyInterlaceRev( interlace, nodeVec ); + + AddElement( nodeVec, anyFace.Init( elem )); + + while ( srcElements.Length() < myLastCreatedElems.Length() ) + srcElements.Append( elem ); + } + } + } // loop on swept elements } //======================================================================= -/*! - * \brief Create groups of elements made during transformation - * \param nodeGens - nodes making corresponding myLastCreatedNodes - * \param elemGens - elements making corresponding myLastCreatedElems - * \param postfix - to append to names of new groups - */ +//function : RotationSweep +//purpose : //======================================================================= SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, - const SMESH_SequenceOfElemPtr& elemGens, - const std::string& postfix, - SMESH_Mesh* targetMesh) +SMESH_MeshEditor::RotationSweep(TIDSortedElemSet theElemSets[2], + const gp_Ax1& theAxis, + const double theAngle, + const int theNbSteps, + const double theTol, + const bool theMakeGroups, + const bool theMakeWalls) { - PGroupIDs newGroupIDs( new list ); - SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh(); + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); - // Sort existing groups by types and collect their names + // source elements for each generated one + SMESH_SequenceOfElemPtr srcElems, srcNodes; - // to store an old group and a generated new one - typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup; - vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes ); - // group names - set< string > groupNames; - // - SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0; - SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups(); - while ( groupIt->more() ) { - SMESH_Group * group = groupIt->next(); - if ( !group ) continue; - SMESHDS_GroupBase* groupDS = group->GetGroupDS(); - if ( !groupDS || groupDS->IsEmpty() ) continue; - groupNames.insert( group->GetName() ); - groupDS->SetStoreName( group->GetName() ); - groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup )); - } + MESSAGE( "RotationSweep()"); + gp_Trsf aTrsf; + aTrsf.SetRotation( theAxis, theAngle ); + gp_Trsf aTrsf2; + aTrsf2.SetRotation( theAxis, theAngle/2. ); - // Groups creation + gp_Lin aLine( theAxis ); + double aSqTol = theTol * theTol; - // loop on nodes and elements - for ( int isNodes = 0; isNodes < 2; ++isNodes ) - { - const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens; - const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems; - if ( gens.Length() != elems.Length() ) - throw SMESH_Exception(LOCALIZED("invalid args")); + SMESHDS_Mesh* aMesh = GetMeshDS(); - // loop on created elements - for (int iElem = 1; iElem <= elems.Length(); ++iElem ) - { - const SMDS_MeshElement* sourceElem = gens( iElem ); - if ( !sourceElem ) { - MESSAGE("generateGroups(): NULL source element"); - continue; - } - list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ]; - if ( groupsOldNew.empty() ) { - while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem ) - ++iElem; // skip all elements made by sourceElem - continue; - } - // collect all elements made by sourceElem - list< const SMDS_MeshElement* > resultElems; - if ( const SMDS_MeshElement* resElem = elems( iElem )) - if ( resElem != sourceElem ) - resultElems.push_back( resElem ); - while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem ) - if ( const SMDS_MeshElement* resElem = elems( ++iElem )) - if ( resElem != sourceElem ) - resultElems.push_back( resElem ); - // do not generate element groups from node ones - if ( sourceElem->GetType() == SMDSAbs_Node && - elems( iElem )->GetType() != SMDSAbs_Node ) + TNodeOfNodeListMap mapNewNodes; + TElemOfVecOfNnlmiMap mapElemNewNodes; + TTElemOfElemListMap newElemsMap; + + const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) + + myMesh->NbFaces(ORDER_QUADRATIC) + + myMesh->NbVolumes(ORDER_QUADRATIC) ); + // loop on theElemSets + setElemsFirst( theElemSets ); + TIDSortedElemSet::iterator itElem; + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + TIDSortedElemSet& theElems = theElemSets[ is2ndSet ]; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + const SMDS_MeshElement* elem = *itElem; + if ( !elem || elem->GetType() == SMDSAbs_Volume ) continue; + vector & newNodesItVec = mapElemNewNodes[ elem ]; + newNodesItVec.reserve( elem->NbNodes() ); - // add resultElems to groups made by ones the sourceElem belongs to - list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end(); - for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew ) + // loop on elem nodes + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) { - SMESHDS_GroupBase* oldGroup = gOldNew->first; - if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup + const SMDS_MeshNode* node = cast2Node( itN->next() ); + + gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); + double coord[3]; + aXYZ.Coord( coord[0], coord[1], coord[2] ); + bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol ); + + // check if a node has been already sweeped + TNodeOfNodeListMapItr nIt = + mapNewNodes.insert( make_pair( node, list() )).first; + list& listNewNodes = nIt->second; + if ( listNewNodes.empty() ) { - SMDS_MeshGroup* & newGroup = gOldNew->second; - if ( !newGroup )// create a new group + // check if we are to create medium nodes between corner ones + bool needMediumNodes = false; + if ( isQuadraticMesh ) { - // make a name - string name = oldGroup->GetStoreName(); - if ( !targetMesh ) { - name += "_"; - name += postfix; - int nb = 0; - while ( !groupNames.insert( name ).second ) // name exists + SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); + while (it->more() && !needMediumNodes ) + { + const SMDS_MeshElement* invElem = it->next(); + if ( invElem != elem && !theElems.count( invElem )) continue; + needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); + if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) + needMediumNodes = true; + } + } + + // make new nodes + const SMDS_MeshNode * newNode = node; + for ( int i = 0; i < theNbSteps; i++ ) { + if ( !isOnAxis ) { + if ( needMediumNodes ) // create a medium node { - if ( nb == 0 ) { - name += "_1"; - } - else { - TCollection_AsciiString nbStr(nb+1); - name.resize( name.rfind('_')+1 ); - name += nbStr.ToCString(); - } - ++nb; + aTrsf2.Transforms( coord[0], coord[1], coord[2] ); + newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); + myLastCreatedNodes.Append(newNode); + srcNodes.Append( node ); + listNewNodes.push_back( newNode ); + aTrsf2.Transforms( coord[0], coord[1], coord[2] ); + } + else { + aTrsf.Transforms( coord[0], coord[1], coord[2] ); } + // create a corner node + newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); + myLastCreatedNodes.Append(newNode); + srcNodes.Append( node ); + listNewNodes.push_back( newNode ); + } + else { + listNewNodes.push_back( newNode ); + // if ( needMediumNodes ) + // listNewNodes.push_back( newNode ); } - // make a group - int id; - SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(), - name.c_str(), id ); - SMESHDS_Group* groupDS = static_cast(group->GetGroupDS()); - newGroup = & groupDS->SMDSGroup(); - newGroupIDs->push_back( id ); } - - // fill in a new group - list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt; - for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt ) - newGroup->Add( *resElemIt ); } + newNodesItVec.push_back( nIt ); } - } // loop on created elements - }// loop on nodes and elements + // make new elements + sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems ); + } + } + + if ( theMakeWalls ) + makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], theNbSteps, srcElems ); + + PGroupIDs newGroupIDs; + if ( theMakeGroups ) + newGroupIDs = generateGroups( srcNodes, srcElems, "rotated"); return newGroupIDs; } //======================================================================= -//function : FindCoincidentNodes -//purpose : Return list of group of nodes close to each other within theTolerance -// Search among theNodes or in the whole mesh if theNodes is empty using -// an Octree algorithm +//function : ExtrusParam +//purpose : standard construction //======================================================================= -void SMESH_MeshEditor::FindCoincidentNodes (set & theNodes, - const double theTolerance, - TListOfListOfNodes & theGroupsOfNodes) +SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Vec& theStep, + const int theNbSteps, + const int theFlags, + const double theTolerance): + myDir( theStep ), + myFlags( theFlags ), + myTolerance( theTolerance ), + myElemsToUse( NULL ) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + mySteps = new TColStd_HSequenceOfReal; + const double stepSize = theStep.Magnitude(); + for (int i=1; i<=theNbSteps; i++ ) + mySteps->Append( stepSize ); - set nodes; - if ( theNodes.empty() ) - { // get all nodes in the mesh - SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(); - while ( nIt->more() ) - nodes.insert( nodes.end(),nIt->next()); + if (( theFlags & EXTRUSION_FLAG_SEW ) && + ( theTolerance > 0 )) + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew; } else - nodes=theNodes; - SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance); - + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir; + } } //======================================================================= -/*! - * \brief Implementation of search for the node closest to point - */ +//function : ExtrusParam +//purpose : steps are given explicitly //======================================================================= -struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher +SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Dir& theDir, + Handle(TColStd_HSequenceOfReal) theSteps, + const int theFlags, + const double theTolerance): + myDir( theDir ), + mySteps( theSteps ), + myFlags( theFlags ), + myTolerance( theTolerance ), + myElemsToUse( NULL ) { - /*! - * \brief Constructor - */ - SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh ) + if (( theFlags & EXTRUSION_FLAG_SEW ) && + ( theTolerance > 0 )) { - set nodes; - if ( theMesh ) { - SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(); - while ( nIt->more() ) - nodes.insert( nodes.end(), nIt->next() ); - } - myOctreeNode = new SMESH_OctreeNode(nodes) ; + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew; } - /*! - * \brief Do it's job - */ - const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt ) + else { - SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() ); - list nodes; - const double precision = 1e-6; - //myOctreeNode->NodesAround( &tgtNode, &nodes, precision ); - - double minSqDist = DBL_MAX; - Bnd_B3d box; - if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt - { - // sort leafs by their distance from thePnt - typedef map< double, SMESH_OctreeNode* > TDistTreeMap; - TDistTreeMap treeMap; - list< SMESH_OctreeNode* > treeList; - list< SMESH_OctreeNode* >::iterator trIt; - treeList.push_back( myOctreeNode ); - for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt) - { - SMESH_OctreeNode* tree = *trIt; - if ( !tree->isLeaf() ) { // put children to the queue - SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator(); - while ( cIt->more() ) - treeList.push_back( cIt->next() ); - } - else if ( tree->NbNodes() ) { // put tree to treeMap - tree->getBox( box ); - double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() )); - pair it_in = treeMap.insert( make_pair( sqDist, tree )); - if ( !it_in.second ) // not unique distance to box center - treeMap.insert( it_in.first, make_pair( sqDist - 1e-13*treeMap.size(), tree )); - } - } - // find distance after which there is no sense to check tree's - double sqLimit = DBL_MAX; - TDistTreeMap::iterator sqDist_tree = treeMap.begin(); - if ( treeMap.size() > 5 ) { - SMESH_OctreeNode* closestTree = sqDist_tree->second; - closestTree->getBox( box ); - double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() ); - sqLimit = limit * limit; - } - // get all nodes from trees - for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) { - if ( sqDist_tree->first > sqLimit ) - break; - SMESH_OctreeNode* tree = sqDist_tree->second; - tree->NodesAround( tree->GetNodeIterator()->next(), &nodes ); - } - } - // find closest among nodes - minSqDist = DBL_MAX; - const SMDS_MeshNode* closestNode = 0; - list::iterator nIt = nodes.begin(); - for ( ; nIt != nodes.end(); ++nIt ) { - double sqDist = thePnt.SquareDistance( TNodeXYZ( *nIt ) ); - if ( minSqDist > sqDist ) { - closestNode = *nIt; - minSqDist = sqDist; - } - } - return closestNode; + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir; } - /*! - * \brief Destructor - */ - ~SMESH_NodeSearcherImpl() { delete myOctreeNode; } -private: - SMESH_OctreeNode* myOctreeNode; -}; +} //======================================================================= -/*! - * \brief Return SMESH_NodeSearcher - */ +//function : ExtrusParam +//purpose : for extrusion by normal //======================================================================= -SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() +SMESH_MeshEditor::ExtrusParam::ExtrusParam( const double theStepSize, + const int theNbSteps, + const int theFlags, + const int theDim ): + myDir( 1,0,0 ), + mySteps( new TColStd_HSequenceOfReal ), + myFlags( theFlags ), + myTolerance( 0 ), + myElemsToUse( NULL ) { - return new SMESH_NodeSearcherImpl( GetMeshDS() ); + for (int i = 0; i < theNbSteps; i++ ) + mySteps->Append( theStepSize ); + + if ( theDim == 1 ) + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal1D; + } + else + { + myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal2D; + } } //======================================================================= -//function : SimplifyFace -//purpose : +//function : ExtrusParam::SetElementsToUse +//purpose : stores elements to use for extrusion by normal, depending on +// state of EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY flag //======================================================================= -int SMESH_MeshEditor::SimplifyFace (const vector faceNodes, - vector& poly_nodes, - vector& quantities) const + +void SMESH_MeshEditor::ExtrusParam::SetElementsToUse( const TIDSortedElemSet& elems ) { - int nbNodes = faceNodes.size(); + myElemsToUse = ToUseInpElemsOnly() ? & elems : 0; +} - if (nbNodes < 3) - return 0; +//======================================================================= +//function : ExtrusParam::beginStepIter +//purpose : prepare iteration on steps +//======================================================================= - set nodeSet; +void SMESH_MeshEditor::ExtrusParam::beginStepIter( bool withMediumNodes ) +{ + myWithMediumNodes = withMediumNodes; + myNextStep = 1; + myCurSteps.clear(); +} +//======================================================================= +//function : ExtrusParam::moreSteps +//purpose : are there more steps? +//======================================================================= - // get simple seq of nodes - //const SMDS_MeshNode* simpleNodes[ nbNodes ]; - vector simpleNodes( nbNodes ); - int iSimple = 0, nbUnique = 0; +bool SMESH_MeshEditor::ExtrusParam::moreSteps() +{ + return myNextStep <= mySteps->Length() || !myCurSteps.empty(); +} +//======================================================================= +//function : ExtrusParam::nextStep +//purpose : returns the next step +//======================================================================= - simpleNodes[iSimple++] = faceNodes[0]; - nbUnique++; - for (int iCur = 1; iCur < nbNodes; iCur++) { - if (faceNodes[iCur] != simpleNodes[iSimple - 1]) { - simpleNodes[iSimple++] = faceNodes[iCur]; - if (nodeSet.insert( faceNodes[iCur] ).second) - nbUnique++; +double SMESH_MeshEditor::ExtrusParam::nextStep() +{ + double res = 0; + if ( !myCurSteps.empty() ) + { + res = myCurSteps.back(); + myCurSteps.pop_back(); + } + else if ( myNextStep <= mySteps->Length() ) + { + myCurSteps.push_back( mySteps->Value( myNextStep )); + ++myNextStep; + if ( myWithMediumNodes ) + { + myCurSteps.back() /= 2.; + myCurSteps.push_back( myCurSteps.back() ); } + res = nextStep(); } - int nbSimple = iSimple; - if (simpleNodes[nbSimple - 1] == simpleNodes[0]) { - nbSimple--; - iSimple--; + return res; +} + +//======================================================================= +//function : ExtrusParam::makeNodesByDir +//purpose : create nodes for standard extrusion +//======================================================================= + +int SMESH_MeshEditor::ExtrusParam:: +makeNodesByDir( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes) +{ + gp_XYZ p = SMESH_TNodeXYZ( srcNode ); + + int nbNodes = 0; + for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps + { + p += myDir.XYZ() * nextStep(); + const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() ); + newNodes.push_back( newNode ); } + return nbNodes; +} - if (nbUnique < 3) - return 0; +//======================================================================= +//function : ExtrusParam::makeNodesByDirAndSew +//purpose : create nodes for standard extrusion with sewing +//======================================================================= - // separate loops - int nbNew = 0; - bool foundLoop = (nbSimple > nbUnique); - while (foundLoop) { - foundLoop = false; - set loopSet; - for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) { - const SMDS_MeshNode* n = simpleNodes[iSimple]; - if (!loopSet.insert( n ).second) { - foundLoop = true; +int SMESH_MeshEditor::ExtrusParam:: +makeNodesByDirAndSew( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes) +{ + gp_XYZ P1 = SMESH_TNodeXYZ( srcNode ); - // separate loop - int iC = 0, curLast = iSimple; - for (; iC < curLast; iC++) { - if (simpleNodes[iC] == n) break; - } - int loopLen = curLast - iC; - if (loopLen > 2) { - // create sub-element - nbNew++; - quantities.push_back(loopLen); - for (; iC < curLast; iC++) { - poly_nodes.push_back(simpleNodes[iC]); - } + int nbNodes = 0; + for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps + { + P1 += myDir.XYZ() * nextStep(); + + // try to search in sequence of existing nodes + // if myNodes.Length()>0 we 'nave to use given sequence + // else - use all nodes of mesh + const SMDS_MeshNode * node = 0; + if ( myNodes.Length() > 0 ) { + int i; + for(i=1; i<=myNodes.Length(); i++) { + gp_XYZ P2 = SMESH_TNodeXYZ( myNodes.Value(i) ); + if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance ) + { + node = myNodes.Value(i); + break; } - // shift the rest nodes (place from the first loop position) - for (iC = curLast + 1; iC < nbSimple; iC++) { - simpleNodes[iC - loopLen] = simpleNodes[iC]; + } + } + else { + SMDS_NodeIteratorPtr itn = mesh->nodesIterator(); + while(itn->more()) { + SMESH_TNodeXYZ P2( itn->next() ); + if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance ) + { + node = P2._node; + break; } - nbSimple -= loopLen; - iSimple -= loopLen; } - } // for (iSimple = 0; iSimple < nbSimple; iSimple++) - } // while (foundLoop) + } - if (iSimple > 2) { - nbNew++; - quantities.push_back(iSimple); - for (int i = 0; i < iSimple; i++) - poly_nodes.push_back(simpleNodes[i]); - } + if ( !node ) + node = mesh->AddNode( P1.X(), P1.Y(), P1.Z() ); - return nbNew; + newNodes.push_back( node ); + + } // loop on steps + + return nbNodes; } //======================================================================= -//function : MergeNodes -//purpose : In each group, the cdr of nodes are substituted by the first one -// in all elements. +//function : ExtrusParam::makeNodesByNormal2D +//purpose : create nodes for extrusion using normals of faces //======================================================================= -void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) +int SMESH_MeshEditor::ExtrusParam:: +makeNodesByNormal2D( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + const bool alongAvgNorm = ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL ); - SMESHDS_Mesh* aMesh = GetMeshDS(); + gp_XYZ p = SMESH_TNodeXYZ( srcNode ); - TNodeNodeMap nodeNodeMap; // node to replace - new node - set elems; // all elements with changed nodes - list< int > rmElemIds, rmNodeIds; + // get normals to faces sharing srcNode + vector< gp_XYZ > norms, baryCenters; + gp_XYZ norm, avgNorm( 0,0,0 ); + SMDS_ElemIteratorPtr faceIt = srcNode->GetInverseElementIterator( SMDSAbs_Face ); + while ( faceIt->more() ) + { + const SMDS_MeshElement* face = faceIt->next(); + if ( myElemsToUse && !myElemsToUse->count( face )) + continue; + if ( SMESH_MeshAlgos::FaceNormal( face, norm, /*normalized=*/true )) + { + norms.push_back( norm ); + avgNorm += norm; + if ( !alongAvgNorm ) + { + gp_XYZ bc(0,0,0); + int nbN = 0; + for ( SMDS_ElemIteratorPtr nIt = face->nodesIterator(); nIt->more(); ++nbN ) + bc += SMESH_TNodeXYZ( nIt->next() ); + baryCenters.push_back( bc / nbN ); + } + } + } - // Fill nodeNodeMap and elems + if ( norms.empty() ) return 0; - TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin(); - for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) { - list& nodes = *grIt; - list::iterator nIt = nodes.begin(); - const SMDS_MeshNode* nToKeep = *nIt; - for ( ++nIt; nIt != nodes.end(); nIt++ ) { - const SMDS_MeshNode* nToRemove = *nIt; - nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep )); - if ( nToRemove != nToKeep ) { - rmNodeIds.push_back( nToRemove->GetID() ); - AddToSameGroups( nToKeep, nToRemove, aMesh ); - } + double normSize = avgNorm.Modulus(); + if ( normSize < std::numeric_limits::min() ) + return 0; - SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator(); - while ( invElemIt->more() ) { - const SMDS_MeshElement* elem = invElemIt->next(); - elems.insert(elem); - } - } + if ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL ) // extrude along avgNorm + { + myDir = avgNorm; + return makeNodesByDir( mesh, srcNode, newNodes, makeMediumNodes ); } - // Change element nodes or remove an element - set::iterator eIt = elems.begin(); - for ( ; eIt != elems.end(); eIt++ ) { - const SMDS_MeshElement* elem = *eIt; - int nbNodes = elem->NbNodes(); - int aShapeId = FindShape( elem ); + avgNorm /= normSize; - set nodeSet; - vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes ); - int iUnique = 0, iCur = 0, nbRepl = 0; - vector iRepl( nbNodes ); + int nbNodes = 0; + for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps + { + gp_XYZ pNew = p; + double stepSize = nextStep(); - // get new seq of nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { - const SMDS_MeshNode* n = - static_cast( itN->next() ); + if ( norms.size() > 1 ) + { + for ( size_t iF = 0; iF < norms.size(); ++iF ) // loop on faces + { + // translate plane of a face + baryCenters[ iF ] += norms[ iF ] * stepSize; - TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n ); - if ( nnIt != nodeNodeMap.end() ) { // n sticks - n = (*nnIt).second; - // BUG 0020185: begin - { - bool stopRecur = false; - set nodesRecur; - nodesRecur.insert(n); - while (!stopRecur) { - TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n ); - if ( nnIt_i != nodeNodeMap.end() ) { // n sticks - n = (*nnIt_i).second; - if (!nodesRecur.insert(n).second) { - // error: recursive dependancy - stopRecur = true; - } - } - else - stopRecur = true; - } - } - // BUG 0020185: end - iRepl[ nbRepl++ ] = iCur; + // find point of intersection of the face plane located at baryCenters[ iF ] + // and avgNorm located at pNew + double d = -( norms[ iF ] * baryCenters[ iF ]); // d of plane equation ax+by+cz+d=0 + double dot = ( norms[ iF ] * avgNorm ); + if ( dot < std::numeric_limits::min() ) + dot = stepSize * 1e-3; + double step = -( norms[ iF ] * pNew + d ) / dot; + pNew += step * avgNorm; } - curNodes[ iCur ] = n; - bool isUnique = nodeSet.insert( n ).second; - if ( isUnique ) - uniqueNodes[ iUnique++ ] = n; - iCur++; } + else + { + pNew += stepSize * avgNorm; + } + p = pNew; - // Analyse element topology after replacement + const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() ); + newNodes.push_back( newNode ); + } + return nbNodes; +} - bool isOk = true; - int nbUniqueNodes = nodeSet.size(); - if ( nbNodes != nbUniqueNodes ) { // some nodes stick - // Polygons and Polyhedral volumes - if (elem->IsPoly()) { - - if (elem->GetType() == SMDSAbs_Face) { - // Polygon - vector face_nodes (nbNodes); - int inode = 0; - for (; inode < nbNodes; inode++) { - face_nodes[inode] = curNodes[inode]; - } +//======================================================================= +//function : ExtrusParam::makeNodesByNormal1D +//purpose : create nodes for extrusion using normals of edges +//======================================================================= - vector polygons_nodes; - vector quantities; - int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities); - - if (nbNew > 0) { - inode = 0; - for (int iface = 0; iface < nbNew - 1; iface++) { - int nbNodes = quantities[iface]; - vector poly_nodes (nbNodes); - for (int ii = 0; ii < nbNodes; ii++, inode++) { - poly_nodes[ii] = polygons_nodes[inode]; - } - SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes); - myLastCreatedElems.Append(newElem); - if (aShapeId) - aMesh->SetMeshElementOnShape(newElem, aShapeId); - } - aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]); - } - else { - rmElemIds.push_back(elem->GetID()); - } +int SMESH_MeshEditor::ExtrusParam:: +makeNodesByNormal1D( SMESHDS_Mesh* mesh, + const SMDS_MeshNode* srcNode, + std::list & newNodes, + const bool makeMediumNodes) +{ + throw SALOME_Exception("Extrusion 1D by Normal not implemented"); + return 0; +} - } - else if (elem->GetType() == SMDSAbs_Volume) { - // Polyhedral volume - if (nbUniqueNodes < 4) { - rmElemIds.push_back(elem->GetID()); - } - else { - // each face has to be analized in order to check volume validity - const SMDS_PolyhedralVolumeOfNodes* aPolyedre = - static_cast( elem ); - if (aPolyedre) { - int nbFaces = aPolyedre->NbFaces(); +//======================================================================= +//function : ExtrusionSweep +//purpose : +//======================================================================= - vector poly_nodes; - vector quantities; +SMESH_MeshEditor::PGroupIDs +SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElems[2], + const gp_Vec& theStep, + const int theNbSteps, + TTElemOfElemListMap& newElemsMap, + const int theFlags, + const double theTolerance) +{ + ExtrusParam aParams( theStep, theNbSteps, theFlags, theTolerance ); + return ExtrusionSweep( theElems, aParams, newElemsMap ); +} - for (int iface = 1; iface <= nbFaces; iface++) { - int nbFaceNodes = aPolyedre->NbFaceNodes(iface); - vector faceNodes (nbFaceNodes); - for (int inode = 1; inode <= nbFaceNodes; inode++) { - const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode); - TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode); - if (nnIt != nodeNodeMap.end()) { // faceNode sticks - faceNode = (*nnIt).second; - } - faceNodes[inode - 1] = faceNode; - } +//======================================================================= +//function : ExtrusionSweep +//purpose : +//======================================================================= - SimplifyFace(faceNodes, poly_nodes, quantities); - } +SMESH_MeshEditor::PGroupIDs +SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElemSets[2], + ExtrusParam& theParams, + TTElemOfElemListMap& newElemsMap) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); - if (quantities.size() > 3) { - // to be done: remove coincident faces - } + // source elements for each generated one + SMESH_SequenceOfElemPtr srcElems, srcNodes; - if (quantities.size() > 3) - aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); - else - rmElemIds.push_back(elem->GetID()); + SMESHDS_Mesh* aMesh = GetMeshDS(); + + setElemsFirst( theElemSets ); + const int nbSteps = theParams.NbSteps(); + theParams.SetElementsToUse( theElemSets[0] ); + + TNodeOfNodeListMap mapNewNodes; + //TNodeOfNodeVecMap mapNewNodes; + TElemOfVecOfNnlmiMap mapElemNewNodes; + //TElemOfVecOfMapNodesMap mapElemNewNodes; + + const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) + + myMesh->NbFaces(ORDER_QUADRATIC) + + myMesh->NbVolumes(ORDER_QUADRATIC) ); + // loop on theElems + TIDSortedElemSet::iterator itElem; + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + TIDSortedElemSet& theElems = theElemSets[ is2ndSet ]; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) + { + // check element type + const SMDS_MeshElement* elem = *itElem; + if ( !elem || elem->GetType() == SMDSAbs_Volume ) + continue; + + const size_t nbNodes = elem->NbNodes(); + vector & newNodesItVec = mapElemNewNodes[ elem ]; + newNodesItVec.reserve( nbNodes ); + + // loop on elem nodes + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + // check if a node has been already sweeped + const SMDS_MeshNode* node = cast2Node( itN->next() ); + TNodeOfNodeListMap::iterator nIt = + mapNewNodes.insert( make_pair( node, list() )).first; + list& listNewNodes = nIt->second; + if ( listNewNodes.empty() ) + { + // make new nodes + // check if we are to create medium nodes between corner ones + bool needMediumNodes = false; + if ( isQuadraticMesh ) + { + SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); + while (it->more() && !needMediumNodes ) + { + const SMDS_MeshElement* invElem = it->next(); + if ( invElem != elem && !theElems.count( invElem )) continue; + needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); + if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) + needMediumNodes = true; } - else { - rmElemIds.push_back(elem->GetID()); + } + // create nodes for all steps + if ( theParams.MakeNodes( GetMeshDS(), node, listNewNodes, needMediumNodes )) + { + list::iterator newNodesIt = listNewNodes.begin(); + for ( ; newNodesIt != listNewNodes.end(); ++newNodesIt ) + { + myLastCreatedNodes.Append( *newNodesIt ); + srcNodes.Append( node ); } } + else + { + break; // newNodesItVec will be shorter than nbNodes + } } - else { - } - - continue; + newNodesItVec.push_back( nIt ); } + // make new elements + if ( newNodesItVec.size() == nbNodes ) + sweepElement( elem, newNodesItVec, newElemsMap[elem], nbSteps, srcElems ); + } + } - // Regular elements - switch ( nbNodes ) { - case 2: ///////////////////////////////////// EDGE - isOk = false; break; - case 3: ///////////////////////////////////// TRIANGLE - isOk = false; break; - case 4: - if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON - isOk = false; - else { //////////////////////////////////// QUADRANGLE - if ( nbUniqueNodes < 3 ) - isOk = false; - else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 ) - isOk = false; // opposite nodes stick + if ( theParams.ToMakeBoundary() ) { + makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], nbSteps, srcElems ); + } + PGroupIDs newGroupIDs; + if ( theParams.ToMakeGroups() ) + newGroupIDs = generateGroups( srcNodes, srcElems, "extruded"); + + return newGroupIDs; +} + +//======================================================================= +//function : ExtrusionAlongTrack +//purpose : +//======================================================================= +SMESH_MeshEditor::Extrusion_Error +SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], + SMESH_subMesh* theTrack, + const SMDS_MeshNode* theN1, + const bool theHasAngles, + list& theAngles, + const bool theLinearVariation, + const bool theHasRefPoint, + const gp_Pnt& theRefPoint, + const bool theMakeGroups) +{ + MESSAGE("ExtrusionAlongTrack"); + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + int aNbE; + std::list aPrms; + TIDSortedElemSet::iterator itElem; + + gp_XYZ aGC; + TopoDS_Edge aTrackEdge; + TopoDS_Vertex aV1, aV2; + + SMDS_ElemIteratorPtr aItE; + SMDS_NodeIteratorPtr aItN; + SMDSAbs_ElementType aTypeE; + + TNodeOfNodeListMap mapNewNodes; + + // 1. Check data + aNbE = theElements[0].size() + theElements[1].size(); + // nothing to do + if ( !aNbE ) + return EXTR_NO_ELEMENTS; + + // 1.1 Track Pattern + ASSERT( theTrack ); + + SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS(); + if ( !pSubMeshDS ) + return ExtrusionAlongTrack( theElements, theTrack->GetFather(), theN1, + theHasAngles, theAngles, theLinearVariation, + theHasRefPoint, theRefPoint, theMakeGroups ); + + aItE = pSubMeshDS->GetElements(); + while ( aItE->more() ) { + const SMDS_MeshElement* pE = aItE->next(); + aTypeE = pE->GetType(); + // Pattern must contain links only + if ( aTypeE != SMDSAbs_Edge ) + return EXTR_PATH_NOT_EDGE; + } + + list fullList; + + const TopoDS_Shape& aS = theTrack->GetSubShape(); + // Sub-shape for the Pattern must be an Edge or Wire + if( aS.ShapeType() == TopAbs_EDGE ) { + aTrackEdge = TopoDS::Edge( aS ); + // the Edge must not be degenerated + if ( SMESH_Algo::isDegenerated( aTrackEdge ) ) + return EXTR_BAD_PATH_SHAPE; + TopExp::Vertices( aTrackEdge, aV1, aV2 ); + aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes(); + const SMDS_MeshNode* aN1 = aItN->next(); + aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes(); + const SMDS_MeshNode* aN2 = aItN->next(); + // starting node must be aN1 or aN2 + if ( !( aN1 == theN1 || aN2 == theN1 ) ) + return EXTR_BAD_STARTING_NODE; + aItN = pSubMeshDS->GetNodes(); + while ( aItN->more() ) { + const SMDS_MeshNode* pNode = aItN->next(); + const SMDS_EdgePosition* pEPos = + static_cast( pNode->GetPosition() ); + double aT = pEPos->GetUParameter(); + aPrms.push_back( aT ); + } + //Extrusion_Error err = + MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList); + } else if( aS.ShapeType() == TopAbs_WIRE ) { + list< SMESH_subMesh* > LSM; + TopTools_SequenceOfShape Edges; + SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true); + while(itSM->more()) { + SMESH_subMesh* SM = itSM->next(); + LSM.push_back(SM); + const TopoDS_Shape& aS = SM->GetSubShape(); + Edges.Append(aS); + } + list< list > LLPPs; + int startNid = theN1->GetID(); + TColStd_MapOfInteger UsedNums; + + int NbEdges = Edges.Length(); + int i = 1; + for(; i<=NbEdges; i++) { + int k = 0; + list< SMESH_subMesh* >::iterator itLSM = LSM.begin(); + for(; itLSM!=LSM.end(); itLSM++) { + k++; + if(UsedNums.Contains(k)) continue; + aTrackEdge = TopoDS::Edge( Edges.Value(k) ); + SMESH_subMesh* locTrack = *itLSM; + SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS(); + TopExp::Vertices( aTrackEdge, aV1, aV2 ); + aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes(); + const SMDS_MeshNode* aN1 = aItN->next(); + aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes(); + const SMDS_MeshNode* aN2 = aItN->next(); + // starting node must be aN1 or aN2 + if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue; + // 2. Collect parameters on the track edge + aPrms.clear(); + aItN = locMeshDS->GetNodes(); + while ( aItN->more() ) { + const SMDS_MeshNode* pNode = aItN->next(); + const SMDS_EdgePosition* pEPos = + static_cast( pNode->GetPosition() ); + double aT = pEPos->GetUParameter(); + aPrms.push_back( aT ); } + list LPP; + //Extrusion_Error err = + MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP); + LLPPs.push_back(LPP); + UsedNums.Add(k); + // update startN for search following egde + if( aN1->GetID() == startNid ) startNid = aN2->GetID(); + else startNid = aN1->GetID(); break; - case 6: ///////////////////////////////////// PENTAHEDRON - if ( nbUniqueNodes == 4 ) { - // ---------------------------------> tetrahedron - if (nbRepl == 3 && - iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) { - // all top nodes stick: reverse a bottom - uniqueNodes[ 0 ] = curNodes [ 1 ]; - uniqueNodes[ 1 ] = curNodes [ 0 ]; - } - else if (nbRepl == 3 && - iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) { - // all bottom nodes stick: set a top before - uniqueNodes[ 3 ] = uniqueNodes [ 0 ]; - uniqueNodes[ 0 ] = curNodes [ 3 ]; - uniqueNodes[ 1 ] = curNodes [ 4 ]; - uniqueNodes[ 2 ] = curNodes [ 5 ]; - } - else if (nbRepl == 4 && - iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) { - // a lateral face turns into a line: reverse a bottom - uniqueNodes[ 0 ] = curNodes [ 1 ]; - uniqueNodes[ 1 ] = curNodes [ 0 ]; - } - else - isOk = false; + } + } + list< list >::iterator itLLPP = LLPPs.begin(); + list firstList = *itLLPP; + list::iterator itPP = firstList.begin(); + for(; itPP!=firstList.end(); itPP++) { + fullList.push_back( *itPP ); + } + SMESH_MeshEditor_PathPoint PP1 = fullList.back(); + fullList.pop_back(); + itLLPP++; + for(; itLLPP!=LLPPs.end(); itLLPP++) { + list currList = *itLLPP; + itPP = currList.begin(); + SMESH_MeshEditor_PathPoint PP2 = currList.front(); + gp_Dir D1 = PP1.Tangent(); + gp_Dir D2 = PP2.Tangent(); + gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2, + (D1.Z()+D2.Z())/2 ) ); + PP1.SetTangent(Dnew); + fullList.push_back(PP1); + itPP++; + for(; itPP!=firstList.end(); itPP++) { + fullList.push_back( *itPP ); + } + PP1 = fullList.back(); + fullList.pop_back(); + } + // if wire not closed + fullList.push_back(PP1); + // else ??? + } + else { + return EXTR_BAD_PATH_SHAPE; + } + + return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation, + theHasRefPoint, theRefPoint, theMakeGroups); +} + + +//======================================================================= +//function : ExtrusionAlongTrack +//purpose : +//======================================================================= +SMESH_MeshEditor::Extrusion_Error +SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], + SMESH_Mesh* theTrack, + const SMDS_MeshNode* theN1, + const bool theHasAngles, + list& theAngles, + const bool theLinearVariation, + const bool theHasRefPoint, + const gp_Pnt& theRefPoint, + const bool theMakeGroups) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + int aNbE; + std::list aPrms; + TIDSortedElemSet::iterator itElem; + + gp_XYZ aGC; + TopoDS_Edge aTrackEdge; + TopoDS_Vertex aV1, aV2; + + SMDS_ElemIteratorPtr aItE; + SMDS_NodeIteratorPtr aItN; + SMDSAbs_ElementType aTypeE; + + TNodeOfNodeListMap mapNewNodes; + + // 1. Check data + aNbE = theElements[0].size() + theElements[1].size(); + // nothing to do + if ( !aNbE ) + return EXTR_NO_ELEMENTS; + + // 1.1 Track Pattern + ASSERT( theTrack ); + + SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS(); + + aItE = pMeshDS->elementsIterator(); + while ( aItE->more() ) { + const SMDS_MeshElement* pE = aItE->next(); + aTypeE = pE->GetType(); + // Pattern must contain links only + if ( aTypeE != SMDSAbs_Edge ) + return EXTR_PATH_NOT_EDGE; + } + + list fullList; + + const TopoDS_Shape& aS = theTrack->GetShapeToMesh(); + + if ( !theTrack->HasShapeToMesh() ) { + //Mesh without shape + const SMDS_MeshNode* currentNode = NULL; + const SMDS_MeshNode* prevNode = theN1; + std::vector aNodesList; + aNodesList.push_back(theN1); + int nbEdges = 0, conn=0; + const SMDS_MeshElement* prevElem = NULL; + const SMDS_MeshElement* currentElem = NULL; + int totalNbEdges = theTrack->NbEdges(); + SMDS_ElemIteratorPtr nIt; + + //check start node + if( !theTrack->GetMeshDS()->Contains(theN1) ) { + return EXTR_BAD_STARTING_NODE; + } + + conn = nbEdgeConnectivity(theN1); + if( conn != 1 ) + return EXTR_PATH_NOT_EDGE; + + aItE = theN1->GetInverseElementIterator(); + prevElem = aItE->next(); + currentElem = prevElem; + //Get all nodes + if(totalNbEdges == 1 ) { + nIt = currentElem->nodesIterator(); + currentNode = static_cast(nIt->next()); + if(currentNode == prevNode) + currentNode = static_cast(nIt->next()); + aNodesList.push_back(currentNode); + } else { + nIt = currentElem->nodesIterator(); + while( nIt->more() ) { + currentNode = static_cast(nIt->next()); + if(currentNode == prevNode) + currentNode = static_cast(nIt->next()); + aNodesList.push_back(currentNode); + + //case of the closed mesh + if(currentNode == theN1) { + nbEdges++; + break; } - else if ( nbUniqueNodes == 5 ) { - // PENTAHEDRON --------------------> 2 tetrahedrons - if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) { - // a bottom node sticks with a linked top one - // 1. - SMDS_MeshElement* newElem = - aMesh->AddVolume(curNodes[ 3 ], - curNodes[ 4 ], - curNodes[ 5 ], - curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]); - myLastCreatedElems.Append(newElem); - if ( aShapeId ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - // 2. : reverse a bottom - uniqueNodes[ 0 ] = curNodes [ 1 ]; - uniqueNodes[ 1 ] = curNodes [ 0 ]; - nbUniqueNodes = 4; - } - else - isOk = false; + + conn = nbEdgeConnectivity(currentNode); + if(conn > 2) { + return EXTR_PATH_NOT_EDGE; + }else if( conn == 1 && nbEdges > 0 ) { + //End of the path + nbEdges++; + break; + }else { + prevNode = currentNode; + aItE = currentNode->GetInverseElementIterator(); + currentElem = aItE->next(); + if( currentElem == prevElem) + currentElem = aItE->next(); + nIt = currentElem->nodesIterator(); + prevElem = currentElem; + nbEdges++; } - else - isOk = false; + } + } + + if(nbEdges != totalNbEdges) + return EXTR_PATH_NOT_EDGE; + + TopTools_SequenceOfShape Edges; + double x1,x2,y1,y2,z1,z2; + list< list > LLPPs; + int startNid = theN1->GetID(); + for(int i = 1; i < aNodesList.size(); i++) { + x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X(); + y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y(); + z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z(); + TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2)); + list LPP; + aPrms.clear(); + MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP); + LLPPs.push_back(LPP); + if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID(); + else startNid = aNodesList[i-1]->GetID(); + + } + + list< list >::iterator itLLPP = LLPPs.begin(); + list firstList = *itLLPP; + list::iterator itPP = firstList.begin(); + for(; itPP!=firstList.end(); itPP++) { + fullList.push_back( *itPP ); + } + + SMESH_MeshEditor_PathPoint PP1 = fullList.back(); + SMESH_MeshEditor_PathPoint PP2; + fullList.pop_back(); + itLLPP++; + for(; itLLPP!=LLPPs.end(); itLLPP++) { + list currList = *itLLPP; + itPP = currList.begin(); + PP2 = currList.front(); + gp_Dir D1 = PP1.Tangent(); + gp_Dir D2 = PP2.Tangent(); + gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2, + (D1.Z()+D2.Z())/2 ) ); + PP1.SetTangent(Dnew); + fullList.push_back(PP1); + itPP++; + for(; itPP!=currList.end(); itPP++) { + fullList.push_back( *itPP ); + } + PP1 = fullList.back(); + fullList.pop_back(); + } + fullList.push_back(PP1); + + } // Sub-shape for the Pattern must be an Edge or Wire + else if( aS.ShapeType() == TopAbs_EDGE ) { + aTrackEdge = TopoDS::Edge( aS ); + // the Edge must not be degenerated + if ( SMESH_Algo::isDegenerated( aTrackEdge ) ) + return EXTR_BAD_PATH_SHAPE; + TopExp::Vertices( aTrackEdge, aV1, aV2 ); + const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS ); + const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS ); + // starting node must be aN1 or aN2 + if ( !( aN1 == theN1 || aN2 == theN1 ) ) + return EXTR_BAD_STARTING_NODE; + aItN = pMeshDS->nodesIterator(); + while ( aItN->more() ) { + const SMDS_MeshNode* pNode = aItN->next(); + if( pNode==aN1 || pNode==aN2 ) continue; + const SMDS_EdgePosition* pEPos = + static_cast( pNode->GetPosition() ); + double aT = pEPos->GetUParameter(); + aPrms.push_back( aT ); + } + //Extrusion_Error err = + MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList); + } + else if( aS.ShapeType() == TopAbs_WIRE ) { + list< SMESH_subMesh* > LSM; + TopTools_SequenceOfShape Edges; + TopExp_Explorer eExp(aS, TopAbs_EDGE); + for(; eExp.More(); eExp.Next()) { + TopoDS_Edge E = TopoDS::Edge( eExp.Current() ); + if( SMESH_Algo::isDegenerated(E) ) continue; + SMESH_subMesh* SM = theTrack->GetSubMesh(E); + if(SM) { + LSM.push_back(SM); + Edges.Append(E); + } + } + list< list > LLPPs; + TopoDS_Vertex aVprev; + TColStd_MapOfInteger UsedNums; + int NbEdges = Edges.Length(); + int i = 1; + for(; i<=NbEdges; i++) { + int k = 0; + list< SMESH_subMesh* >::iterator itLSM = LSM.begin(); + for(; itLSM!=LSM.end(); itLSM++) { + k++; + if(UsedNums.Contains(k)) continue; + aTrackEdge = TopoDS::Edge( Edges.Value(k) ); + SMESH_subMesh* locTrack = *itLSM; + SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS(); + TopExp::Vertices( aTrackEdge, aV1, aV2 ); + bool aN1isOK = false, aN2isOK = false; + if ( aVprev.IsNull() ) { + // if previous vertex is not yet defined, it means that we in the beginning of wire + // and we have to find initial vertex corresponding to starting node theN1 + const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS ); + const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS ); + // starting node must be aN1 or aN2 + aN1isOK = ( aN1 && aN1 == theN1 ); + aN2isOK = ( aN2 && aN2 == theN1 ); + } + else { + // we have specified ending vertex of the previous edge on the previous iteration + // and we have just to check that it corresponds to any vertex in current segment + aN1isOK = aVprev.IsSame( aV1 ); + aN2isOK = aVprev.IsSame( aV2 ); + } + if ( !aN1isOK && !aN2isOK ) continue; + // 2. Collect parameters on the track edge + aPrms.clear(); + aItN = locMeshDS->GetNodes(); + while ( aItN->more() ) { + const SMDS_MeshNode* pNode = aItN->next(); + const SMDS_EdgePosition* pEPos = + static_cast( pNode->GetPosition() ); + double aT = pEPos->GetUParameter(); + aPrms.push_back( aT ); + } + list LPP; + //Extrusion_Error err = + MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP); + LLPPs.push_back(LPP); + UsedNums.Add(k); + // update startN for search following egde + if ( aN1isOK ) aVprev = aV2; + else aVprev = aV1; break; - case 8: { - if(elem->IsQuadratic()) { // Quadratic quadrangle - // 1 5 2 - // +---+---+ - // | | - // | | - // 4+ +6 - // | | - // | | - // +---+---+ - // 0 7 3 - isOk = false; - if(nbRepl==3) { - nbUniqueNodes = 6; - if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[2]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[5]; - uniqueNodes[4] = curNodes[6]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[2]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[5]; - uniqueNodes[5] = curNodes[6]; - isOk = true; - } - if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) { - uniqueNodes[0] = curNodes[1]; - uniqueNodes[1] = curNodes[2]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[5]; - uniqueNodes[4] = curNodes[6]; - uniqueNodes[5] = curNodes[0]; - isOk = true; - } - if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[6]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[2]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[1]; - uniqueNodes[4] = curNodes[6]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[2]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[5]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[3]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[2]; - uniqueNodes[5] = curNodes[7]; - isOk = true; - } - if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) { - uniqueNodes[0] = curNodes[0]; - uniqueNodes[1] = curNodes[1]; - uniqueNodes[2] = curNodes[2]; - uniqueNodes[3] = curNodes[4]; - uniqueNodes[4] = curNodes[5]; - uniqueNodes[5] = curNodes[3]; - isOk = true; - } - } - break; + } + } + list< list >::iterator itLLPP = LLPPs.begin(); + list& firstList = *itLLPP; + fullList.splice( fullList.end(), firstList ); + + SMESH_MeshEditor_PathPoint PP1 = fullList.back(); + fullList.pop_back(); + itLLPP++; + for(; itLLPP!=LLPPs.end(); itLLPP++) { + list& currList = *itLLPP; + SMESH_MeshEditor_PathPoint PP2 = currList.front(); + gp_Dir D1 = PP1.Tangent(); + gp_Dir D2 = PP2.Tangent(); + gp_Dir Dnew( D1.XYZ() + D2.XYZ() ); + PP1.SetTangent(Dnew); + fullList.push_back(PP1); + fullList.splice( fullList.end(), currList, ++currList.begin(), currList.end() ); + PP1 = fullList.back(); + fullList.pop_back(); + } + // if wire not closed + fullList.push_back(PP1); + // else ??? + } + else { + return EXTR_BAD_PATH_SHAPE; + } + + return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation, + theHasRefPoint, theRefPoint, theMakeGroups); +} + + +//======================================================================= +//function : MakeEdgePathPoints +//purpose : auxilary for ExtrusionAlongTrack +//======================================================================= +SMESH_MeshEditor::Extrusion_Error +SMESH_MeshEditor::MakeEdgePathPoints(std::list& aPrms, + const TopoDS_Edge& aTrackEdge, + bool FirstIsStart, + list& LPP) +{ + Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2; + aTolVec=1.e-7; + aTolVec2=aTolVec*aTolVec; + double aT1, aT2; + TopoDS_Vertex aV1, aV2; + TopExp::Vertices( aTrackEdge, aV1, aV2 ); + aT1=BRep_Tool::Parameter( aV1, aTrackEdge ); + aT2=BRep_Tool::Parameter( aV2, aTrackEdge ); + // 2. Collect parameters on the track edge + aPrms.push_front( aT1 ); + aPrms.push_back( aT2 ); + // sort parameters + aPrms.sort(); + if( FirstIsStart ) { + if ( aT1 > aT2 ) { + aPrms.reverse(); + } + } + else { + if ( aT2 > aT1 ) { + aPrms.reverse(); + } + } + // 3. Path Points + SMESH_MeshEditor_PathPoint aPP; + Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 ); + std::list::iterator aItD = aPrms.begin(); + for(; aItD != aPrms.end(); ++aItD) { + double aT = *aItD; + gp_Pnt aP3D; + gp_Vec aVec; + aC3D->D1( aT, aP3D, aVec ); + aL2 = aVec.SquareMagnitude(); + if ( aL2 < aTolVec2 ) + return EXTR_CANT_GET_TANGENT; + gp_Dir aTgt( FirstIsStart ? aVec : -aVec ); + aPP.SetPnt( aP3D ); + aPP.SetTangent( aTgt ); + aPP.SetParameter( aT ); + LPP.push_back(aPP); + } + return EXTR_OK; +} + + +//======================================================================= +//function : MakeExtrElements +//purpose : auxilary for ExtrusionAlongTrack +//======================================================================= +SMESH_MeshEditor::Extrusion_Error +SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets[2], + list& fullList, + const bool theHasAngles, + list& theAngles, + const bool theLinearVariation, + const bool theHasRefPoint, + const gp_Pnt& theRefPoint, + const bool theMakeGroups) +{ + const int aNbTP = fullList.size(); + + // Angles + if( theHasAngles && !theAngles.empty() && theLinearVariation ) + LinearAngleVariation(aNbTP-1, theAngles); + + // fill vector of path points with angles + vector aPPs; + list::iterator itPP = fullList.begin(); + list::iterator itAngles = theAngles.begin(); + aPPs.push_back( *itPP++ ); + for( ; itPP != fullList.end(); itPP++) { + aPPs.push_back( *itPP ); + if ( theHasAngles && itAngles != theAngles.end() ) + aPPs.back().SetAngle( *itAngles++ ); + } + + TNodeOfNodeListMap mapNewNodes; + TElemOfVecOfNnlmiMap mapElemNewNodes; + TTElemOfElemListMap newElemsMap; + TIDSortedElemSet::iterator itElem; + // source elements for each generated one + SMESH_SequenceOfElemPtr srcElems, srcNodes; + + // 3. Center of rotation aV0 + gp_Pnt aV0 = theRefPoint; + if ( !theHasRefPoint ) + { + gp_XYZ aGC( 0.,0.,0. ); + TIDSortedElemSet newNodes; + + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + TIDSortedElemSet& theElements = theElemSets[ is2ndSet ]; + itElem = theElements.begin(); + for ( ; itElem != theElements.end(); itElem++ ) + { + const SMDS_MeshElement* elem = *itElem; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) { + const SMDS_MeshElement* node = itN->next(); + if ( newNodes.insert( node ).second ) + aGC += SMESH_TNodeXYZ( node ); } - //////////////////////////////////// HEXAHEDRON - isOk = false; - SMDS_VolumeTool hexa (elem); - hexa.SetExternalNormal(); - if ( nbUniqueNodes == 4 && nbRepl == 6 ) { - //////////////////////// ---> tetrahedron - for ( int iFace = 0; iFace < 6; iFace++ ) { - const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes - if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] && - curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] && - curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) { - // one face turns into a point ... - int iOppFace = hexa.GetOppFaceIndex( iFace ); - ind = hexa.GetFaceNodesIndices( iOppFace ); - int nbStick = 0; - iUnique = 2; // reverse a tetrahedron bottom - for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) { - if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] ) - nbStick++; - else if ( iUnique >= 0 ) - uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]]; - } - if ( nbStick == 1 ) { - // ... and the opposite one - into a triangle. - // set a top node - ind = hexa.GetFaceNodesIndices( iFace ); - uniqueNodes[ 3 ] = curNodes[ind[ 0 ]]; - isOk = true; - } - break; + } + } + aGC /= newNodes.size(); + aV0.SetXYZ( aGC ); + } // if (!theHasRefPoint) { + + // 4. Processing the elements + SMESHDS_Mesh* aMesh = GetMeshDS(); + list emptyList; + + setElemsFirst( theElemSets ); + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + TIDSortedElemSet& theElements = theElemSets[ is2ndSet ]; + for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) + { + const SMDS_MeshElement* elem = *itElem; + + vector & newNodesItVec = mapElemNewNodes[ elem ]; + newNodesItVec.reserve( elem->NbNodes() ); + + // loop on elem nodes + int nodeIndex = -1; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + ++nodeIndex; + // check if a node has been already processed + const SMDS_MeshNode* node = cast2Node( itN->next() ); + TNodeOfNodeListMap::iterator nIt = mapNewNodes.insert( make_pair( node, emptyList )).first; + list& listNewNodes = nIt->second; + if ( listNewNodes.empty() ) + { + // make new nodes + Standard_Real aAngle1x, aAngleT1T0, aTolAng; + gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x; + gp_Ax1 anAx1, anAxT1T0; + gp_Dir aDT1x, aDT0x, aDT1T0; + + aTolAng=1.e-4; + + aV0x = aV0; + aPN0 = SMESH_TNodeXYZ( node ); + + const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0]; + aP0x = aPP0.Pnt(); + aDT0x= aPP0.Tangent(); + + for ( int j = 1; j < aNbTP; ++j ) { + const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j]; + aP1x = aPP1.Pnt(); + aDT1x = aPP1.Tangent(); + aAngle1x = aPP1.Angle(); + + gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0; + // Translation + gp_Vec aV01x( aP0x, aP1x ); + aTrsf.SetTranslation( aV01x ); + + // traslated point + aV1x = aV0x.Transformed( aTrsf ); + aPN1 = aPN0.Transformed( aTrsf ); + + // rotation 1 [ T1,T0 ] + aAngleT1T0=-aDT1x.Angle( aDT0x ); + if (fabs(aAngleT1T0) > aTolAng) + { + aDT1T0=aDT1x^aDT0x; + anAxT1T0.SetLocation( aV1x ); + anAxT1T0.SetDirection( aDT1T0 ); + aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 ); + + aPN1 = aPN1.Transformed( aTrsfRotT1T0 ); } - } - } - else if (nbUniqueNodes == 5 && nbRepl == 4 ) { - //////////////////// HEXAHEDRON ---> 2 tetrahedrons - for ( int iFace = 0; iFace < 6; iFace++ ) { - const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes - if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] && - curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] && - curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) { - // one face turns into a point ... - int iOppFace = hexa.GetOppFaceIndex( iFace ); - ind = hexa.GetFaceNodesIndices( iOppFace ); - int nbStick = 0; - iUnique = 2; // reverse a tetrahedron 1 bottom - for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) { - if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] ) - nbStick++; - else if ( iUnique >= 0 ) - uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]]; - } - if ( nbStick == 0 ) { - // ... and the opposite one is a quadrangle - // set a top node - const int* indTop = hexa.GetFaceNodesIndices( iFace ); - uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]]; - nbUniqueNodes = 4; - // tetrahedron 2 - SMDS_MeshElement* newElem = - aMesh->AddVolume(curNodes[ind[ 0 ]], - curNodes[ind[ 3 ]], - curNodes[ind[ 2 ]], - curNodes[indTop[ 0 ]]); - myLastCreatedElems.Append(newElem); - if ( aShapeId ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - isOk = true; - } - break; + + // rotation 2 + if ( theHasAngles ) { + anAx1.SetLocation( aV1x ); + anAx1.SetDirection( aDT1x ); + aTrsfRot.SetRotation( anAx1, aAngle1x ); + + aPN1 = aPN1.Transformed( aTrsfRot ); + } + + // make new node + if ( elem->IsQuadratic() && !elem->IsMediumNode(node) ) + { + // create additional node + gp_XYZ midP = 0.5 * ( aPN1.XYZ() + aPN0.XYZ() ); + const SMDS_MeshNode* newNode = aMesh->AddNode( midP.X(), midP.Y(), midP.Z() ); + myLastCreatedNodes.Append(newNode); + srcNodes.Append( node ); + listNewNodes.push_back( newNode ); } + const SMDS_MeshNode* newNode = aMesh->AddNode( aPN1.X(), aPN1.Y(), aPN1.Z() ); + myLastCreatedNodes.Append(newNode); + srcNodes.Append( node ); + listNewNodes.push_back( newNode ); + + aPN0 = aPN1; + aP0x = aP1x; + aV0x = aV1x; + aDT0x = aDT1x; } } - else if ( nbUniqueNodes == 6 && nbRepl == 4 ) { - ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism - // find indices of quad and tri faces - int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace; - for ( iFace = 0; iFace < 6; iFace++ ) { - const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes - nodeSet.clear(); - for ( iCur = 0; iCur < 4; iCur++ ) - nodeSet.insert( curNodes[ind[ iCur ]] ); - nbUniqueNodes = nodeSet.size(); - if ( nbUniqueNodes == 3 ) - iTriFace[ nbTri++ ] = iFace; - else if ( nbUniqueNodes == 4 ) - iQuadFace[ nbQuad++ ] = iFace; - } - if (nbQuad == 2 && nbTri == 4 && - hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) { - // 2 opposite quadrangles stuck with a diagonal; - // sample groups of merged indices: (0-4)(2-6) - // --------------------------------------------> 2 tetrahedrons - const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes - const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]); - int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top - if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] && - curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) { - // stuck with 0-2 diagonal - i0 = ind1[ 3 ]; - i1d = ind1[ 0 ]; - i2 = ind1[ 1 ]; - i3d = ind1[ 2 ]; - i0t = ind2[ 1 ]; - i2t = ind2[ 3 ]; - } - else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] && - curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) { - // stuck with 1-3 diagonal - i0 = ind1[ 0 ]; - i1d = ind1[ 1 ]; - i2 = ind1[ 2 ]; - i3d = ind1[ 3 ]; - i0t = ind2[ 0 ]; - i2t = ind2[ 1 ]; + else if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) + { + // if current elem is quadratic and current node is not medium + // we have to check - may be it is needed to insert additional nodes + list< const SMDS_MeshNode* > & listNewNodes = nIt->second; + if ( listNewNodes.size() == aNbTP-1 ) + { + vector aNodes(2*(aNbTP-1)); + gp_XYZ P(node->X(), node->Y(), node->Z()); + list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin(); + int i; + for(i=0; iX() + P.X() )/2.; + double y = ( N->Y() + P.Y() )/2.; + double z = ( N->Z() + P.Z() )/2.; + const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z); + srcNodes.Append( node ); + myLastCreatedNodes.Append(newN); + aNodes[2*i] = newN; + aNodes[2*i+1] = N; + P = gp_XYZ(N->X(),N->Y(),N->Z()); } - else { - ASSERT(0); + listNewNodes.clear(); + for(i=0; i<2*(aNbTP-1); i++) { + listNewNodes.push_back(aNodes[i]); } - // tetrahedron 1 - uniqueNodes[ 0 ] = curNodes [ i0 ]; - uniqueNodes[ 1 ] = curNodes [ i1d ]; - uniqueNodes[ 2 ] = curNodes [ i3d ]; - uniqueNodes[ 3 ] = curNodes [ i0t ]; - nbUniqueNodes = 4; - // tetrahedron 2 - SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ], - curNodes[ i2 ], - curNodes[ i3d ], - curNodes[ i2t ]); - myLastCreatedElems.Append(newElem); - if ( aShapeId ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - isOk = true; + } + } + + newNodesItVec.push_back( nIt ); + } + + // make new elements + sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems ); + } + } + + makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], aNbTP-1, srcElems ); + + if ( theMakeGroups ) + generateGroups( srcNodes, srcElems, "extruded"); + + return EXTR_OK; +} + + +//======================================================================= +//function : LinearAngleVariation +//purpose : auxilary for ExtrusionAlongTrack +//======================================================================= +void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps, + list& Angles) +{ + int nbAngles = Angles.size(); + if( nbSteps > nbAngles ) { + vector theAngles(nbAngles); + list::iterator it = Angles.begin(); + int i = -1; + for(; it!=Angles.end(); it++) { + i++; + theAngles[i] = (*it); + } + list res; + double rAn2St = double( nbAngles ) / double( nbSteps ); + double angPrev = 0, angle; + for ( int iSt = 0; iSt < nbSteps; ++iSt ) { + double angCur = rAn2St * ( iSt+1 ); + double angCurFloor = floor( angCur ); + double angPrevFloor = floor( angPrev ); + if ( angPrevFloor == angCurFloor ) + angle = rAn2St * theAngles[ int( angCurFloor ) ]; + else { + int iP = int( angPrevFloor ); + double angPrevCeil = ceil(angPrev); + angle = ( angPrevCeil - angPrev ) * theAngles[ iP ]; + + int iC = int( angCurFloor ); + if ( iC < nbAngles ) + angle += ( angCur - angCurFloor ) * theAngles[ iC ]; + + iP = int( angPrevCeil ); + while ( iC-- > iP ) + angle += theAngles[ iC ]; + } + res.push_back(angle); + angPrev = angCur; + } + Angles.clear(); + it = res.begin(); + for(; it!=res.end(); it++) + Angles.push_back( *it ); + } +} + + +//================================================================================ +/*! + * \brief Move or copy theElements applying theTrsf to their nodes + * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes + * \param theTrsf - transformation to apply + * \param theCopy - if true, create translated copies of theElems + * \param theMakeGroups - if true and theCopy, create translated groups + * \param theTargetMesh - mesh to copy translated elements into + * \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups + */ +//================================================================================ + +SMESH_MeshEditor::PGroupIDs +SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, + const gp_Trsf& theTrsf, + const bool theCopy, + const bool theMakeGroups, + SMESH_Mesh* theTargetMesh) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + bool needReverse = false; + string groupPostfix; + switch ( theTrsf.Form() ) { + case gp_PntMirror: + MESSAGE("gp_PntMirror"); + needReverse = true; + groupPostfix = "mirrored"; + break; + case gp_Ax1Mirror: + MESSAGE("gp_Ax1Mirror"); + groupPostfix = "mirrored"; + break; + case gp_Ax2Mirror: + MESSAGE("gp_Ax2Mirror"); + needReverse = true; + groupPostfix = "mirrored"; + break; + case gp_Rotation: + MESSAGE("gp_Rotation"); + groupPostfix = "rotated"; + break; + case gp_Translation: + MESSAGE("gp_Translation"); + groupPostfix = "translated"; + break; + case gp_Scale: + MESSAGE("gp_Scale"); + groupPostfix = "scaled"; + break; + case gp_CompoundTrsf: // different scale by axis + MESSAGE("gp_CompoundTrsf"); + groupPostfix = "scaled"; + break; + default: + MESSAGE("default"); + needReverse = false; + groupPostfix = "transformed"; + } + + SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0; + SMESHDS_Mesh* aMesh = GetMeshDS(); + + SMESH_MeshEditor targetMeshEditor( theTargetMesh ); + SMESH_MeshEditor* editor = theTargetMesh ? & targetMeshEditor : theCopy ? this : 0; + SMESH_MeshEditor::ElemFeatures elemType; + + // map old node to new one + TNodeNodeMap nodeMap; + + // elements sharing moved nodes; those of them which have all + // nodes mirrored but are not in theElems are to be reversed + TIDSortedElemSet inverseElemSet; + + // source elements for each generated one + SMESH_SequenceOfElemPtr srcElems, srcNodes; + + // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh + TIDSortedElemSet orphanNode; + + if ( theElems.empty() ) // transform the whole mesh + { + // add all elements + SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator(); + while ( eIt->more() ) theElems.insert( eIt->next() ); + // add orphan nodes + SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator(); + while ( nIt->more() ) + { + const SMDS_MeshNode* node = nIt->next(); + if ( node->NbInverseElements() == 0) + orphanNode.insert( node ); + } + } + + // loop on elements to transform nodes : first orphan nodes then elems + TIDSortedElemSet::iterator itElem; + TIDSortedElemSet *elements[] = { &orphanNode, &theElems }; + for (int i=0; i<2; i++) + for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) + { + const SMDS_MeshElement* elem = *itElem; + if ( !elem ) + continue; + + // loop on elem nodes + double coord[3]; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + const SMDS_MeshNode* node = cast2Node( itN->next() ); + // check if a node has been already transformed + pair n2n_isnew = + nodeMap.insert( make_pair ( node, node )); + if ( !n2n_isnew.second ) + continue; + + node->GetXYZ( coord ); + theTrsf.Transforms( coord[0], coord[1], coord[2] ); + if ( theTargetMesh ) { + const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] ); + n2n_isnew.first->second = newNode; + myLastCreatedNodes.Append(newNode); + srcNodes.Append( node ); + } + else if ( theCopy ) { + const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); + n2n_isnew.first->second = newNode; + myLastCreatedNodes.Append(newNode); + srcNodes.Append( node ); + } + else { + aMesh->MoveNode( node, coord[0], coord[1], coord[2] ); + // node position on shape becomes invalid + const_cast< SMDS_MeshNode* > ( node )->SetPosition + ( SMDS_SpacePosition::originSpacePosition() ); + } + + // keep inverse elements + if ( !theCopy && !theTargetMesh && needReverse ) { + SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator(); + while ( invElemIt->more() ) { + const SMDS_MeshElement* iel = invElemIt->next(); + inverseElemSet.insert( iel ); + } + } + } + } // loop on elems in { &orphanNode, &theElems }; + + // either create new elements or reverse mirrored ones + if ( !theCopy && !needReverse && !theTargetMesh ) + return PGroupIDs(); + + theElems.insert( inverseElemSet.begin(),inverseElemSet.end() ); + + // Replicate or reverse elements + + std::vector iForw; + vector nodes; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) + { + const SMDS_MeshElement* elem = *itElem; + if ( !elem ) continue; + + SMDSAbs_GeometryType geomType = elem->GetGeomType(); + int nbNodes = elem->NbNodes(); + if ( geomType == SMDSGeom_NONE ) continue; // node + + nodes.resize( nbNodes ); + + if ( geomType == SMDSGeom_POLYHEDRA ) // ------------------ polyhedral volume + { + const SMDS_VtkVolume* aPolyedre = dynamic_cast( elem ); + if (!aPolyedre) + continue; + nodes.clear(); + bool allTransformed = true; + int nbFaces = aPolyedre->NbFaces(); + for (int iface = 1; iface <= nbFaces && allTransformed; iface++) + { + int nbFaceNodes = aPolyedre->NbFaceNodes(iface); + for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) + { + const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode); + TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node); + if ( nodeMapIt == nodeMap.end() ) + allTransformed = false; // not all nodes transformed + else + nodes.push_back((*nodeMapIt).second); + } + if ( needReverse && allTransformed ) + std::reverse( nodes.end() - nbFaceNodes, nodes.end() ); + } + if ( !allTransformed ) + continue; // not all nodes transformed + } + else // ----------------------- the rest element types + { + while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() ); + const vector& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType(), nbNodes ); + const vector& i = needReverse ? iRev : iForw; + + // find transformed nodes + int iNode = 0; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) { + const SMDS_MeshNode* node = static_cast( itN->next() ); + TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node ); + if ( nodeMapIt == nodeMap.end() ) + break; // not all nodes transformed + nodes[ i [ iNode++ ]] = (*nodeMapIt).second; + } + if ( iNode != nbNodes ) + continue; // not all nodes transformed + } + + if ( editor ) { + // copy in this or a new mesh + if ( editor->AddElement( nodes, elemType.Init( elem, /*basicOnly=*/false ))) + srcElems.Append( elem ); + } + else { + // reverse element as it was reversed by transformation + if ( nbNodes > 2 ) + aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes ); + } + + } // loop on elements + + if ( editor && editor != this ) + myLastCreatedElems = editor->myLastCreatedElems; + + PGroupIDs newGroupIDs; + + if ( ( theMakeGroups && theCopy ) || + ( theMakeGroups && theTargetMesh ) ) + newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh, false ); + + return newGroupIDs; +} + +//======================================================================= +/*! + * \brief Create groups of elements made during transformation + * \param nodeGens - nodes making corresponding myLastCreatedNodes + * \param elemGens - elements making corresponding myLastCreatedElems + * \param postfix - to append to names of new groups + * \param targetMesh - mesh to create groups in + * \param topPresent - is there "top" elements that are created by sweeping + */ +//======================================================================= + +SMESH_MeshEditor::PGroupIDs +SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, + const SMESH_SequenceOfElemPtr& elemGens, + const std::string& postfix, + SMESH_Mesh* targetMesh, + const bool topPresent) +{ + PGroupIDs newGroupIDs( new list ); + SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh(); + + // Sort existing groups by types and collect their names + + // containers to store an old group and generated new ones; + // 1st new group is for result elems of different type than a source one; + // 2nd new group is for same type result elems ("top" group at extrusion) + using boost::tuple; + using boost::make_tuple; + typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup; + vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes ); + vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups + // group names + set< string > groupNames; + + SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups(); + if ( !groupIt->more() ) return newGroupIDs; + + int newGroupID = mesh->GetGroupIds().back()+1; + while ( groupIt->more() ) + { + SMESH_Group * group = groupIt->next(); + if ( !group ) continue; + SMESHDS_GroupBase* groupDS = group->GetGroupDS(); + if ( !groupDS || groupDS->IsEmpty() ) continue; + groupNames.insert ( group->GetName() ); + groupDS->SetStoreName( group->GetName() ); + const SMDSAbs_ElementType type = groupDS->GetType(); + SMESHDS_Group* newGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type ); + SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type ); + groupsByType[ type ].push_back( make_tuple( groupDS, newGroup, newTopGroup )); + orderedOldNewGroups.push_back( & groupsByType[ type ].back() ); + } + + // Loop on nodes and elements to add them in new groups + + vector< const SMDS_MeshElement* > resultElems; + for ( int isNodes = 0; isNodes < 2; ++isNodes ) + { + const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens; + const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems; + if ( gens.Length() != elems.Length() ) + throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args"); + + // loop on created elements + for (int iElem = 1; iElem <= elems.Length(); ++iElem ) + { + const SMDS_MeshElement* sourceElem = gens( iElem ); + if ( !sourceElem ) { + MESSAGE("generateGroups(): NULL source element"); + continue; + } + list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ]; + if ( groupsOldNew.empty() ) { // no groups of this type at all + while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem ) + ++iElem; // skip all elements made by sourceElem + continue; + } + // collect all elements made by the iElem-th sourceElem + resultElems.clear(); + if ( const SMDS_MeshElement* resElem = elems( iElem )) + if ( resElem != sourceElem ) + resultElems.push_back( resElem ); + while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem ) + if ( const SMDS_MeshElement* resElem = elems( ++iElem )) + if ( resElem != sourceElem ) + resultElems.push_back( resElem ); + + const SMDS_MeshElement* topElem = 0; + if ( isNodes ) // there must be a top element + { + topElem = resultElems.back(); + resultElems.pop_back(); + } + else + { + vector< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin(); + for ( ; resElemIt != resultElems.rend() ; ++resElemIt ) + if ( (*resElemIt)->GetType() == sourceElem->GetType() ) + { + topElem = *resElemIt; + *resElemIt = 0; // erase *resElemIt + break; + } + } + // add resultElems to groups originted from ones the sourceElem belongs to + list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end(); + for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew ) + { + SMESHDS_GroupBase* oldGroup = gOldNew->get<0>(); + if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup + { + // fill in a new group + SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup(); + vector< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt; + for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt ) + if ( *resElemIt ) + newGroup.Add( *resElemIt ); + + // fill a "top" group + if ( topElem ) + { + SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup(); + newTopGroup.Add( topElem ); + } + } + } + } // loop on created elements + }// loop on nodes and elements + + // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups + + list topGrouIds; + for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i ) + { + SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->get<0>(); + SMESHDS_Group* newGroups[2] = { orderedOldNewGroups[i]->get<1>(), + orderedOldNewGroups[i]->get<2>() }; + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + SMESHDS_Group* newGroupDS = newGroups[ is2nd ]; + if ( newGroupDS->IsEmpty() ) + { + mesh->GetMeshDS()->RemoveGroup( newGroupDS ); + } + else + { + // set group type + newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() ); + + // make a name + const bool isTop = ( topPresent && + newGroupDS->GetType() == oldGroupDS->GetType() && + is2nd ); + + string name = oldGroupDS->GetStoreName(); + { // remove trailing whitespaces (issue 22599) + size_t size = name.size(); + while ( size > 1 && isspace( name[ size-1 ])) + --size; + if ( size != name.size() ) + { + name.resize( size ); + oldGroupDS->SetStoreName( name.c_str() ); + } + } + if ( !targetMesh ) { + string suffix = ( isTop ? "top": postfix.c_str() ); + name += "_"; + name += suffix; + int nb = 1; + while ( !groupNames.insert( name ).second ) // name exists + name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++; + } + else if ( isTop ) { + name += "_top"; + } + newGroupDS->SetStoreName( name.c_str() ); + + // make a SMESH_Groups + mesh->AddGroup( newGroupDS ); + if ( isTop ) + topGrouIds.push_back( newGroupDS->GetID() ); + else + newGroupIDs->push_back( newGroupDS->GetID() ); + } + } + } + newGroupIDs->splice( newGroupIDs->end(), topGrouIds ); + + return newGroupIDs; +} + +//================================================================================ +/*! + * * \brief Return list of group of nodes close to each other within theTolerance + * * Search among theNodes or in the whole mesh if theNodes is empty using + * * an Octree algorithm + * \param [in,out] theNodes - the nodes to treat + * \param [in] theTolerance - the tolerance + * \param [out] theGroupsOfNodes - the result groups of coincident nodes + * \param [in] theSeparateCornersAndMedium - if \c true, in quadratic mesh puts + * corner and medium nodes in separate groups + */ +//================================================================================ + +void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes, + const double theTolerance, + TListOfListOfNodes & theGroupsOfNodes, + bool theSeparateCornersAndMedium) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + if ( myMesh->NbEdges ( ORDER_QUADRATIC ) + + myMesh->NbFaces ( ORDER_QUADRATIC ) + + myMesh->NbVolumes( ORDER_QUADRATIC ) == 0 ) + theSeparateCornersAndMedium = false; + + TIDSortedNodeSet& corners = theNodes; + TIDSortedNodeSet medium; + + if ( theNodes.empty() ) // get all nodes in the mesh + { + TIDSortedNodeSet* nodes[2] = { &corners, &medium }; + SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true); + if ( theSeparateCornersAndMedium ) + while ( nIt->more() ) + { + const SMDS_MeshNode* n = nIt->next(); + TIDSortedNodeSet* & nodeSet = nodes[ SMESH_MesherHelper::IsMedium( n )]; + nodeSet->insert( nodeSet->end(), n ); + } + else + while ( nIt->more() ) + theNodes.insert( theNodes.end(),nIt->next() ); + } + else if ( theSeparateCornersAndMedium ) // separate corners from medium nodes + { + TIDSortedNodeSet::iterator nIt = corners.begin(); + while ( nIt != corners.end() ) + if ( SMESH_MesherHelper::IsMedium( *nIt )) + { + medium.insert( medium.end(), *nIt ); + corners.erase( nIt++ ); + } + else + { + ++nIt; + } + } + + if ( !corners.empty() ) + SMESH_OctreeNode::FindCoincidentNodes ( corners, &theGroupsOfNodes, theTolerance ); + if ( !medium.empty() ) + SMESH_OctreeNode::FindCoincidentNodes ( medium, &theGroupsOfNodes, theTolerance ); +} + +//======================================================================= +//function : SimplifyFace +//purpose : split a chain of nodes into several closed chains +//======================================================================= + +int SMESH_MeshEditor::SimplifyFace (const vector& faceNodes, + vector& poly_nodes, + vector& quantities) const +{ + int nbNodes = faceNodes.size(); + + if (nbNodes < 3) + return 0; + + set nodeSet; + + // get simple seq of nodes + vector simpleNodes( nbNodes ); + int iSimple = 0; + + simpleNodes[iSimple++] = faceNodes[0]; + for (int iCur = 1; iCur < nbNodes; iCur++) { + if (faceNodes[iCur] != simpleNodes[iSimple - 1]) { + simpleNodes[iSimple++] = faceNodes[iCur]; + nodeSet.insert( faceNodes[iCur] ); + } + } + int nbUnique = nodeSet.size(); + int nbSimple = iSimple; + if (simpleNodes[nbSimple - 1] == simpleNodes[0]) { + nbSimple--; + iSimple--; + } + + if (nbUnique < 3) + return 0; + + // separate loops + int nbNew = 0; + bool foundLoop = (nbSimple > nbUnique); + while (foundLoop) { + foundLoop = false; + set loopSet; + for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) { + const SMDS_MeshNode* n = simpleNodes[iSimple]; + if (!loopSet.insert( n ).second) { + foundLoop = true; + + // separate loop + int iC = 0, curLast = iSimple; + for (; iC < curLast; iC++) { + if (simpleNodes[iC] == n) break; + } + int loopLen = curLast - iC; + if (loopLen > 2) { + // create sub-element + nbNew++; + quantities.push_back(loopLen); + for (; iC < curLast; iC++) { + poly_nodes.push_back(simpleNodes[iC]); + } + } + // shift the rest nodes (place from the first loop position) + for (iC = curLast + 1; iC < nbSimple; iC++) { + simpleNodes[iC - loopLen] = simpleNodes[iC]; + } + nbSimple -= loopLen; + iSimple -= loopLen; + } + } // for (iSimple = 0; iSimple < nbSimple; iSimple++) + } // while (foundLoop) + + if (iSimple > 2) { + nbNew++; + quantities.push_back(iSimple); + for (int i = 0; i < iSimple; i++) + poly_nodes.push_back(simpleNodes[i]); + } + + return nbNew; +} + +//======================================================================= +//function : MergeNodes +//purpose : In each group, the cdr of nodes are substituted by the first one +// in all elements. +//======================================================================= + +void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) +{ + MESSAGE("MergeNodes"); + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + SMESHDS_Mesh* aMesh = GetMeshDS(); + + TNodeNodeMap nodeNodeMap; // node to replace - new node + set elems; // all elements with changed nodes + list< int > rmElemIds, rmNodeIds; + + // Fill nodeNodeMap and elems + + TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin(); + for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) + { + list& nodes = *grIt; + list::iterator nIt = nodes.begin(); + const SMDS_MeshNode* nToKeep = *nIt; + for ( ++nIt; nIt != nodes.end(); nIt++ ) + { + const SMDS_MeshNode* nToRemove = *nIt; + nodeNodeMap.insert( make_pair( nToRemove, nToKeep )); + if ( nToRemove != nToKeep ) + { + rmNodeIds.push_back( nToRemove->GetID() ); + AddToSameGroups( nToKeep, nToRemove, aMesh ); + // set _alwaysComputed to a sub-mesh of VERTEX to enable mesh computing + // after MergeNodes() w/o creating node in place of merged ones. + const SMDS_PositionPtr& pos = nToRemove->GetPosition(); + if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX ) + if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() )) + sm->SetIsAlwaysComputed( true ); + } + SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator(); + while ( invElemIt->more() ) { + const SMDS_MeshElement* elem = invElemIt->next(); + elems.insert(elem); + } + } + } + // Change element nodes or remove an element + + set nodeSet; + vector< const SMDS_MeshNode*> curNodes, uniqueNodes; + vector iRepl; + ElemFeatures elemType; + + set::iterator eIt = elems.begin(); + for ( ; eIt != elems.end(); eIt++ ) + { + const SMDS_MeshElement* elem = *eIt; + const int nbNodes = elem->NbNodes(); + const int aShapeId = FindShape( elem ); + + nodeSet.clear(); + curNodes.resize( nbNodes ); + uniqueNodes.resize( nbNodes ); + iRepl.resize( nbNodes ); + int iUnique = 0, iCur = 0, nbRepl = 0; + + // get new seq of nodes + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + const SMDS_MeshNode* n = static_cast( itN->next() ); + + TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n ); + if ( nnIt != nodeNodeMap.end() ) { // n sticks + n = (*nnIt).second; + { ////////// BUG 0020185: begin + bool stopRecur = false; + set nodesRecur; + nodesRecur.insert(n); + while (!stopRecur) { + TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n ); + if ( nnIt_i != nodeNodeMap.end() ) { // n sticks + n = (*nnIt_i).second; + if (!nodesRecur.insert(n).second) { + // error: recursive dependancy + stopRecur = true; + } + } + else + stopRecur = true; + } + } ////////// BUG 0020185: end + } + curNodes[ iCur ] = n; + bool isUnique = nodeSet.insert( n ).second; + if ( isUnique ) + uniqueNodes[ iUnique++ ] = n; + else + iRepl[ nbRepl++ ] = iCur; + iCur++; + } + + // Analyse element topology after replacement + + bool isOk = true; + int nbUniqueNodes = nodeSet.size(); + if ( nbNodes != nbUniqueNodes ) // some nodes stick + { + if (elem->IsPoly()) // Polygons and Polyhedral volumes + { + if (elem->GetType() == SMDSAbs_Face) // Polygon + { + elemType.Init( elem ); + const bool isQuad = elemType.myIsQuad; + if ( isQuad ) + SMDS_MeshCell::applyInterlace // interlace medium and corner nodes + ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, nbNodes ), curNodes ); + + // a polygon can divide into several elements + vector polygons_nodes; + vector quantities; + int nbNew = SimplifyFace( curNodes, polygons_nodes, quantities ); + if (nbNew > 0) + { + vector face_nodes; + int inode = 0; + for (int iface = 0; iface < nbNew; iface++) + { + int nbNewNodes = quantities[iface]; + face_nodes.assign( polygons_nodes.begin() + inode, + polygons_nodes.begin() + inode + nbNewNodes ); + inode += nbNewNodes; + if ( isQuad ) // check if a result elem is a valid quadratic polygon + { + bool isValid = ( nbNewNodes % 2 == 0 ); + for ( int i = 0; i < nbNewNodes && isValid; ++i ) + isValid = ( elem->IsMediumNode( face_nodes[i]) == bool( i % 2 )); + elemType.SetQuad( isValid ); + if ( isValid ) // put medium nodes after corners + SMDS_MeshCell::applyInterlaceRev + ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, + nbNewNodes ), face_nodes ); + } + elemType.SetPoly(( nbNewNodes / ( elemType.myIsQuad + 1 ) > 4 )); + + SMDS_MeshElement* newElem = AddElement( face_nodes, elemType ); + if ( aShapeId ) + aMesh->SetMeshElementOnShape(newElem, aShapeId); + } + } + rmElemIds.push_back(elem->GetID()); + + } // Polygon + + else if (elem->GetType() == SMDSAbs_Volume) // Polyhedral volume + { + if (nbUniqueNodes < 4) { + rmElemIds.push_back(elem->GetID()); + } + else { + // each face has to be analyzed in order to check volume validity + const SMDS_VtkVolume* aPolyedre = dynamic_cast( elem ); + if (aPolyedre) + { + int nbFaces = aPolyedre->NbFaces(); + + vector poly_nodes; + vector quantities; + + for (int iface = 1; iface <= nbFaces; iface++) { + int nbFaceNodes = aPolyedre->NbFaceNodes(iface); + vector faceNodes (nbFaceNodes); + + for (int inode = 1; inode <= nbFaceNodes; inode++) { + const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode); + TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode); + if (nnIt != nodeNodeMap.end()) { // faceNode sticks + faceNode = (*nnIt).second; + } + faceNodes[inode - 1] = faceNode; + } + + SimplifyFace(faceNodes, poly_nodes, quantities); + } + + if (quantities.size() > 3) { + // to be done: remove coincident faces + } + + if (quantities.size() > 3) + { + const SMDS_MeshElement* newElem = + aMesh->AddPolyhedralVolume(poly_nodes, quantities); + myLastCreatedElems.Append(newElem); + if ( aShapeId && newElem ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + rmElemIds.push_back(elem->GetID()); + } + } + else { + rmElemIds.push_back(elem->GetID()); + } + } + } + else { + } + + continue; + } // poly element + + // Regular elements + // TODO not all the possible cases are solved. Find something more generic? + switch ( nbNodes ) { + case 2: ///////////////////////////////////// EDGE + isOk = false; break; + case 3: ///////////////////////////////////// TRIANGLE + isOk = false; break; + case 4: + if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON + isOk = false; + else { //////////////////////////////////// QUADRANGLE + if ( nbUniqueNodes < 3 ) + isOk = false; + else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 ) + isOk = false; // opposite nodes stick + //MESSAGE("isOk " << isOk); + } + break; + case 6: ///////////////////////////////////// PENTAHEDRON + if ( nbUniqueNodes == 4 ) { + // ---------------------------------> tetrahedron + if (nbRepl == 3 && + iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) { + // all top nodes stick: reverse a bottom + uniqueNodes[ 0 ] = curNodes [ 1 ]; + uniqueNodes[ 1 ] = curNodes [ 0 ]; + } + else if (nbRepl == 3 && + iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) { + // all bottom nodes stick: set a top before + uniqueNodes[ 3 ] = uniqueNodes [ 0 ]; + uniqueNodes[ 0 ] = curNodes [ 3 ]; + uniqueNodes[ 1 ] = curNodes [ 4 ]; + uniqueNodes[ 2 ] = curNodes [ 5 ]; + } + else if (nbRepl == 4 && + iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) { + // a lateral face turns into a line: reverse a bottom + uniqueNodes[ 0 ] = curNodes [ 1 ]; + uniqueNodes[ 1 ] = curNodes [ 0 ]; + } + else + isOk = false; + } + else if ( nbUniqueNodes == 5 ) { + // PENTAHEDRON --------------------> 2 tetrahedrons + if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) { + // a bottom node sticks with a linked top one + // 1. + SMDS_MeshElement* newElem = + aMesh->AddVolume(curNodes[ 3 ], + curNodes[ 4 ], + curNodes[ 5 ], + curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]); + myLastCreatedElems.Append(newElem); + if ( aShapeId ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + // 2. : reverse a bottom + uniqueNodes[ 0 ] = curNodes [ 1 ]; + uniqueNodes[ 1 ] = curNodes [ 0 ]; + nbUniqueNodes = 4; + } + else + isOk = false; + } + else + isOk = false; + break; + case 8: { + if(elem->IsQuadratic()) { // Quadratic quadrangle + // 1 5 2 + // +---+---+ + // | | + // | | + // 4+ +6 + // | | + // | | + // +---+---+ + // 0 7 3 + isOk = false; + if(nbRepl==2) { + MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]); + } + if(nbRepl==3) { + MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]); + nbUniqueNodes = 6; + if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) { + uniqueNodes[0] = curNodes[0]; + uniqueNodes[1] = curNodes[2]; + uniqueNodes[2] = curNodes[3]; + uniqueNodes[3] = curNodes[5]; + uniqueNodes[4] = curNodes[6]; + uniqueNodes[5] = curNodes[7]; + isOk = true; + } + if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) { + uniqueNodes[0] = curNodes[0]; + uniqueNodes[1] = curNodes[1]; + uniqueNodes[2] = curNodes[2]; + uniqueNodes[3] = curNodes[4]; + uniqueNodes[4] = curNodes[5]; + uniqueNodes[5] = curNodes[6]; + isOk = true; + } + if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) { + uniqueNodes[0] = curNodes[1]; + uniqueNodes[1] = curNodes[2]; + uniqueNodes[2] = curNodes[3]; + uniqueNodes[3] = curNodes[5]; + uniqueNodes[4] = curNodes[6]; + uniqueNodes[5] = curNodes[0]; + isOk = true; + } + if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) { + uniqueNodes[0] = curNodes[0]; + uniqueNodes[1] = curNodes[1]; + uniqueNodes[2] = curNodes[3]; + uniqueNodes[3] = curNodes[4]; + uniqueNodes[4] = curNodes[6]; + uniqueNodes[5] = curNodes[7]; + isOk = true; + } + if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) { + uniqueNodes[0] = curNodes[0]; + uniqueNodes[1] = curNodes[2]; + uniqueNodes[2] = curNodes[3]; + uniqueNodes[3] = curNodes[1]; + uniqueNodes[4] = curNodes[6]; + uniqueNodes[5] = curNodes[7]; + isOk = true; + } + if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) { + uniqueNodes[0] = curNodes[0]; + uniqueNodes[1] = curNodes[1]; + uniqueNodes[2] = curNodes[2]; + uniqueNodes[3] = curNodes[4]; + uniqueNodes[4] = curNodes[5]; + uniqueNodes[5] = curNodes[7]; + isOk = true; + } + if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) { + uniqueNodes[0] = curNodes[0]; + uniqueNodes[1] = curNodes[1]; + uniqueNodes[2] = curNodes[3]; + uniqueNodes[3] = curNodes[4]; + uniqueNodes[4] = curNodes[2]; + uniqueNodes[5] = curNodes[7]; + isOk = true; + } + if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) { + uniqueNodes[0] = curNodes[0]; + uniqueNodes[1] = curNodes[1]; + uniqueNodes[2] = curNodes[2]; + uniqueNodes[3] = curNodes[4]; + uniqueNodes[4] = curNodes[5]; + uniqueNodes[5] = curNodes[3]; + isOk = true; + } + } + if(nbRepl==4) { + MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]); + } + if(nbRepl==5) { + MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]); + } + break; + } + //////////////////////////////////// HEXAHEDRON + isOk = false; + SMDS_VolumeTool hexa (elem); + hexa.SetExternalNormal(); + if ( nbUniqueNodes == 4 && nbRepl == 4 ) { + //////////////////////// HEX ---> 1 tetrahedron + for ( int iFace = 0; iFace < 6; iFace++ ) { + const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes + if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] && + curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] && + curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) { + // one face turns into a point ... + int iOppFace = hexa.GetOppFaceIndex( iFace ); + ind = hexa.GetFaceNodesIndices( iOppFace ); + int nbStick = 0; + for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) { + if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] ) + nbStick++; + } + if ( nbStick == 1 ) { + // ... and the opposite one - into a triangle. + // set a top node + ind = hexa.GetFaceNodesIndices( iFace ); + uniqueNodes[ 3 ] = curNodes[ind[ 0 ]]; + isOk = true; + } + break; + } + } + } + else if ( nbUniqueNodes == 6 && nbRepl == 2 ) { + //////////////////////// HEX ---> 1 prism + int nbTria = 0, iTria[3]; + const int *ind; // indices of face nodes + // look for triangular faces + for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) { + ind = hexa.GetFaceNodesIndices( iFace ); + TIDSortedNodeSet faceNodes; + for ( iCur = 0; iCur < 4; iCur++ ) + faceNodes.insert( curNodes[ind[iCur]] ); + if ( faceNodes.size() == 3 ) + iTria[ nbTria++ ] = iFace; + } + // check if triangles are opposite + if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] )) + { + isOk = true; + // set nodes of the bottom triangle + ind = hexa.GetFaceNodesIndices( iTria[ 0 ]); + vector indB; + for ( iCur = 0; iCur < 4; iCur++ ) + if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1]) + indB.push_back( ind[iCur] ); + if ( !hexa.IsForward() ) + std::swap( indB[0], indB[2] ); + for ( iCur = 0; iCur < 3; iCur++ ) + uniqueNodes[ iCur ] = curNodes[indB[iCur]]; + // set nodes of the top triangle + const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]); + for ( iCur = 0; iCur < 3; ++iCur ) + for ( int j = 0; j < 4; ++j ) + if ( hexa.IsLinked( indB[ iCur ], indT[ j ] )) + { + uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]]; + break; + } + } + break; + } + else if (nbUniqueNodes == 5 && nbRepl == 4 ) { + //////////////////// HEXAHEDRON ---> 2 tetrahedrons + for ( int iFace = 0; iFace < 6; iFace++ ) { + const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes + if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] && + curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] && + curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) { + // one face turns into a point ... + int iOppFace = hexa.GetOppFaceIndex( iFace ); + ind = hexa.GetFaceNodesIndices( iOppFace ); + int nbStick = 0; + iUnique = 2; // reverse a tetrahedron 1 bottom + for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) { + if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] ) + nbStick++; + else if ( iUnique >= 0 ) + uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]]; + } + if ( nbStick == 0 ) { + // ... and the opposite one is a quadrangle + // set a top node + const int* indTop = hexa.GetFaceNodesIndices( iFace ); + uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]]; + nbUniqueNodes = 4; + // tetrahedron 2 + SMDS_MeshElement* newElem = + aMesh->AddVolume(curNodes[ind[ 0 ]], + curNodes[ind[ 3 ]], + curNodes[ind[ 2 ]], + curNodes[indTop[ 0 ]]); + myLastCreatedElems.Append(newElem); + if ( aShapeId ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + isOk = true; + } + break; + } + } + } + else if ( nbUniqueNodes == 6 && nbRepl == 4 ) { + ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism + // find indices of quad and tri faces + int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace; + for ( iFace = 0; iFace < 6; iFace++ ) { + const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes + nodeSet.clear(); + for ( iCur = 0; iCur < 4; iCur++ ) + nodeSet.insert( curNodes[ind[ iCur ]] ); + nbUniqueNodes = nodeSet.size(); + if ( nbUniqueNodes == 3 ) + iTriFace[ nbTri++ ] = iFace; + else if ( nbUniqueNodes == 4 ) + iQuadFace[ nbQuad++ ] = iFace; + } + if (nbQuad == 2 && nbTri == 4 && + hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) { + // 2 opposite quadrangles stuck with a diagonal; + // sample groups of merged indices: (0-4)(2-6) + // --------------------------------------------> 2 tetrahedrons + const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes + const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]); + int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top + if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] && + curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) { + // stuck with 0-2 diagonal + i0 = ind1[ 3 ]; + i1d = ind1[ 0 ]; + i2 = ind1[ 1 ]; + i3d = ind1[ 2 ]; + i0t = ind2[ 1 ]; + i2t = ind2[ 3 ]; + } + else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] && + curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) { + // stuck with 1-3 diagonal + i0 = ind1[ 0 ]; + i1d = ind1[ 1 ]; + i2 = ind1[ 2 ]; + i3d = ind1[ 3 ]; + i0t = ind2[ 0 ]; + i2t = ind2[ 1 ]; + } + else { + ASSERT(0); + } + // tetrahedron 1 + uniqueNodes[ 0 ] = curNodes [ i0 ]; + uniqueNodes[ 1 ] = curNodes [ i1d ]; + uniqueNodes[ 2 ] = curNodes [ i3d ]; + uniqueNodes[ 3 ] = curNodes [ i0t ]; + nbUniqueNodes = 4; + // tetrahedron 2 + SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ], + curNodes[ i2 ], + curNodes[ i3d ], + curNodes[ i2t ]); + myLastCreatedElems.Append(newElem); + if ( aShapeId ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + isOk = true; } else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5) ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5) @@ -5301,2488 +7893,4962 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) } } } - } // if ( nbUniqueNodes == 6 && nbRepl == 4 ) - break; - } // HEXAHEDRON + } // if ( nbUniqueNodes == 6 && nbRepl == 4 ) + else + { + MESSAGE("MergeNodes() removes hexahedron "<< elem); + } + break; + } // HEXAHEDRON + + default: + isOk = false; + } // switch ( nbNodes ) + + } // if ( nbNodes != nbUniqueNodes ) // some nodes stick + + if ( isOk ) // the non-poly elem remains valid after sticking nodes + { + if ( nbNodes != nbUniqueNodes || + !aMesh->ChangeElementNodes( elem, & curNodes[0], nbNodes )) + { + elemType.Init( elem ).SetID( elem->GetID() ); + + SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0; + aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false); + + uniqueNodes.resize(nbUniqueNodes); + SMDS_MeshElement* newElem = this->AddElement( uniqueNodes, elemType ); + if ( sm && newElem ) + sm->AddElement( newElem ); + if ( elem != newElem ) + ReplaceElemInGroups( elem, newElem, aMesh ); + } + } + else { + // Remove invalid regular element or invalid polygon + rmElemIds.push_back( elem->GetID() ); + } + + } // loop on elements + + // Remove bad elements, then equal nodes (order important) + + Remove( rmElemIds, false ); + Remove( rmNodeIds, true ); + + return; +} + + +// ======================================================== +// class : SortableElement +// purpose : allow sorting elements basing on their nodes +// ======================================================== +class SortableElement : public set +{ +public: + + SortableElement( const SMDS_MeshElement* theElem ) + { + myElem = theElem; + SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); + while ( nodeIt->more() ) + this->insert( nodeIt->next() ); + } + + const SMDS_MeshElement* Get() const + { return myElem; } + +private: + mutable const SMDS_MeshElement* myElem; +}; + +//======================================================================= +//function : FindEqualElements +//purpose : Return list of group of elements built on the same nodes. +// Search among theElements or in the whole mesh if theElements is empty +//======================================================================= + +void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet & theElements, + TListOfListOfElementsID & theGroupsOfElementsID) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + typedef map< SortableElement, int > TMapOfNodeSet; + typedef list TGroupOfElems; + + if ( theElements.empty() ) + { // get all elements in the mesh + SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator(); + while ( eIt->more() ) + theElements.insert( theElements.end(), eIt->next() ); + } + + vector< TGroupOfElems > arrayOfGroups; + TGroupOfElems groupOfElems; + TMapOfNodeSet mapOfNodeSet; + + TIDSortedElemSet::iterator elemIt = theElements.begin(); + for ( int i = 0; elemIt != theElements.end(); ++elemIt ) + { + const SMDS_MeshElement* curElem = *elemIt; + SortableElement SE(curElem); + // check uniqueness + pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i)); + if ( !pp.second ) { // one more coincident elem + TMapOfNodeSet::iterator& itSE = pp.first; + int ind = (*itSE).second; + arrayOfGroups[ind].push_back( curElem->GetID() ); + } + else { + arrayOfGroups.push_back( groupOfElems ); + arrayOfGroups.back().push_back( curElem->GetID() ); + i++; + } + } + + groupOfElems.clear(); + vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin(); + for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) + { + if ( groupIt->size() > 1 ) { + //groupOfElems.sort(); -- theElements is sorted already + theGroupsOfElementsID.push_back( groupOfElems ); + theGroupsOfElementsID.back().splice( theGroupsOfElementsID.back().end(), *groupIt ); + } + } +} + +//======================================================================= +//function : MergeElements +//purpose : In each given group, substitute all elements by the first one. +//======================================================================= + +void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + typedef list TListOfIDs; + TListOfIDs rmElemIds; // IDs of elems to remove + + SMESHDS_Mesh* aMesh = GetMeshDS(); + + TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin(); + while ( groupsIt != theGroupsOfElementsID.end() ) { + TListOfIDs& aGroupOfElemID = *groupsIt; + aGroupOfElemID.sort(); + int elemIDToKeep = aGroupOfElemID.front(); + const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep); + aGroupOfElemID.pop_front(); + TListOfIDs::iterator idIt = aGroupOfElemID.begin(); + while ( idIt != aGroupOfElemID.end() ) { + int elemIDToRemove = *idIt; + const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove); + // add the kept element in groups of removed one (PAL15188) + AddToSameGroups( elemToKeep, elemToRemove, aMesh ); + rmElemIds.push_back( elemIDToRemove ); + ++idIt; + } + ++groupsIt; + } + + Remove( rmElemIds, false ); +} + +//======================================================================= +//function : MergeEqualElements +//purpose : Remove all but one of elements built on the same nodes. +//======================================================================= + +void SMESH_MeshEditor::MergeEqualElements() +{ + TIDSortedElemSet aMeshElements; /* empty input == + to merge equal elements in the whole mesh */ + TListOfListOfElementsID aGroupsOfElementsID; + FindEqualElements(aMeshElements, aGroupsOfElementsID); + MergeElements(aGroupsOfElementsID); +} + +//======================================================================= +//function : findAdjacentFace +//purpose : +//======================================================================= + +static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshElement* elem) +{ + TIDSortedElemSet elemSet, avoidSet; + if ( elem ) + avoidSet.insert ( elem ); + return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet ); +} + +//======================================================================= +//function : findSegment +//purpose : Return a mesh segment by two nodes one of which can be medium +//======================================================================= + +static const SMDS_MeshElement* findSegment(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2) +{ + SMDS_ElemIteratorPtr it = n1->GetInverseElementIterator( SMDSAbs_Edge ); + while ( it->more() ) + { + const SMDS_MeshElement* seg = it->next(); + if ( seg->GetNodeIndex( n2 ) >= 0 ) + return seg; + } + return 0; +} + +//======================================================================= +//function : FindFreeBorder +//purpose : +//======================================================================= + +#define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge + +bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode, + const SMDS_MeshNode* theSecondNode, + const SMDS_MeshNode* theLastNode, + list< const SMDS_MeshNode* > & theNodes, + list< const SMDS_MeshElement* >& theFaces) +{ + if ( !theFirstNode || !theSecondNode ) + return false; + // find border face between theFirstNode and theSecondNode + const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 ); + if ( !curElem ) + return false; + + theFaces.push_back( curElem ); + theNodes.push_back( theFirstNode ); + theNodes.push_back( theSecondNode ); + + const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode; + TIDSortedElemSet foundElems; + bool needTheLast = ( theLastNode != 0 ); + + while ( nStart != theLastNode ) { + if ( nStart == theFirstNode ) + return !needTheLast; + + // find all free border faces sharing form nStart + + list< const SMDS_MeshElement* > curElemList; + list< const SMDS_MeshNode* > nStartList; + SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face); + while ( invElemIt->more() ) { + const SMDS_MeshElement* e = invElemIt->next(); + if ( e == curElem || foundElems.insert( e ).second ) { + // get nodes + int iNode = 0, nbNodes = e->NbNodes(); + vector nodes(nbNodes+1); + + if ( e->IsQuadratic() ) { + const SMDS_VtkFace* F = + dynamic_cast(e); + if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace")); + // use special nodes iterator + SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator(); + while( anIter->more() ) { + nodes[ iNode++ ] = cast2Node(anIter->next()); + } + } + else { + SMDS_ElemIteratorPtr nIt = e->nodesIterator(); + while ( nIt->more() ) + nodes[ iNode++ ] = static_cast( nIt->next() ); + } + nodes[ iNode ] = nodes[ 0 ]; + // check 2 links + for ( iNode = 0; iNode < nbNodes; iNode++ ) + if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) || + (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) && + ControlFreeBorder( &nodes[ iNode ], e->GetID() )) + { + nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]); + curElemList.push_back( e ); + } + } + } + // analyse the found + + int nbNewBorders = curElemList.size(); + if ( nbNewBorders == 0 ) { + // no free border furthermore + return !needTheLast; + } + else if ( nbNewBorders == 1 ) { + // one more element found + nIgnore = nStart; + nStart = nStartList.front(); + curElem = curElemList.front(); + theFaces.push_back( curElem ); + theNodes.push_back( nStart ); + } + else { + // several continuations found + list< const SMDS_MeshElement* >::iterator curElemIt; + list< const SMDS_MeshNode* >::iterator nStartIt; + // check if one of them reached the last node + if ( needTheLast ) { + for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin(); + curElemIt!= curElemList.end(); + curElemIt++, nStartIt++ ) + if ( *nStartIt == theLastNode ) { + theFaces.push_back( *curElemIt ); + theNodes.push_back( *nStartIt ); + return true; + } + } + // find the best free border by the continuations + list contNodes[ 2 ], *cNL; + list contFaces[ 2 ], *cFL; + for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin(); + curElemIt!= curElemList.end(); + curElemIt++, nStartIt++ ) + { + cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ]; + cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ]; + // find one more free border + if ( ! SMESH_MeshEditor::FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) { + cNL->clear(); + cFL->clear(); + } + else if ( !contNodes[0].empty() && !contNodes[1].empty() ) { + // choice: clear a worse one + int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 ); + int iWorse = ( needTheLast ? 1 - iLongest : iLongest ); + contNodes[ iWorse ].clear(); + contFaces[ iWorse ].clear(); + } + } + if ( contNodes[0].empty() && contNodes[1].empty() ) + return false; + + // append the best free border + cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ]; + cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ]; + theNodes.pop_back(); // remove nIgnore + theNodes.pop_back(); // remove nStart + theFaces.pop_back(); // remove curElem + list< const SMDS_MeshNode* >::iterator nIt = cNL->begin(); + list< const SMDS_MeshElement* >::iterator fIt = cFL->begin(); + for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt ); + for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt ); + return true; + + } // several continuations found + } // while ( nStart != theLastNode ) + + return true; +} + +//======================================================================= +//function : CheckFreeBorderNodes +//purpose : Return true if the tree nodes are on a free border +//======================================================================= + +bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1, + const SMDS_MeshNode* theNode2, + const SMDS_MeshNode* theNode3) +{ + list< const SMDS_MeshNode* > nodes; + list< const SMDS_MeshElement* > faces; + return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces); +} + +//======================================================================= +//function : SewFreeBorder +//purpose : +//warning : for border-to-side sewing theSideSecondNode is considered as +// the last side node and theSideThirdNode is not used +//======================================================================= + +SMESH_MeshEditor::Sew_Error +SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, + const SMDS_MeshNode* theBordSecondNode, + const SMDS_MeshNode* theBordLastNode, + const SMDS_MeshNode* theSideFirstNode, + const SMDS_MeshNode* theSideSecondNode, + const SMDS_MeshNode* theSideThirdNode, + const bool theSideIsFreeBorder, + const bool toCreatePolygons, + const bool toCreatePolyedrs) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + MESSAGE("::SewFreeBorder()"); + Sew_Error aResult = SEW_OK; + + // ==================================== + // find side nodes and elements + // ==================================== + + list< const SMDS_MeshNode* > nSide[ 2 ]; + list< const SMDS_MeshElement* > eSide[ 2 ]; + list< const SMDS_MeshNode* >::iterator nIt[ 2 ]; + list< const SMDS_MeshElement* >::iterator eIt[ 2 ]; + + // Free border 1 + // -------------- + if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode, + nSide[0], eSide[0])) { + MESSAGE(" Free Border 1 not found " ); + aResult = SEW_BORDER1_NOT_FOUND; + } + if (theSideIsFreeBorder) { + // Free border 2 + // -------------- + if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode, + nSide[1], eSide[1])) { + MESSAGE(" Free Border 2 not found " ); + aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND ); + } + } + if ( aResult != SEW_OK ) + return aResult; + + if (!theSideIsFreeBorder) { + // Side 2 + // -------------- + + // ------------------------------------------------------------------------- + // Algo: + // 1. If nodes to merge are not coincident, move nodes of the free border + // from the coord sys defined by the direction from the first to last + // nodes of the border to the correspondent sys of the side 2 + // 2. On the side 2, find the links most co-directed with the correspondent + // links of the free border + // ------------------------------------------------------------------------- + + // 1. Since sewing may break if there are volumes to split on the side 2, + // we wont move nodes but just compute new coordinates for them + typedef map TNodeXYZMap; + TNodeXYZMap nBordXYZ; + list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ]; + list< const SMDS_MeshNode* >::iterator nBordIt; + + gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() ); + gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() ); + gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() ); + gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() ); + double tol2 = 1.e-8; + gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 ); + if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) { + // Need node movement. + + // find X and Z axes to create trsf + gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 ); + gp_Vec X = Zs ^ Zb; + if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() ) + // Zb || Zs + X = gp_Ax2( gp::Origin(), Zb ).XDirection(); + + // coord systems + gp_Ax3 toBordAx( Pb1, Zb, X ); + gp_Ax3 fromSideAx( Ps1, Zs, X ); + gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() ); + // set trsf + gp_Trsf toBordSys, fromSide2Sys; + toBordSys.SetTransformation( toBordAx ); + fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx ); + fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() ); + + // move + for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) { + const SMDS_MeshNode* n = *nBordIt; + gp_XYZ xyz( n->X(),n->Y(),n->Z() ); + toBordSys.Transforms( xyz ); + fromSide2Sys.Transforms( xyz ); + nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz )); + } + } + else { + // just insert nodes XYZ in the nBordXYZ map + for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) { + const SMDS_MeshNode* n = *nBordIt; + nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() ))); + } + } + + // 2. On the side 2, find the links most co-directed with the correspondent + // links of the free border + + list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ]; + list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ]; + sideNodes.push_back( theSideFirstNode ); + + bool hasVolumes = false; + LinkID_Gen aLinkID_Gen( GetMeshDS() ); + set foundSideLinkIDs, checkedLinkIDs; + SMDS_VolumeTool volume; + //const SMDS_MeshNode* faceNodes[ 4 ]; + + const SMDS_MeshNode* sideNode; + const SMDS_MeshElement* sideElem; + const SMDS_MeshNode* prevSideNode = theSideFirstNode; + const SMDS_MeshNode* prevBordNode = theBordFirstNode; + nBordIt = bordNodes.begin(); + nBordIt++; + // border node position and border link direction to compare with + gp_XYZ bordPos = nBordXYZ[ *nBordIt ]; + gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ]; + // choose next side node by link direction or by closeness to + // the current border node: + bool searchByDir = ( *nBordIt != theBordLastNode ); + do { + // find the next node on the Side 2 + sideNode = 0; + double maxDot = -DBL_MAX, minDist = DBL_MAX; + long linkID; + checkedLinkIDs.clear(); + gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() ); + + // loop on inverse elements of current node (prevSideNode) on the Side 2 + SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator(); + while ( invElemIt->more() ) + { + const SMDS_MeshElement* elem = invElemIt->next(); + // prepare data for a loop on links coming to prevSideNode, of a face or a volume + int iPrevNode, iNode = 0, nbNodes = elem->NbNodes(); + vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 ); + bool isVolume = volume.Set( elem ); + const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0]; + if ( isVolume ) // --volume + hasVolumes = true; + else if ( elem->GetType()==SMDSAbs_Face ) { // --face + // retrieve all face nodes and find iPrevNode - an index of the prevSideNode + if(elem->IsQuadratic()) { + const SMDS_VtkFace* F = + dynamic_cast(elem); + if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace")); + // use special nodes iterator + SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator(); + while( anIter->more() ) { + nodes[ iNode ] = cast2Node(anIter->next()); + if ( nodes[ iNode++ ] == prevSideNode ) + iPrevNode = iNode - 1; + } + } + else { + SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); + while ( nIt->more() ) { + nodes[ iNode ] = cast2Node( nIt->next() ); + if ( nodes[ iNode++ ] == prevSideNode ) + iPrevNode = iNode - 1; + } + } + // there are 2 links to check + nbNodes = 2; + } + else // --edge + continue; + // loop on links, to be precise, on the second node of links + for ( iNode = 0; iNode < nbNodes; iNode++ ) { + const SMDS_MeshNode* n = nodes[ iNode ]; + if ( isVolume ) { + if ( !volume.IsLinked( n, prevSideNode )) + continue; + } + else { + if ( iNode ) // a node before prevSideNode + n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ]; + else // a node after prevSideNode + n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ]; + } + // check if this link was already used + long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n ); + bool isJustChecked = !checkedLinkIDs.insert( iLink ).second; + if (!isJustChecked && + foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() ) + { + // test a link geometrically + gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() ); + bool linkIsBetter = false; + double dot = 0.0, dist = 0.0; + if ( searchByDir ) { // choose most co-directed link + dot = bordDir * ( nextXYZ - prevXYZ ).Normalized(); + linkIsBetter = ( dot > maxDot ); + } + else { // choose link with the node closest to bordPos + dist = ( nextXYZ - bordPos ).SquareModulus(); + linkIsBetter = ( dist < minDist ); + } + if ( linkIsBetter ) { + maxDot = dot; + minDist = dist; + linkID = iLink; + sideNode = n; + sideElem = elem; + } + } + } + } // loop on inverse elements of prevSideNode + + if ( !sideNode ) { + MESSAGE(" Cant find path by links of the Side 2 "); + return SEW_BAD_SIDE_NODES; + } + sideNodes.push_back( sideNode ); + sideElems.push_back( sideElem ); + foundSideLinkIDs.insert ( linkID ); + prevSideNode = sideNode; + + if ( *nBordIt == theBordLastNode ) + searchByDir = false; + else { + // find the next border link to compare with + gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() ); + searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 ); + // move to next border node if sideNode is before forward border node (bordPos) + while ( *nBordIt != theBordLastNode && !searchByDir ) { + prevBordNode = *nBordIt; + nBordIt++; + bordPos = nBordXYZ[ *nBordIt ]; + bordDir = bordPos - nBordXYZ[ prevBordNode ]; + searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 ); + } + } + } + while ( sideNode != theSideSecondNode ); + + if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) { + MESSAGE("VOLUME SPLITTING IS FORBIDDEN"); + return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden + } + } // end nodes search on the side 2 + + // ============================ + // sew the border to the side 2 + // ============================ + + int nbNodes[] = { (int)nSide[0].size(), (int)nSide[1].size() }; + int maxNbNodes = Max( nbNodes[0], nbNodes[1] ); + + bool toMergeConformal = ( nbNodes[0] == nbNodes[1] ); + if ( toMergeConformal && toCreatePolygons ) + { + // do not merge quadrangles if polygons are OK (IPAL0052824) + eIt[0] = eSide[0].begin(); + eIt[1] = eSide[1].begin(); + bool allQuads[2] = { true, true }; + for ( int iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders + for ( ; allQuads[iBord] && eIt[iBord] != eSide[iBord].end(); ++eIt[iBord] ) + allQuads[iBord] = ( (*eIt[iBord])->NbCornerNodes() == 4 ); + } + toMergeConformal = ( !allQuads[0] && !allQuads[1] ); + } + + TListOfListOfNodes nodeGroupsToMerge; + if (( toMergeConformal ) || + ( theSideIsFreeBorder && !theSideThirdNode )) { + + // all nodes are to be merged + + for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin(); + nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end(); + nIt[0]++, nIt[1]++ ) + { + nodeGroupsToMerge.push_back( list() ); + nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep + nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove + } + } + else { + + // insert new nodes into the border and the side to get equal nb of segments + + // get normalized parameters of nodes on the borders + vector< double > param[ 2 ]; + param[0].resize( maxNbNodes ); + param[1].resize( maxNbNodes ); + int iNode, iBord; + for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders + list< const SMDS_MeshNode* >& nodes = nSide[ iBord ]; + list< const SMDS_MeshNode* >::iterator nIt = nodes.begin(); + const SMDS_MeshNode* nPrev = *nIt; + double bordLength = 0; + for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes + const SMDS_MeshNode* nCur = *nIt; + gp_XYZ segment (nCur->X() - nPrev->X(), + nCur->Y() - nPrev->Y(), + nCur->Z() - nPrev->Z()); + double segmentLen = segment.Modulus(); + bordLength += segmentLen; + param[ iBord ][ iNode ] = bordLength; + nPrev = nCur; + } + // normalize within [0,1] + for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) { + param[ iBord ][ iNode ] /= bordLength; + } + } + + // loop on border segments + const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 }; + int i[ 2 ] = { 0, 0 }; + nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin(); + nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin(); + + TElemOfNodeListMap insertMap; + TElemOfNodeListMap::iterator insertMapIt; + // insertMap is + // key: elem to insert nodes into + // value: 2 nodes to insert between + nodes to be inserted + do { + bool next[ 2 ] = { false, false }; + + // find min adjacent segment length after sewing + double nextParam = 10., prevParam = 0; + for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders + if ( i[ iBord ] + 1 < nbNodes[ iBord ]) + nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]); + if ( i[ iBord ] > 0 ) + prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]); + } + double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]); + double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]); + double minSegLen = Min( nextParam - minParam, maxParam - prevParam ); + + // choose to insert or to merge nodes + double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ]; + if ( Abs( du ) <= minSegLen * 0.2 ) { + // merge + // ------ + nodeGroupsToMerge.push_back( list() ); + const SMDS_MeshNode* n0 = *nIt[0]; + const SMDS_MeshNode* n1 = *nIt[1]; + nodeGroupsToMerge.back().push_back( n1 ); + nodeGroupsToMerge.back().push_back( n0 ); + // position of node of the border changes due to merge + param[ 0 ][ i[0] ] += du; + // move n1 for the sake of elem shape evaluation during insertion. + // n1 will be removed by MergeNodes() anyway + const_cast( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() ); + next[0] = next[1] = true; + } + else { + // insert + // ------ + int intoBord = ( du < 0 ) ? 0 : 1; + const SMDS_MeshElement* elem = *eIt [ intoBord ]; + const SMDS_MeshNode* n1 = nPrev[ intoBord ]; + const SMDS_MeshNode* n2 = *nIt [ intoBord ]; + const SMDS_MeshNode* nIns = *nIt [ 1 - intoBord ]; + if ( intoBord == 1 ) { + // move node of the border to be on a link of elem of the side + gp_XYZ p1 (n1->X(), n1->Y(), n1->Z()); + gp_XYZ p2 (n2->X(), n2->Y(), n2->Z()); + double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]); + gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio; + GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() ); + } + insertMapIt = insertMap.find( elem ); + bool notFound = ( insertMapIt == insertMap.end() ); + bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 ); + if ( otherLink ) { + // insert into another link of the same element: + // 1. perform insertion into the other link of the elem + list & nodeList = (*insertMapIt).second; + const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front(); + const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front(); + InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons ); + // 2. perform insertion into the link of adjacent faces + while ( const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem )) { + InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons ); + } + while ( const SMDS_MeshElement* seg = findSegment( n12, n22 )) { + InsertNodesIntoLink( seg, n12, n22, nodeList ); + } + if (toCreatePolyedrs) { + // perform insertion into the links of adjacent volumes + UpdateVolumes(n12, n22, nodeList); + } + // 3. find an element appeared on n1 and n2 after the insertion + insertMap.erase( elem ); + elem = findAdjacentFace( n1, n2, 0 ); + } + if ( notFound || otherLink ) { + // add element and nodes of the side into the insertMap + insertMapIt = insertMap.insert( make_pair( elem, list() )).first; + (*insertMapIt).second.push_back( n1 ); + (*insertMapIt).second.push_back( n2 ); + } + // add node to be inserted into elem + (*insertMapIt).second.push_back( nIns ); + next[ 1 - intoBord ] = true; + } + + // go to the next segment + for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders + if ( next[ iBord ] ) { + if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end()) + eIt[ iBord ]++; + nPrev[ iBord ] = *nIt[ iBord ]; + nIt[ iBord ]++; i[ iBord ]++; + } + } + } + while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end()); + + // perform insertion of nodes into elements + + for (insertMapIt = insertMap.begin(); + insertMapIt != insertMap.end(); + insertMapIt++ ) + { + const SMDS_MeshElement* elem = (*insertMapIt).first; + list & nodeList = (*insertMapIt).second; + const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front(); + const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front(); + + InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons ); + + while ( const SMDS_MeshElement* seg = findSegment( n1, n2 )) { + InsertNodesIntoLink( seg, n1, n2, nodeList ); + } + + if ( !theSideIsFreeBorder ) { + // look for and insert nodes into the faces adjacent to elem + while ( const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem )) { + InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons ); + } + } + if (toCreatePolyedrs) { + // perform insertion into the links of adjacent volumes + UpdateVolumes(n1, n2, nodeList); + } + } + } // end: insert new nodes + + MergeNodes ( nodeGroupsToMerge ); + + + // Remove coincident segments + + // get new segments + TIDSortedElemSet segments; + SMESH_SequenceOfElemPtr newFaces; + for ( int i = 1; i <= myLastCreatedElems.Length(); ++i ) + { + if ( !myLastCreatedElems(i) ) continue; + if ( myLastCreatedElems(i)->GetType() == SMDSAbs_Edge ) + segments.insert( segments.end(), myLastCreatedElems(i) ); + else + newFaces.Append( myLastCreatedElems(i) ); + } + // get segments adjacent to merged nodes + TListOfListOfNodes::iterator groupIt = nodeGroupsToMerge.begin(); + for ( ; groupIt != nodeGroupsToMerge.end(); groupIt++ ) + { + const list& nodes = *groupIt; + SMDS_ElemIteratorPtr segIt = nodes.front()->GetInverseElementIterator( SMDSAbs_Edge ); + while ( segIt->more() ) + segments.insert( segIt->next() ); + } + + // find coincident + TListOfListOfElementsID equalGroups; + if ( !segments.empty() ) + FindEqualElements( segments, equalGroups ); + if ( !equalGroups.empty() ) + { + // remove from segments those that will be removed + TListOfListOfElementsID::iterator itGroups = equalGroups.begin(); + for ( ; itGroups != equalGroups.end(); ++itGroups ) + { + list< int >& group = *itGroups; + list< int >::iterator id = group.begin(); + for ( ++id; id != group.end(); ++id ) + if ( const SMDS_MeshElement* seg = GetMeshDS()->FindElement( *id )) + segments.erase( seg ); + } + // remove equal segments + MergeElements( equalGroups ); + + // restore myLastCreatedElems + myLastCreatedElems = newFaces; + TIDSortedElemSet::iterator seg = segments.begin(); + for ( ; seg != segments.end(); ++seg ) + myLastCreatedElems.Append( *seg ); + } + + return aResult; +} + +//======================================================================= +//function : InsertNodesIntoLink +//purpose : insert theNodesToInsert into theElement between theBetweenNode1 +// and theBetweenNode2 and split theElement +//======================================================================= + +void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theElement, + const SMDS_MeshNode* theBetweenNode1, + const SMDS_MeshNode* theBetweenNode2, + list& theNodesToInsert, + const bool toCreatePoly) +{ + if ( !theElement ) return; + + SMESHDS_Mesh *aMesh = GetMeshDS(); + vector newElems; + + if ( theElement->GetType() == SMDSAbs_Edge ) + { + theNodesToInsert.push_front( theBetweenNode1 ); + theNodesToInsert.push_back ( theBetweenNode2 ); + list::iterator n = theNodesToInsert.begin(); + const SMDS_MeshNode* n1 = *n; + for ( ++n; n != theNodesToInsert.end(); ++n ) + { + const SMDS_MeshNode* n2 = *n; + if ( const SMDS_MeshElement* seg = aMesh->FindEdge( n1, n2 )) + AddToSameGroups( seg, theElement, aMesh ); + else + newElems.push_back( aMesh->AddEdge ( n1, n2 )); + n1 = n2; + } + theNodesToInsert.pop_front(); + theNodesToInsert.pop_back(); + + if ( theElement->IsQuadratic() ) // add a not split part + { + vector nodes( theElement->begin_nodes(), + theElement->end_nodes() ); + int iOther = 0, nbN = nodes.size(); + for ( ; iOther < nbN; ++iOther ) + if ( nodes[iOther] != theBetweenNode1 && + nodes[iOther] != theBetweenNode2 ) + break; + if ( iOther == 0 ) + { + if ( const SMDS_MeshElement* seg = aMesh->FindEdge( nodes[0], nodes[1] )) + AddToSameGroups( seg, theElement, aMesh ); + else + newElems.push_back( aMesh->AddEdge ( nodes[0], nodes[1] )); + } + else if ( iOther == 2 ) + { + if ( const SMDS_MeshElement* seg = aMesh->FindEdge( nodes[1], nodes[2] )) + AddToSameGroups( seg, theElement, aMesh ); + else + newElems.push_back( aMesh->AddEdge ( nodes[1], nodes[2] )); + } + } + // treat new elements + for ( size_t i = 0; i < newElems.size(); ++i ) + if ( newElems[i] ) + { + aMesh->SetMeshElementOnShape( newElems[i], theElement->getshapeId() ); + myLastCreatedElems.Append( newElems[i] ); + } + ReplaceElemInGroups( theElement, newElems, aMesh ); + aMesh->RemoveElement( theElement ); + return; + + } // if ( theElement->GetType() == SMDSAbs_Edge ) + + const SMDS_MeshElement* theFace = theElement; + if ( theFace->GetType() != SMDSAbs_Face ) return; + + // find indices of 2 link nodes and of the rest nodes + int iNode = 0, il1, il2, i3, i4; + il1 = il2 = i3 = i4 = -1; + vector nodes( theFace->NbNodes() ); + + SMDS_NodeIteratorPtr nodeIt = theFace->interlacedNodesIterator(); + while ( nodeIt->more() ) { + const SMDS_MeshNode* n = nodeIt->next(); + if ( n == theBetweenNode1 ) + il1 = iNode; + else if ( n == theBetweenNode2 ) + il2 = iNode; + else if ( i3 < 0 ) + i3 = iNode; + else + i4 = iNode; + nodes[ iNode++ ] = n; + } + if ( il1 < 0 || il2 < 0 || i3 < 0 ) + return ; + + // arrange link nodes to go one after another regarding the face orientation + bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 ); + list aNodesToInsert = theNodesToInsert; + if ( reverse ) { + iNode = il1; + il1 = il2; + il2 = iNode; + aNodesToInsert.reverse(); + } + // check that not link nodes of a quadrangles are in good order + int nbFaceNodes = theFace->NbNodes(); + if ( nbFaceNodes == 4 && i4 - i3 != 1 ) { + iNode = i3; + i3 = i4; + i4 = iNode; + } + + if (toCreatePoly || theFace->IsPoly()) { + + iNode = 0; + vector poly_nodes (nbFaceNodes + aNodesToInsert.size()); + + // add nodes of face up to first node of link + bool isFLN = false; + + if ( theFace->IsQuadratic() ) { + const SMDS_VtkFace* F = dynamic_cast(theFace); + if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace")); + // use special nodes iterator + SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator(); + while( anIter->more() && !isFLN ) { + const SMDS_MeshNode* n = cast2Node(anIter->next()); + poly_nodes[iNode++] = n; + if (n == nodes[il1]) { + isFLN = true; + } + } + // add nodes to insert + list::iterator nIt = aNodesToInsert.begin(); + for (; nIt != aNodesToInsert.end(); nIt++) { + poly_nodes[iNode++] = *nIt; + } + // add nodes of face starting from last node of link + while ( anIter->more() ) { + poly_nodes[iNode++] = cast2Node(anIter->next()); + } + } + else { + SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator(); + while ( nodeIt->more() && !isFLN ) { + const SMDS_MeshNode* n = static_cast( nodeIt->next() ); + poly_nodes[iNode++] = n; + if (n == nodes[il1]) { + isFLN = true; + } + } + // add nodes to insert + list::iterator nIt = aNodesToInsert.begin(); + for (; nIt != aNodesToInsert.end(); nIt++) { + poly_nodes[iNode++] = *nIt; + } + // add nodes of face starting from last node of link + while ( nodeIt->more() ) { + const SMDS_MeshNode* n = static_cast( nodeIt->next() ); + poly_nodes[iNode++] = n; + } + } + + // make a new face + newElems.push_back( aMesh->AddPolygonalFace( poly_nodes )); + } + + else if ( !theFace->IsQuadratic() ) + { + // put aNodesToInsert between theBetweenNode1 and theBetweenNode2 + int nbLinkNodes = 2 + aNodesToInsert.size(); + //const SMDS_MeshNode* linkNodes[ nbLinkNodes ]; + vector linkNodes( nbLinkNodes ); + linkNodes[ 0 ] = nodes[ il1 ]; + linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ]; + list::iterator nIt = aNodesToInsert.begin(); + for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) { + linkNodes[ iNode++ ] = *nIt; + } + // decide how to split a quadrangle: compare possible variants + // and choose which of splits to be a quadrangle + int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad; + if ( nbFaceNodes == 3 ) { + iBestQuad = nbSplits; + i4 = i3; + } + else if ( nbFaceNodes == 4 ) { + SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio); + double aBestRate = DBL_MAX; + for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) { + i1 = 0; i2 = 1; + double aBadRate = 0; + // evaluate elements quality + for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) { + if ( iSplit == iQuad ) { + SMDS_FaceOfNodes quad (linkNodes[ i1++ ], + linkNodes[ i2++ ], + nodes[ i3 ], + nodes[ i4 ]); + aBadRate += getBadRate( &quad, aCrit ); + } + else { + SMDS_FaceOfNodes tria (linkNodes[ i1++ ], + linkNodes[ i2++ ], + nodes[ iSplit < iQuad ? i4 : i3 ]); + aBadRate += getBadRate( &tria, aCrit ); + } + } + // choice + if ( aBadRate < aBestRate ) { + iBestQuad = iQuad; + aBestRate = aBadRate; + } + } + } + + // create new elements + i1 = 0; i2 = 1; + for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) { + SMDS_MeshElement* newElem = 0; + if ( iSplit == iBestQuad ) + newElems.push_back( aMesh->AddFace (linkNodes[ i1++ ], + linkNodes[ i2++ ], + nodes[ i3 ], + nodes[ i4 ])); + else + newElems.push_back( aMesh->AddFace (linkNodes[ i1++ ], + linkNodes[ i2++ ], + nodes[ iSplit < iBestQuad ? i4 : i3 ])); + } + + const SMDS_MeshNode* newNodes[ 4 ]; + newNodes[ 0 ] = linkNodes[ i1 ]; + newNodes[ 1 ] = linkNodes[ i2 ]; + newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ]; + newNodes[ 3 ] = nodes[ i4 ]; + if (iSplit == iBestQuad) + newElems.push_back( aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] )); + else + newElems.push_back( aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] )); + + } // end if(!theFace->IsQuadratic()) + + else { // theFace is quadratic + // we have to split theFace on simple triangles and one simple quadrangle + int tmp = il1/2; + int nbshift = tmp*2; + // shift nodes in nodes[] by nbshift + int i,j; + for(i=0; iAddFace( nodes[3], nodes[4], nodes[5] )); + if ( theFace->IsMediumNode(nodes[il1]) ) { + // create quadrangle + newElems.push_back( aMesh->AddFace( nodes[0], nodes[1], nodes[3], nodes[5] )); + n1 = 1; + n2 = 2; + n3 = 3; + } + else { + // create quadrangle + newElems.push_back( aMesh->AddFace( nodes[1], nodes[2], nodes[3], nodes[5] )); + n1 = 0; + n2 = 1; + n3 = 5; + } + } + else { // nbFaceNodes==8 - quadratic quadrangle + newElems.push_back( aMesh->AddFace( nodes[3], nodes[4], nodes[5] )); + newElems.push_back( aMesh->AddFace( nodes[5], nodes[6], nodes[7] )); + newElems.push_back( aMesh->AddFace( nodes[5], nodes[7], nodes[3] )); + if ( theFace->IsMediumNode( nodes[ il1 ])) { + // create quadrangle + newElems.push_back( aMesh->AddFace( nodes[0], nodes[1], nodes[3], nodes[7] )); + n1 = 1; + n2 = 2; + n3 = 3; + } + else { + // create quadrangle + newElems.push_back( aMesh->AddFace( nodes[1], nodes[2], nodes[3], nodes[7] )); + n1 = 0; + n2 = 1; + n3 = 7; + } + } + // create needed triangles using n1,n2,n3 and inserted nodes + int nbn = 2 + aNodesToInsert.size(); + vector aNodes(nbn); + aNodes[0 ] = nodes[n1]; + aNodes[nbn-1] = nodes[n2]; + list::iterator nIt = aNodesToInsert.begin(); + for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) { + aNodes[iNode++] = *nIt; + } + for ( i = 1; i < nbn; i++ ) + newElems.push_back( aMesh->AddFace( aNodes[i-1], aNodes[i], nodes[n3] )); + } - default: - isOk = false; - } // switch ( nbNodes ) + // remove the old face + for ( size_t i = 0; i < newElems.size(); ++i ) + if ( newElems[i] ) + { + aMesh->SetMeshElementOnShape( newElems[i], theFace->getshapeId() ); + myLastCreatedElems.Append( newElems[i] ); + } + ReplaceElemInGroups( theFace, newElems, aMesh ); + aMesh->RemoveElement(theFace); - } // if ( nbNodes != nbUniqueNodes ) // some nodes stick +} // InsertNodesIntoLink() + +//======================================================================= +//function : UpdateVolumes +//purpose : +//======================================================================= + +void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1, + const SMDS_MeshNode* theBetweenNode2, + list& theNodesToInsert) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume); + while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1 + const SMDS_MeshElement* elem = invElemIt->next(); + + // check, if current volume has link theBetweenNode1 - theBetweenNode2 + SMDS_VolumeTool aVolume (elem); + if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2)) + continue; + + // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2 + int iface, nbFaces = aVolume.NbFaces(); + vector poly_nodes; + vector quantities (nbFaces); - if ( isOk ) { - if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) { - // Change nodes of polyedre - const SMDS_PolyhedralVolumeOfNodes* aPolyedre = - static_cast( elem ); - if (aPolyedre) { - int nbFaces = aPolyedre->NbFaces(); + for (iface = 0; iface < nbFaces; iface++) { + int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0; + // faceNodes will contain (nbFaceNodes + 1) nodes, last = first + const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface); - vector poly_nodes; - vector quantities (nbFaces); + for (int inode = 0; inode < nbFaceNodes; inode++) { + poly_nodes.push_back(faceNodes[inode]); - for (int iface = 1; iface <= nbFaces; iface++) { - int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface); - quantities[iface - 1] = nbFaceNodes; + if (nbInserted == 0) { + if (faceNodes[inode] == theBetweenNode1) { + if (faceNodes[inode + 1] == theBetweenNode2) { + nbInserted = theNodesToInsert.size(); - for (inode = 1; inode <= nbFaceNodes; inode++) { - const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode); + // add nodes to insert + list::iterator nIt = theNodesToInsert.begin(); + for (; nIt != theNodesToInsert.end(); nIt++) { + poly_nodes.push_back(*nIt); + } + } + } + else if (faceNodes[inode] == theBetweenNode2) { + if (faceNodes[inode + 1] == theBetweenNode1) { + nbInserted = theNodesToInsert.size(); - TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode ); - if (nnIt != nodeNodeMap.end()) { // curNode sticks - curNode = (*nnIt).second; + // add nodes to insert in reversed order + list::iterator nIt = theNodesToInsert.end(); + nIt--; + for (; nIt != theNodesToInsert.begin(); nIt--) { + poly_nodes.push_back(*nIt); } - poly_nodes.push_back(curNode); + poly_nodes.push_back(*nIt); } } - aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities ); + else { + } } } - else { - // Change regular element or polygon - aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes ); - } - } - else { - // Remove invalid regular element or invalid polygon - rmElemIds.push_back( elem->GetID() ); + quantities[iface] = nbFaceNodes + nbInserted; } - } // loop on elements - - // Remove equal nodes and bad elements - - Remove( rmNodeIds, true ); - Remove( rmElemIds, false ); + // Replace the volume + SMESHDS_Mesh *aMesh = GetMeshDS(); + if ( SMDS_MeshElement* newElem = aMesh->AddPolyhedralVolume( poly_nodes, quantities )) + { + aMesh->SetMeshElementOnShape( newElem, elem->getshapeId() ); + myLastCreatedElems.Append( newElem ); + ReplaceElemInGroups( elem, newElem, aMesh ); + } + aMesh->RemoveElement( elem ); + } } - -// ======================================================== -// class : SortableElement -// purpose : allow sorting elements basing on their nodes -// ======================================================== -class SortableElement : public set +namespace { - public: + //================================================================================ + /*! + * \brief Transform any volume into data of SMDSEntity_Polyhedra + */ + //================================================================================ - SortableElement( const SMDS_MeshElement* theElem ) + void volumeToPolyhedron( const SMDS_MeshElement* elem, + vector & nodes, + vector & nbNodeInFaces ) + { + nodes.clear(); + nbNodeInFaces.clear(); + SMDS_VolumeTool vTool ( elem ); + for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) { - myElem = theElem; - SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); - while ( nodeIt->more() ) - this->insert( nodeIt->next() ); + const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF ); + nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF )); + nbNodeInFaces.push_back( vTool.NbFaceNodes( iF )); } + } +} - const SMDS_MeshElement* Get() const - { return myElem; } +//======================================================================= +/*! + * \brief Convert elements contained in a sub-mesh to quadratic + * \return int - nb of checked elements + */ +//======================================================================= + +int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, + SMESH_MesherHelper& theHelper, + const bool theForce3d) +{ + int nbElem = 0; + if( !theSm ) return nbElem; - void Set(const SMDS_MeshElement* e) const - { myElem = e; } + vector nbNodeInFaces; + vector nodes; + SMDS_ElemIteratorPtr ElemItr = theSm->GetElements(); + while(ElemItr->more()) + { + nbElem++; + const SMDS_MeshElement* elem = ElemItr->next(); + if( !elem ) continue; + // analyse a necessity of conversion + const SMDSAbs_ElementType aType = elem->GetType(); + if ( aType < SMDSAbs_Edge || aType > SMDSAbs_Volume ) + continue; + const SMDSAbs_EntityType aGeomType = elem->GetEntityType(); + bool hasCentralNodes = false; + if ( elem->IsQuadratic() ) + { + bool alreadyOK; + switch ( aGeomType ) { + case SMDSEntity_Quad_Triangle: + case SMDSEntity_Quad_Quadrangle: + case SMDSEntity_Quad_Hexa: + alreadyOK = !theHelper.GetIsBiQuadratic(); break; + + case SMDSEntity_BiQuad_Triangle: + case SMDSEntity_BiQuad_Quadrangle: + case SMDSEntity_TriQuad_Hexa: + alreadyOK = theHelper.GetIsBiQuadratic(); + hasCentralNodes = true; + break; + default: + alreadyOK = true; + } + // take into account already present modium nodes + switch ( aType ) { + case SMDSAbs_Volume: + theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( elem )); break; + case SMDSAbs_Face: + theHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); break; + case SMDSAbs_Edge: + theHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( elem )); break; + default:; + } + if ( alreadyOK ) + continue; + } + // get elem data needed to re-create it + // + const int id = elem->GetID(); + const int nbNodes = elem->NbCornerNodes(); + nodes.assign(elem->begin_nodes(), elem->end_nodes()); + if ( aGeomType == SMDSEntity_Polyhedra ) + nbNodeInFaces = static_cast( elem )->GetQuantities(); + else if ( aGeomType == SMDSEntity_Hexagonal_Prism ) + volumeToPolyhedron( elem, nodes, nbNodeInFaces ); + + // remove a linear element + GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false); + + // remove central nodes of biquadratic elements (biquad->quad convertion) + if ( hasCentralNodes ) + for ( size_t i = nbNodes * 2; i < nodes.size(); ++i ) + if ( nodes[i]->NbInverseElements() == 0 ) + GetMeshDS()->RemoveFreeNode( nodes[i], theSm, /*fromGroups=*/true ); - private: - mutable const SMDS_MeshElement* myElem; -}; + const SMDS_MeshElement* NewElem = 0; + switch( aType ) + { + case SMDSAbs_Edge : + { + NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d); + break; + } + case SMDSAbs_Face : + { + switch(nbNodes) + { + case 3: + NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d); + break; + case 4: + NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); + break; + default: + NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d); + } + break; + } + case SMDSAbs_Volume : + { + switch( aGeomType ) + { + case SMDSEntity_Tetra: + NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); + break; + case SMDSEntity_Pyramid: + NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d); + break; + case SMDSEntity_Penta: + NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d); + break; + case SMDSEntity_Hexa: + case SMDSEntity_Quad_Hexa: + case SMDSEntity_TriQuad_Hexa: + NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d); + break; + case SMDSEntity_Hexagonal_Prism: + default: + NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d); + } + break; + } + default : + continue; + } + ReplaceElemInGroups( elem, NewElem, GetMeshDS()); + if( NewElem && NewElem->getshapeId() < 1 ) + theSm->AddElement( NewElem ); + } + return nbElem; +} //======================================================================= -//function : FindEqualElements -//purpose : Return list of group of elements built on the same nodes. -// Search among theElements or in the whole mesh if theElements is empty +//function : ConvertToQuadratic +//purpose : //======================================================================= -void SMESH_MeshEditor::FindEqualElements(set & theElements, - TListOfListOfElementsID & theGroupsOfElementsID) + +void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + SMESHDS_Mesh* meshDS = GetMeshDS(); - typedef set TElemsSet; - typedef map< SortableElement, int > TMapOfNodeSet; - typedef list TGroupOfElems; + SMESH_MesherHelper aHelper(*myMesh); - TElemsSet elems; - if ( theElements.empty() ) - { // get all elements in the mesh - SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator(); - while ( eIt->more() ) - elems.insert( elems.end(), eIt->next()); + aHelper.SetIsQuadratic( true ); + aHelper.SetIsBiQuadratic( theToBiQuad ); + aHelper.SetElementsOnShape(true); + aHelper.ToFixNodeParameters( true ); + + // convert elements assigned to sub-meshes + int nbCheckedElems = 0; + if ( myMesh->HasShapeToMesh() ) + { + if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh())) + { + SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false); + while ( smIt->more() ) { + SMESH_subMesh* sm = smIt->next(); + if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) { + aHelper.SetSubShape( sm->GetSubShape() ); + nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d); + } + } + } } - else - elems = theElements; - vector< TGroupOfElems > arrayOfGroups; - TGroupOfElems groupOfElems; - TMapOfNodeSet mapOfNodeSet; + // convert elements NOT assigned to sub-meshes + int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes(); + if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes + { + aHelper.SetElementsOnShape(false); + SMESHDS_SubMesh *smDS = 0; - TElemsSet::iterator elemIt = elems.begin(); - for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) { - const SMDS_MeshElement* curElem = *elemIt; - SortableElement SE(curElem); - int ind = -1; - // check uniqueness - pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i)); - if( !(pp.second) ) { - TMapOfNodeSet::iterator& itSE = pp.first; - ind = (*itSE).second; - arrayOfGroups[ind].push_back(curElem->GetID()); + // convert edges + SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator(); + while( aEdgeItr->more() ) + { + const SMDS_MeshEdge* edge = aEdgeItr->next(); + if ( !edge->IsQuadratic() ) + { + int id = edge->GetID(); + const SMDS_MeshNode* n1 = edge->GetNode(0); + const SMDS_MeshNode* n2 = edge->GetNode(1); + + meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false); + + const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d); + ReplaceElemInGroups( edge, NewEdge, GetMeshDS()); + } + else + { + aHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( edge )); + } } - else { - groupOfElems.clear(); - groupOfElems.push_back(curElem->GetID()); - arrayOfGroups.push_back(groupOfElems); - i++; + + // convert faces + SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator(); + while( aFaceItr->more() ) + { + const SMDS_MeshFace* face = aFaceItr->next(); + if ( !face ) continue; + + const SMDSAbs_EntityType type = face->GetEntityType(); + bool alreadyOK; + switch( type ) + { + case SMDSEntity_Quad_Triangle: + case SMDSEntity_Quad_Quadrangle: + alreadyOK = !theToBiQuad; + aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face )); + break; + case SMDSEntity_BiQuad_Triangle: + case SMDSEntity_BiQuad_Quadrangle: + alreadyOK = theToBiQuad; + aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face )); + break; + default: alreadyOK = false; + } + if ( alreadyOK ) + continue; + + const int id = face->GetID(); + vector nodes ( face->begin_nodes(), face->end_nodes()); + + meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false); + + SMDS_MeshFace * NewFace = 0; + switch( type ) + { + case SMDSEntity_Triangle: + case SMDSEntity_Quad_Triangle: + case SMDSEntity_BiQuad_Triangle: + NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d); + if ( nodes.size() == 7 && nodes[6]->NbInverseElements() == 0 ) // rm a central node + GetMeshDS()->RemoveFreeNode( nodes[6], /*sm=*/0, /*fromGroups=*/true ); + break; + + case SMDSEntity_Quadrangle: + case SMDSEntity_Quad_Quadrangle: + case SMDSEntity_BiQuad_Quadrangle: + NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); + if ( nodes.size() == 9 && nodes[8]->NbInverseElements() == 0 ) // rm a central node + GetMeshDS()->RemoveFreeNode( nodes[8], /*sm=*/0, /*fromGroups=*/true ); + break; + + default:; + NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d); + } + ReplaceElemInGroups( face, NewFace, GetMeshDS()); } - } - vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin(); - for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) { - groupOfElems = *groupIt; - if ( groupOfElems.size() > 1 ) { - groupOfElems.sort(); - theGroupsOfElementsID.push_back(groupOfElems); + // convert volumes + vector nbNodeInFaces; + SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator(); + while(aVolumeItr->more()) + { + const SMDS_MeshVolume* volume = aVolumeItr->next(); + if ( !volume ) continue; + + const SMDSAbs_EntityType type = volume->GetEntityType(); + if ( volume->IsQuadratic() ) + { + bool alreadyOK; + switch ( type ) + { + case SMDSEntity_Quad_Hexa: alreadyOK = !theToBiQuad; break; + case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break; + default: alreadyOK = true; + } + if ( alreadyOK ) + { + aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume )); + continue; + } + } + const int id = volume->GetID(); + vector nodes (volume->begin_nodes(), volume->end_nodes()); + if ( type == SMDSEntity_Polyhedra ) + nbNodeInFaces = static_cast(volume)->GetQuantities(); + else if ( type == SMDSEntity_Hexagonal_Prism ) + volumeToPolyhedron( volume, nodes, nbNodeInFaces ); + + meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false); + + SMDS_MeshVolume * NewVolume = 0; + switch ( type ) + { + case SMDSEntity_Tetra: + NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d ); + break; + case SMDSEntity_Hexa: + case SMDSEntity_Quad_Hexa: + case SMDSEntity_TriQuad_Hexa: + NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d); + for ( size_t i = 20; i < nodes.size(); ++i ) // rm central nodes + if ( nodes[i]->NbInverseElements() == 0 ) + GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true ); + break; + case SMDSEntity_Pyramid: + NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], + nodes[3], nodes[4], id, theForce3d); + break; + case SMDSEntity_Penta: + NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], + nodes[3], nodes[4], nodes[5], id, theForce3d); + break; + case SMDSEntity_Hexagonal_Prism: + default: + NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d); + } + ReplaceElemInGroups(volume, NewVolume, meshDS); } } + + if ( !theForce3d ) + { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion + // aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh + // aHelper.FixQuadraticElements(myError); + SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError); + } } -//======================================================================= -//function : MergeElements -//purpose : In each given group, substitute all elements by the first one. -//======================================================================= +//================================================================================ +/*! + * \brief Makes given elements quadratic + * \param theForce3d - if true, the medium nodes will be placed in the middle of link + * \param theElements - elements to make quadratic + */ +//================================================================================ -void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID) +void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, + TIDSortedElemSet& theElements, + const bool theToBiQuad) { - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + if ( theElements.empty() ) return; - typedef list TListOfIDs; - TListOfIDs rmElemIds; // IDs of elems to remove + // we believe that all theElements are of the same type + const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType(); - SMESHDS_Mesh* aMesh = GetMeshDS(); + // get all nodes shared by theElements + TIDSortedNodeSet allNodes; + TIDSortedElemSet::iterator eIt = theElements.begin(); + for ( ; eIt != theElements.end(); ++eIt ) + allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() ); - TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin(); - while ( groupsIt != theGroupsOfElementsID.end() ) { - TListOfIDs& aGroupOfElemID = *groupsIt; - aGroupOfElemID.sort(); - int elemIDToKeep = aGroupOfElemID.front(); - const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep); - aGroupOfElemID.pop_front(); - TListOfIDs::iterator idIt = aGroupOfElemID.begin(); - while ( idIt != aGroupOfElemID.end() ) { - int elemIDToRemove = *idIt; - const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove); - // add the kept element in groups of removed one (PAL15188) - AddToSameGroups( elemToKeep, elemToRemove, aMesh ); - rmElemIds.push_back( elemIDToRemove ); - ++idIt; + // complete theElements with elements of lower dim whose all nodes are in allNodes + + TIDSortedElemSet quadAdjacentElems [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements + TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ]; + TIDSortedNodeSet::iterator nIt = allNodes.begin(); + for ( ; nIt != allNodes.end(); ++nIt ) + { + const SMDS_MeshNode* n = *nIt; + SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator(); + while ( invIt->more() ) + { + const SMDS_MeshElement* e = invIt->next(); + const SMDSAbs_ElementType type = e->GetType(); + if ( e->IsQuadratic() ) + { + quadAdjacentElems[ type ].insert( e ); + + bool alreadyOK; + switch ( e->GetEntityType() ) { + case SMDSEntity_Quad_Triangle: + case SMDSEntity_Quad_Quadrangle: + case SMDSEntity_Quad_Hexa: alreadyOK = !theToBiQuad; break; + case SMDSEntity_BiQuad_Triangle: + case SMDSEntity_BiQuad_Quadrangle: + case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break; + default: alreadyOK = true; + } + if ( alreadyOK ) + continue; + } + if ( type >= elemType ) + continue; // same type or more complex linear element + + if ( !checkedAdjacentElems[ type ].insert( e ).second ) + continue; // e is already checked + + // check nodes + bool allIn = true; + SMDS_NodeIteratorPtr nodeIt = e->nodeIterator(); + while ( nodeIt->more() && allIn ) + allIn = allNodes.count( nodeIt->next() ); + if ( allIn ) + theElements.insert(e ); } - ++groupsIt; } - Remove( rmElemIds, false ); -} + SMESH_MesherHelper helper(*myMesh); + helper.SetIsQuadratic( true ); + helper.SetIsBiQuadratic( theToBiQuad ); -//======================================================================= -//function : MergeEqualElements -//purpose : Remove all but one of elements built on the same nodes. -//======================================================================= + // add links of quadratic adjacent elements to the helper -void SMESH_MeshEditor::MergeEqualElements() -{ - set aMeshElements; /* empty input - - to merge equal elements in the whole mesh */ - TListOfListOfElementsID aGroupsOfElementsID; - FindEqualElements(aMeshElements, aGroupsOfElementsID); - MergeElements(aGroupsOfElementsID); -} + if ( !quadAdjacentElems[SMDSAbs_Edge].empty() ) + for ( eIt = quadAdjacentElems[SMDSAbs_Edge].begin(); + eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt ) + { + helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) ); + } + if ( !quadAdjacentElems[SMDSAbs_Face].empty() ) + for ( eIt = quadAdjacentElems[SMDSAbs_Face].begin(); + eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt ) + { + helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) ); + } + if ( !quadAdjacentElems[SMDSAbs_Volume].empty() ) + for ( eIt = quadAdjacentElems[SMDSAbs_Volume].begin(); + eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt ) + { + helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) ); + } -//======================================================================= -//function : FindFaceInSet -//purpose : Return a face having linked nodes n1 and n2 and which is -// - not in avoidSet, -// - in elemSet provided that !elemSet.empty() -//======================================================================= + // make quadratic (or bi-tri-quadratic) elements instead of linear ones -const SMDS_MeshElement* - SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1, - const SMDS_MeshNode* n2, - const TIDSortedElemSet& elemSet, - const TIDSortedElemSet& avoidSet) + SMESHDS_Mesh* meshDS = GetMeshDS(); + SMESHDS_SubMesh* smDS = 0; + for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt ) + { + const SMDS_MeshElement* elem = *eIt; -{ - SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face); - while ( invElemIt->more() ) { // loop on inverse elements of n1 - const SMDS_MeshElement* elem = invElemIt->next(); - if (avoidSet.find( elem ) != avoidSet.end() ) - continue; - if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end()) - continue; - // get face nodes and find index of n1 - int i1, nbN = elem->NbNodes(), iNode = 0; - //const SMDS_MeshNode* faceNodes[ nbN ], *n; - vector faceNodes( nbN ); - const SMDS_MeshNode* n; - SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); - while ( nIt->more() ) { - faceNodes[ iNode ] = static_cast( nIt->next() ); - if ( faceNodes[ iNode++ ] == n1 ) - i1 = iNode - 1; - } - // find a n2 linked to n1 - if(!elem->IsQuadratic()) { - for ( iNode = 0; iNode < 2; iNode++ ) { - if ( iNode ) // node before n1 - n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ]; - else // node after n1 - n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ]; - if ( n == n2 ) - return elem; - } - } - else { // analysis for quadratic elements - bool IsFind = false; - // check using only corner nodes - for ( iNode = 0; iNode < 2; iNode++ ) { - if ( iNode ) // node before n1 - n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ]; - else // node after n1 - n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ]; - if ( n == n2 ) - IsFind = true; - } - if(IsFind) { - return elem; - } - else { - // check using all nodes - const SMDS_QuadraticFaceOfNodes* F = - static_cast(elem); - // use special nodes iterator - iNode = 0; - SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); - while ( anIter->more() ) { - faceNodes[iNode] = static_cast(anIter->next()); - if ( faceNodes[ iNode++ ] == n1 ) - i1 = iNode - 1; - } - for ( iNode = 0; iNode < 2; iNode++ ) { - if ( iNode ) // node before n1 - n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ]; - else // node after n1 - n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ]; - if ( n == n2 ) { - return elem; - } - } - } - } // end analysis for quadratic elements + bool alreadyOK; + int nbCentralNodes = 0; + switch ( elem->GetEntityType() ) { + // linear convertible + case SMDSEntity_Edge: + case SMDSEntity_Triangle: + case SMDSEntity_Quadrangle: + case SMDSEntity_Tetra: + case SMDSEntity_Pyramid: + case SMDSEntity_Hexa: + case SMDSEntity_Penta: alreadyOK = false; nbCentralNodes = 0; break; + // quadratic that can become bi-quadratic + case SMDSEntity_Quad_Triangle: + case SMDSEntity_Quad_Quadrangle: + case SMDSEntity_Quad_Hexa: alreadyOK =!theToBiQuad; nbCentralNodes = 0; break; + // bi-quadratic + case SMDSEntity_BiQuad_Triangle: + case SMDSEntity_BiQuad_Quadrangle: alreadyOK = theToBiQuad; nbCentralNodes = 1; break; + case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; nbCentralNodes = 7; break; + // the rest + default: alreadyOK = true; + } + if ( alreadyOK ) continue; + + const SMDSAbs_ElementType type = elem->GetType(); + const int id = elem->GetID(); + const int nbNodes = elem->NbCornerNodes(); + vector nodes ( elem->begin_nodes(), elem->end_nodes()); + + helper.SetSubShape( elem->getshapeId() ); + + if ( !smDS || !smDS->Contains( elem )) + smDS = meshDS->MeshElements( elem->getshapeId() ); + meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false); + + SMDS_MeshElement * newElem = 0; + switch( nbNodes ) + { + case 4: // cases for most frequently used element types go first (for optimization) + if ( type == SMDSAbs_Volume ) + newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); + else + newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); + break; + case 8: + newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d); + break; + case 3: + newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], id, theForce3d); + break; + case 2: + newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d); + break; + case 5: + newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], id, theForce3d); + break; + case 6: + newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], nodes[5], id, theForce3d); + break; + default:; + } + ReplaceElemInGroups( elem, newElem, meshDS); + if( newElem && smDS ) + smDS->AddElement( newElem ); + + // remove central nodes + for ( size_t i = nodes.size() - nbCentralNodes; i < nodes.size(); ++i ) + if ( nodes[i]->NbInverseElements() == 0 ) + meshDS->RemoveFreeNode( nodes[i], smDS, /*fromGroups=*/true ); + + } // loop on theElements + + if ( !theForce3d ) + { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion + // helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh + // helper.FixQuadraticElements( myError ); + SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError); } - return 0; } //======================================================================= -//function : findAdjacentFace -//purpose : +/*! + * \brief Convert quadratic elements to linear ones and remove quadratic nodes + * \return int - nb of checked elements + */ //======================================================================= -static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1, - const SMDS_MeshNode* n2, - const SMDS_MeshElement* elem) +int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, + SMDS_ElemIteratorPtr theItr, + const int theShapeID) { - TIDSortedElemSet elemSet, avoidSet; - if ( elem ) - avoidSet.insert ( elem ); - return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet ); -} - -//======================================================================= -//function : FindFreeBorder -//purpose : -//======================================================================= + int nbElem = 0; + SMESHDS_Mesh* meshDS = GetMeshDS(); + ElemFeatures elemType; + vector nodes; -#define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge + while( theItr->more() ) + { + const SMDS_MeshElement* elem = theItr->next(); + nbElem++; + if( elem && elem->IsQuadratic()) + { + // get elem data + int nbCornerNodes = elem->NbCornerNodes(); + nodes.assign( elem->begin_nodes(), elem->end_nodes() ); -bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode, - const SMDS_MeshNode* theSecondNode, - const SMDS_MeshNode* theLastNode, - list< const SMDS_MeshNode* > & theNodes, - list< const SMDS_MeshElement* >& theFaces) -{ - if ( !theFirstNode || !theSecondNode ) - return false; - // find border face between theFirstNode and theSecondNode - const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 ); - if ( !curElem ) - return false; + elemType.Init( elem, /*basicOnly=*/false ).SetID( elem->GetID() ).SetQuad( false ); - theFaces.push_back( curElem ); - theNodes.push_back( theFirstNode ); - theNodes.push_back( theSecondNode ); + //remove a quadratic element + if ( !theSm || !theSm->Contains( elem )) + theSm = meshDS->MeshElements( elem->getshapeId() ); + meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false ); - //vector nodes; - const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode; - set < const SMDS_MeshElement* > foundElems; - bool needTheLast = ( theLastNode != 0 ); + // remove medium nodes + for ( size_t i = nbCornerNodes; i < nodes.size(); ++i ) + if ( nodes[i]->NbInverseElements() == 0 ) + meshDS->RemoveFreeNode( nodes[i], theSm ); - while ( nStart != theLastNode ) { - if ( nStart == theFirstNode ) - return !needTheLast; + // add a linear element + nodes.resize( nbCornerNodes ); + SMDS_MeshElement * newElem = AddElement( nodes, elemType ); + ReplaceElemInGroups(elem, newElem, meshDS); + if( theSm && newElem ) + theSm->AddElement( newElem ); + } + } + return nbElem; +} - // find all free border faces sharing form nStart +//======================================================================= +//function : ConvertFromQuadratic +//purpose : +//======================================================================= - list< const SMDS_MeshElement* > curElemList; - list< const SMDS_MeshNode* > nStartList; - SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face); - while ( invElemIt->more() ) { - const SMDS_MeshElement* e = invElemIt->next(); - if ( e == curElem || foundElems.insert( e ).second ) { - // get nodes - int iNode = 0, nbNodes = e->NbNodes(); - //const SMDS_MeshNode* nodes[nbNodes+1]; - vector nodes(nbNodes+1); - - if(e->IsQuadratic()) { - const SMDS_QuadraticFaceOfNodes* F = - static_cast(e); - // use special nodes iterator - SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); - while( anIter->more() ) { - nodes[ iNode++ ] = anIter->next(); - } - } - else { - SMDS_ElemIteratorPtr nIt = e->nodesIterator(); - while ( nIt->more() ) - nodes[ iNode++ ] = static_cast( nIt->next() ); - } - nodes[ iNode ] = nodes[ 0 ]; - // check 2 links - for ( iNode = 0; iNode < nbNodes; iNode++ ) - if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) || - (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) && - ControlFreeBorder( &nodes[ iNode ], e->GetID() )) - { - nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]); - curElemList.push_back( e ); - } +bool SMESH_MeshEditor::ConvertFromQuadratic() +{ + int nbCheckedElems = 0; + if ( myMesh->HasShapeToMesh() ) + { + if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh())) + { + SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false); + while ( smIt->more() ) { + SMESH_subMesh* sm = smIt->next(); + if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) + nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() ); } } - // analyse the found + } - int nbNewBorders = curElemList.size(); - if ( nbNewBorders == 0 ) { - // no free border furthermore - return !needTheLast; - } - else if ( nbNewBorders == 1 ) { - // one more element found - nIgnore = nStart; - nStart = nStartList.front(); - curElem = curElemList.front(); - theFaces.push_back( curElem ); - theNodes.push_back( nStart ); - } - else { - // several continuations found - list< const SMDS_MeshElement* >::iterator curElemIt; - list< const SMDS_MeshNode* >::iterator nStartIt; - // check if one of them reached the last node - if ( needTheLast ) { - for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin(); - curElemIt!= curElemList.end(); - curElemIt++, nStartIt++ ) - if ( *nStartIt == theLastNode ) { - theFaces.push_back( *curElemIt ); - theNodes.push_back( *nStartIt ); - return true; - } - } - // find the best free border by the continuations - list contNodes[ 2 ], *cNL; - list contFaces[ 2 ], *cFL; - for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin(); - curElemIt!= curElemList.end(); - curElemIt++, nStartIt++ ) - { - cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ]; - cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ]; - // find one more free border - if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) { - cNL->clear(); - cFL->clear(); - } - else if ( !contNodes[0].empty() && !contNodes[1].empty() ) { - // choice: clear a worse one - int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 ); - int iWorse = ( needTheLast ? 1 - iLongest : iLongest ); - contNodes[ iWorse ].clear(); - contFaces[ iWorse ].clear(); - } - } - if ( contNodes[0].empty() && contNodes[1].empty() ) - return false; + int totalNbElems = + GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes(); + if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes + { + SMESHDS_SubMesh *aSM = 0; + removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 ); + } - // append the best free border - cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ]; - cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ]; - theNodes.pop_back(); // remove nIgnore - theNodes.pop_back(); // remove nStart - theFaces.pop_back(); // remove curElem - list< const SMDS_MeshNode* >::iterator nIt = cNL->begin(); - list< const SMDS_MeshElement* >::iterator fIt = cFL->begin(); - for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt ); - for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt ); - return true; + return true; +} - } // several continuations found - } // while ( nStart != theLastNode ) +namespace +{ + //================================================================================ + /*! + * \brief Return true if all medium nodes of the element are in the node set + */ + //================================================================================ - return true; + bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet ) + { + for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i ) + if ( !nodeSet.count( elem->GetNode(i) )) + return false; + return true; + } } -//======================================================================= -//function : CheckFreeBorderNodes -//purpose : Return true if the tree nodes are on a free border -//======================================================================= +//================================================================================ +/*! + * \brief Makes given elements linear + */ +//================================================================================ -bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1, - const SMDS_MeshNode* theNode2, - const SMDS_MeshNode* theNode3) +void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements) { - list< const SMDS_MeshNode* > nodes; - list< const SMDS_MeshElement* > faces; - return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces); + if ( theElements.empty() ) return; + + // collect IDs of medium nodes of theElements; some of these nodes will be removed + set mediumNodeIDs; + TIDSortedElemSet::iterator eIt = theElements.begin(); + for ( ; eIt != theElements.end(); ++eIt ) + { + const SMDS_MeshElement* e = *eIt; + for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i ) + mediumNodeIDs.insert( e->GetNode(i)->GetID() ); + } + + // replace given elements by linear ones + SMDS_ElemIteratorPtr elemIt = elemSetIterator( theElements ); + removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 ); + + // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs + // except those elements sharing medium nodes of quadratic element whose medium nodes + // are not all in mediumNodeIDs + + // get remaining medium nodes + TIDSortedNodeSet mediumNodes; + set::iterator nIdsIt = mediumNodeIDs.begin(); + for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt ) + if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt )) + mediumNodes.insert( mediumNodes.end(), n ); + + // find more quadratic elements to convert + TIDSortedElemSet moreElemsToConvert; + TIDSortedNodeSet::iterator nIt = mediumNodes.begin(); + for ( ; nIt != mediumNodes.end(); ++nIt ) + { + SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator(); + while ( invIt->more() ) + { + const SMDS_MeshElement* e = invIt->next(); + if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes )) + { + // find a more complex element including e and + // whose medium nodes are not in mediumNodes + bool complexFound = false; + for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type ) + { + SMDS_ElemIteratorPtr invIt2 = + (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type )); + while ( invIt2->more() ) + { + const SMDS_MeshElement* eComplex = invIt2->next(); + if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes)) + { + int nbCommonNodes = SMESH_MeshAlgos::GetCommonNodes( e, eComplex ).size(); + if ( nbCommonNodes == e->NbNodes()) + { + complexFound = true; + type = SMDSAbs_NbElementTypes; // to quit from the outer loop + break; + } + } + } + } + if ( !complexFound ) + moreElemsToConvert.insert( e ); + } + } + } + elemIt = elemSetIterator( moreElemsToConvert ); + removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 ); } //======================================================================= -//function : SewFreeBorder +//function : SewSideElements //purpose : //======================================================================= SMESH_MeshEditor::Sew_Error - SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, - const SMDS_MeshNode* theBordSecondNode, - const SMDS_MeshNode* theBordLastNode, - const SMDS_MeshNode* theSideFirstNode, - const SMDS_MeshNode* theSideSecondNode, - const SMDS_MeshNode* theSideThirdNode, - const bool theSideIsFreeBorder, - const bool toCreatePolygons, - const bool toCreatePolyedrs) +SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, + TIDSortedElemSet& theSide2, + const SMDS_MeshNode* theFirstNode1, + const SMDS_MeshNode* theFirstNode2, + const SMDS_MeshNode* theSecondNode1, + const SMDS_MeshNode* theSecondNode2) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); - MESSAGE("::SewFreeBorder()"); + MESSAGE ("::::SewSideElements()"); + if ( theSide1.size() != theSide2.size() ) + return SEW_DIFF_NB_OF_ELEMENTS; + Sew_Error aResult = SEW_OK; + // Algo: + // 1. Build set of faces representing each side + // 2. Find which nodes of the side 1 to merge with ones on the side 2 + // 3. Replace nodes in elements of the side 1 and remove replaced nodes - // ==================================== - // find side nodes and elements - // ==================================== + // ======================================================================= + // 1. Build set of faces representing each side: + // ======================================================================= + // a. build set of nodes belonging to faces + // b. complete set of faces: find missing faces whose nodes are in set of nodes + // c. create temporary faces representing side of volumes if correspondent + // face does not exist - list< const SMDS_MeshNode* > nSide[ 2 ]; - list< const SMDS_MeshElement* > eSide[ 2 ]; - list< const SMDS_MeshNode* >::iterator nIt[ 2 ]; - list< const SMDS_MeshElement* >::iterator eIt[ 2 ]; + SMESHDS_Mesh* aMesh = GetMeshDS(); + // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes + //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh + TIDSortedElemSet faceSet1, faceSet2; + set volSet1, volSet2; + set nodeSet1, nodeSet2; + TIDSortedElemSet * faceSetPtr[] = { &faceSet1, &faceSet2 }; + set * volSetPtr[] = { &volSet1, &volSet2 }; + set * nodeSetPtr[] = { &nodeSet1, &nodeSet2 }; + TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 }; + int iSide, iFace, iNode; + + list tempFaceList; + for ( iSide = 0; iSide < 2; iSide++ ) { + set * nodeSet = nodeSetPtr[ iSide ]; + TIDSortedElemSet * elemSet = elemSetPtr[ iSide ]; + TIDSortedElemSet * faceSet = faceSetPtr[ iSide ]; + set * volSet = volSetPtr [ iSide ]; + set::iterator vIt; + TIDSortedElemSet::iterator eIt; + set::iterator nIt; + + // check that given nodes belong to given elements + const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2; + const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2; + int firstIndex = -1, secondIndex = -1; + for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) { + const SMDS_MeshElement* elem = *eIt; + if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 ); + if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 ); + if ( firstIndex > -1 && secondIndex > -1 ) break; + } + if ( firstIndex < 0 || secondIndex < 0 ) { + // we can simply return until temporary faces created + return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES; + } + + // ----------------------------------------------------------- + // 1a. Collect nodes of existing faces + // and build set of face nodes in order to detect missing + // faces corresponding to sides of volumes + // ----------------------------------------------------------- + + set< set > setOfFaceNodeSet; + + // loop on the given element of a side + for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) { + //const SMDS_MeshElement* elem = *eIt; + const SMDS_MeshElement* elem = *eIt; + if ( elem->GetType() == SMDSAbs_Face ) { + faceSet->insert( elem ); + set faceNodeSet; + SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); + while ( nodeIt->more() ) { + const SMDS_MeshNode* n = static_cast( nodeIt->next() ); + nodeSet->insert( n ); + faceNodeSet.insert( n ); + } + setOfFaceNodeSet.insert( faceNodeSet ); + } + else if ( elem->GetType() == SMDSAbs_Volume ) + volSet->insert( elem ); + } + // ------------------------------------------------------------------------------ + // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes + // ------------------------------------------------------------------------------ + + for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide + SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) { // loop on faces sharing a node + const SMDS_MeshElement* f = fIt->next(); + if ( faceSet->find( f ) == faceSet->end() ) { + // check if all nodes are in nodeSet and + // complete setOfFaceNodeSet if they are + set faceNodeSet; + SMDS_ElemIteratorPtr nodeIt = f->nodesIterator(); + bool allInSet = true; + while ( nodeIt->more() && allInSet ) { // loop on nodes of a face + const SMDS_MeshNode* n = static_cast( nodeIt->next() ); + if ( nodeSet->find( n ) == nodeSet->end() ) + allInSet = false; + else + faceNodeSet.insert( n ); + } + if ( allInSet ) { + faceSet->insert( f ); + setOfFaceNodeSet.insert( faceNodeSet ); + } + } + } + } + + // ------------------------------------------------------------------------- + // 1c. Create temporary faces representing sides of volumes if correspondent + // face does not exist + // ------------------------------------------------------------------------- + + if ( !volSet->empty() ) { + //int nodeSetSize = nodeSet->size(); + + // loop on given volumes + for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) { + SMDS_VolumeTool vol (*vIt); + // loop on volume faces: find free faces + // -------------------------------------- + list freeFaceList; + for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) { + if ( !vol.IsFreeFace( iFace )) + continue; + // check if there is already a face with same nodes in a face set + const SMDS_MeshElement* aFreeFace = 0; + const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace ); + int nbNodes = vol.NbFaceNodes( iFace ); + set faceNodeSet; + vol.GetFaceNodes( iFace, faceNodeSet ); + bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second; + if ( isNewFace ) { + // no such a face is given but it still can exist, check it + vector nodes ( fNodes, fNodes + nbNodes); + aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false ); + } + if ( !aFreeFace ) { + // create a temporary face + if ( nbNodes == 3 ) { + //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] ); + aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] ); + } + else if ( nbNodes == 4 ) { + //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] ); + aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] ); + } + else { + vector poly_nodes ( fNodes, & fNodes[nbNodes]); + //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes); + aFreeFace = aMesh->AddPolygonalFace(poly_nodes); + } + if ( aFreeFace ) + tempFaceList.push_back( aFreeFace ); + } + + if ( aFreeFace ) + freeFaceList.push_back( aFreeFace ); + + } // loop on faces of a volume + + // choose one of several free faces of a volume + // -------------------------------------------- + if ( freeFaceList.size() > 1 ) { + // choose a face having max nb of nodes shared by other elems of a side + int maxNbNodes = -1; + list::iterator fIt = freeFaceList.begin(); + while ( fIt != freeFaceList.end() ) { // loop on free faces + int nbSharedNodes = 0; + SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator(); + while ( nodeIt->more() ) { // loop on free face nodes + const SMDS_MeshNode* n = + static_cast( nodeIt->next() ); + SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator(); + while ( invElemIt->more() ) { + const SMDS_MeshElement* e = invElemIt->next(); + nbSharedNodes += faceSet->count( e ); + nbSharedNodes += elemSet->count( e ); + } + } + if ( nbSharedNodes > maxNbNodes ) { + maxNbNodes = nbSharedNodes; + freeFaceList.erase( freeFaceList.begin(), fIt++ ); + } + else if ( nbSharedNodes == maxNbNodes ) { + fIt++; + } + else { + freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase + } + } + if ( freeFaceList.size() > 1 ) + { + // could not choose one face, use another way + // choose a face most close to the bary center of the opposite side + gp_XYZ aBC( 0., 0., 0. ); + set addedNodes; + TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ]; + eIt = elemSet2->begin(); + for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) { + SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator(); + while ( nodeIt->more() ) { // loop on free face nodes + const SMDS_MeshNode* n = + static_cast( nodeIt->next() ); + if ( addedNodes.insert( n ).second ) + aBC += gp_XYZ( n->X(),n->Y(),n->Z() ); + } + } + aBC /= addedNodes.size(); + double minDist = DBL_MAX; + fIt = freeFaceList.begin(); + while ( fIt != freeFaceList.end() ) { // loop on free faces + double dist = 0; + SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator(); + while ( nodeIt->more() ) { // loop on free face nodes + const SMDS_MeshNode* n = + static_cast( nodeIt->next() ); + gp_XYZ p( n->X(),n->Y(),n->Z() ); + dist += ( aBC - p ).SquareModulus(); + } + if ( dist < minDist ) { + minDist = dist; + freeFaceList.erase( freeFaceList.begin(), fIt++ ); + } + else + fIt = freeFaceList.erase( fIt++ ); + } + } + } // choose one of several free faces of a volume + + if ( freeFaceList.size() == 1 ) { + const SMDS_MeshElement* aFreeFace = freeFaceList.front(); + faceSet->insert( aFreeFace ); + // complete a node set with nodes of a found free face + // for ( iNode = 0; iNode < ; iNode++ ) + // nodeSet->insert( fNodes[ iNode ] ); + } + + } // loop on volumes of a side + + // // complete a set of faces if new nodes in a nodeSet appeared + // // ---------------------------------------------------------- + // if ( nodeSetSize != nodeSet->size() ) { + // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide + // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face); + // while ( fIt->more() ) { // loop on faces sharing a node + // const SMDS_MeshElement* f = fIt->next(); + // if ( faceSet->find( f ) == faceSet->end() ) { + // // check if all nodes are in nodeSet and + // // complete setOfFaceNodeSet if they are + // set faceNodeSet; + // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator(); + // bool allInSet = true; + // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face + // const SMDS_MeshNode* n = static_cast( nodeIt->next() ); + // if ( nodeSet->find( n ) == nodeSet->end() ) + // allInSet = false; + // else + // faceNodeSet.insert( n ); + // } + // if ( allInSet ) { + // faceSet->insert( f ); + // setOfFaceNodeSet.insert( faceNodeSet ); + // } + // } + // } + // } + // } + } // Create temporary faces, if there are volumes given + } // loop on sides - // Free border 1 - // -------------- - if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode, - nSide[0], eSide[0])) { - MESSAGE(" Free Border 1 not found " ); - aResult = SEW_BORDER1_NOT_FOUND; - } - if (theSideIsFreeBorder) { - // Free border 2 - // -------------- - if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode, - nSide[1], eSide[1])) { - MESSAGE(" Free Border 2 not found " ); - aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND ); - } + if ( faceSet1.size() != faceSet2.size() ) { + // delete temporary faces: they are in reverseElements of actual nodes +// SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator(); +// while ( tmpFaceIt->more() ) +// aTmpFacesMesh.RemoveElement( tmpFaceIt->next() ); +// list::iterator tmpFaceIt = tempFaceList.begin(); +// for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt) +// aMesh->RemoveElement(*tmpFaceIt); + MESSAGE("Diff nb of faces"); + return SEW_TOPO_DIFF_SETS_OF_ELEMENTS; } - if ( aResult != SEW_OK ) - return aResult; - - if (!theSideIsFreeBorder) { - // Side 2 - // -------------- - // ------------------------------------------------------------------------- - // Algo: - // 1. If nodes to merge are not coincident, move nodes of the free border - // from the coord sys defined by the direction from the first to last - // nodes of the border to the correspondent sys of the side 2 - // 2. On the side 2, find the links most co-directed with the correspondent - // links of the free border - // ------------------------------------------------------------------------- + // ============================================================ + // 2. Find nodes to merge: + // bind a node to remove to a node to put instead + // ============================================================ - // 1. Since sewing may brake if there are volumes to split on the side 2, - // we wont move nodes but just compute new coordinates for them - typedef map TNodeXYZMap; - TNodeXYZMap nBordXYZ; - list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ]; - list< const SMDS_MeshNode* >::iterator nBordIt; + TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead + if ( theFirstNode1 != theFirstNode2 ) + nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 )); + if ( theSecondNode1 != theSecondNode2 ) + nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 )); - gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() ); - gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() ); - gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() ); - gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() ); - double tol2 = 1.e-8; - gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 ); - if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) { - // Need node movement. + LinkID_Gen aLinkID_Gen( GetMeshDS() ); + set< long > linkIdSet; // links to process + linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 )); - // find X and Z axes to create trsf - gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 ); - gp_Vec X = Zs ^ Zb; - if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() ) - // Zb || Zs - X = gp_Ax2( gp::Origin(), Zb ).XDirection(); + typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink; + list< NLink > linkList[2]; + linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 )); + linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 )); + // loop on links in linkList; find faces by links and append links + // of the found faces to linkList + list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ; + for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) + { + NLink link[] = { *linkIt[0], *linkIt[1] }; + long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second ); + if ( !linkIdSet.count( linkID ) ) + continue; - // coord systems - gp_Ax3 toBordAx( Pb1, Zb, X ); - gp_Ax3 fromSideAx( Ps1, Zs, X ); - gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() ); - // set trsf - gp_Trsf toBordSys, fromSide2Sys; - toBordSys.SetTransformation( toBordAx ); - fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx ); - fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() ); + // by links, find faces in the face sets, + // and find indices of link nodes in the found faces; + // in a face set, there is only one or no face sharing a link + // --------------------------------------------------------------- - // move - for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) { - const SMDS_MeshNode* n = *nBordIt; - gp_XYZ xyz( n->X(),n->Y(),n->Z() ); - toBordSys.Transforms( xyz ); - fromSide2Sys.Transforms( xyz ); - nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz )); + const SMDS_MeshElement* face[] = { 0, 0 }; + vector fnodes[2]; + int iLinkNode[2][2]; + TIDSortedElemSet avoidSet; + for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides + const SMDS_MeshNode* n1 = link[iSide].first; + const SMDS_MeshNode* n2 = link[iSide].second; + //cout << "Side " << iSide << " "; + //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl; + // find a face by two link nodes + face[ iSide ] = SMESH_MeshAlgos::FindFaceInSet( n1, n2, + *faceSetPtr[ iSide ], avoidSet, + &iLinkNode[iSide][0], + &iLinkNode[iSide][1] ); + if ( face[ iSide ]) + { + //cout << " F " << face[ iSide]->GetID() <erase( face[ iSide ]); + // put face nodes to fnodes + if ( face[ iSide ]->IsQuadratic() ) + { + // use interlaced nodes iterator + const SMDS_VtkFace* F = dynamic_cast( face[ iSide ]); + if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace")); + SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator(); + while ( nIter->more() ) + fnodes[ iSide ].push_back( cast2Node( nIter->next() )); + } + else + { + fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(), + face[ iSide ]->end_nodes() ); + } + fnodes[ iSide ].push_back( fnodes[ iSide ].front()); } } - else { - // just insert nodes XYZ in the nBordXYZ map - for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) { - const SMDS_MeshNode* n = *nBordIt; - nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() ))); + + // check similarity of elements of the sides + if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) { + MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 )); + if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found + aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES ); + } + else { + aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS; } + break; // do not return because it's necessary to remove tmp faces } - // 2. On the side 2, find the links most co-directed with the correspondent - // links of the free border - - list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ]; - list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ]; - sideNodes.push_back( theSideFirstNode ); + // set nodes to merge + // ------------------- - bool hasVolumes = false; - LinkID_Gen aLinkID_Gen( GetMeshDS() ); - set foundSideLinkIDs, checkedLinkIDs; - SMDS_VolumeTool volume; - //const SMDS_MeshNode* faceNodes[ 4 ]; + if ( face[0] && face[1] ) { + const int nbNodes = face[0]->NbNodes(); + if ( nbNodes != face[1]->NbNodes() ) { + MESSAGE("Diff nb of face nodes"); + aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS; + break; // do not return because it s necessary to remove tmp faces + } + bool reverse[] = { false, false }; // order of nodes in the link + for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides + // analyse link orientation in faces + int i1 = iLinkNode[ iSide ][ 0 ]; + int i2 = iLinkNode[ iSide ][ 1 ]; + reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1; + } + int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1; + int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2; + for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 ) + { + nReplaceMap.insert ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ], + fnodes[1][ ( i2 + nbNodes ) % nbNodes ])); + } - const SMDS_MeshNode* sideNode; - const SMDS_MeshElement* sideElem; - const SMDS_MeshNode* prevSideNode = theSideFirstNode; - const SMDS_MeshNode* prevBordNode = theBordFirstNode; - nBordIt = bordNodes.begin(); - nBordIt++; - // border node position and border link direction to compare with - gp_XYZ bordPos = nBordXYZ[ *nBordIt ]; - gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ]; - // choose next side node by link direction or by closeness to - // the current border node: - bool searchByDir = ( *nBordIt != theBordLastNode ); - do { - // find the next node on the Side 2 - sideNode = 0; - double maxDot = -DBL_MAX, minDist = DBL_MAX; - long linkID; - checkedLinkIDs.clear(); - gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() ); + // add other links of the faces to linkList + // ----------------------------------------- - // loop on inverse elements of current node (prevSideNode) on the Side 2 - SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator(); - while ( invElemIt->more() ) - { - const SMDS_MeshElement* elem = invElemIt->next(); - // prepare data for a loop on links coming to prevSideNode, of a face or a volume - int iPrevNode, iNode = 0, nbNodes = elem->NbNodes(); - vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 ); - bool isVolume = volume.Set( elem ); - const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0]; - if ( isVolume ) // --volume - hasVolumes = true; - else if ( elem->GetType()==SMDSAbs_Face ) { // --face - // retrieve all face nodes and find iPrevNode - an index of the prevSideNode - if(elem->IsQuadratic()) { - const SMDS_QuadraticFaceOfNodes* F = - static_cast(elem); - // use special nodes iterator - SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); - while( anIter->more() ) { - nodes[ iNode ] = anIter->next(); - if ( nodes[ iNode++ ] == prevSideNode ) - iPrevNode = iNode - 1; - } - } - else { - SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); - while ( nIt->more() ) { - nodes[ iNode ] = cast2Node( nIt->next() ); - if ( nodes[ iNode++ ] == prevSideNode ) - iPrevNode = iNode - 1; - } - } - // there are 2 links to check - nbNodes = 2; + for ( iNode = 0; iNode < nbNodes; iNode++ ) { + linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] ); + pair< set::iterator, bool > iter_isnew = linkIdSet.insert( linkID ); + if ( !iter_isnew.second ) { // already in a set: no need to process + linkIdSet.erase( iter_isnew.first ); } - else // --edge - continue; - // loop on links, to be precise, on the second node of links - for ( iNode = 0; iNode < nbNodes; iNode++ ) { - const SMDS_MeshNode* n = nodes[ iNode ]; - if ( isVolume ) { - if ( !volume.IsLinked( n, prevSideNode )) - continue; - } - else { - if ( iNode ) // a node before prevSideNode - n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ]; - else // a node after prevSideNode - n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ]; - } - // check if this link was already used - long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n ); - bool isJustChecked = !checkedLinkIDs.insert( iLink ).second; - if (!isJustChecked && - foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() ) - { - // test a link geometrically - gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() ); - bool linkIsBetter = false; - double dot = 0.0, dist = 0.0; - if ( searchByDir ) { // choose most co-directed link - dot = bordDir * ( nextXYZ - prevXYZ ).Normalized(); - linkIsBetter = ( dot > maxDot ); - } - else { // choose link with the node closest to bordPos - dist = ( nextXYZ - bordPos ).SquareModulus(); - linkIsBetter = ( dist < minDist ); - } - if ( linkIsBetter ) { - maxDot = dot; - minDist = dist; - linkID = iLink; - sideNode = n; - sideElem = elem; - } + else // new in set == encountered for the first time: add + { + const SMDS_MeshNode* n1 = fnodes[0][ iNode ]; + const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1]; + linkList[0].push_back ( NLink( n1, n2 )); + linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] )); + } + } + } // 2 faces found + + if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() ) + break; + + } // loop on link lists + + if ( aResult == SEW_OK && + ( //linkIt[0] != linkList[0].end() || + !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) { + MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) << + " " << (faceSetPtr[1]->empty())); + aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS; + } + + // ==================================================================== + // 3. Replace nodes in elements of the side 1 and remove replaced nodes + // ==================================================================== + + // delete temporary faces +// SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator(); +// while ( tmpFaceIt->more() ) +// aTmpFacesMesh.RemoveElement( tmpFaceIt->next() ); + list::iterator tmpFaceIt = tempFaceList.begin(); + for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt) + aMesh->RemoveElement(*tmpFaceIt); + + if ( aResult != SEW_OK) + return aResult; + + list< int > nodeIDsToRemove; + vector< const SMDS_MeshNode*> nodes; + ElemFeatures elemType; + + // loop on nodes replacement map + TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt; + for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ ) + if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) + { + const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first; + nodeIDsToRemove.push_back( nToRemove->GetID() ); + // loop on elements sharing nToRemove + SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator(); + while ( invElemIt->more() ) { + const SMDS_MeshElement* e = invElemIt->next(); + // get a new suite of nodes: make replacement + int nbReplaced = 0, i = 0, nbNodes = e->NbNodes(); + nodes.resize( nbNodes ); + SMDS_ElemIteratorPtr nIt = e->nodesIterator(); + while ( nIt->more() ) { + const SMDS_MeshNode* n = static_cast( nIt->next() ); + nnIt = nReplaceMap.find( n ); + if ( nnIt != nReplaceMap.end() ) { + nbReplaced++; + n = (*nnIt).second; } + nodes[ i++ ] = n; } - } // loop on inverse elements of prevSideNode - - if ( !sideNode ) { - MESSAGE(" Cant find path by links of the Side 2 "); - return SEW_BAD_SIDE_NODES; - } - sideNodes.push_back( sideNode ); - sideElems.push_back( sideElem ); - foundSideLinkIDs.insert ( linkID ); - prevSideNode = sideNode; + // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face ) + // elemIDsToRemove.push_back( e->GetID() ); + // else + if ( nbReplaced ) + { + elemType.Init( e, /*basicOnly=*/false ).SetID( e->GetID() ); + aMesh->RemoveElement( e ); - if ( *nBordIt == theBordLastNode ) - searchByDir = false; - else { - // find the next border link to compare with - gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() ); - searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 ); - // move to next border node if sideNode is before forward border node (bordPos) - while ( *nBordIt != theBordLastNode && !searchByDir ) { - prevBordNode = *nBordIt; - nBordIt++; - bordPos = nBordXYZ[ *nBordIt ]; - bordDir = bordPos - nBordXYZ[ prevBordNode ]; - searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 ); + if ( SMDS_MeshElement* newElem = this->AddElement( nodes, elemType )) + { + AddToSameGroups( newElem, e, aMesh ); + if ( int aShapeId = e->getshapeId() ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + } } } } - while ( sideNode != theSideSecondNode ); - if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) { - MESSAGE("VOLUME SPLITTING IS FORBIDDEN"); - return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden - } - } // end nodes search on the side 2 + Remove( nodeIDsToRemove, true ); - // ============================ - // sew the border to the side 2 - // ============================ + return aResult; +} - int nbNodes[] = { (int)nSide[0].size(), (int)nSide[1].size() }; - int maxNbNodes = Max( nbNodes[0], nbNodes[1] ); +//================================================================================ +/*! + * \brief Find corresponding nodes in two sets of faces + * \param theSide1 - first face set + * \param theSide2 - second first face + * \param theFirstNode1 - a boundary node of set 1 + * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1 + * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1 + * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1 + * \param nReplaceMap - output map of corresponding nodes + * \return bool - is a success or not + */ +//================================================================================ - TListOfListOfNodes nodeGroupsToMerge; - if ( nbNodes[0] == nbNodes[1] || - ( theSideIsFreeBorder && !theSideThirdNode)) { +#ifdef _DEBUG_ +//#define DEBUG_MATCHING_NODES +#endif - // all nodes are to be merged +SMESH_MeshEditor::Sew_Error +SMESH_MeshEditor::FindMatchingNodes(set& theSide1, + set& theSide2, + const SMDS_MeshNode* theFirstNode1, + const SMDS_MeshNode* theFirstNode2, + const SMDS_MeshNode* theSecondNode1, + const SMDS_MeshNode* theSecondNode2, + TNodeNodeMap & nReplaceMap) +{ + set * faceSetPtr[] = { &theSide1, &theSide2 }; - for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin(); - nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end(); - nIt[0]++, nIt[1]++ ) - { - nodeGroupsToMerge.push_back( list() ); - nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep - nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove - } - } - else { + nReplaceMap.clear(); + if ( theFirstNode1 != theFirstNode2 ) + nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 )); + if ( theSecondNode1 != theSecondNode2 ) + nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 )); - // insert new nodes into the border and the side to get equal nb of segments + set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored + linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 )); - // get normalized parameters of nodes on the borders - //double param[ 2 ][ maxNbNodes ]; - double* param[ 2 ]; - param[0] = new double [ maxNbNodes ]; - param[1] = new double [ maxNbNodes ]; - int iNode, iBord; - for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders - list< const SMDS_MeshNode* >& nodes = nSide[ iBord ]; - list< const SMDS_MeshNode* >::iterator nIt = nodes.begin(); - const SMDS_MeshNode* nPrev = *nIt; - double bordLength = 0; - for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes - const SMDS_MeshNode* nCur = *nIt; - gp_XYZ segment (nCur->X() - nPrev->X(), - nCur->Y() - nPrev->Y(), - nCur->Z() - nPrev->Z()); - double segmentLen = segment.Modulus(); - bordLength += segmentLen; - param[ iBord ][ iNode ] = bordLength; - nPrev = nCur; - } - // normalize within [0,1] - for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) { - param[ iBord ][ iNode ] /= bordLength; - } - } + list< NLink > linkList[2]; + linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 )); + linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 )); - // loop on border segments - const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 }; - int i[ 2 ] = { 0, 0 }; - nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin(); - nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin(); + // loop on links in linkList; find faces by links and append links + // of the found faces to linkList + list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ; + for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) { + NLink link[] = { *linkIt[0], *linkIt[1] }; + if ( linkSet.find( link[0] ) == linkSet.end() ) + continue; - TElemOfNodeListMap insertMap; - TElemOfNodeListMap::iterator insertMapIt; - // insertMap is - // key: elem to insert nodes into - // value: 2 nodes to insert between + nodes to be inserted - do { - bool next[ 2 ] = { false, false }; + // by links, find faces in the face sets, + // and find indices of link nodes in the found faces; + // in a face set, there is only one or no face sharing a link + // --------------------------------------------------------------- - // find min adjacent segment length after sewing - double nextParam = 10., prevParam = 0; - for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders - if ( i[ iBord ] + 1 < nbNodes[ iBord ]) - nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]); - if ( i[ iBord ] > 0 ) - prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]); - } - double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]); - double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]); - double minSegLen = Min( nextParam - minParam, maxParam - prevParam ); + const SMDS_MeshElement* face[] = { 0, 0 }; + list notLinkNodes[2]; + //bool reverse[] = { false, false }; // order of notLinkNodes + int nbNodes[2]; + for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides + { + const SMDS_MeshNode* n1 = link[iSide].first; + const SMDS_MeshNode* n2 = link[iSide].second; + set * faceSet = faceSetPtr[ iSide ]; + set< const SMDS_MeshElement* > facesOfNode1; + for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link + { + // during a loop of the first node, we find all faces around n1, + // during a loop of the second node, we find one face sharing both n1 and n2 + const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link + SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) { // loop on faces sharing a node + const SMDS_MeshElement* f = fIt->next(); + if (faceSet->find( f ) != faceSet->end() && // f is in face set + ! facesOfNode1.insert( f ).second ) // f encounters twice + { + if ( face[ iSide ] ) { + MESSAGE( "2 faces per link " ); + return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES ); + } + face[ iSide ] = f; + faceSet->erase( f ); - // choose to insert or to merge nodes - double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ]; - if ( Abs( du ) <= minSegLen * 0.2 ) { - // merge - // ------ - nodeGroupsToMerge.push_back( list() ); - const SMDS_MeshNode* n0 = *nIt[0]; - const SMDS_MeshNode* n1 = *nIt[1]; - nodeGroupsToMerge.back().push_back( n1 ); - nodeGroupsToMerge.back().push_back( n0 ); - // position of node of the border changes due to merge - param[ 0 ][ i[0] ] += du; - // move n1 for the sake of elem shape evaluation during insertion. - // n1 will be removed by MergeNodes() anyway - const_cast( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() ); - next[0] = next[1] = true; - } - else { - // insert - // ------ - int intoBord = ( du < 0 ) ? 0 : 1; - const SMDS_MeshElement* elem = *eIt[ intoBord ]; - const SMDS_MeshNode* n1 = nPrev[ intoBord ]; - const SMDS_MeshNode* n2 = *nIt[ intoBord ]; - const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ]; - if ( intoBord == 1 ) { - // move node of the border to be on a link of elem of the side - gp_XYZ p1 (n1->X(), n1->Y(), n1->Z()); - gp_XYZ p2 (n2->X(), n2->Y(), n2->Z()); - double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]); - gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio; - GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() ); - } - insertMapIt = insertMap.find( elem ); - bool notFound = ( insertMapIt == insertMap.end() ); - bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 ); - if ( otherLink ) { - // insert into another link of the same element: - // 1. perform insertion into the other link of the elem - list & nodeList = (*insertMapIt).second; - const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front(); - const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front(); - InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons ); - // 2. perform insertion into the link of adjacent faces - while (true) { - const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem ); - if ( adjElem ) - InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons ); - else - break; - } - if (toCreatePolyedrs) { - // perform insertion into the links of adjacent volumes - UpdateVolumes(n12, n22, nodeList); + // get not link nodes + int nbN = f->NbNodes(); + if ( f->IsQuadratic() ) + nbN /= 2; + nbNodes[ iSide ] = nbN; + list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ]; + int i1 = f->GetNodeIndex( n1 ); + int i2 = f->GetNodeIndex( n2 ); + int iEnd = nbN, iBeg = -1, iDelta = 1; + bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 ); + if ( reverse ) { + std::swap( iEnd, iBeg ); iDelta = -1; + } + int i = i2; + while ( true ) { + i += iDelta; + if ( i == iEnd ) i = iBeg + iDelta; + if ( i == i1 ) break; + nodes.push_back ( f->GetNode( i ) ); + } } - // 3. find an element appeared on n1 and n2 after the insertion - insertMap.erase( elem ); - elem = findAdjacentFace( n1, n2, 0 ); - } - if ( notFound || otherLink ) { - // add element and nodes of the side into the insertMap - insertMapIt = insertMap.insert - ( TElemOfNodeListMap::value_type( elem, list() )).first; - (*insertMapIt).second.push_back( n1 ); - (*insertMapIt).second.push_back( n2 ); } - // add node to be inserted into elem - (*insertMapIt).second.push_back( nIns ); - next[ 1 - intoBord ] = true; } - - // go to the next segment - for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders - if ( next[ iBord ] ) { - if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end()) - eIt[ iBord ]++; - nPrev[ iBord ] = *nIt[ iBord ]; - nIt[ iBord ]++; i[ iBord ]++; - } + } + // check similarity of elements of the sides + if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) { + MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 )); + if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found + return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES ); + } + else { + return SEW_TOPO_DIFF_SETS_OF_ELEMENTS; } } - while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end()); - - // perform insertion of nodes into elements - - for (insertMapIt = insertMap.begin(); - insertMapIt != insertMap.end(); - insertMapIt++ ) - { - const SMDS_MeshElement* elem = (*insertMapIt).first; - list & nodeList = (*insertMapIt).second; - const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front(); - const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front(); - InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons ); + // set nodes to merge + // ------------------- - if ( !theSideIsFreeBorder ) { - // look for and insert nodes into the faces adjacent to elem - while (true) { - const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem ); - if ( adjElem ) - InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons ); - else - break; - } + if ( face[0] && face[1] ) { + if ( nbNodes[0] != nbNodes[1] ) { + MESSAGE("Diff nb of face nodes"); + return SEW_TOPO_DIFF_SETS_OF_ELEMENTS; } - if (toCreatePolyedrs) { - // perform insertion into the links of adjacent volumes - UpdateVolumes(n1, n2, nodeList); +#ifdef DEBUG_MATCHING_NODES + MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID() + << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" " + << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ; +#endif + int nbN = nbNodes[0]; + { + list::iterator n1 = notLinkNodes[0].begin(); + list::iterator n2 = notLinkNodes[1].begin(); + for ( int i = 0 ; i < nbN - 2; ++i ) { +#ifdef DEBUG_MATCHING_NODES + MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() ); +#endif + nReplaceMap.insert( make_pair( *(n1++), *(n2++) )); + } } - } - delete param[0]; - delete param[1]; - } // end: insert new nodes + // add other links of the face 1 to linkList + // ----------------------------------------- - MergeNodes ( nodeGroupsToMerge ); + const SMDS_MeshElement* f0 = face[0]; + const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 ); + for ( int i = 0; i < nbN; i++ ) + { + const SMDS_MeshNode* n2 = f0->GetNode( i ); + pair< set< SMESH_TLink >::iterator, bool > iter_isnew = + linkSet.insert( SMESH_TLink( n1, n2 )); + if ( !iter_isnew.second ) { // already in a set: no need to process + linkSet.erase( iter_isnew.first ); + } + else // new in set == encountered for the first time: add + { +#ifdef DEBUG_MATCHING_NODES + MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " " + << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " ); +#endif + linkList[0].push_back ( NLink( n1, n2 )); + linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] )); + } + n1 = n2; + } + } // 2 faces found + } // loop on link lists - return aResult; + return SEW_OK; } -//======================================================================= -//function : InsertNodesIntoLink -//purpose : insert theNodesToInsert into theFace between theBetweenNode1 -// and theBetweenNode2 and split theElement -//======================================================================= +//================================================================================ +/*! + * \brief Create elements equal (on same nodes) to given ones + * \param [in] theElements - a set of elems to duplicate. If it is empty, all + * elements of the uppest dimension are duplicated. + */ +//================================================================================ -void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace, - const SMDS_MeshNode* theBetweenNode1, - const SMDS_MeshNode* theBetweenNode2, - list& theNodesToInsert, - const bool toCreatePoly) +void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements ) { - if ( theFace->GetType() != SMDSAbs_Face ) return; - - // find indices of 2 link nodes and of the rest nodes - int iNode = 0, il1, il2, i3, i4; - il1 = il2 = i3 = i4 = -1; - //const SMDS_MeshNode* nodes[ theFace->NbNodes() ]; - vector nodes( theFace->NbNodes() ); + ClearLastCreated(); + SMESHDS_Mesh* mesh = GetMeshDS(); - if(theFace->IsQuadratic()) { - const SMDS_QuadraticFaceOfNodes* F = - static_cast(theFace); - // use special nodes iterator - SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); - while( anIter->more() ) { - const SMDS_MeshNode* n = anIter->next(); - if ( n == theBetweenNode1 ) - il1 = iNode; - else if ( n == theBetweenNode2 ) - il2 = iNode; - else if ( i3 < 0 ) - i3 = iNode; - else - i4 = iNode; - nodes[ iNode++ ] = n; - } - } - else { - SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator(); - while ( nodeIt->more() ) { - const SMDS_MeshNode* n = static_cast( nodeIt->next() ); - if ( n == theBetweenNode1 ) - il1 = iNode; - else if ( n == theBetweenNode2 ) - il2 = iNode; - else if ( i3 < 0 ) - i3 = iNode; - else - i4 = iNode; - nodes[ iNode++ ] = n; - } - } - if ( il1 < 0 || il2 < 0 || i3 < 0 ) - return ; + // get an element type and an iterator over elements - // arrange link nodes to go one after another regarding the face orientation - bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 ); - list aNodesToInsert = theNodesToInsert; - if ( reverse ) { - iNode = il1; - il1 = il2; - il2 = iNode; - aNodesToInsert.reverse(); + SMDSAbs_ElementType type; + SMDS_ElemIteratorPtr elemIt; + vector< const SMDS_MeshElement* > allElems; + if ( theElements.empty() ) + { + if ( mesh->NbNodes() == 0 ) + return; + // get most complex type + SMDSAbs_ElementType types[SMDSAbs_NbElementTypes] = { + SMDSAbs_Volume, SMDSAbs_Face, SMDSAbs_Edge, + SMDSAbs_0DElement, SMDSAbs_Ball, SMDSAbs_Node + }; + for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i ) + if ( mesh->GetMeshInfo().NbElements( types[i] )) + { + type = types[i]; + break; + } + // put all elements in the vector + allElems.reserve( mesh->GetMeshInfo().NbElements( type )); + elemIt = mesh->elementsIterator( type ); + while ( elemIt->more() ) + allElems.push_back( elemIt->next()); + elemIt = elemSetIterator( allElems ); } - // check that not link nodes of a quadrangles are in good order - int nbFaceNodes = theFace->NbNodes(); - if ( nbFaceNodes == 4 && i4 - i3 != 1 ) { - iNode = i3; - i3 = i4; - i4 = iNode; + else + { + type = (*theElements.begin())->GetType(); + elemIt = elemSetIterator( theElements ); } - if (toCreatePoly || theFace->IsPoly()) { - - iNode = 0; - vector poly_nodes (nbFaceNodes + aNodesToInsert.size()); - - // add nodes of face up to first node of link - bool isFLN = false; - - if(theFace->IsQuadratic()) { - const SMDS_QuadraticFaceOfNodes* F = - static_cast(theFace); - // use special nodes iterator - SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); - while( anIter->more() && !isFLN ) { - const SMDS_MeshNode* n = anIter->next(); - poly_nodes[iNode++] = n; - if (n == nodes[il1]) { - isFLN = true; - } - } - // add nodes to insert - list::iterator nIt = aNodesToInsert.begin(); - for (; nIt != aNodesToInsert.end(); nIt++) { - poly_nodes[iNode++] = *nIt; - } - // add nodes of face starting from last node of link - while ( anIter->more() ) { - poly_nodes[iNode++] = anIter->next(); - } - } - else { - SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator(); - while ( nodeIt->more() && !isFLN ) { - const SMDS_MeshNode* n = static_cast( nodeIt->next() ); - poly_nodes[iNode++] = n; - if (n == nodes[il1]) { - isFLN = true; - } - } - // add nodes to insert - list::iterator nIt = aNodesToInsert.begin(); - for (; nIt != aNodesToInsert.end(); nIt++) { - poly_nodes[iNode++] = *nIt; - } - // add nodes of face starting from last node of link - while ( nodeIt->more() ) { - const SMDS_MeshNode* n = static_cast( nodeIt->next() ); - poly_nodes[iNode++] = n; - } - } + // duplicate elements - // edit or replace the face - SMESHDS_Mesh *aMesh = GetMeshDS(); + ElemFeatures elemType; - if (theFace->IsPoly()) { - aMesh->ChangePolygonNodes(theFace, poly_nodes); - } - else { - int aShapeId = FindShape( theFace ); + vector< const SMDS_MeshNode* > nodes; + while ( elemIt->more() ) + { + const SMDS_MeshElement* elem = elemIt->next(); + if ( elem->GetType() != type ) + continue; - SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); + elemType.Init( elem, /*basicOnly=*/false ); + nodes.assign( elem->begin_nodes(), elem->end_nodes() ); - aMesh->RemoveElement(theFace); - } - return; + AddElement( nodes, elemType ); } +} - if( !theFace->IsQuadratic() ) { - - // put aNodesToInsert between theBetweenNode1 and theBetweenNode2 - int nbLinkNodes = 2 + aNodesToInsert.size(); - //const SMDS_MeshNode* linkNodes[ nbLinkNodes ]; - vector linkNodes( nbLinkNodes ); - linkNodes[ 0 ] = nodes[ il1 ]; - linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ]; - list::iterator nIt = aNodesToInsert.begin(); - for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) { - linkNodes[ iNode++ ] = *nIt; - } - // decide how to split a quadrangle: compare possible variants - // and choose which of splits to be a quadrangle - int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad; - if ( nbFaceNodes == 3 ) { - iBestQuad = nbSplits; - i4 = i3; - } - else if ( nbFaceNodes == 4 ) { - SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio); - double aBestRate = DBL_MAX; - for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) { - i1 = 0; i2 = 1; - double aBadRate = 0; - // evaluate elements quality - for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) { - if ( iSplit == iQuad ) { - SMDS_FaceOfNodes quad (linkNodes[ i1++ ], - linkNodes[ i2++ ], - nodes[ i3 ], - nodes[ i4 ]); - aBadRate += getBadRate( &quad, aCrit ); - } - else { - SMDS_FaceOfNodes tria (linkNodes[ i1++ ], - linkNodes[ i2++ ], - nodes[ iSplit < iQuad ? i4 : i3 ]); - aBadRate += getBadRate( &tria, aCrit ); - } - } - // choice - if ( aBadRate < aBestRate ) { - iBestQuad = iQuad; - aBestRate = aBadRate; - } - } - } +//================================================================================ +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + \param theElems - the list of elements (edges or faces) to be replicated + The nodes for duplication could be found from these elements + \param theNodesNot - list of nodes to NOT replicate + \param theAffectedElems - the list of elements (cells and edges) to which the + replicated nodes should be associated to. + \return TRUE if operation has been completed successfully, FALSE otherwise +*/ +//================================================================================ - // create new elements - SMESHDS_Mesh *aMesh = GetMeshDS(); - int aShapeId = FindShape( theFace ); +bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + const TIDSortedElemSet& theAffectedElems ) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); - i1 = 0; i2 = 1; - for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) { - SMDS_MeshElement* newElem = 0; - if ( iSplit == iBestQuad ) - newElem = aMesh->AddFace (linkNodes[ i1++ ], - linkNodes[ i2++ ], - nodes[ i3 ], - nodes[ i4 ]); - else - newElem = aMesh->AddFace (linkNodes[ i1++ ], - linkNodes[ i2++ ], - nodes[ iSplit < iBestQuad ? i4 : i3 ]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - } + if ( theElems.size() == 0 ) + return false; - // change nodes of theFace - const SMDS_MeshNode* newNodes[ 4 ]; - newNodes[ 0 ] = linkNodes[ i1 ]; - newNodes[ 1 ] = linkNodes[ i2 ]; - newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ]; - newNodes[ 3 ] = nodes[ i4 ]; - aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 ); - } // end if(!theFace->IsQuadratic()) - else { // theFace is quadratic - // we have to split theFace on simple triangles and one simple quadrangle - int tmp = il1/2; - int nbshift = tmp*2; - // shift nodes in nodes[] by nbshift - int i,j; - for(i=0; iAddFace(nodes[3],nodes[4],nodes[5]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - if(theFace->IsMediumNode(nodes[il1])) { - // create quadrangle - newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - n1 = 1; - n2 = 2; - n3 = 3; - } - else { - // create quadrangle - newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - n1 = 0; - n2 = 1; - n3 = 5; - } - } - else { // nbFaceNodes==8 - quadratic quadrangle - SMDS_MeshElement* newElem = - aMesh->AddFace(nodes[3],nodes[4],nodes[5]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - if(theFace->IsMediumNode(nodes[il1])) { - // create quadrangle - newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - n1 = 1; - n2 = 2; - n3 = 3; +//================================================================================ +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + \param theMeshDS - mesh instance + \param theElems - the elements replicated or modified (nodes should be changed) + \param theNodesNot - nodes to NOT replicate + \param theNodeNodeMap - relation of old node to new created node + \param theIsDoubleElem - flag os to replicate element or modify + \return TRUE if operation has been completed successfully, FALSE otherwise +*/ +//================================================================================ + +bool SMESH_MeshEditor::doubleNodes(SMESHDS_Mesh* theMeshDS, + const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + TNodeNodeMap& theNodeNodeMap, + const bool theIsDoubleElem ) +{ + MESSAGE("doubleNodes"); + // iterate through element and duplicate them (by nodes duplication) + bool res = false; + std::vector newNodes; + ElemFeatures elemType; + + TIDSortedElemSet::const_iterator elemItr = theElems.begin(); + for ( ; elemItr != theElems.end(); ++elemItr ) + { + const SMDS_MeshElement* anElem = *elemItr; + if (!anElem) + continue; + + // duplicate nodes to duplicate element + bool isDuplicate = false; + newNodes.resize( anElem->NbNodes() ); + SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); + int ind = 0; + while ( anIter->more() ) + { + const SMDS_MeshNode* aCurrNode = static_cast( anIter->next() ); + const SMDS_MeshNode* aNewNode = aCurrNode; + TNodeNodeMap::iterator n2n = theNodeNodeMap.find( aCurrNode ); + if ( n2n != theNodeNodeMap.end() ) + { + aNewNode = n2n->second; } - else { - // create quadrangle - newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - n1 = 0; - n2 = 1; - n3 = 7; + else if ( theIsDoubleElem && !theNodesNot.count( aCurrNode )) + { + // duplicate node + aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() ); + copyPosition( aCurrNode, aNewNode ); + theNodeNodeMap[ aCurrNode ] = aNewNode; + myLastCreatedNodes.Append( aNewNode ); } + isDuplicate |= (aCurrNode != aNewNode); + newNodes[ ind++ ] = aNewNode; } - // create needed triangles using n1,n2,n3 and inserted nodes - int nbn = 2 + aNodesToInsert.size(); - //const SMDS_MeshNode* aNodes[nbn]; - vector aNodes(nbn); - aNodes[0] = nodes[n1]; - aNodes[nbn-1] = nodes[n2]; - list::iterator nIt = aNodesToInsert.begin(); - for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) { - aNodes[iNode++] = *nIt; - } - for(i=1; iAddFace(aNodes[i-1],aNodes[i],nodes[n3]); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - } - // remove old quadratic face - aMesh->RemoveElement(theFace); + if ( !isDuplicate ) + continue; + + if ( theIsDoubleElem ) + AddElement( newNodes, elemType.Init( anElem, /*basicOnly=*/false )); + else + theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], newNodes.size() ); + + res = true; } + return res; } -//======================================================================= -//function : UpdateVolumes -//purpose : -//======================================================================= -void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1, - const SMDS_MeshNode* theBetweenNode2, - list& theNodesToInsert) +//================================================================================ +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + \param theNodes - identifiers of nodes to be doubled + \param theModifiedElems - identifiers of elements to be updated by the new (doubled) + nodes. If list of element identifiers is empty then nodes are doubled but + they not assigned to elements + \return TRUE if operation has been completed successfully, FALSE otherwise +*/ +//================================================================================ + +bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, + const std::list< int >& theListOfModifiedElems ) { + MESSAGE("DoubleNodes"); myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); - SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume); - while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1 - const SMDS_MeshElement* elem = invElemIt->next(); - - // check, if current volume has link theBetweenNode1 - theBetweenNode2 - SMDS_VolumeTool aVolume (elem); - if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2)) - continue; + if ( theListOfNodes.size() == 0 ) + return false; - // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2 - int iface, nbFaces = aVolume.NbFaces(); - vector poly_nodes; - vector quantities (nbFaces); + SMESHDS_Mesh* aMeshDS = GetMeshDS(); + if ( !aMeshDS ) + return false; - for (iface = 0; iface < nbFaces; iface++) { - int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0; - // faceNodes will contain (nbFaceNodes + 1) nodes, last = first - const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface); + // iterate through nodes and duplicate them - for (int inode = 0; inode < nbFaceNodes; inode++) { - poly_nodes.push_back(faceNodes[inode]); + std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode; - if (nbInserted == 0) { - if (faceNodes[inode] == theBetweenNode1) { - if (faceNodes[inode + 1] == theBetweenNode2) { - nbInserted = theNodesToInsert.size(); + std::list< int >::const_iterator aNodeIter; + for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter ) + { + int aCurr = *aNodeIter; + SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr ); + if ( !aNode ) + continue; - // add nodes to insert - list::iterator nIt = theNodesToInsert.begin(); - for (; nIt != theNodesToInsert.end(); nIt++) { - poly_nodes.push_back(*nIt); - } - } - } - else if (faceNodes[inode] == theBetweenNode2) { - if (faceNodes[inode + 1] == theBetweenNode1) { - nbInserted = theNodesToInsert.size(); + // duplicate node - // add nodes to insert in reversed order - list::iterator nIt = theNodesToInsert.end(); - nIt--; - for (; nIt != theNodesToInsert.begin(); nIt--) { - poly_nodes.push_back(*nIt); - } - poly_nodes.push_back(*nIt); - } - } - else { - } - } - } - quantities[iface] = nbFaceNodes + nbInserted; + const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() ); + if ( aNewNode ) + { + copyPosition( aNode, aNewNode ); + anOldNodeToNewNode[ aNode ] = aNewNode; + myLastCreatedNodes.Append( aNewNode ); } + } - // Replace or update the volume - SMESHDS_Mesh *aMesh = GetMeshDS(); + // Create map of new nodes for modified elements - if (elem->IsPoly()) { - aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); + std::map< SMDS_MeshElement*, vector > anElemToNodes; - } - else { - int aShapeId = FindShape( elem ); + std::list< int >::const_iterator anElemIter; + for ( anElemIter = theListOfModifiedElems.begin(); + anElemIter != theListOfModifiedElems.end(); ++anElemIter ) + { + int aCurr = *anElemIter; + SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr ); + if ( !anElem ) + continue; - SMDS_MeshElement* newElem = - aMesh->AddPolyhedralVolume(poly_nodes, quantities); - myLastCreatedElems.Append(newElem); - if (aShapeId && newElem) - aMesh->SetMeshElementOnShape(newElem, aShapeId); + vector aNodeArr( anElem->NbNodes() ); - aMesh->RemoveElement(elem); + SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); + int ind = 0; + while ( anIter->more() ) + { + SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next(); + if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() ) + { + const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ]; + aNodeArr[ ind++ ] = aNewNode; + } + else + aNodeArr[ ind++ ] = aCurrNode; } + anElemToNodes[ anElem ] = aNodeArr; } -} -//======================================================================= -/*! - * \brief Convert elements contained in a submesh to quadratic - * \retval int - nb of checked elements - */ -//======================================================================= + // Change nodes of elements -int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, - SMESH_MesherHelper& theHelper, - const bool theForce3d) -{ - int nbElem = 0; - if( !theSm ) return nbElem; + std::map< SMDS_MeshElement*, vector >::iterator + anElemToNodesIter = anElemToNodes.begin(); + for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter ) + { + const SMDS_MeshElement* anElem = anElemToNodesIter->first; + vector aNodeArr = anElemToNodesIter->second; + if ( anElem ) + { + MESSAGE("ChangeElementNodes"); + aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() ); + } + } - const bool notFromGroups = false; - SMDS_ElemIteratorPtr ElemItr = theSm->GetElements(); - while(ElemItr->more()) + return true; +} + +namespace { + + //================================================================================ + /*! + \brief Check if element located inside shape + \return TRUE if IN or ON shape, FALSE otherwise + */ + //================================================================================ + + template + bool isInside(const SMDS_MeshElement* theElem, + Classifier& theClassifier, + const double theTol) { - nbElem++; - const SMDS_MeshElement* elem = ElemItr->next(); - if( !elem || elem->IsQuadratic() ) continue; + gp_XYZ centerXYZ (0, 0, 0); + SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator(); + while (aNodeItr->more()) + centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next())); + + gp_Pnt aPnt = centerXYZ / theElem->NbNodes(); + theClassifier.Perform(aPnt, theTol); + TopAbs_State aState = theClassifier.State(); + return (aState == TopAbs_IN || aState == TopAbs_ON ); + } + + //================================================================================ + /*! + * \brief Classifier of the 3D point on the TopoDS_Face + * with interaface suitable for isInside() + */ + //================================================================================ - int id = elem->GetID(); - int nbNodes = elem->NbNodes(); - vector aNds (nbNodes); + struct _FaceClassifier + { + Extrema_ExtPS _extremum; + BRepAdaptor_Surface _surface; + TopAbs_State _state; - for(int i = 0; i < nbNodes; i++) + _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT) { - aNds[i] = elem->GetNode(i); + _extremum.Initialize( _surface, + _surface.FirstUParameter(), _surface.LastUParameter(), + _surface.FirstVParameter(), _surface.LastVParameter(), + _surface.Tolerance(), _surface.Tolerance() ); } - SMDSAbs_ElementType aType = elem->GetType(); - - GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups); - - const SMDS_MeshElement* NewElem = 0; - - switch( aType ) + void Perform(const gp_Pnt& aPnt, double theTol) { - case SMDSAbs_Edge : + theTol *= theTol; + _state = TopAbs_OUT; + _extremum.Perform(aPnt); + if ( _extremum.IsDone() ) + for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol) + _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT ); + } + TopAbs_State State() const { - NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d); - break; + return _state; } - case SMDSAbs_Face : + }; +} + +//================================================================================ +/*! + \brief Identify the elements that will be affected by node duplication (actual duplication is not performed). + This method is the first step of DoubleNodeElemGroupsInRegion. + \param theElems - list of groups of elements (edges or faces) to be replicated + \param theNodesNot - list of groups of nodes not to replicated + \param theShape - shape to detect affected elements (element which geometric center + located on or inside shape). If the shape is null, detection is done on faces orientations + (select elements with a gravity center on the side given by faces normals). + This mode (null shape) is faster, but works only when theElems are faces, with coherents orientations. + The replicated nodes should be associated to affected elements. + \return groups of affected elements + \sa DoubleNodeElemGroupsInRegion() + */ +//================================================================================ + +bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + const TopoDS_Shape& theShape, + TIDSortedElemSet& theAffectedElems) +{ + if ( theShape.IsNull() ) + { + std::set alreadyCheckedNodes; + std::set alreadyCheckedElems; + std::set edgesToCheck; + alreadyCheckedNodes.clear(); + alreadyCheckedElems.clear(); + edgesToCheck.clear(); + + // --- iterates on elements to be replicated and get elements by back references from their nodes + + TIDSortedElemSet::const_iterator elemItr = theElems.begin(); + int ielem; + for ( ielem=1; elemItr != theElems.end(); ++elemItr ) { - switch(nbNodes) + SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr; + if (!anElem || (anElem->GetType() != SMDSAbs_Face)) + continue; + gp_XYZ normal; + SMESH_MeshAlgos::FaceNormal( anElem, normal, /*normalized=*/true ); + MESSAGE("element " << ielem++ << " normal " << normal.X() << " " << normal.Y() << " " << normal.Z()); + std::set nodesElem; + nodesElem.clear(); + SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator(); + while ( nodeItr->more() ) { - case 3: - NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d); - break; - case 4: - NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d); - break; - default: - continue; + const SMDS_MeshNode* aNode = cast2Node(nodeItr->next()); + nodesElem.insert(aNode); } - break; - } - case SMDSAbs_Volume : - { - switch(nbNodes) + std::set::iterator nodit = nodesElem.begin(); + for (; nodit != nodesElem.end(); nodit++) { - case 4: - NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d); - break; - case 6: - NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d); - break; - case 8: - NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], - aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d); - break; - default: - continue; + MESSAGE(" noeud "); + const SMDS_MeshNode* aNode = *nodit; + if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() ) + continue; + if (alreadyCheckedNodes.find(aNode) != alreadyCheckedNodes.end()) + continue; + alreadyCheckedNodes.insert(aNode); + SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator(); + while ( backElemItr->more() ) + { + MESSAGE(" backelem "); + const SMDS_MeshElement* curElem = backElemItr->next(); + if (alreadyCheckedElems.find(curElem) != alreadyCheckedElems.end()) + continue; + if (theElems.find(curElem) != theElems.end()) + continue; + alreadyCheckedElems.insert(curElem); + double x=0, y=0, z=0; + int nb = 0; + SMDS_ElemIteratorPtr nodeItr2 = curElem->nodesIterator(); + while ( nodeItr2->more() ) + { + const SMDS_MeshNode* anotherNode = cast2Node(nodeItr2->next()); + x += anotherNode->X(); + y += anotherNode->Y(); + z += anotherNode->Z(); + nb++; + } + gp_XYZ p; + p.SetCoord( x/nb -aNode->X(), + y/nb -aNode->Y(), + z/nb -aNode->Z() ); + MESSAGE(" check " << p.X() << " " << p.Y() << " " << p.Z()); + if (normal*p > 0) + { + MESSAGE(" --- inserted") + theAffectedElems.insert( curElem ); + } + else if (curElem->GetType() == SMDSAbs_Edge) + edgesToCheck.insert(curElem); + } } - break; - } - default : - continue; } - ReplaceElemInGroups( elem, NewElem, GetMeshDS()); - if( NewElem ) - theSm->AddElement( NewElem ); - } - return nbElem; -} - -//======================================================================= -//function : ConvertToQuadratic -//purpose : -//======================================================================= -void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) -{ - SMESHDS_Mesh* meshDS = GetMeshDS(); - - SMESH_MesherHelper aHelper(*myMesh); - aHelper.SetIsQuadratic( true ); - const bool notFromGroups = false; - - int nbCheckedElems = 0; - if ( myMesh->HasShapeToMesh() ) - { - if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh())) + // --- add also edges lying on the set of faces (all nodes in alreadyCheckedNodes) + std::set::iterator eit = edgesToCheck.begin(); + for( ; eit != edgesToCheck.end(); eit++) { - SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false); - while ( smIt->more() ) { - SMESH_subMesh* sm = smIt->next(); - if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) { - aHelper.SetSubShape( sm->GetSubShape() ); - nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d); + bool onside = true; + const SMDS_MeshElement* anEdge = *eit; + SMDS_ElemIteratorPtr nodeItr = anEdge->nodesIterator(); + while ( nodeItr->more() ) + { + const SMDS_MeshNode* aNode = cast2Node(nodeItr->next()); + if (alreadyCheckedNodes.find(aNode) == alreadyCheckedNodes.end()) + { + onside = false; + break; } } + if (onside) + { + MESSAGE(" --- edge onside inserted") + theAffectedElems.insert(anEdge); + } } } - int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes(); - if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes + else { - SMESHDS_SubMesh *smDS = 0; - SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator(); - while(aEdgeItr->more()) + const double aTol = Precision::Confusion(); + auto_ptr< BRepClass3d_SolidClassifier> bsc3d; + auto_ptr<_FaceClassifier> aFaceClassifier; + if ( theShape.ShapeType() == TopAbs_SOLID ) { - const SMDS_MeshEdge* edge = aEdgeItr->next(); - if(edge && !edge->IsQuadratic()) - { - int id = edge->GetID(); - const SMDS_MeshNode* n1 = edge->GetNode(0); - const SMDS_MeshNode* n2 = edge->GetNode(1); - - meshDS->RemoveFreeElement(edge, smDS, notFromGroups); - - const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d); - ReplaceElemInGroups( edge, NewEdge, GetMeshDS()); - } + bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));; + bsc3d->PerformInfinitePoint(aTol); } - SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator(); - while(aFaceItr->more()) + else if (theShape.ShapeType() == TopAbs_FACE ) { - const SMDS_MeshFace* face = aFaceItr->next(); - if(!face || face->IsQuadratic() ) continue; - - int id = face->GetID(); - int nbNodes = face->NbNodes(); - vector aNds (nbNodes); - - for(int i = 0; i < nbNodes; i++) - { - aNds[i] = face->GetNode(i); - } - - meshDS->RemoveFreeElement(face, smDS, notFromGroups); + aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape))); + } - SMDS_MeshFace * NewFace = 0; - switch(nbNodes) + // iterates on indicated elements and get elements by back references from their nodes + TIDSortedElemSet::const_iterator elemItr = theElems.begin(); + int ielem; + for ( ielem = 1; elemItr != theElems.end(); ++elemItr ) + { + MESSAGE("element " << ielem++); + SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr; + if (!anElem) + continue; + SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator(); + while ( nodeItr->more() ) { - case 3: - NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d); - break; - case 4: - NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d); - break; - default: - continue; + MESSAGE(" noeud "); + const SMDS_MeshNode* aNode = cast2Node(nodeItr->next()); + if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() ) + continue; + SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator(); + while ( backElemItr->more() ) + { + MESSAGE(" backelem "); + const SMDS_MeshElement* curElem = backElemItr->next(); + if ( curElem && theElems.find(curElem) == theElems.end() && + ( bsc3d.get() ? + isInside( curElem, *bsc3d, aTol ) : + isInside( curElem, *aFaceClassifier, aTol ))) + theAffectedElems.insert( curElem ); + } } - ReplaceElemInGroups( face, NewFace, GetMeshDS()); } - SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator(); - while(aVolumeItr->more()) - { - const SMDS_MeshVolume* volume = aVolumeItr->next(); - if(!volume || volume->IsQuadratic() ) continue; + } + return true; +} + +//================================================================================ +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + \param theElems - group of of elements (edges or faces) to be replicated + \param theNodesNot - group of nodes not to replicate + \param theShape - shape to detect affected elements (element which geometric center + located on or inside shape). + The replicated nodes should be associated to affected elements. + \return TRUE if operation has been completed successfully, FALSE otherwise +*/ +//================================================================================ - int id = volume->GetID(); - int nbNodes = volume->NbNodes(); - vector aNds (nbNodes); +bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + const TopoDS_Shape& theShape ) +{ + if ( theShape.IsNull() ) + return false; - for(int i = 0; i < nbNodes; i++) - { - aNds[i] = volume->GetNode(i); - } + const double aTol = Precision::Confusion(); + auto_ptr< BRepClass3d_SolidClassifier> bsc3d; + auto_ptr<_FaceClassifier> aFaceClassifier; + if ( theShape.ShapeType() == TopAbs_SOLID ) + { + bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));; + bsc3d->PerformInfinitePoint(aTol); + } + else if (theShape.ShapeType() == TopAbs_FACE ) + { + aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape))); + } - meshDS->RemoveFreeElement(volume, smDS, notFromGroups); + // iterates on indicated elements and get elements by back references from their nodes + TIDSortedElemSet anAffected; + TIDSortedElemSet::const_iterator elemItr = theElems.begin(); + for ( ; elemItr != theElems.end(); ++elemItr ) + { + SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr; + if (!anElem) + continue; - SMDS_MeshVolume * NewVolume = 0; - switch(nbNodes) + SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator(); + while ( nodeItr->more() ) + { + const SMDS_MeshNode* aNode = cast2Node(nodeItr->next()); + if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() ) + continue; + SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator(); + while ( backElemItr->more() ) { - case 4: - NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], - aNds[3], id, theForce3d ); - break; - case 6: - NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], - aNds[3], aNds[4], aNds[5], id, theForce3d); - break; - case 8: - NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], - aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d); - break; - default: - continue; + const SMDS_MeshElement* curElem = backElemItr->next(); + if ( curElem && theElems.find(curElem) == theElems.end() && + ( bsc3d.get() ? + isInside( curElem, *bsc3d, aTol ) : + isInside( curElem, *aFaceClassifier, aTol ))) + anAffected.insert( curElem ); } - ReplaceElemInGroups(volume, NewVolume, meshDS); } } + return DoubleNodes( theElems, theNodesNot, anAffected ); } -//======================================================================= /*! - * \brief Convert quadratic elements to linear ones and remove quadratic nodes - * \retval int - nb of checked elements + * \brief compute an oriented angle between two planes defined by four points. + * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2) + * @param p0 base of the rotation axe + * @param p1 extremity of the rotation axe + * @param g1 belongs to the first plane + * @param g2 belongs to the second plane */ -//======================================================================= - -int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, - SMDS_ElemIteratorPtr theItr, - const int theShapeID) +double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2) { - int nbElem = 0; - SMESHDS_Mesh* meshDS = GetMeshDS(); - const bool notFromGroups = false; +// MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z()); +// MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z()); +// MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z()); +// MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z()); + gp_Vec vref(p0, p1); + gp_Vec v1(p0, g1); + gp_Vec v2(p0, g2); + gp_Vec n1 = vref.Crossed(v1); + gp_Vec n2 = vref.Crossed(v2); + try { + return n2.AngleWithRef(n1, vref); + } + catch ( Standard_Failure ) { + } + return Max( v1.Magnitude(), v2.Magnitude() ); +} - while( theItr->more() ) - { - const SMDS_MeshElement* elem = theItr->next(); - nbElem++; - if( elem && elem->IsQuadratic()) +/*! + * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand. + * The list of groups must contain at least two groups. The groups have to be disjoint: no common element into two different groups. + * The nodes of the internal faces at the boundaries of the groups are doubled. Optionally, the internal faces are replaced by flat elements. + * Triangles are transformed into prisms, and quadrangles into hexahedrons. + * The flat elements are stored in groups of volumes. These groups are named according to the position of the group in the list: + * the group j_n_p is the group of the flat elements that are built between the group #n and the group #p in the list. + * If there is no shared faces between the group #n and the group #p in the list, the group j_n_p is not created. + * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation). + * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples". + * \param theElems - list of groups of volumes, where a group of volume is a set of + * SMDS_MeshElements sorted by Id. + * \param createJointElems - if TRUE, create the elements + * \param onAllBoundaries - if TRUE, the nodes and elements are also created on + * the boundary between \a theDomains and the rest mesh + * \return TRUE if operation has been completed successfully, FALSE otherwise + */ +bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector& theElems, + bool createJointElems, + bool onAllBoundaries) +{ + MESSAGE("----------------------------------------------"); + MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries"); + MESSAGE("----------------------------------------------"); + + SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS(); + meshDS->BuildDownWardConnectivity(true); + CHRONO(50); + SMDS_UnstructuredGrid *grid = meshDS->getGrid(); + + // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes + // build the list of cells with only a node or an edge on the border, with their domain and volume indexes + // build the list of nodes shared by 2 or more domains, with their domain indexes + + std::map, DownIdCompare> faceDomains; // face --> (id domain --> id volume) + std::mapcelldom; // cell vtkId --> domain + std::map, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell) + std::map > nodeDomains; // oldId --> (domainId --> newId) + faceDomains.clear(); + celldom.clear(); + cellDomains.clear(); + nodeDomains.clear(); + std::map emptyMap; + std::set emptySet; + emptyMap.clear(); + + MESSAGE(".. Number of domains :"<GetID(); - int nbNodes = elem->NbNodes(); - vector aNds, mediumNodes; - aNds.reserve( nbNodes ); - mediumNodes.reserve( nbNodes ); +// MESSAGE("... Check of domain #" << idom); + const TIDSortedElemSet& domain = theElems[idom]; + TIDSortedElemSet::const_iterator elemItr = domain.begin(); + for (; elemItr != domain.end(); ++elemItr) + { + const SMDS_MeshElement* anElem = *elemItr; + int idombisdeb = idom + 1 ; + for (int idombis = idombisdeb; idombis < theElems.size(); idombis++) // check if the element belongs to a domain further in the list + { + const TIDSortedElemSet& domainbis = theElems[idombis]; + if ( domainbis.count(anElem) ) + { + MESSAGE(".... Domain #" << idom); + MESSAGE(".... Domain #" << idombis); + throw SALOME_Exception("The domains are not disjoint."); + return false ; + } + } + } + } - for(int i = 0; i < nbNodes; i++) - { - const SMDS_MeshNode* n = elem->GetNode(i); + for (int idom = 0; idom < nbDomains; idom++) + { - if( elem->IsMediumNode( n ) ) - mediumNodes.push_back( n ); - else - aNds.push_back( n ); - } - if( aNds.empty() ) continue; - SMDSAbs_ElementType aType = elem->GetType(); + // --- build a map (face to duplicate --> volume to modify) + // with all the faces shared by 2 domains (group of elements) + // and corresponding volume of this domain, for each shared face. + // a volume has a face shared by 2 domains if it has a neighbor which is not in his domain. - //remove old quadratic element - meshDS->RemoveFreeElement( elem, theSm, notFromGroups ); + MESSAGE("... Neighbors of domain #" << idom); + const TIDSortedElemSet& domain = theElems[idom]; + TIDSortedElemSet::const_iterator elemItr = domain.begin(); + for (; elemItr != domain.end(); ++elemItr) + { + const SMDS_MeshElement* anElem = *elemItr; + if (!anElem) + continue; + int vtkId = anElem->getVtkId(); + //MESSAGE(" vtkId " << vtkId << " smdsId " << anElem->GetID()); + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId); + for (int n = 0; n < nbNeighbors; n++) + { + int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]); + const SMDS_MeshElement* elem = meshDS->FindElement(smdsId); + if (elem && ! domain.count(elem)) // neighbor is in another domain : face is shared + { + bool ok = false ; + for (int idombis = 0; idombis < theElems.size() && !ok; idombis++) // check if the neighbor belongs to another domain of the list + { + // MESSAGE("Domain " << idombis); + const TIDSortedElemSet& domainbis = theElems[idombis]; + if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept + } + if ( ok || onAllBoundaries ) // the characteristics of the face is stored + { + DownIdType face(downIds[n], downTypes[n]); + if (!faceDomains[face].count(idom)) + { + faceDomains[face][idom] = vtkId; // volume associated to face in this domain + celldom[vtkId] = idom; + //MESSAGE(" cell with a border " << vtkId << " domain " << idom); + } + if ( !ok ) + { + theRestDomElems.insert( elem ); + faceDomains[face][iRestDom] = neighborsVtkIds[n]; + celldom[neighborsVtkIds[n]] = iRestDom; + } + } + } + } + } + } - SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id ); - ReplaceElemInGroups(elem, NewElem, meshDS); - if( theSm && NewElem ) - theSm->AddElement( NewElem ); + //MESSAGE("Number of shared faces " << faceDomains.size()); + std::map, DownIdCompare>::iterator itface; - // remove medium nodes - vector::iterator nIt = mediumNodes.begin(); - for ( ; nIt != mediumNodes.end(); ++nIt ) { - const SMDS_MeshNode* n = *nIt; - if ( n->NbInverseElements() == 0 ) { - if ( n->GetPosition()->GetShapeId() != theShapeID ) - meshDS->RemoveFreeNode( n, meshDS->MeshElements - ( n->GetPosition()->GetShapeId() )); - else - meshDS->RemoveFreeNode( n, theSm ); - } - } - } - } - return nbElem; -} + // --- explore the shared faces domain by domain, + // explore the nodes of the face and see if they belong to a cell in the domain, + // which has only a node or an edge on the border (not a shared face) -//======================================================================= -//function : ConvertFromQuadratic -//purpose : -//======================================================================= -bool SMESH_MeshEditor::ConvertFromQuadratic() -{ - int nbCheckedElems = 0; - if ( myMesh->HasShapeToMesh() ) - { - if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh())) + for (int idomain = idom0; idomain < nbDomains; idomain++) { - SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false); - while ( smIt->more() ) { - SMESH_subMesh* sm = smIt->next(); - if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) - nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() ); - } + //MESSAGE("Domain " << idomain); + const TIDSortedElemSet& domain = (idomain == iRestDom) ? theRestDomElems : theElems[idomain]; + itface = faceDomains.begin(); + for (; itface != faceDomains.end(); ++itface) + { + const std::map& domvol = itface->second; + if (!domvol.count(idomain)) + continue; + DownIdType face = itface->first; + //MESSAGE(" --- face " << face.cellId); + std::set oldNodes; + oldNodes.clear(); + grid->GetNodeIds(oldNodes, face.cellId, face.cellType); + std::set::iterator itn = oldNodes.begin(); + for (; itn != oldNodes.end(); ++itn) + { + int oldId = *itn; + //MESSAGE(" node " << oldId); + vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId); + for (int i=0; iFindElement(GetMeshDS()->fromVtkToSmds(vtkId)); + if (!domain.count(anElem)) + continue; + int vtkType = grid->GetCellType(vtkId); + int downId = grid->CellIdToDownId(vtkId); + if (downId < 0) + { + MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem"); + continue; // not OK at this stage of the algorithm: + //no cells created after BuildDownWardConnectivity + } + DownIdType aCell(downId, vtkType); + cellDomains[aCell][idomain] = vtkId; + celldom[vtkId] = idomain; + //MESSAGE(" cell " << vtkId << " domain " << idomain); + } + } + } } - } - - int totalNbElems = - GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes(); - if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes - { - SMESHDS_SubMesh *aSM = 0; - removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 ); - } - - return true; -} -//======================================================================= -//function : SewSideElements -//purpose : -//======================================================================= + // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way + // for each shared face, get the nodes + // for each node, for each domain of the face, create a clone of the node -SMESH_MeshEditor::Sew_Error - SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, - TIDSortedElemSet& theSide2, - const SMDS_MeshNode* theFirstNode1, - const SMDS_MeshNode* theFirstNode2, - const SMDS_MeshNode* theSecondNode1, - const SMDS_MeshNode* theSecondNode2) -{ - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); + // --- edges at the intersection of 3 or 4 domains, with the order of domains to build + // junction elements of type prism or hexa. the key is the pair of nodesId (lower first) + // the value is the ordered domain ids. (more than 4 domains not taken into account) - MESSAGE ("::::SewSideElements()"); - if ( theSide1.size() != theSide2.size() ) - return SEW_DIFF_NB_OF_ELEMENTS; + std::map, std::vector > edgesMultiDomains; // nodes of edge --> ordered domains + std::map > mutipleNodes; // nodes multi domains with domain order + std::map > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains) - Sew_Error aResult = SEW_OK; - // Algo: - // 1. Build set of faces representing each side - // 2. Find which nodes of the side 1 to merge with ones on the side 2 - // 3. Replace nodes in elements of the side 1 and remove replaced nodes + MESSAGE(".. Duplication of the nodes"); + for (int idomain = idom0; idomain < nbDomains; idomain++) + { + itface = faceDomains.begin(); + for (; itface != faceDomains.end(); ++itface) + { + const std::map& domvol = itface->second; + if (!domvol.count(idomain)) + continue; + DownIdType face = itface->first; + //MESSAGE(" --- face " << face.cellId); + std::set oldNodes; + oldNodes.clear(); + grid->GetNodeIds(oldNodes, face.cellId, face.cellType); + std::set::iterator itn = oldNodes.begin(); + for (; itn != oldNodes.end(); ++itn) + { + int oldId = *itn; + if (nodeDomains[oldId].empty()) + { + nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain + //MESSAGE("-+-+-b oldNode " << oldId << " domain " << idomain); + } + std::map::const_iterator itdom = domvol.begin(); + for (; itdom != domvol.end(); ++itdom) + { + int idom = itdom->first; + //MESSAGE(" domain " << idom); + if (!nodeDomains[oldId].count(idom)) // --- node to clone + { + if (nodeDomains[oldId].size() >= 2) // a multiple node + { + vector orderedDoms; + //MESSAGE("multiple node " << oldId); + if (mutipleNodes.count(oldId)) + orderedDoms = mutipleNodes[oldId]; + else + { + map::iterator it = nodeDomains[oldId].begin(); + for (; it != nodeDomains[oldId].end(); ++it) + orderedDoms.push_back(it->first); + } + orderedDoms.push_back(idom); // TODO order ==> push_front or back + //stringstream txt; + //for (int i=0; iGetPoint(oldId); + SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]); + copyPosition( meshDS->FindNodeVtk( oldId ), newNode ); + int newId = newNode->getVtkId(); + nodeDomains[oldId][idom] = newId; // cloned node for other domains + //MESSAGE("-+-+-c oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" < domvol = itface->second; + if (!domvol.count(idomain)) + continue; + DownIdType face = itface->first; + //MESSAGE(" --- face " << face.cellId); + std::set oldNodes; + oldNodes.clear(); + grid->GetNodeIds(oldNodes, face.cellId, face.cellType); + int nbMultipleNodes = 0; + std::set::iterator itn = oldNodes.begin(); + for (; itn != oldNodes.end(); ++itn) + { + int oldId = *itn; + if (mutipleNodes.count(oldId)) + nbMultipleNodes++; + } + if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains + { + //MESSAGE("multiple Nodes detected on a shared face"); + int downId = itface->first.cellId; + unsigned char cellType = itface->first.cellType; + // --- shared edge or shared face ? + if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces) + { + int nodes[3]; + int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes); + for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1 + if (mutipleNodes.count(nodes[i])) + if (!mutipleNodesToFace.count(nodes[i])) + mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]]; + } + else // shared face (between two volumes) + { + int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId); + const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId); + const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId); + for (int ie =0; ie < nbEdges; ie++) + { + int nodes[3]; + int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes); + if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1])) + { + vector vn0 = mutipleNodes[nodes[0]]; + vector vn1 = mutipleNodes[nodes[nbNodes - 1]]; + vector doms; + for (int i0 = 0; i0 < vn0.size(); i0++) + for (int i1 = 0; i1 < vn1.size(); i1++) + if (vn0[i0] == vn1[i1]) + doms.push_back(vn0[i0]); + if (doms.size() >2) + { + //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]); + double *coords = grid->GetPoint(nodes[0]); + gp_Pnt p0(coords[0], coords[1], coords[2]); + coords = grid->GetPoint(nodes[nbNodes - 1]); + gp_Pnt p1(coords[0], coords[1], coords[2]); + gp_Pnt gref; + int vtkVolIds[1000]; // an edge can belong to a lot of volumes + map domvol; // domain --> a volume with the edge + map angleDom; // oriented angles between planes defined by edge and volume centers + int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]); + for (int id=0; id < doms.size(); id++) + { + int idom = doms[id]; + const TIDSortedElemSet& domain = (idom == iRestDom) ? theRestDomElems : theElems[idom]; + for (int ivol=0; ivolfromVtkToSmds(vtkVolIds[ivol]); + SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId); + if (domain.count(elem)) + { + SMDS_VtkVolume* svol = dynamic_cast(elem); + domvol[idom] = svol; + //MESSAGE(" domain " << idom << " volume " << elem->GetID()); + double values[3]; + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(vtkVolIds[ivol], npts, pts); + SMDS_VtkVolume::gravityCenter(grid, pts, npts, values); + if (id ==0) + { + gref.SetXYZ(gp_XYZ(values[0], values[1], values[2])); + angleDom[idom] = 0; + } + else + { + gp_Pnt g(values[0], values[1], values[2]); + angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pisecond << " angle " << ib->first); + } + for (int ino = 0; ino < nbNodes; ino++) + vnodes.push_back(nodes[ino]); + edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains + } + } + } + } + } + } + } - SMESHDS_Mesh* aMesh = GetMeshDS(); - SMDS_Mesh aTmpFacesMesh; - set faceSet1, faceSet2; - set volSet1, volSet2; - set nodeSet1, nodeSet2; - set * faceSetPtr[] = { &faceSet1, &faceSet2 }; - set * volSetPtr[] = { &volSet1, &volSet2 }; - set * nodeSetPtr[] = { &nodeSet1, &nodeSet2 }; - TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 }; - int iSide, iFace, iNode; + // --- iterate on shared faces (volumes to modify, face to extrude) + // get node id's of the face (id SMDS = id VTK) + // create flat element with old and new nodes if requested - for ( iSide = 0; iSide < 2; iSide++ ) { - set * nodeSet = nodeSetPtr[ iSide ]; - TIDSortedElemSet * elemSet = elemSetPtr[ iSide ]; - set * faceSet = faceSetPtr[ iSide ]; - set * volSet = volSetPtr [ iSide ]; - set::iterator vIt; - TIDSortedElemSet::iterator eIt; - set::iterator nIt; + // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId) + // (domain1 X domain2) = domain1 + MAXINT*domain2 - // check that given nodes belong to given elements - const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2; - const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2; - int firstIndex = -1, secondIndex = -1; - for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) { - const SMDS_MeshElement* elem = *eIt; - if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 ); - if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 ); - if ( firstIndex > -1 && secondIndex > -1 ) break; + std::map > nodeQuadDomains; + std::map mapOfJunctionGroups; + + MESSAGE(".. Creation of elements: simple junction"); + if (createJointElems) + { + int idg; + string joints2DName = "joints2D"; + mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg); + SMESHDS_Group *joints2DGrp = dynamic_cast(mapOfJunctionGroups[joints2DName]->GetGroupDS()); + string joints3DName = "joints3D"; + mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg); + SMESHDS_Group *joints3DGrp = dynamic_cast(mapOfJunctionGroups[joints3DName]->GetGroupDS()); + + itface = faceDomains.begin(); + for (; itface != faceDomains.end(); ++itface) + { + DownIdType face = itface->first; + std::set oldNodes; + std::set::iterator itn; + oldNodes.clear(); + grid->GetNodeIds(oldNodes, face.cellId, face.cellType); + + std::map domvol = itface->second; + std::map::iterator itdom = domvol.begin(); + int dom1 = itdom->first; + int vtkVolId = itdom->second; + itdom++; + int dom2 = itdom->first; + SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains, + nodeQuadDomains); + stringstream grpname; + grpname << "j_"; + if (dom1 < dom2) + grpname << dom1 << "_" << dom2; + else + grpname << dom2 << "_" << dom1; + string namegrp = grpname.str(); + if (!mapOfJunctionGroups.count(namegrp)) + mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg); + SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); + if (sgrp) + sgrp->Add(vol->GetID()); + if (vol->GetType() == SMDSAbs_Volume) + joints3DGrp->Add(vol->GetID()); + else if (vol->GetType() == SMDSAbs_Face) + joints2DGrp->Add(vol->GetID()); + } } - if ( firstIndex < 0 || secondIndex < 0 ) { - // we can simply return until temporary faces created - return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES; + + // --- create volumes on multiple domain intersection if requested + // iterate on mutipleNodesToFace + // iterate on edgesMultiDomains + + MESSAGE(".. Creation of elements: multiple junction"); + if (createJointElems) + { + // --- iterate on mutipleNodesToFace + + std::map >::iterator itn = mutipleNodesToFace.begin(); + for (; itn != mutipleNodesToFace.end(); ++itn) + { + int node = itn->first; + vector orderDom = itn->second; + vector orderedNodes; + for (int idom = 0; idom GetMeshDS()->AddFaceFromVtkIds(orderedNodes); + + stringstream grpname; + grpname << "m2j_"; + grpname << 0 << "_" << 0; + int idg; + string namegrp = grpname.str(); + if (!mapOfJunctionGroups.count(namegrp)) + mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg); + SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); + if (sgrp) + sgrp->Add(face->GetID()); + } + + // --- iterate on edgesMultiDomains + + std::map, std::vector >::iterator ite = edgesMultiDomains.begin(); + for (; ite != edgesMultiDomains.end(); ++ite) + { + vector nodes = ite->first; + vector orderDom = ite->second; + vector orderedNodes; + if (nodes.size() == 2) + { + //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]); + for (int ino=0; ino < nodes.size(); ino++) + if (orderDom.size() == 3) + for (int idom = 0; idom =0; idom--) + orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] ); + SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes); + + int idg; + string namegrp = "jointsMultiples"; + if (!mapOfJunctionGroups.count(namegrp)) + mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg); + SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); + if (sgrp) + sgrp->Add(vol->GetID()); + } + else + { + //INFOS("Quadratic multiple joints not implemented"); + // TODO quadratic nodes + } + } } - // ----------------------------------------------------------- - // 1a. Collect nodes of existing faces - // and build set of face nodes in order to detect missing - // faces corresponing to sides of volumes - // ----------------------------------------------------------- + // --- list the explicit faces and edges of the mesh that need to be modified, + // i.e. faces and edges built with one or more duplicated nodes. + // associate these faces or edges to their corresponding domain. + // only the first domain found is kept when a face or edge is shared - set< set > setOfFaceNodeSet; + std::map, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell) + std::map feDom; // vtk id of cell to modify --> id domain + faceOrEdgeDom.clear(); + feDom.clear(); - // loop on the given element of a side - for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) { - //const SMDS_MeshElement* elem = *eIt; - const SMDS_MeshElement* elem = *eIt; - if ( elem->GetType() == SMDSAbs_Face ) { - faceSet->insert( elem ); - set faceNodeSet; - SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); - while ( nodeIt->more() ) { - const SMDS_MeshNode* n = static_cast( nodeIt->next() ); - nodeSet->insert( n ); - faceNodeSet.insert( n ); + MESSAGE(".. Modification of elements"); + for (int idomain = idom0; idomain < nbDomains; idomain++) + { + std::map >::const_iterator itnod = nodeDomains.begin(); + for (; itnod != nodeDomains.end(); ++itnod) + { + int oldId = itnod->first; + //MESSAGE(" node " << oldId); + vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId); + for (int i = 0; i < l.ncells; i++) + { + int vtkId = l.cells[i]; + int vtkType = grid->GetCellType(vtkId); + int downId = grid->CellIdToDownId(vtkId); + if (downId < 0) + continue; // new cells: not to be modified + DownIdType aCell(downId, vtkType); + int volParents[1000]; + int nbvol = grid->GetParentVolumes(volParents, vtkId); + for (int j = 0; j < nbvol; j++) + if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain)) + if (!feDom.count(vtkId)) + { + feDom[vtkId] = idomain; + faceOrEdgeDom[aCell] = emptyMap; + faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only + //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain + // << " type " << vtkType << " downId " << downId); + } + } } - setOfFaceNodeSet.insert( faceNodeSet ); - } - else if ( elem->GetType() == SMDSAbs_Volume ) - volSet->insert( elem ); } - // ------------------------------------------------------------------------------ - // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes - // ------------------------------------------------------------------------------ - for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide - SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face); - while ( fIt->more() ) { // loop on faces sharing a node - const SMDS_MeshElement* f = fIt->next(); - if ( faceSet->find( f ) == faceSet->end() ) { - // check if all nodes are in nodeSet and - // complete setOfFaceNodeSet if they are - set faceNodeSet; - SMDS_ElemIteratorPtr nodeIt = f->nodesIterator(); - bool allInSet = true; - while ( nodeIt->more() && allInSet ) { // loop on nodes of a face - const SMDS_MeshNode* n = static_cast( nodeIt->next() ); - if ( nodeSet->find( n ) == nodeSet->end() ) - allInSet = false; - else - faceNodeSet.insert( n ); - } - if ( allInSet ) { - faceSet->insert( f ); - setOfFaceNodeSet.insert( faceNodeSet ); - } + // --- iterate on shared faces (volumes to modify, face to extrude) + // get node id's of the face + // replace old nodes by new nodes in volumes, and update inverse connectivity + + std::map, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom}; + for (int m=0; m<3; m++) + { + std::map, DownIdCompare>* amap = maps[m]; + itface = (*amap).begin(); + for (; itface != (*amap).end(); ++itface) + { + DownIdType face = itface->first; + std::set oldNodes; + std::set::iterator itn; + oldNodes.clear(); + grid->GetNodeIds(oldNodes, face.cellId, face.cellType); + //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType)); + std::map localClonedNodeIds; + + std::map domvol = itface->second; + std::map::iterator itdom = domvol.begin(); + for (; itdom != domvol.end(); ++itdom) + { + int idom = itdom->first; + int vtkVolId = itdom->second; + //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom); + localClonedNodeIds.clear(); + for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn) + { + int oldId = *itn; + if (nodeDomains[oldId].count(idom)) + { + localClonedNodeIds[oldId] = nodeDomains[oldId][idom]; + //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]); + } + } + meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds); + } } - } } - // ------------------------------------------------------------------------- - // 1c. Create temporary faces representing sides of volumes if correspondent - // face does not exist - // ------------------------------------------------------------------------- + // Remove empty groups (issue 0022812) + std::map::iterator name_group = mapOfJunctionGroups.begin(); + for ( ; name_group != mapOfJunctionGroups.end(); ++name_group ) + { + if ( name_group->second && name_group->second->GetGroupDS()->IsEmpty() ) + myMesh->RemoveGroup( name_group->second->GetGroupDS()->GetID() ); + } - if ( !volSet->empty() ) { - //int nodeSetSize = nodeSet->size(); + meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory + grid->BuildLinks(); - // loop on given volumes - for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) { - SMDS_VolumeTool vol (*vIt); - // loop on volume faces: find free faces - // -------------------------------------- - list freeFaceList; - for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) { - if ( !vol.IsFreeFace( iFace )) + CHRONOSTOP(50); + counters::stats(); + return true; +} + +/*! + * \brief Double nodes on some external faces and create flat elements. + * Flat elements are mainly used by some types of mechanic calculations. + * + * Each group of the list must be constituted of faces. + * Triangles are transformed in prisms, and quadrangles in hexahedrons. + * @param theElems - list of groups of faces, where a group of faces is a set of + * SMDS_MeshElements sorted by Id. + * @return TRUE if operation has been completed successfully, FALSE otherwise + */ +bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector& theElems) +{ + MESSAGE("-------------------------------------------------"); + MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups"); + MESSAGE("-------------------------------------------------"); + + SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS(); + + // --- For each group of faces + // duplicate the nodes, create a flat element based on the face + // replace the nodes of the faces by their clones + + std::map clonedNodes; + std::map intermediateNodes; + clonedNodes.clear(); + intermediateNodes.clear(); + std::map mapOfJunctionGroups; + mapOfJunctionGroups.clear(); + + for (int idom = 0; idom < theElems.size(); idom++) + { + const TIDSortedElemSet& domain = theElems[idom]; + TIDSortedElemSet::const_iterator elemItr = domain.begin(); + for (; elemItr != domain.end(); ++elemItr) + { + SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr; + SMDS_MeshFace* aFace = dynamic_cast (anElem); + if (!aFace) continue; - // check if there is already a face with same nodes in a face set - const SMDS_MeshElement* aFreeFace = 0; - const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace ); - int nbNodes = vol.NbFaceNodes( iFace ); - set faceNodeSet; - vol.GetFaceNodes( iFace, faceNodeSet ); - bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second; - if ( isNewFace ) { - // no such a face is given but it still can exist, check it - if ( nbNodes == 3 ) { - aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] ); - } - else if ( nbNodes == 4 ) { - aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] ); - } - else { - vector poly_nodes ( fNodes, & fNodes[nbNodes]); - aFreeFace = aMesh->FindFace(poly_nodes); - } - } - if ( !aFreeFace ) { - // create a temporary face - if ( nbNodes == 3 ) { - aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] ); - } - else if ( nbNodes == 4 ) { - aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] ); - } - else { - vector poly_nodes ( fNodes, & fNodes[nbNodes]); - aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes); - } - } - if ( aFreeFace ) - freeFaceList.push_back( aFreeFace ); + // MESSAGE("aFace=" << aFace->GetID()); + bool isQuad = aFace->IsQuadratic(); + vector ln0, ln1, ln2, ln3, ln4; - } // loop on faces of a volume + // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face - // choose one of several free faces - // -------------------------------------- - if ( freeFaceList.size() > 1 ) { - // choose a face having max nb of nodes shared by other elems of a side - int maxNbNodes = -1/*, nbExcludedFaces = 0*/; - list::iterator fIt = freeFaceList.begin(); - while ( fIt != freeFaceList.end() ) { // loop on free faces - int nbSharedNodes = 0; - SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator(); - while ( nodeIt->more() ) { // loop on free face nodes - const SMDS_MeshNode* n = - static_cast( nodeIt->next() ); - SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator(); - while ( invElemIt->more() ) { - const SMDS_MeshElement* e = invElemIt->next(); - if ( faceSet->find( e ) != faceSet->end() ) - nbSharedNodes++; - if ( elemSet->find( e ) != elemSet->end() ) - nbSharedNodes++; - } - } - if ( nbSharedNodes >= maxNbNodes ) { - maxNbNodes = nbSharedNodes; - fIt++; - } - else - freeFaceList.erase( fIt++ ); // here fIt++ occures before erase - } - if ( freeFaceList.size() > 1 ) - { - // could not choose one face, use another way - // choose a face most close to the bary center of the opposite side - gp_XYZ aBC( 0., 0., 0. ); - set addedNodes; - TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ]; - eIt = elemSet2->begin(); - for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) { - SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator(); - while ( nodeIt->more() ) { // loop on free face nodes - const SMDS_MeshNode* n = - static_cast( nodeIt->next() ); - if ( addedNodes.insert( n ).second ) - aBC += gp_XYZ( n->X(),n->Y(),n->Z() ); - } - } - aBC /= addedNodes.size(); - double minDist = DBL_MAX; - fIt = freeFaceList.begin(); - while ( fIt != freeFaceList.end() ) { // loop on free faces - double dist = 0; - SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator(); - while ( nodeIt->more() ) { // loop on free face nodes - const SMDS_MeshNode* n = - static_cast( nodeIt->next() ); - gp_XYZ p( n->X(),n->Y(),n->Z() ); - dist += ( aBC - p ).SquareModulus(); - } - if ( dist < minDist ) { - minDist = dist; - freeFaceList.erase( freeFaceList.begin(), fIt++ ); - } + SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator(); + while (nodeIt->more()) + { + const SMDS_MeshNode* node = static_cast (nodeIt->next()); + bool isMedium = isQuad && (aFace->IsMediumNode(node)); + if (isMedium) + ln2.push_back(node); else - fIt = freeFaceList.erase( fIt++ ); + ln0.push_back(node); + + const SMDS_MeshNode* clone = 0; + if (!clonedNodes.count(node)) + { + clone = meshDS->AddNode(node->X(), node->Y(), node->Z()); + copyPosition( node, clone ); + clonedNodes[node] = clone; + } + else + clone = clonedNodes[node]; + + if (isMedium) + ln3.push_back(clone); + else + ln1.push_back(clone); + + const SMDS_MeshNode* inter = 0; + if (isQuad && (!isMedium)) + { + if (!intermediateNodes.count(node)) + { + inter = meshDS->AddNode(node->X(), node->Y(), node->Z()); + copyPosition( node, inter ); + intermediateNodes[node] = inter; + } + else + inter = intermediateNodes[node]; + ln4.push_back(inter); + } } + + // --- extrude the face + + vector ln; + SMDS_MeshVolume* vol = 0; + vtkIdType aType = aFace->GetVtkType(); + switch (aType) + { + case VTK_TRIANGLE: + vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]); + // MESSAGE("vol prism " << vol->GetID()); + ln.push_back(ln1[0]); + ln.push_back(ln1[1]); + ln.push_back(ln1[2]); + break; + case VTK_QUAD: + vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]); + // MESSAGE("vol hexa " << vol->GetID()); + ln.push_back(ln1[0]); + ln.push_back(ln1[1]); + ln.push_back(ln1[2]); + ln.push_back(ln1[3]); + break; + case VTK_QUADRATIC_TRIANGLE: + vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2], + ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]); + // MESSAGE("vol quad prism " << vol->GetID()); + ln.push_back(ln1[0]); + ln.push_back(ln1[1]); + ln.push_back(ln1[2]); + ln.push_back(ln3[0]); + ln.push_back(ln3[1]); + ln.push_back(ln3[2]); + break; + case VTK_QUADRATIC_QUAD: +// vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3], +// ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3], +// ln4[0], ln4[1], ln4[2], ln4[3]); + vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3], + ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3], + ln4[0], ln4[1], ln4[2], ln4[3]); + // MESSAGE("vol quad hexa " << vol->GetID()); + ln.push_back(ln1[0]); + ln.push_back(ln1[1]); + ln.push_back(ln1[2]); + ln.push_back(ln1[3]); + ln.push_back(ln3[0]); + ln.push_back(ln3[1]); + ln.push_back(ln3[2]); + ln.push_back(ln3[3]); + break; + case VTK_POLYGON: + break; + default: + break; } - } // choose one of several free faces of a volume - if ( freeFaceList.size() == 1 ) { - const SMDS_MeshElement* aFreeFace = freeFaceList.front(); - faceSet->insert( aFreeFace ); - // complete a node set with nodes of a found free face -// for ( iNode = 0; iNode < ; iNode++ ) -// nodeSet->insert( fNodes[ iNode ] ); + if (vol) + { + stringstream grpname; + grpname << "jf_"; + grpname << idom; + int idg; + string namegrp = grpname.str(); + if (!mapOfJunctionGroups.count(namegrp)) + mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg); + SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); + if (sgrp) + sgrp->Add(vol->GetID()); + } + + // --- modify the face + + aFace->ChangeNodes(&ln[0], ln.size()); } + } + return true; +} + +/*! + * \brief identify all the elements around a geom shape, get the faces delimiting the hole + * Build groups of volume to remove, groups of faces to replace on the skin of the object, + * groups of faces to remove inside the object, (idem edges). + * Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape) + */ +void SMESH_MeshEditor::CreateHoleSkin(double radius, + const TopoDS_Shape& theShape, + SMESH_NodeSearcher* theNodeSearcher, + const char* groupName, + std::vector& nodesCoords, + std::vector >& listOfListOfNodes) +{ + MESSAGE("--------------------------------"); + MESSAGE("SMESH_MeshEditor::CreateHoleSkin"); + MESSAGE("--------------------------------"); + + // --- zone of volumes to remove is given : + // 1 either by a geom shape (one or more vertices) and a radius, + // 2 either by a group of nodes (representative of the shape)to use with the radius, + // 3 either by a group of nodes where all the elements build on one of this nodes are to remove, + // In the case 2, the group of nodes is an external group of nodes from another mesh, + // In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter), + // defined by it's name. + + SMESHDS_GroupBase* groupDS = 0; + SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups(); + while ( groupIt->more() ) + { + groupDS = 0; + SMESH_Group * group = groupIt->next(); + if ( !group ) continue; + groupDS = group->GetGroupDS(); + if ( !groupDS || groupDS->IsEmpty() ) continue; + std::string grpName = group->GetName(); + //MESSAGE("grpName=" << grpName); + if (grpName == groupName) + break; + else + groupDS = 0; + } + + bool isNodeGroup = false; + bool isNodeCoords = false; + if (groupDS) + { + if (groupDS->GetType() != SMDSAbs_Node) + return; + isNodeGroup = true; // a group of nodes exists and it is in this mesh + } + + if (nodesCoords.size() > 0) + isNodeCoords = true; // a list o nodes given by their coordinates + //MESSAGE("---" << isNodeGroup << " " << isNodeCoords); - } // loop on volumes of a side + // --- define groups to build -// // complete a set of faces if new nodes in a nodeSet appeared -// // ---------------------------------------------------------- -// if ( nodeSetSize != nodeSet->size() ) { -// for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide -// SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face); -// while ( fIt->more() ) { // loop on faces sharing a node -// const SMDS_MeshElement* f = fIt->next(); -// if ( faceSet->find( f ) == faceSet->end() ) { -// // check if all nodes are in nodeSet and -// // complete setOfFaceNodeSet if they are -// set faceNodeSet; -// SMDS_ElemIteratorPtr nodeIt = f->nodesIterator(); -// bool allInSet = true; -// while ( nodeIt->more() && allInSet ) { // loop on nodes of a face -// const SMDS_MeshNode* n = static_cast( nodeIt->next() ); -// if ( nodeSet->find( n ) == nodeSet->end() ) -// allInSet = false; -// else -// faceNodeSet.insert( n ); -// } -// if ( allInSet ) { -// faceSet->insert( f ); -// setOfFaceNodeSet.insert( faceNodeSet ); -// } -// } -// } -// } -// } - } // Create temporary faces, if there are volumes given - } // loop on sides + int idg; // --- group of SMDS volumes + string grpvName = groupName; + grpvName += "_vol"; + SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg); + if (!grp) + { + MESSAGE("group not created " << grpvName); + return; + } + SMESHDS_Group *sgrp = dynamic_cast(grp->GetGroupDS()); - if ( faceSet1.size() != faceSet2.size() ) { - // delete temporary faces: they are in reverseElements of actual nodes - SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator(); - while ( tmpFaceIt->more() ) - aTmpFacesMesh.RemoveElement( tmpFaceIt->next() ); - MESSAGE("Diff nb of faces"); - return SEW_TOPO_DIFF_SETS_OF_ELEMENTS; - } + int idgs; // --- group of SMDS faces on the skin + string grpsName = groupName; + grpsName += "_skin"; + SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs); + if (!grps) + { + MESSAGE("group not created " << grpsName); + return; + } + SMESHDS_Group *sgrps = dynamic_cast(grps->GetGroupDS()); - // ============================================================ - // 2. Find nodes to merge: - // bind a node to remove to a node to put instead - // ============================================================ + int idgi; // --- group of SMDS faces internal (several shapes) + string grpiName = groupName; + grpiName += "_internalFaces"; + SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi); + if (!grpi) + { + MESSAGE("group not created " << grpiName); + return; + } + SMESHDS_Group *sgrpi = dynamic_cast(grpi->GetGroupDS()); - TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead - if ( theFirstNode1 != theFirstNode2 ) - nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 )); - if ( theSecondNode1 != theSecondNode2 ) - nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 )); + int idgei; // --- group of SMDS faces internal (several shapes) + string grpeiName = groupName; + grpeiName += "_internalEdges"; + SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei); + if (!grpei) + { + MESSAGE("group not created " << grpeiName); + return; + } + SMESHDS_Group *sgrpei = dynamic_cast(grpei->GetGroupDS()); - LinkID_Gen aLinkID_Gen( GetMeshDS() ); - set< long > linkIdSet; // links to process - linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 )); + // --- build downward connectivity - typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink; - list< NLink > linkList[2]; - linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 )); - linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 )); - // loop on links in linkList; find faces by links and append links - // of the found faces to linkList - list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ; - for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) { - NLink link[] = { *linkIt[0], *linkIt[1] }; - long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second ); - if ( linkIdSet.find( linkID ) == linkIdSet.end() ) - continue; + SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS(); + meshDS->BuildDownWardConnectivity(true); + SMDS_UnstructuredGrid* grid = meshDS->getGrid(); - // by links, find faces in the face sets, - // and find indices of link nodes in the found faces; - // in a face set, there is only one or no face sharing a link - // --------------------------------------------------------------- + // --- set of volumes detected inside - const SMDS_MeshElement* face[] = { 0, 0 }; - //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ]; - vector fnodes1(9); - vector fnodes2(9); - //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ; - vector notLinkNodes1(6); - vector notLinkNodes2(6); - int iLinkNode[2][2]; - for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides - const SMDS_MeshNode* n1 = link[iSide].first; - const SMDS_MeshNode* n2 = link[iSide].second; - set * faceSet = faceSetPtr[ iSide ]; - set< const SMDS_MeshElement* > fMap; - for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link - const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link - SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face); - while ( fIt->more() ) { // loop on faces sharing a node - const SMDS_MeshElement* f = fIt->next(); - if (faceSet->find( f ) != faceSet->end() && // f is in face set - ! fMap.insert( f ).second ) // f encounters twice - { - if ( face[ iSide ] ) { - MESSAGE( "2 faces per link " ); - aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES; - break; - } - face[ iSide ] = f; - faceSet->erase( f ); - // get face nodes and find ones of a link - iNode = 0; - int nbl = -1; - if(f->IsPoly()) { - if(iSide==0) { - fnodes1.resize(f->NbNodes()+1); - notLinkNodes1.resize(f->NbNodes()-2); - } - else { - fnodes2.resize(f->NbNodes()+1); - notLinkNodes2.resize(f->NbNodes()-2); - } + std::set setOfInsideVol; + std::set setOfVolToCheck; + + std::vector gpnts; + gpnts.clear(); + + if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes + { + MESSAGE("group of nodes provided"); + SMDS_ElemIteratorPtr elemIt = groupDS->GetElements(); + while ( elemIt->more() ) + { + const SMDS_MeshElement* elem = elemIt->next(); + if (!elem) + continue; + const SMDS_MeshNode* node = dynamic_cast(elem); + if (!node) + continue; + SMDS_MeshElement* vol = 0; + SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume); + while (volItr->more()) + { + vol = (SMDS_MeshElement*)volItr->next(); + setOfInsideVol.insert(vol->getVtkId()); + sgrp->Add(vol->GetID()); } - if(!f->IsQuadratic()) { - SMDS_ElemIteratorPtr nIt = f->nodesIterator(); - while ( nIt->more() ) { - const SMDS_MeshNode* n = - static_cast( nIt->next() ); - if ( n == n1 ) { - iLinkNode[ iSide ][ 0 ] = iNode; - } - else if ( n == n2 ) { - iLinkNode[ iSide ][ 1 ] = iNode; - } - //else if ( notLinkNodes[ iSide ][ 0 ] ) - // notLinkNodes[ iSide ][ 1 ] = n; - //else - // notLinkNodes[ iSide ][ 0 ] = n; - else { - nbl++; - if(iSide==0) - notLinkNodes1[nbl] = n; - //notLinkNodes1.push_back(n); - else - notLinkNodes2[nbl] = n; - //notLinkNodes2.push_back(n); + } + } + else if (isNodeCoords) + { + MESSAGE("list of nodes coordinates provided"); + int i = 0; + int k = 0; + while (i < nodesCoords.size()-2) + { + double x = nodesCoords[i++]; + double y = nodesCoords[i++]; + double z = nodesCoords[i++]; + gp_Pnt p = gp_Pnt(x, y ,z); + gpnts.push_back(p); + MESSAGE("TopoDS_Vertex " << k << " " << p.X() << " " << p.Y() << " " << p.Z()); + k++; + } + } + else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius + { + MESSAGE("no group of nodes provided, using vertices from geom shape, and radius"); + TopTools_IndexedMapOfShape vertexMap; + TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap ); + gp_Pnt p = gp_Pnt(0,0,0); + if (vertexMap.Extent() < 1) + return; + + for ( int i = 1; i <= vertexMap.Extent(); ++i ) + { + const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i )); + p = BRep_Tool::Pnt(vertex); + gpnts.push_back(p); + MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z()); + } + } + + if (gpnts.size() > 0) + { + int nodeId = 0; + const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]); + if (startNode) + nodeId = startNode->GetID(); + MESSAGE("nodeId " << nodeId); + + double radius2 = radius*radius; + MESSAGE("radius2 " << radius2); + + // --- volumes on start node + + setOfVolToCheck.clear(); + SMDS_MeshElement* startVol = 0; + SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume); + while (volItr->more()) + { + startVol = (SMDS_MeshElement*)volItr->next(); + setOfVolToCheck.insert(startVol->getVtkId()); + } + if (setOfVolToCheck.empty()) + { + MESSAGE("No volumes found"); + return; + } + + // --- starting with central volumes then their neighbors, check if they are inside + // or outside the domain, until no more new neighbor volume is inside. + // Fill the group of inside volumes + + std::map mapOfNodeDistance2; + mapOfNodeDistance2.clear(); + std::set setOfOutsideVol; + while (!setOfVolToCheck.empty()) + { + std::set::iterator it = setOfVolToCheck.begin(); + int vtkId = *it; + MESSAGE("volume to check, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + bool volInside = false; + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(vtkId, npts, pts); + for (int i=0; iGetPoint(pts[i]); + gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]); + distance2 = 1.E40; + for (int j=0; jAdd(meshDS->fromVtkToSmds(vtkId)); + break; } - } } - else { // f->IsQuadratic() - const SMDS_QuadraticFaceOfNodes* F = - static_cast(f); - // use special nodes iterator - SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); - while ( anIter->more() ) { - const SMDS_MeshNode* n = - static_cast( anIter->next() ); - if ( n == n1 ) { - iLinkNode[ iSide ][ 0 ] = iNode; - } - else if ( n == n2 ) { - iLinkNode[ iSide ][ 1 ] = iNode; - } - else { - nbl++; - if(iSide==0) { - notLinkNodes1[nbl] = n; - } - else { - notLinkNodes2[nbl] = n; - } + if (volInside) + { + setOfInsideVol.insert(vtkId); + MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId); + for (int n = 0; n < nbNeighbors; n++) + if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n])) + setOfVolToCheck.insert(neighborsVtkIds[n]); + } + else + { + setOfOutsideVol.insert(vtkId); + MESSAGE(" volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + } + setOfVolToCheck.erase(vtkId); + } + } + + // --- for outside hexahedrons, check if they have more than one neighbor volume inside + // If yes, add the volume to the inside set + + bool addedInside = true; + std::set setOfVolToReCheck; + while (addedInside) + { + MESSAGE(" --------------------------- re check"); + addedInside = false; + std::set::iterator itv = setOfInsideVol.begin(); + for (; itv != setOfInsideVol.end(); ++itv) + { + int vtkId = *itv; + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId); + for (int n = 0; n < nbNeighbors; n++) + if (!setOfInsideVol.count(neighborsVtkIds[n])) + setOfVolToReCheck.insert(neighborsVtkIds[n]); + } + setOfVolToCheck = setOfVolToReCheck; + setOfVolToReCheck.clear(); + while (!setOfVolToCheck.empty()) + { + std::set::iterator it = setOfVolToCheck.begin(); + int vtkId = *it; + if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON) + { + MESSAGE("volume to recheck, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + int countInside = 0; + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId); + for (int n = 0; n < nbNeighbors; n++) + if (setOfInsideVol.count(neighborsVtkIds[n])) + countInside++; + MESSAGE("countInside " << countInside); + if (countInside > 1) + { + MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + setOfInsideVol.insert(vtkId); + sgrp->Add(meshDS->fromVtkToSmds(vtkId)); + addedInside = true; } - if(iSide==0) { - fnodes1[iNode++] = n; + else + setOfVolToReCheck.insert(vtkId); + } + setOfVolToCheck.erase(vtkId); + } + } + + // --- map of Downward faces at the boundary, inside the global volume + // map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin) + // fill group of SMDS faces inside the volume (when several volume shapes) + // fill group of SMDS faces on the skin of the global volume (if skin) + + std::map boundaryFaces; // boundary faces inside the volume --> corresponding cell + std::map skinFaces; // faces on the skin of the global volume --> corresponding cell + std::set::iterator it = setOfInsideVol.begin(); + for (; it != setOfInsideVol.end(); ++it) + { + int vtkId = *it; + //MESSAGE(" vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true); + for (int n = 0; n < nbNeighbors; n++) + { + int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n])); + if (neighborDim == 3) + { + if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary + { + DownIdType face(downIds[n], downTypes[n]); + boundaryFaces[face] = vtkId; } - else { - fnodes2[iNode++] = n; + // if the face between to volumes is in the mesh, get it (internal face between shapes) + int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]); + if (vtkFaceId >= 0) + { + sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId)); + // find also the smds edges on this face + int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]); + const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]); + const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]); + for (int i = 0; i < nbEdges; i++) + { + int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]); + if (vtkEdgeId >= 0) + sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId)); + } } - } } - //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ]; - if(iSide==0) { - fnodes1[iNode] = fnodes1[0]; - } - else { - fnodes2[iNode] = fnodes1[0]; + else if (neighborDim == 2) // skin of the volume + { + DownIdType face(downIds[n], downTypes[n]); + skinFaces[face] = vtkId; + int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]); + if (vtkFaceId >= 0) + sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId)); } - } } - } } - // check similarity of elements of the sides - if ((aResult == SEW_OK && ( face[0] && !face[1] )) || ( !face[0] && face[1] )) { - MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 )); - if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found - aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES ); - } - else { - aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS; - } - break; // do not return because it s necessary to remove tmp faces + // --- identify the edges constituting the wire of each subshape on the skin + // define polylines with the nodes of edges, equivalent to wires + // project polylines on subshapes, and partition, to get geom faces + + std::map > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin + std::set emptySet; + emptySet.clear(); + std::set shapeIds; + + SMDS_ElemIteratorPtr itelem = sgrps->GetElements(); + while (itelem->more()) + { + const SMDS_MeshElement *elem = itelem->next(); + int shapeId = elem->getshapeId(); + int vtkId = elem->getVtkId(); + if (!shapeIdToVtkIdSet.count(shapeId)) + { + shapeIdToVtkIdSet[shapeId] = emptySet; + shapeIds.insert(shapeId); + } + shapeIdToVtkIdSet[shapeId].insert(vtkId); } - // set nodes to merge - // ------------------- + std::map > shapeIdToEdges; // shapeId --> set of downward edges + std::set emptyEdges; + emptyEdges.clear(); - if ( face[0] && face[1] ) { - int nbNodes = face[0]->NbNodes(); - if ( nbNodes != face[1]->NbNodes() ) { - MESSAGE("Diff nb of face nodes"); - aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS; - break; // do not return because it s necessary to remove tmp faces - } - bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle - if ( nbNodes == 3 ) { - //nReplaceMap.insert( TNodeNodeMap::value_type - // ( notLinkNodes[0][0], notLinkNodes[1][0] )); - nReplaceMap.insert( TNodeNodeMap::value_type - ( notLinkNodes1[0], notLinkNodes2[0] )); - } - else { - for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides - // analyse link orientation in faces - int i1 = iLinkNode[ iSide ][ 0 ]; - int i2 = iLinkNode[ iSide ][ 1 ]; - reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1; - // if notLinkNodes are the first and the last ones, then - // their order does not correspond to the link orientation - if (( i1 == 1 && i2 == 2 ) || - ( i1 == 2 && i2 == 1 )) - reverse[ iSide ] = !reverse[ iSide ]; - } - if ( reverse[0] == reverse[1] ) { - //nReplaceMap.insert( TNodeNodeMap::value_type - // ( notLinkNodes[0][0], notLinkNodes[1][0] )); - //nReplaceMap.insert( TNodeNodeMap::value_type - // ( notLinkNodes[0][1], notLinkNodes[1][1] )); - for(int nn=0; nn >::iterator itShape = shapeIdToVtkIdSet.begin(); + for (; itShape != shapeIdToVtkIdSet.end(); ++itShape) + { + int shapeId = itShape->first; + MESSAGE(" --- Shape ID --- "<< shapeId); + shapeIdToEdges[shapeId] = emptyEdges; + + std::vector nodesEdges; + + std::set::iterator its = itShape->second.begin(); + for (; its != itShape->second.end(); ++its) + { + int vtkId = *its; + MESSAGE(" " << vtkId); + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId); + for (int n = 0; n < nbNeighbors; n++) + { + if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here + continue; + int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]); + const SMDS_MeshElement* elem = meshDS->FindElement(smdsId); + if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group + { + DownIdType edge(downIds[n], downTypes[n]); + if (!shapeIdToEdges[shapeId].count(edge)) + { + shapeIdToEdges[shapeId].insert(edge); + int vtkNodeId[3]; + int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId); + nodesEdges.push_back(vtkNodeId[0]); + nodesEdges.push_back(vtkNodeId[nbNodes-1]); + MESSAGE(" --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1); + } + } + } } - else { - //nReplaceMap.insert( TNodeNodeMap::value_type - // ( notLinkNodes[0][0], notLinkNodes[1][1] )); - //nReplaceMap.insert( TNodeNodeMap::value_type - // ( notLinkNodes[0][1], notLinkNodes[1][0] )); - for(int nn=0; nn order; + order.clear(); + if (nodesEdges.size() > 0) + { + order.push_back(nodesEdges[0]); MESSAGE(" --- back " << order.back()+1); // SMDS id = VTK id + 1; + nodesEdges[0] = -1; + order.push_back(nodesEdges[1]); MESSAGE(" --- back " << order.back()+1); + nodesEdges[1] = -1; // do not reuse this edge + bool found = true; + while (found) + { + int nodeTofind = order.back(); // try first to push back + int i = 0; + for (i = 0; i use the previous one + if (nodesEdges[i-1] < 0) + found = false; + else + { + order.push_back(nodesEdges[i-1]); MESSAGE(" --- back " << order.back()+1); + nodesEdges[i-1] = -1; + } + else // even ==> use the next one + if (nodesEdges[i+1] < 0) + found = false; + else + { + order.push_back(nodesEdges[i+1]); MESSAGE(" --- back " << order.back()+1); + nodesEdges[i+1] = -1; + } + } + if (found) + continue; + // try to push front + found = true; + nodeTofind = order.front(); // try to push front + for (i = 0; i use the previous one + if (nodesEdges[i-1] < 0) + found = false; + else + { + order.push_front(nodesEdges[i-1]); MESSAGE(" --- front " << order.front()+1); + nodesEdges[i-1] = -1; + } + else // even ==> use the next one + if (nodesEdges[i+1] < 0) + found = false; + else + { + order.push_front(nodesEdges[i+1]); MESSAGE(" --- front " << order.front()+1); + nodesEdges[i+1] = -1; + } + } } - } - // add other links of the faces to linkList - // ----------------------------------------- - //const SMDS_MeshNode** nodes = faceNodes[ 0 ]; - for ( iNode = 0; iNode < nbNodes; iNode++ ) { - //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] ); - linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] ); - pair< set::iterator, bool > iter_isnew = linkIdSet.insert( linkID ); - if ( !iter_isnew.second ) { // already in a set: no need to process - linkIdSet.erase( iter_isnew.first ); - } - else // new in set == encountered for the first time: add + std::vector nodes; + nodes.push_back(shapeId); + std::list::iterator itl = order.begin(); + for (; itl != order.end(); itl++) { - //const SMDS_MeshNode* n1 = nodes[ iNode ]; - //const SMDS_MeshNode* n2 = nodes[ iNode + 1]; - const SMDS_MeshNode* n1 = fnodes1[ iNode ]; - const SMDS_MeshNode* n2 = fnodes1[ iNode + 1]; - linkList[0].push_back ( NLink( n1, n2 )); - linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] )); + nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1; + MESSAGE(" ordered node " << nodes[nodes.size()-1]); } - } - } // 2 faces found - } // loop on link lists + listOfListOfNodes.push_back(nodes); + } - if ( aResult == SEW_OK && - ( linkIt[0] != linkList[0].end() || - !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) { - MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) << - " " << (faceSetPtr[1]->empty())); - aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS; - } + // partition geom faces with blocFissure + // mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose) + // mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose) - // ==================================================================== - // 3. Replace nodes in elements of the side 1 and remove replaced nodes - // ==================================================================== + return; +} - // delete temporary faces: they are in reverseElements of actual nodes - SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator(); - while ( tmpFaceIt->more() ) - aTmpFacesMesh.RemoveElement( tmpFaceIt->next() ); - if ( aResult != SEW_OK) - return aResult; +//================================================================================ +/*! + * \brief Generates skin mesh (containing 2D cells) from 3D mesh + * The created 2D mesh elements based on nodes of free faces of boundary volumes + * \return TRUE if operation has been completed successfully, FALSE otherwise + */ +//================================================================================ - list< int > nodeIDsToRemove/*, elemIDsToRemove*/; - // loop on nodes replacement map - TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt; - for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ ) - if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) { - const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first; - nodeIDsToRemove.push_back( nToRemove->GetID() ); - // loop on elements sharing nToRemove - SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator(); - while ( invElemIt->more() ) { - const SMDS_MeshElement* e = invElemIt->next(); - // get a new suite of nodes: make replacement - int nbReplaced = 0, i = 0, nbNodes = e->NbNodes(); - vector< const SMDS_MeshNode*> nodes( nbNodes ); - SMDS_ElemIteratorPtr nIt = e->nodesIterator(); - while ( nIt->more() ) { - const SMDS_MeshNode* n = - static_cast( nIt->next() ); - nnIt = nReplaceMap.find( n ); - if ( nnIt != nReplaceMap.end() ) { - nbReplaced++; - n = (*nnIt).second; - } - nodes[ i++ ] = n; - } - // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face ) - // elemIDsToRemove.push_back( e->GetID() ); - // else - if ( nbReplaced ) - aMesh->ChangeElementNodes( e, & nodes[0], nbNodes ); +bool SMESH_MeshEditor::Make2DMeshFrom3D() +{ + // iterates on volume elements and detect all free faces on them + SMESHDS_Mesh* aMesh = GetMeshDS(); + if (!aMesh) + return false; + + ElemFeatures faceType( SMDSAbs_Face ); + int nbFree = 0, nbExisted = 0, nbCreated = 0; + SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator(); + while(vIt->more()) + { + const SMDS_MeshVolume* volume = vIt->next(); + SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false ); + vTool.SetExternalNormal(); + const int iQuad = volume->IsQuadratic(); + faceType.SetQuad( iQuad ); + for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ ) + { + if (!vTool.IsFreeFace(iface)) + continue; + nbFree++; + vector nodes; + int nbFaceNodes = vTool.NbFaceNodes(iface); + const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface); + int inode = 0; + for ( ; inode < nbFaceNodes; inode += iQuad+1) + nodes.push_back(faceNodes[inode]); + + if (iQuad) // add medium nodes + { + for ( inode = 1; inode < nbFaceNodes; inode += 2) + nodes.push_back(faceNodes[inode]); + if ( nbFaceNodes == 9 ) // bi-quadratic quad + nodes.push_back(faceNodes[8]); + } + // add new face based on volume nodes + if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) + { + nbExisted++; // face already exsist + } + else + { + AddElement( nodes, faceType.SetPoly( nbFaceNodes/(iQuad+1) > 4 )); + nbCreated++; } } - - Remove( nodeIDsToRemove, true ); - - return aResult; + } + return ( nbFree == ( nbExisted + nbCreated )); } +namespace +{ + inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node) + { + if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() )) + return n; + return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() ); + } +} //================================================================================ - /*! - * \brief Find corresponding nodes in two sets of faces - * \param theSide1 - first face set - * \param theSide2 - second first face - * \param theFirstNode1 - a boundary node of set 1 - * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1 - * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1 - * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1 - * \param nReplaceMap - output map of corresponding nodes - * \retval bool - is a success or not - */ +/*! + * \brief Creates missing boundary elements + * \param elements - elements whose boundary is to be checked + * \param dimension - defines type of boundary elements to create + * \param group - a group to store created boundary elements in + * \param targetMesh - a mesh to store created boundary elements in + * \param toCopyElements - if true, the checked elements will be copied into the targetMesh + * \param toCopyExistingBoundary - if true, not only new but also pre-existing + * boundary elements will be copied into the targetMesh + * \param toAddExistingBondary - if true, not only new but also pre-existing + * boundary elements will be added into the new group + * \param aroundElements - if true, elements will be created on boundary of given + * elements else, on boundary of the whole mesh. + * \return nb of added boundary elements + */ //================================================================================ -#ifdef _DEBUG_ -//#define DEBUG_MATCHING_NODES -#endif - -SMESH_MeshEditor::Sew_Error -SMESH_MeshEditor::FindMatchingNodes(set& theSide1, - set& theSide2, - const SMDS_MeshNode* theFirstNode1, - const SMDS_MeshNode* theFirstNode2, - const SMDS_MeshNode* theSecondNode1, - const SMDS_MeshNode* theSecondNode2, - TNodeNodeMap & nReplaceMap) +int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, + Bnd_Dimension dimension, + SMESH_Group* group/*=0*/, + SMESH_Mesh* targetMesh/*=0*/, + bool toCopyElements/*=false*/, + bool toCopyExistingBoundary/*=false*/, + bool toAddExistingBondary/*= false*/, + bool aroundElements/*= false*/) { - set * faceSetPtr[] = { &theSide1, &theSide2 }; - - nReplaceMap.clear(); - if ( theFirstNode1 != theFirstNode2 ) - nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 )); - if ( theSecondNode1 != theSecondNode2 ) - nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 )); - - set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored - linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 )); - - list< NLink > linkList[2]; - linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 )); - linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 )); - - // loop on links in linkList; find faces by links and append links - // of the found faces to linkList - list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ; - for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) { - NLink link[] = { *linkIt[0], *linkIt[1] }; - if ( linkSet.find( link[0] ) == linkSet.end() ) - continue; - - // by links, find faces in the face sets, - // and find indices of link nodes in the found faces; - // in a face set, there is only one or no face sharing a link - // --------------------------------------------------------------- - - const SMDS_MeshElement* face[] = { 0, 0 }; - list notLinkNodes[2]; - //bool reverse[] = { false, false }; // order of notLinkNodes - int nbNodes[2]; - for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides + SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge; + SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume; + // hope that all elements are of the same type, do not check them all + if ( !elements.empty() && (*elements.begin())->GetType() != elemType ) + throw SALOME_Exception(LOCALIZED("wrong element type")); + + if ( !targetMesh ) + toCopyElements = toCopyExistingBoundary = false; + + SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh ); + SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS(); + int nbAddedBnd = 0; + + // editor adding present bnd elements and optionally holding elements to add to the group + SMESH_MeshEditor* presentEditor; + SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() ); + presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2; + + SMESH_MesherHelper helper( *myMesh ); + const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE ); + SMDS_VolumeTool vTool; + TIDSortedElemSet avoidSet; + const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet; + size_t inode; + + typedef vector TConnectivity; + TConnectivity tgtNodes; + ElemFeatures elemKind( missType ), elemToCopy; + + vector presentBndElems; + vector missingBndElems; + vector freeFacets; + TConnectivity nodes, elemNodes; + + SMDS_ElemIteratorPtr eIt; + if (elements.empty()) eIt = aMesh->elementsIterator(elemType); + else eIt = elemSetIterator( elements ); + + while (eIt->more()) + { + const SMDS_MeshElement* elem = eIt->next(); + const int iQuad = elem->IsQuadratic(); + elemKind.SetQuad( iQuad ); + + // ------------------------------------------------------------------------------------ + // 1. For an elem, get present bnd elements and connectivities of missing bnd elements + // ------------------------------------------------------------------------------------ + presentBndElems.clear(); + missingBndElems.clear(); + freeFacets.clear(); nodes.clear(); elemNodes.clear(); + if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume -------------- { - const SMDS_MeshNode* n1 = link[iSide].first; - const SMDS_MeshNode* n2 = link[iSide].second; - set * faceSet = faceSetPtr[ iSide ]; - set< const SMDS_MeshElement* > facesOfNode1; - for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link + const SMDS_MeshElement* otherVol = 0; + for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ ) { - // during a loop of the first node, we find all faces around n1, - // during a loop of the second node, we find one face sharing both n1 and n2 - const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link - SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face); - while ( fIt->more() ) { // loop on faces sharing a node - const SMDS_MeshElement* f = fIt->next(); - if (faceSet->find( f ) != faceSet->end() && // f is in face set - ! facesOfNode1.insert( f ).second ) // f encounters twice + if ( !vTool.IsFreeFace(iface, &otherVol) && + ( !aroundElements || elements.count( otherVol ))) + continue; + freeFacets.push_back( iface ); + } + if ( missType == SMDSAbs_Face ) + vTool.SetExternalNormal(); + for ( size_t i = 0; i < freeFacets.size(); ++i ) + { + int iface = freeFacets[i]; + const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface); + const size_t nbFaceNodes = vTool.NbFaceNodes (iface); + if ( missType == SMDSAbs_Edge ) // boundary edges + { + nodes.resize( 2+iQuad ); + for ( int i = 0; i < nbFaceNodes; i += 1+iQuad) { - if ( face[ iSide ] ) { - MESSAGE( "2 faces per link " ); - return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES ); - } - face[ iSide ] = f; - faceSet->erase( f ); + for ( int j = 0; j < nodes.size(); ++j ) + nodes[j] = nn[ i+j ]; + if ( const SMDS_MeshElement* edge = + aMesh->FindElement( nodes, SMDSAbs_Edge, /*noMedium=*/false )) + presentBndElems.push_back( edge ); + else + missingBndElems.push_back( nodes ); + } + } + else // boundary face + { + nodes.clear(); + for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad) + nodes.push_back( nn[inode] ); // add corner nodes + if (iQuad) + for ( inode = 1; inode < nbFaceNodes; inode += 2) + nodes.push_back( nn[inode] ); // add medium nodes + int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27 + if ( iCenter > 0 ) + nodes.push_back( vTool.GetNodes()[ iCenter ] ); + + if (const SMDS_MeshElement * f = aMesh->FindElement( nodes, + SMDSAbs_Face, /*noMedium=*/false )) + presentBndElems.push_back( f ); + else + missingBndElems.push_back( nodes ); - // get not link nodes - int nbN = f->NbNodes(); - if ( f->IsQuadratic() ) - nbN /= 2; - nbNodes[ iSide ] = nbN; - list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ]; - int i1 = f->GetNodeIndex( n1 ); - int i2 = f->GetNodeIndex( n2 ); - int iEnd = nbN, iBeg = -1, iDelta = 1; - bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 ); - if ( reverse ) { - std::swap( iEnd, iBeg ); iDelta = -1; - } - int i = i2; - while ( true ) { - i += iDelta; - if ( i == iEnd ) i = iBeg + iDelta; - if ( i == i1 ) break; - nodes.push_back ( f->GetNode( i ) ); + if ( targetMesh != myMesh ) + { + // add 1D elements on face boundary to be added to a new mesh + const SMDS_MeshElement* edge; + for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad) + { + if ( iQuad ) + edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]); + else + edge = aMesh->FindEdge( nn[inode], nn[inode+1]); + if ( edge && avoidSet.insert( edge ).second ) + presentBndElems.push_back( edge ); } } } } } - // check similarity of elements of the sides - if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) { - MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 )); - if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found - return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES ); - } - else { - return SEW_TOPO_DIFF_SETS_OF_ELEMENTS; + else if ( elem->GetType() == SMDSAbs_Face ) // elem is a face ------------------------ + { + avoidSet.clear(), avoidSet.insert( elem ); + elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesElemIterator() ), + SMDS_MeshElement::iterator() ); + elemNodes.push_back( elemNodes[0] ); + nodes.resize( 2 + iQuad ); + const int nbLinks = elem->NbCornerNodes(); + for ( int i = 0, iN = 0; i < nbLinks; i++, iN += 1+iQuad ) + { + nodes[0] = elemNodes[iN]; + nodes[1] = elemNodes[iN+1+iQuad]; + if ( SMESH_MeshAlgos::FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet)) + continue; // not free link + + if ( iQuad ) nodes[2] = elemNodes[iN+1]; + if ( const SMDS_MeshElement* edge = + aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false)) + presentBndElems.push_back( edge ); + else + missingBndElems.push_back( nodes ); } } - // set nodes to merge - // ------------------- - - if ( face[0] && face[1] ) { - if ( nbNodes[0] != nbNodes[1] ) { - MESSAGE("Diff nb of face nodes"); - return SEW_TOPO_DIFF_SETS_OF_ELEMENTS; - } -#ifdef DEBUG_MATCHING_NODES - MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID() - << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" " - << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ; -#endif - int nbN = nbNodes[0]; + // --------------------------------- + // 2. Add missing boundary elements + // --------------------------------- + if ( targetMesh != myMesh ) + // instead of making a map of nodes in this mesh and targetMesh, + // we create nodes with same IDs. + for ( size_t i = 0; i < missingBndElems.size(); ++i ) { - list::iterator n1 = notLinkNodes[0].begin(); - list::iterator n2 = notLinkNodes[1].begin(); - for ( int i = 0 ; i < nbN - 2; ++i ) { -#ifdef DEBUG_MATCHING_NODES - MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() ); -#endif - nReplaceMap.insert( make_pair( *(n1++), *(n2++) )); - } + TConnectivity& srcNodes = missingBndElems[i]; + tgtNodes.resize( srcNodes.size() ); + for ( inode = 0; inode < srcNodes.size(); ++inode ) + tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] ); + if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( tgtNodes, + missType, + /*noMedium=*/false)) + continue; + tgtEditor.AddElement( tgtNodes, elemKind.SetPoly( tgtNodes.size()/(iQuad+1) > 4 )); + ++nbAddedBnd; } - - // add other links of the face 1 to linkList - // ----------------------------------------- - - const SMDS_MeshElement* f0 = face[0]; - const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 ); - for ( int i = 0; i < nbN; i++ ) + else + for ( int i = 0; i < missingBndElems.size(); ++i ) { - const SMDS_MeshNode* n2 = f0->GetNode( i ); - pair< set< SMESH_TLink >::iterator, bool > iter_isnew = - linkSet.insert( SMESH_TLink( n1, n2 )); - if ( !iter_isnew.second ) { // already in a set: no need to process - linkSet.erase( iter_isnew.first ); - } - else // new in set == encountered for the first time: add + TConnectivity& nodes = missingBndElems[i]; + if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes, + missType, + /*noMedium=*/false)) + continue; + SMDS_MeshElement* newElem = + tgtEditor.AddElement( nodes, elemKind.SetPoly( nodes.size()/(iQuad+1) > 4 )); + nbAddedBnd += bool( newElem ); + + // try to set a new element to a shape + if ( myMesh->HasShapeToMesh() ) { -#ifdef DEBUG_MATCHING_NODES - MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " " - << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " ); -#endif - linkList[0].push_back ( NLink( n1, n2 )); - linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] )); + bool ok = true; + set< pair > mediumShapes; + const size_t nbN = nodes.size() / (iQuad+1 ); + for ( inode = 0; inode < nbN && ok; ++inode ) + { + pair i_stype = + helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]); + if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE ))) + mediumShapes.insert( make_pair ( i_stype.second, i_stype.first )); + } + if ( ok && mediumShapes.size() > 1 ) + { + set< pair >::iterator stype_i = mediumShapes.begin(); + pair stype_i_0 = *stype_i; + for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i ) + { + if (( ok = ( stype_i->first != stype_i_0.first ))) + ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ), + aMesh->IndexToShape( stype_i_0.second )); + } + } + if ( ok && mediumShapes.begin()->first == missShapeType ) + aMesh->SetMeshElementOnShape( newElem, mediumShapes.begin()->second ); } - n1 = n2; } - } // 2 faces found - } // loop on link lists - - return SEW_OK; -} - -/*! - \brief Creates a hole in a mesh by doubling the nodes of some particular elements - \param theNodes - identifiers of nodes to be doubled - \param theModifiedElems - identifiers of elements to be updated by the new (doubled) - nodes. If list of element identifiers is empty then nodes are doubled but - they not assigned to elements - \return TRUE if operation has been completed successfully, FALSE otherwise -*/ -bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, - const std::list< int >& theListOfModifiedElems ) -{ - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); - - if ( theListOfNodes.size() == 0 ) - return false; - SMESHDS_Mesh* aMeshDS = GetMeshDS(); - if ( !aMeshDS ) - return false; - - // iterate through nodes and duplicate them + // ---------------------------------- + // 3. Copy present boundary elements + // ---------------------------------- + if ( toCopyExistingBoundary ) + for ( int i = 0 ; i < presentBndElems.size(); ++i ) + { + const SMDS_MeshElement* e = presentBndElems[i]; + tgtNodes.resize( e->NbNodes() ); + for ( inode = 0; inode < nodes.size(); ++inode ) + tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) ); + presentEditor->AddElement( tgtNodes, elemToCopy.Init( e )); + } + else // store present elements to add them to a group + for ( int i = 0 ; i < presentBndElems.size(); ++i ) + { + presentEditor->myLastCreatedElems.Append( presentBndElems[i] ); + } - std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode; + } // loop on given elements - std::list< int >::const_iterator aNodeIter; - for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter ) + // --------------------------------------------- + // 4. Fill group with boundary elements + // --------------------------------------------- + if ( group ) { - int aCurr = *aNodeIter; - SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr ); - if ( !aNode ) - continue; - - // duplicate node + if ( SMESHDS_Group* g = dynamic_cast( group->GetGroupDS() )) + for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i ) + g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 )); + } + tgtEditor.myLastCreatedElems.Clear(); + tgtEditor2.myLastCreatedElems.Clear(); - const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() ); - if ( aNewNode ) + // ----------------------- + // 5. Copy given elements + // ----------------------- + if ( toCopyElements && targetMesh != myMesh ) + { + if (elements.empty()) eIt = aMesh->elementsIterator(elemType); + else eIt = elemSetIterator( elements ); + while (eIt->more()) { - anOldNodeToNewNode[ aNode ] = aNewNode; - myLastCreatedNodes.Append( aNewNode ); + const SMDS_MeshElement* elem = eIt->next(); + tgtNodes.resize( elem->NbNodes() ); + for ( inode = 0; inode < tgtNodes.size(); ++inode ) + tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) ); + tgtEditor.AddElement( tgtNodes, elemToCopy.Init( elem )); + + tgtEditor.myLastCreatedElems.Clear(); } } + return nbAddedBnd; +} - // Create map of new nodes for modified elements +//================================================================================ +/*! + * \brief Copy node position and set \a to node on the same geometry + */ +//================================================================================ - std::map< SMDS_MeshElement*, vector > anElemToNodes; +void SMESH_MeshEditor::copyPosition( const SMDS_MeshNode* from, + const SMDS_MeshNode* to ) +{ + if ( !from || !to ) return; - std::list< int >::const_iterator anElemIter; - for ( anElemIter = theListOfModifiedElems.begin(); - anElemIter != theListOfModifiedElems.end(); ++anElemIter ) - { - int aCurr = *anElemIter; - SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr ); - if ( !anElem ) - continue; + SMDS_PositionPtr pos = from->GetPosition(); + if ( !pos || from->getshapeId() < 1 ) return; - vector aNodeArr( anElem->NbNodes() ); + switch ( pos->GetTypeOfPosition() ) + { + case SMDS_TOP_3DSPACE: break; - SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); - int ind = 0; - while ( anIter->more() ) - { - SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next(); - if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() ) - { - const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ]; - aNodeArr[ ind++ ] = aNewNode; - } - else - aNodeArr[ ind++ ] = aCurrNode; - } - anElemToNodes[ anElem ] = aNodeArr; + case SMDS_TOP_FACE: + { + const SMDS_FacePosition* fPos = static_cast< const SMDS_FacePosition* >( pos ); + GetMeshDS()->SetNodeOnFace( to, from->getshapeId(), + fPos->GetUParameter(), fPos->GetVParameter() ); + break; } - - // Change nodes of elements - - std::map< SMDS_MeshElement*, vector >::iterator - anElemToNodesIter = anElemToNodes.begin(); - for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter ) + case SMDS_TOP_EDGE: { - const SMDS_MeshElement* anElem = anElemToNodesIter->first; - vector aNodeArr = anElemToNodesIter->second; - if ( anElem ) - aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() ); + // WARNING: it is dangerous to set equal nodes on one EDGE!!!!!!!! + const SMDS_EdgePosition* ePos = static_cast< const SMDS_EdgePosition* >( pos ); + GetMeshDS()->SetNodeOnEdge( to, from->getshapeId(), ePos->GetUParameter() ); + break; + } + case SMDS_TOP_VERTEX: + { + GetMeshDS()->SetNodeOnVertex( to, from->getshapeId() ); + break; + } + case SMDS_TOP_UNSPEC: + default:; } - - return true; } diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshVSLink.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshVSLink.cpp index eebf3bd9ec90..de4071e2fd58 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshVSLink.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshVSLink.cpp @@ -1,342 +1,342 @@ -// SMESH SMESH_MeshVSLink : Connection of SMESH with MeshVS from OCC -// -// 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 : SMESH_MeshVSLink.cxx -// Created : Mon Dec 1 09:00:00 2008 -// Author : Sioutis Fotios -// Module : SMESH - -//local headers -#include -#include - -//occ headers -#include -#include -#include - -//BEGIN sortNodes CHANGE /* -#include - -#include -#include -#include - -#if OCC_VERSION_HEX >= 0x070000 -IMPLEMENT_STANDARD_RTTIEXT(SMESH_MeshVSLink,MeshVS_DataSource3D) -#endif - -#define MAX_SORT_NODE_COUNT 12 - -typedef std::map T_Double_NodeID_Map; - -//======================================================================= -//function : sortNodes -//purpose : -//======================================================================= -bool sortNodes (const SMDS_MeshElement* theTool, const int* idNodes, int theNodeCount, int *myResult) -{ - if (theNodeCount < 3) return false; - //INITIAL VARS - TColgp_Array1OfXYZ myNodeList(1, theNodeCount); - TColgp_Array1OfVec myVectList(1, theNodeCount); - TColStd_Array1OfReal myAngleList(1, theNodeCount); - gp_XYZ BaryCenter(0.,0.,0.); - //int myResult[MAX_SORT_NODE_COUNT]; - //INITIALIZE THE POINTS - for (int i = 1; i <= theNodeCount; i++ ) { - const SMDS_MeshNode *n = theTool->GetNode( idNodes[i-1] ); - gp_XYZ aPoint(n->X(), n->Y(), n->Z()); - myNodeList.SetValue(i, aPoint); - } - //CALCULATE THE BARYCENTER - for (int i = 1; i <= theNodeCount; i++ ) - BaryCenter += myNodeList.Value(i); - BaryCenter /= theNodeCount; - //CREATE THE VECTORS - for (int i = 1; i <= theNodeCount; i++ ) { - gp_Vec aVector(BaryCenter, myNodeList.Value(i)); - myVectList.SetValue(i, aVector); - } - //CALCULATE THE NORMAL USING FIRST THREE POINTS - gp_XYZ q1 = myNodeList.Value(2)-myNodeList.Value(1); - gp_XYZ q2 = myNodeList.Value(3)-myNodeList.Value(1); - gp_XYZ normal = q1 ^ q2; - double modul = normal.Modulus(); - if ( modul > 0 ) - normal /= modul; - //COUNT THE ANGLE OF THE FIRST WITH EACH - for (int i = 1; i <= theNodeCount; i++ ) - myAngleList.SetValue(i, myVectList.Value(1).AngleWithRef(myVectList.Value(i), normal)); - //CREATE THE RESULT MAP (WILL SORT THE VERTICES) - T_Double_NodeID_Map myMap; - for (int i = 1; i <= theNodeCount; i++ ) - myMap.insert( make_pair(myAngleList.Value(i), idNodes[i-1])); - int resID = 0; - T_Double_NodeID_Map::iterator it; - for(it = myMap.begin(); it!= myMap.end(); ++it) - myResult[resID++] = it->second; - - return true; -} -//END sortNodes CHANGE */ - -//================================================================ -// Function : Constructor -// Purpose : -//================================================================ -SMESH_MeshVSLink::SMESH_MeshVSLink(const SMESH_Mesh *aMesh) -{ - myMesh = (SMESH_Mesh*) aMesh; - //add the nodes - SMDS_NodeIteratorPtr aNodeIter = myMesh->GetMeshDS()->nodesIterator(); - for(;aNodeIter->more();) { - const SMDS_MeshNode* aNode = aNodeIter->next(); - myNodes.Add( aNode->GetID() ); - } - //add the edges - SMDS_EdgeIteratorPtr anEdgeIter = myMesh->GetMeshDS()->edgesIterator(); - for(;anEdgeIter->more();) { - const SMDS_MeshEdge* anElem = anEdgeIter->next(); - myElements.Add( anElem->GetID() ); - } - //add the faces - SMDS_FaceIteratorPtr aFaceIter = myMesh->GetMeshDS()->facesIterator(); - for(;aFaceIter->more();) { - const SMDS_MeshFace* anElem = aFaceIter->next(); - myElements.Add( anElem->GetID() ); - } - //add the volumes - SMDS_VolumeIteratorPtr aVolumeIter = myMesh->GetMeshDS()->volumesIterator(); - for(;aVolumeIter->more();) { - const SMDS_MeshVolume* anElem = aVolumeIter->next(); - myElements.Add( anElem->GetID() ); - } - //add the groups - const std::set& groups = myMesh->GetMeshDS()->GetGroups(); - if (!groups.empty()) { - std::set::const_iterator GrIt = groups.begin(); - for (; GrIt != groups.end(); GrIt++) { - SMESHDS_Group* grp = dynamic_cast(*GrIt); - if (!grp || grp->IsEmpty()) continue; - myGroups.Add(grp->GetID()); - } - } -} - -//================================================================ -// Function : GetGeom -// Purpose : -//================================================================ -Standard_Boolean SMESH_MeshVSLink::GetGeom - ( const Standard_Integer ID, const Standard_Boolean IsElement, - TColStd_Array1OfReal& Coords, Standard_Integer& NbNodes, - MeshVS_EntityType& Type ) const -{ - if( IsElement ) { - const SMDS_MeshElement* myElem = myMesh->GetMeshDS()->FindElement(ID); - if (!myElem) return Standard_False; - if (myElem->GetType() == SMDSAbs_Edge) - Type = MeshVS_ET_Link; - else if (myElem->GetType() == SMDSAbs_Face) - Type = MeshVS_ET_Face; - else if (myElem->GetType() == SMDSAbs_Volume) - Type = MeshVS_ET_Volume; - else - Type = MeshVS_ET_Element; - NbNodes = myElem->NbNodes(); - int nbCoord = 1; - for(Standard_Integer i = 0; i < NbNodes; i++ ) { - Coords(nbCoord++) = myElem->GetNode(i)->X(); - Coords(nbCoord++) = myElem->GetNode(i)->Y(); - Coords(nbCoord++) = myElem->GetNode(i)->Z(); - } - } - else { - const SMDS_MeshNode* myNode = myMesh->GetMeshDS()->FindNode(ID); - if (!myNode) return Standard_False; - if (myNode->GetType() == SMDSAbs_Node) - Type = MeshVS_ET_Node; - else - Type = MeshVS_ET_0D; - NbNodes = 1; - Coords(1) = myNode->X(); - Coords(2) = myNode->Y(); - Coords(3) = myNode->Z(); - } - return Standard_True; -} - -//================================================================ -// Function : Get3DGeom -// Purpose : -//================================================================ -Standard_Boolean SMESH_MeshVSLink::Get3DGeom - ( const Standard_Integer ID, Standard_Integer& NbNodes, - Handle(MeshVS_HArray1OfSequenceOfInteger)& Data) const -{ - //check validity of element - const SMDS_MeshElement* myVolume = myMesh->GetMeshDS()->FindElement(ID); - if (!myVolume) return Standard_False; - if (myVolume->GetType() != SMDSAbs_Volume) return Standard_False; - - //initialize VolumeTool - SMDS_VolumeTool aTool; - aTool.Set(myVolume); - //set the nodes number - NbNodes = aTool.NbNodes();// myVolume->NbNodes(); - //check validity or create Data - int NbFaces = aTool.NbFaces(); - if (Data.IsNull()) - Data = new MeshVS_HArray1OfSequenceOfInteger(1, NbFaces); - else if (Data->Length() != NbFaces) { - Data.Nullify(); - Data = new MeshVS_HArray1OfSequenceOfInteger(1, NbFaces); - } - //iterate the faces and their nodes and add them to Data - for (int itr=0;itr < NbFaces;itr++) { - int NbThisFaceNodeCount = aTool.NbFaceNodes(itr); - const int *FaceIndices = aTool.GetFaceNodesIndices(itr); - int sortedFaceIndices[MAX_SORT_NODE_COUNT]; - TColStd_SequenceOfInteger aSeq; - if (sortNodes(myVolume, FaceIndices, NbThisFaceNodeCount, sortedFaceIndices)) { - for (int itrX=0;itrX < NbThisFaceNodeCount;itrX++) - aSeq.Append(sortedFaceIndices[itrX]); - } else { - for (int itrX=0;itrX < NbThisFaceNodeCount;itrX++) - aSeq.Append(FaceIndices[itrX]); - } - Data->SetValue(itr+1, aSeq); - } - return Standard_True; -} - -//================================================================ -// Function : GetGeomType -// Purpose : -//================================================================ -Standard_Boolean SMESH_MeshVSLink::GetGeomType - ( const Standard_Integer ID, - const Standard_Boolean IsElement, - MeshVS_EntityType& Type ) const -{ - if( IsElement ) { - const SMDS_MeshElement* myElem = myMesh->GetMeshDS()->FindElement(ID); - if (!myElem) return Standard_False; - if (myElem->GetType() == SMDSAbs_Edge) - Type = MeshVS_ET_Link; - else if (myElem->GetType() == SMDSAbs_Face) - Type = MeshVS_ET_Face; - else if (myElem->GetType() == SMDSAbs_Volume) - Type = MeshVS_ET_Volume; - else - Type = MeshVS_ET_Element; - } - else { - const SMDS_MeshNode* myNode = myMesh->GetMeshDS()->FindNode(ID); - if (!myNode) return Standard_False; - if (myNode->GetType() == SMDSAbs_Node) - Type = MeshVS_ET_Node; - else - Type = MeshVS_ET_0D; - } - return Standard_True; -} - -//================================================================ -// Function : GetAddr -// Purpose : -//================================================================ -Standard_Address SMESH_MeshVSLink::GetAddr - ( const Standard_Integer, const Standard_Boolean ) const -{ - return NULL; -} - -//================================================================ -// Function : GetNodesByElement -// Purpose : -//================================================================ -Standard_Boolean SMESH_MeshVSLink::GetNodesByElement - ( const Standard_Integer ID,TColStd_Array1OfInteger& NodeIDs,Standard_Integer& NbNodes ) const -{ - const SMDS_MeshElement* myElem = myMesh->GetMeshDS()->FindElement(ID); - if (!myElem) return Standard_False; - NbNodes = myElem->NbNodes(); - for(Standard_Integer i = 0; i < NbNodes; i++ ) { - const SMDS_MeshNode* aNode = myElem->GetNode(i); - if (!aNode) return Standard_False; - NodeIDs.SetValue(i+1, aNode->GetID()); - } - return Standard_True; -} - -//================================================================ -// Function : GetAllNodes -// Purpose : -//================================================================ -const TColStd_PackedMapOfInteger& SMESH_MeshVSLink::GetAllNodes() const -{ - return myNodes; -} - -//================================================================ -// Function : GetAllElements -// Purpose : -//================================================================ -const TColStd_PackedMapOfInteger& SMESH_MeshVSLink::GetAllElements() const -{ - return myElements; -} - -//================================================================ -// Function : GetAllElements -// Purpose : -//================================================================ -void SMESH_MeshVSLink::GetAllGroups(TColStd_PackedMapOfInteger& Ids) const -{ - Ids = myGroups; -} - -//================================================================ -// Function : GetNormal -// Purpose : -//================================================================ -Standard_Boolean SMESH_MeshVSLink::GetNormal - ( const Standard_Integer Id, const Standard_Integer Max, - Standard_Real& nx, Standard_Real& ny,Standard_Real& nz ) const -{ - if(Max<3) return Standard_False; - const SMDS_MeshElement* myElem = myMesh->GetMeshDS()->FindElement(Id); - if(!myElem) return Standard_False; - if(myElem->NbNodes() < 3) return Standard_False; - gp_XYZ normal; - gp_XYZ nodes[3]; - for (int itr = 0;itr < 3;itr++) - nodes[itr] = gp_XYZ(myElem->GetNode(itr)->X(), myElem->GetNode(itr)->Y(), myElem->GetNode(itr)->Z()); - normal = (nodes[1]-nodes[0]) ^ (nodes[2]-nodes[0]); - if ( normal.Modulus() > 0 ) - normal /= normal.Modulus(); - nx = normal.X(); - ny = normal.Y(); - nz = normal.Z(); - return Standard_True; -} +// SMESH SMESH_MeshVSLink : Connection of SMESH with MeshVS from OCC +// +// 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 : SMESH_MeshVSLink.cxx +// Created : Mon Dec 1 09:00:00 2008 +// Author : Sioutis Fotios +// Module : SMESH + +//local headers +#include +#include + +//occ headers +#include +#include +#include + +//BEGIN sortNodes CHANGE /* +#include + +#include +#include +#include + +#if OCC_VERSION_HEX >= 0x070000 +IMPLEMENT_STANDARD_RTTIEXT(SMESH_MeshVSLink,MeshVS_DataSource3D) +#endif + +#define MAX_SORT_NODE_COUNT 12 + +typedef std::map T_Double_NodeID_Map; + +//======================================================================= +//function : sortNodes +//purpose : +//======================================================================= +bool sortNodes (const SMDS_MeshElement* theTool, const int* idNodes, int theNodeCount, int *myResult) +{ + if (theNodeCount < 3) return false; + //INITIAL VARS + TColgp_Array1OfXYZ myNodeList(1, theNodeCount); + TColgp_Array1OfVec myVectList(1, theNodeCount); + TColStd_Array1OfReal myAngleList(1, theNodeCount); + gp_XYZ BaryCenter(0.,0.,0.); + //int myResult[MAX_SORT_NODE_COUNT]; + //INITIALIZE THE POINTS + for (int i = 1; i <= theNodeCount; i++ ) { + const SMDS_MeshNode *n = theTool->GetNode( idNodes[i-1] ); + gp_XYZ aPoint(n->X(), n->Y(), n->Z()); + myNodeList.SetValue(i, aPoint); + } + //CALCULATE THE BARYCENTER + for (int i = 1; i <= theNodeCount; i++ ) + BaryCenter += myNodeList.Value(i); + BaryCenter /= theNodeCount; + //CREATE THE VECTORS + for (int i = 1; i <= theNodeCount; i++ ) { + gp_Vec aVector(BaryCenter, myNodeList.Value(i)); + myVectList.SetValue(i, aVector); + } + //CALCULATE THE NORMAL USING FIRST THREE POINTS + gp_XYZ q1 = myNodeList.Value(2)-myNodeList.Value(1); + gp_XYZ q2 = myNodeList.Value(3)-myNodeList.Value(1); + gp_XYZ normal = q1 ^ q2; + double modul = normal.Modulus(); + if ( modul > 0 ) + normal /= modul; + //COUNT THE ANGLE OF THE FIRST WITH EACH + for (int i = 1; i <= theNodeCount; i++ ) + myAngleList.SetValue(i, myVectList.Value(1).AngleWithRef(myVectList.Value(i), normal)); + //CREATE THE RESULT MAP (WILL SORT THE VERTICES) + T_Double_NodeID_Map myMap; + for (int i = 1; i <= theNodeCount; i++ ) + myMap.insert( make_pair(myAngleList.Value(i), idNodes[i-1])); + int resID = 0; + T_Double_NodeID_Map::iterator it; + for(it = myMap.begin(); it!= myMap.end(); ++it) + myResult[resID++] = it->second; + + return true; +} +//END sortNodes CHANGE */ + +//================================================================ +// Function : Constructor +// Purpose : +//================================================================ +SMESH_MeshVSLink::SMESH_MeshVSLink(const SMESH_Mesh *aMesh) +{ + myMesh = (SMESH_Mesh*) aMesh; + //add the nodes + SMDS_NodeIteratorPtr aNodeIter = myMesh->GetMeshDS()->nodesIterator(); + for(;aNodeIter->more();) { + const SMDS_MeshNode* aNode = aNodeIter->next(); + myNodes.Add( aNode->GetID() ); + } + //add the edges + SMDS_EdgeIteratorPtr anEdgeIter = myMesh->GetMeshDS()->edgesIterator(); + for(;anEdgeIter->more();) { + const SMDS_MeshEdge* anElem = anEdgeIter->next(); + myElements.Add( anElem->GetID() ); + } + //add the faces + SMDS_FaceIteratorPtr aFaceIter = myMesh->GetMeshDS()->facesIterator(); + for(;aFaceIter->more();) { + const SMDS_MeshFace* anElem = aFaceIter->next(); + myElements.Add( anElem->GetID() ); + } + //add the volumes + SMDS_VolumeIteratorPtr aVolumeIter = myMesh->GetMeshDS()->volumesIterator(); + for(;aVolumeIter->more();) { + const SMDS_MeshVolume* anElem = aVolumeIter->next(); + myElements.Add( anElem->GetID() ); + } + //add the groups + const std::set& groups = myMesh->GetMeshDS()->GetGroups(); + if (!groups.empty()) { + std::set::const_iterator GrIt = groups.begin(); + for (; GrIt != groups.end(); GrIt++) { + SMESHDS_Group* grp = dynamic_cast(*GrIt); + if (!grp || grp->IsEmpty()) continue; + myGroups.Add(grp->GetID()); + } + } +} + +//================================================================ +// Function : GetGeom +// Purpose : +//================================================================ +Standard_Boolean SMESH_MeshVSLink::GetGeom + ( const Standard_Integer ID, const Standard_Boolean IsElement, + TColStd_Array1OfReal& Coords, Standard_Integer& NbNodes, + MeshVS_EntityType& Type ) const +{ + if( IsElement ) { + const SMDS_MeshElement* myElem = myMesh->GetMeshDS()->FindElement(ID); + if (!myElem) return Standard_False; + if (myElem->GetType() == SMDSAbs_Edge) + Type = MeshVS_ET_Link; + else if (myElem->GetType() == SMDSAbs_Face) + Type = MeshVS_ET_Face; + else if (myElem->GetType() == SMDSAbs_Volume) + Type = MeshVS_ET_Volume; + else + Type = MeshVS_ET_Element; + NbNodes = myElem->NbNodes(); + int nbCoord = 1; + for(Standard_Integer i = 0; i < NbNodes; i++ ) { + Coords(nbCoord++) = myElem->GetNode(i)->X(); + Coords(nbCoord++) = myElem->GetNode(i)->Y(); + Coords(nbCoord++) = myElem->GetNode(i)->Z(); + } + } + else { + const SMDS_MeshNode* myNode = myMesh->GetMeshDS()->FindNode(ID); + if (!myNode) return Standard_False; + if (myNode->GetType() == SMDSAbs_Node) + Type = MeshVS_ET_Node; + else + Type = MeshVS_ET_0D; + NbNodes = 1; + Coords(1) = myNode->X(); + Coords(2) = myNode->Y(); + Coords(3) = myNode->Z(); + } + return Standard_True; +} + +//================================================================ +// Function : Get3DGeom +// Purpose : +//================================================================ +Standard_Boolean SMESH_MeshVSLink::Get3DGeom + ( const Standard_Integer ID, Standard_Integer& NbNodes, + Handle(MeshVS_HArray1OfSequenceOfInteger)& Data) const +{ + //check validity of element + const SMDS_MeshElement* myVolume = myMesh->GetMeshDS()->FindElement(ID); + if (!myVolume) return Standard_False; + if (myVolume->GetType() != SMDSAbs_Volume) return Standard_False; + + //initialize VolumeTool + SMDS_VolumeTool aTool; + aTool.Set(myVolume); + //set the nodes number + NbNodes = aTool.NbNodes();// myVolume->NbNodes(); + //check validity or create Data + int NbFaces = aTool.NbFaces(); + if (Data.IsNull()) + Data = new MeshVS_HArray1OfSequenceOfInteger(1, NbFaces); + else if (Data->Length() != NbFaces) { + Data.Nullify(); + Data = new MeshVS_HArray1OfSequenceOfInteger(1, NbFaces); + } + //iterate the faces and their nodes and add them to Data + for (int itr=0;itr < NbFaces;itr++) { + int NbThisFaceNodeCount = aTool.NbFaceNodes(itr); + const int *FaceIndices = aTool.GetFaceNodesIndices(itr); + int sortedFaceIndices[MAX_SORT_NODE_COUNT]; + TColStd_SequenceOfInteger aSeq; + if (sortNodes(myVolume, FaceIndices, NbThisFaceNodeCount, sortedFaceIndices)) { + for (int itrX=0;itrX < NbThisFaceNodeCount;itrX++) + aSeq.Append(sortedFaceIndices[itrX]); + } else { + for (int itrX=0;itrX < NbThisFaceNodeCount;itrX++) + aSeq.Append(FaceIndices[itrX]); + } + Data->SetValue(itr+1, aSeq); + } + return Standard_True; +} + +//================================================================ +// Function : GetGeomType +// Purpose : +//================================================================ +Standard_Boolean SMESH_MeshVSLink::GetGeomType + ( const Standard_Integer ID, + const Standard_Boolean IsElement, + MeshVS_EntityType& Type ) const +{ + if( IsElement ) { + const SMDS_MeshElement* myElem = myMesh->GetMeshDS()->FindElement(ID); + if (!myElem) return Standard_False; + if (myElem->GetType() == SMDSAbs_Edge) + Type = MeshVS_ET_Link; + else if (myElem->GetType() == SMDSAbs_Face) + Type = MeshVS_ET_Face; + else if (myElem->GetType() == SMDSAbs_Volume) + Type = MeshVS_ET_Volume; + else + Type = MeshVS_ET_Element; + } + else { + const SMDS_MeshNode* myNode = myMesh->GetMeshDS()->FindNode(ID); + if (!myNode) return Standard_False; + if (myNode->GetType() == SMDSAbs_Node) + Type = MeshVS_ET_Node; + else + Type = MeshVS_ET_0D; + } + return Standard_True; +} + +//================================================================ +// Function : GetAddr +// Purpose : +//================================================================ +Standard_Address SMESH_MeshVSLink::GetAddr + ( const Standard_Integer, const Standard_Boolean ) const +{ + return NULL; +} + +//================================================================ +// Function : GetNodesByElement +// Purpose : +//================================================================ +Standard_Boolean SMESH_MeshVSLink::GetNodesByElement + ( const Standard_Integer ID,TColStd_Array1OfInteger& NodeIDs,Standard_Integer& NbNodes ) const +{ + const SMDS_MeshElement* myElem = myMesh->GetMeshDS()->FindElement(ID); + if (!myElem) return Standard_False; + NbNodes = myElem->NbNodes(); + for(Standard_Integer i = 0; i < NbNodes; i++ ) { + const SMDS_MeshNode* aNode = myElem->GetNode(i); + if (!aNode) return Standard_False; + NodeIDs.SetValue(i+1, aNode->GetID()); + } + return Standard_True; +} + +//================================================================ +// Function : GetAllNodes +// Purpose : +//================================================================ +const TColStd_PackedMapOfInteger& SMESH_MeshVSLink::GetAllNodes() const +{ + return myNodes; +} + +//================================================================ +// Function : GetAllElements +// Purpose : +//================================================================ +const TColStd_PackedMapOfInteger& SMESH_MeshVSLink::GetAllElements() const +{ + return myElements; +} + +//================================================================ +// Function : GetAllElements +// Purpose : +//================================================================ +void SMESH_MeshVSLink::GetAllGroups(TColStd_PackedMapOfInteger& Ids) const +{ + Ids = myGroups; +} + +//================================================================ +// Function : GetNormal +// Purpose : +//================================================================ +Standard_Boolean SMESH_MeshVSLink::GetNormal + ( const Standard_Integer Id, const Standard_Integer Max, + Standard_Real& nx, Standard_Real& ny,Standard_Real& nz ) const +{ + if(Max<3) return Standard_False; + const SMDS_MeshElement* myElem = myMesh->GetMeshDS()->FindElement(Id); + if(!myElem) return Standard_False; + if(myElem->NbNodes() < 3) return Standard_False; + gp_XYZ normal; + gp_XYZ nodes[3]; + for (int itr = 0;itr < 3;itr++) + nodes[itr] = gp_XYZ(myElem->GetNode(itr)->X(), myElem->GetNode(itr)->Y(), myElem->GetNode(itr)->Z()); + normal = (nodes[1]-nodes[0]) ^ (nodes[2]-nodes[0]); + if ( normal.Modulus() > 0 ) + normal /= normal.Modulus(); + nx = normal.X(); + ny = normal.Y(); + nz = normal.Z(); + return Standard_True; +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_MesherHelper.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_MesherHelper.cpp index dd0eabb69628..3ceea9fa34ca 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_MesherHelper.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_MesherHelper.cpp @@ -1,55 +1,81 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File: SMESH_MesherHelper.cxx // Created: 15.02.06 15:22:41 // Author: Sergey KUUL // #include "SMESH_MesherHelper.hxx" -#include "SMDS_FacePosition.hxx" #include "SMDS_EdgePosition.hxx" +#include "SMDS_FaceOfNodes.hxx" +#include "SMDS_FacePosition.hxx" +#include "SMDS_IteratorOnIterators.hxx" +#include "SMDS_VolumeTool.hxx" +#include "SMESH_Block.hxx" +#include "SMESH_HypoFilter.hxx" +#include "SMESH_MeshAlgos.hxx" +#include "SMESH_ProxyMesh.hxx" +#include "SMESH_subMesh.hxx" +#include #include #include #include -#include #include +#include +#include #include +#include #include #include #include #include #include +#include #include #include +#include #include +#include #include #include #include +#include + +using namespace std; + #define RETURN_BAD_RESULT(msg) { MESSAGE(msg); return false; } +namespace { + + inline SMESH_TNodeXYZ XYZ(const SMDS_MeshNode* n) { return SMESH_TNodeXYZ(n); } + + enum { U_periodic = 1, V_periodic = 2 }; +} + //================================================================================ /*! * \brief Constructor @@ -57,99 +83,145 @@ //================================================================================ SMESH_MesherHelper::SMESH_MesherHelper(SMESH_Mesh& theMesh) - : myMesh(&theMesh), myShapeID(-1), myCreateQuadratic(false) + : myParIndex(0), + myMesh(&theMesh), + myShapeID(0), + myCreateQuadratic(false), + myCreateBiQuadratic(false), + myFixNodeParameters(false) { + myPar1[0] = myPar2[0] = myPar1[1] = myPar2[1] = 0; mySetElemOnShape = ( ! myMesh->HasShapeToMesh() ); } //======================================================================= -//function : CheckShape +//function : ~SMESH_MesherHelper //purpose : //======================================================================= +SMESH_MesherHelper::~SMESH_MesherHelper() +{ + { + TID2ProjectorOnSurf::iterator i_proj = myFace2Projector.begin(); + for ( ; i_proj != myFace2Projector.end(); ++i_proj ) + delete i_proj->second; + } + { + TID2ProjectorOnCurve::iterator i_proj = myEdge2Projector.begin(); + for ( ; i_proj != myEdge2Projector.end(); ++i_proj ) + delete i_proj->second; + } +} + +//======================================================================= +//function : IsQuadraticSubMesh +//purpose : Check submesh for given shape: if all elements on this shape +// are quadratic, quadratic elements will be created. +// Also fill myTLinkNodeMap +//======================================================================= + bool SMESH_MesherHelper::IsQuadraticSubMesh(const TopoDS_Shape& aSh) { SMESHDS_Mesh* meshDS = GetMeshDS(); // we can create quadratic elements only if all elements - // created on subshapes of given shape are quadratic - // also we have to fill myNLinkNodeMap + // created on sub-shapes of given shape are quadratic + // also we have to fill myTLinkNodeMap myCreateQuadratic = true; mySeamShapeIds.clear(); myDegenShapeIds.clear(); TopAbs_ShapeEnum subType( aSh.ShapeType()==TopAbs_FACE ? TopAbs_EDGE : TopAbs_FACE ); + if ( aSh.ShapeType()==TopAbs_COMPOUND ) + { + TopoDS_Iterator subIt( aSh ); + if ( subIt.More() ) + subType = ( subIt.Value().ShapeType()==TopAbs_FACE ) ? TopAbs_EDGE : TopAbs_FACE; + } SMDSAbs_ElementType elemType( subType==TopAbs_FACE ? SMDSAbs_Face : SMDSAbs_Edge ); - int nbOldLinks = myNLinkNodeMap.size(); - TopExp_Explorer exp( aSh, subType ); - for (; exp.More() && myCreateQuadratic; exp.Next()) { - if ( SMESHDS_SubMesh * subMesh = meshDS->MeshElements( exp.Current() )) { - if ( SMDS_ElemIteratorPtr it = subMesh->GetElements() ) { - while(it->more()) { - const SMDS_MeshElement* e = it->next(); - if ( e->GetType() != elemType || !e->IsQuadratic() ) { - myCreateQuadratic = false; - break; - } - else { - // fill NLinkNodeMap - switch ( e->NbNodes() ) { - case 3: - AddNLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(2)); break; - case 6: - AddNLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(3)); - AddNLinkNode(e->GetNode(1),e->GetNode(2),e->GetNode(4)); - AddNLinkNode(e->GetNode(2),e->GetNode(0),e->GetNode(5)); break; - case 8: - AddNLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(4)); - AddNLinkNode(e->GetNode(1),e->GetNode(2),e->GetNode(5)); - AddNLinkNode(e->GetNode(2),e->GetNode(3),e->GetNode(6)); - AddNLinkNode(e->GetNode(3),e->GetNode(0),e->GetNode(7)); - break; - default: + int nbOldLinks = myTLinkNodeMap.size(); + + if ( !myMesh->HasShapeToMesh() ) + { + if (( myCreateQuadratic = myMesh->NbFaces( ORDER_QUADRATIC ))) + { + SMDS_FaceIteratorPtr fIt = meshDS->facesIterator(); + while ( fIt->more() ) + AddTLinks( static_cast< const SMDS_MeshFace* >( fIt->next() )); + } + } + else + { + TopExp_Explorer exp( aSh, subType ); + TopTools_MapOfShape checkedSubShapes; + for (; exp.More() && myCreateQuadratic; exp.Next()) { + if ( !checkedSubShapes.Add( exp.Current() )) + continue; // needed if aSh is compound of solids + if ( SMESHDS_SubMesh * subMesh = meshDS->MeshElements( exp.Current() )) { + if ( SMDS_ElemIteratorPtr it = subMesh->GetElements() ) { + while(it->more()) { + const SMDS_MeshElement* e = it->next(); + if ( e->GetType() != elemType || !e->IsQuadratic() ) { myCreateQuadratic = false; break; } + else { + // fill TLinkNodeMap + switch ( e->NbCornerNodes() ) { + case 2: + AddTLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(2)); break; + case 3: + AddTLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(3)); + AddTLinkNode(e->GetNode(1),e->GetNode(2),e->GetNode(4)); + AddTLinkNode(e->GetNode(2),e->GetNode(0),e->GetNode(5)); break; + case 4: + AddTLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(4)); + AddTLinkNode(e->GetNode(1),e->GetNode(2),e->GetNode(5)); + AddTLinkNode(e->GetNode(2),e->GetNode(3),e->GetNode(6)); + AddTLinkNode(e->GetNode(3),e->GetNode(0),e->GetNode(7)); + break; + default: + myCreateQuadratic = false; + break; + } + } } } } } } - if ( nbOldLinks == myNLinkNodeMap.size() ) + // if ( nbOldLinks == myTLinkNodeMap.size() ) -- 0023068 + if ( myTLinkNodeMap.empty() ) myCreateQuadratic = false; - if(!myCreateQuadratic) { - myNLinkNodeMap.clear(); - } + if ( !myCreateQuadratic ) + myTLinkNodeMap.clear(); + SetSubShape( aSh ); return myCreateQuadratic; } -//================================================================================ -/*! - * \brief Set geomerty to make elements on - * \param aSh - geomertic shape - */ -//================================================================================ +//======================================================================= +//function : SetSubShape +//purpose : Set geometry to make elements on +//======================================================================= void SMESH_MesherHelper::SetSubShape(const int aShID) { if ( aShID == myShapeID ) return; - if ( aShID > 1 ) + if ( aShID > 0 ) SetSubShape( GetMeshDS()->IndexToShape( aShID )); else SetSubShape( TopoDS_Shape() ); } -//================================================================================ -/*! - * \brief Set geomerty to make elements on - * \param aSh - geomertic shape - */ -//================================================================================ +//======================================================================= +//function : SetSubShape +//purpose : Set geometry to create elements on +//======================================================================= void SMESH_MesherHelper::SetSubShape(const TopoDS_Shape& aSh) { @@ -161,67 +233,120 @@ void SMESH_MesherHelper::SetSubShape(const TopoDS_Shape& aSh) myDegenShapeIds.clear(); if ( myShape.IsNull() ) { - myShapeID = -1; + myShapeID = 0; return; } SMESHDS_Mesh* meshDS = GetMeshDS(); myShapeID = meshDS->ShapeToIndex(aSh); + myParIndex = 0; // treatment of periodic faces for ( TopExp_Explorer eF( aSh, TopAbs_FACE ); eF.More(); eF.Next() ) { const TopoDS_Face& face = TopoDS::Face( eF.Current() ); - BRepAdaptor_Surface surface( face ); - if ( surface.IsUPeriodic() || surface.IsVPeriodic() ) + BRepAdaptor_Surface surf( face, false ); + if ( surf.IsUPeriodic() || surf.IsUClosed() ) { + myParIndex |= U_periodic; + myPar1[0] = surf.FirstUParameter(); + myPar2[0] = surf.LastUParameter(); + } + if ( surf.IsVPeriodic() || surf.IsVClosed() ) { + myParIndex |= V_periodic; + myPar1[1] = surf.FirstVParameter(); + myPar2[1] = surf.LastVParameter(); + } + + gp_Pnt2d uv1, uv2; + for (TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next()) { - for (TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next()) + // look for a "seam" edge, a real seam or an edge on period boundary + TopoDS_Edge edge = TopoDS::Edge( exp.Current() ); + const int edgeID = meshDS->ShapeToIndex( edge ); + if ( myParIndex ) { - // look for a seam edge - const TopoDS_Edge& edge = TopoDS::Edge( exp.Current() ); - if ( BRep_Tool::IsClosed( edge, face )) { - // initialize myPar1, myPar2 and myParIndex - if ( mySeamShapeIds.empty() ) { - gp_Pnt2d uv1, uv2; + BRep_Tool::UVPoints( edge, face, uv1, uv2 ); + const double du = Abs( uv1.Coord(1) - uv2.Coord(1) ); + const double dv = Abs( uv1.Coord(2) - uv2.Coord(2) ); + + bool isSeam = BRep_Tool::IsClosed( edge, face ); + if ( isSeam ) // real seam - having two pcurves on face + { + // pcurve can lie not on pediod boundary (22582, mesh_Quadratic_01/C9) + if ( du < dv ) + { + double u1 = uv1.Coord(1); + edge.Reverse(); BRep_Tool::UVPoints( edge, face, uv1, uv2 ); - if ( Abs( uv1.Coord(1) - uv2.Coord(1) ) < Abs( uv1.Coord(2) - uv2.Coord(2) )) - { - myParIndex = 1; // U periodic - myPar1 = surface.FirstUParameter(); - myPar2 = surface.LastUParameter(); - } - else { - myParIndex = 2; // V periodic - myPar1 = surface.FirstVParameter(); - myPar2 = surface.LastVParameter(); - } + double u2 = uv1.Coord(1); + myPar1[0] = Min( u1, u2 ); + myPar2[0] = Max( u1, u2 ); + } + else + { + double v1 = uv1.Coord(2); + edge.Reverse(); + BRep_Tool::UVPoints( edge, face, uv1, uv2 ); + double v2 = uv1.Coord(2); + myPar1[1] = Min( v1, v2 ); + myPar2[1] = Max( v1, v2 ); + } + } + else //if ( !isSeam ) + { + // one pcurve but on period boundary (22772, mesh_Quadratic_01/D1) + if (( myParIndex & U_periodic ) && du < Precision::PConfusion() ) + { + isSeam = ( Abs( uv1.Coord(1) - myPar1[0] ) < Precision::PConfusion() || + Abs( uv1.Coord(1) - myPar2[0] ) < Precision::PConfusion() ); + } + else if (( myParIndex & V_periodic ) && dv < Precision::PConfusion() ) + { + isSeam = ( Abs( uv1.Coord(2) - myPar1[1] ) < Precision::PConfusion() || + Abs( uv1.Coord(2) - myPar2[1] ) < Precision::PConfusion() ); } - // store seam shape indices, negative if shape encounters twice - int edgeID = meshDS->ShapeToIndex( edge ); + if ( isSeam ) // vertices are on period boundary, check a middle point (23032) + { + double f,l, r = 0.2345; + Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( edge, face, f, l ); + uv2 = C2d->Value( f * r + l * ( 1.-r )); + if ( du < Precision::PConfusion() ) + isSeam = ( Abs( uv1.Coord(1) - uv2.Coord(1) ) < Precision::PConfusion() ); + else + isSeam = ( Abs( uv1.Coord(2) - uv2.Coord(2) ) < Precision::PConfusion() ); + } + } + if ( isSeam ) + { + // store seam shape indices, negative if shape encounters twice ('real seam') mySeamShapeIds.insert( IsSeamShape( edgeID ) ? -edgeID : edgeID ); for ( TopExp_Explorer v( edge, TopAbs_VERTEX ); v.More(); v.Next() ) { int vertexID = meshDS->ShapeToIndex( v.Current() ); mySeamShapeIds.insert( IsSeamShape( vertexID ) ? -vertexID : vertexID ); } } - - // look for a degenerated edge - if ( BRep_Tool::Degenerated( edge )) { - myDegenShapeIds.insert( meshDS->ShapeToIndex( edge )); - for ( TopExp_Explorer v( edge, TopAbs_VERTEX ); v.More(); v.Next() ) - myDegenShapeIds.insert( meshDS->ShapeToIndex( v.Current() )); - } + } + // look for a degenerated edge + if ( SMESH_Algo::isDegenerated( edge )) { + myDegenShapeIds.insert( edgeID ); + for ( TopExp_Explorer v( edge, TopAbs_VERTEX ); v.More(); v.Next() ) + myDegenShapeIds.insert( meshDS->ShapeToIndex( v.Current() )); + } + if ( !BRep_Tool::SameParameter( edge ) || + !BRep_Tool::SameRange( edge )) + { + setPosOnShapeValidity( edgeID, false ); } } } } -//================================================================================ - /*! - * \brief Check if inFaceNode argument is necessary for call GetNodeUV(F,..) - * \param F - the face - * \retval bool - return true if the face is periodic - */ -//================================================================================ +//======================================================================= +//function : GetNodeUVneedInFaceNode +//purpose : Check if inFaceNode argument is necessary for call GetNodeUV(F,..) +// Return true if the face is periodic. +// If F is Null, answer about sub-shape set through IsQuadraticSubMesh() or +// * SetSubShape() +//======================================================================= bool SMESH_MesherHelper::GetNodeUVneedInFaceNode(const TopoDS_Face& F) const { @@ -230,7 +355,8 @@ bool SMESH_MesherHelper::GetNodeUVneedInFaceNode(const TopoDS_Face& F) const if ( !F.IsNull() && !myShape.IsNull() && myShape.IsSame( F )) return !mySeamShapeIds.empty(); - Handle(Geom_Surface) aSurface = BRep_Tool::Surface( F ); + TopLoc_Location loc; + Handle(Geom_Surface) aSurface = BRep_Tool::Surface( F,loc ); if ( !aSurface.IsNull() ) return ( aSurface->IsUPeriodic() || aSurface->IsVPeriodic() ); @@ -243,125 +369,309 @@ bool SMESH_MesherHelper::GetNodeUVneedInFaceNode(const TopoDS_Face& F) const //======================================================================= bool SMESH_MesherHelper::IsMedium(const SMDS_MeshNode* node, - const SMDSAbs_ElementType typeToCheck) + const SMDSAbs_ElementType typeToCheck) { return SMESH_MeshEditor::IsMedium( node, typeToCheck ); } //======================================================================= -//function : AddNLinkNode -//purpose : +//function : GetSubShapeByNode +//purpose : Return support shape of a node +//======================================================================= + +TopoDS_Shape SMESH_MesherHelper::GetSubShapeByNode(const SMDS_MeshNode* node, + const SMESHDS_Mesh* meshDS) +{ + int shapeID = node ? node->getshapeId() : 0; + if ( 0 < shapeID && shapeID <= meshDS->MaxShapeIndex() ) + return meshDS->IndexToShape( shapeID ); + else + return TopoDS_Shape(); +} + + +//======================================================================= +//function : AddTLinkNode +//purpose : add a link in my data structure //======================================================================= + +void SMESH_MesherHelper::AddTLinkNode(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n12) +{ + // add new record to map + SMESH_TLink link( n1, n2 ); + myTLinkNodeMap.insert( make_pair(link,n12)); +} + +//================================================================================ /*! - * Auxilary function for filling myNLinkNodeMap + * \brief Add quadratic links of edge to own data structure */ -void SMESH_MesherHelper::AddNLinkNode(const SMDS_MeshNode* n1, - const SMDS_MeshNode* n2, - const SMDS_MeshNode* n12) +//================================================================================ + +bool SMESH_MesherHelper::AddTLinks(const SMDS_MeshEdge* edge) { - NLink link( n1, n2 ); - if ( n1 > n2 ) link = NLink( n2, n1 ); - // add new record to map - myNLinkNodeMap.insert( make_pair(link,n12)); + if ( edge && edge->IsQuadratic() ) + AddTLinkNode(edge->GetNode(0), edge->GetNode(1), edge->GetNode(2)); + else + return false; + return true; } -//======================================================================= +//================================================================================ +/*! + * \brief Add quadratic links of face to own data structure + */ +//================================================================================ + +bool SMESH_MesherHelper::AddTLinks(const SMDS_MeshFace* f) +{ + bool isQuad = true; + if ( !f->IsPoly() ) + switch ( f->NbNodes() ) { + case 7: + // myMapWithCentralNode.insert + // ( make_pair( TBiQuad( f->GetNode(0),f->GetNode(1),f->GetNode(2) ), + // f->GetNode(6))); + // break; -- add medium nodes as well + case 6: + AddTLinkNode(f->GetNode(0),f->GetNode(1),f->GetNode(3)); + AddTLinkNode(f->GetNode(1),f->GetNode(2),f->GetNode(4)); + AddTLinkNode(f->GetNode(2),f->GetNode(0),f->GetNode(5)); break; + + case 9: + // myMapWithCentralNode.insert + // ( make_pair( TBiQuad( f->GetNode(0),f->GetNode(1),f->GetNode(2),f->GetNode(3) ), + // f->GetNode(8))); + // break; -- add medium nodes as well + case 8: + AddTLinkNode(f->GetNode(0),f->GetNode(1),f->GetNode(4)); + AddTLinkNode(f->GetNode(1),f->GetNode(2),f->GetNode(5)); + AddTLinkNode(f->GetNode(2),f->GetNode(3),f->GetNode(6)); + AddTLinkNode(f->GetNode(3),f->GetNode(0),f->GetNode(7)); break; + default:; + isQuad = false; + } + return isQuad; +} + +//================================================================================ +/*! + * \brief Add quadratic links of volume to own data structure + */ +//================================================================================ + +bool SMESH_MesherHelper::AddTLinks(const SMDS_MeshVolume* volume) +{ + if ( volume->IsQuadratic() ) + { + SMDS_VolumeTool vTool( volume ); + const SMDS_MeshNode** nodes = vTool.GetNodes(); + set addedLinks; + for ( int iF = 1; iF < vTool.NbFaces(); ++iF ) + { + const int nbN = vTool.NbFaceNodes( iF ); + const int* iNodes = vTool.GetFaceNodesIndices( iF ); + for ( int i = 0; i < nbN; ) + { + int iN1 = iNodes[i++]; + int iN12 = iNodes[i++]; + int iN2 = iNodes[i]; + if ( iN1 > iN2 ) std::swap( iN1, iN2 ); + int linkID = iN1 * vTool.NbNodes() + iN2; + pair< set::iterator, bool > it_isNew = addedLinks.insert( linkID ); + if ( it_isNew.second ) + AddTLinkNode( nodes[iN1], nodes[iN2], nodes[iN12] ); + else + addedLinks.erase( it_isNew.first ); // each link encounters only twice + } + if ( vTool.NbNodes() == 27 ) + { + const SMDS_MeshNode* nFCenter = nodes[ vTool.GetCenterNodeIndex( iF )]; + if ( nFCenter->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE ) + myMapWithCentralNode.insert + ( make_pair( TBiQuad( nodes[ iNodes[0]], nodes[ iNodes[1]], + nodes[ iNodes[2]], nodes[ iNodes[3]] ), + nFCenter )); + } + } + return true; + } + return false; +} + +//================================================================================ +/*! + * \brief Return true if position of nodes on the shape hasn't yet been checked or + * the positions proved to be invalid + */ +//================================================================================ + +bool SMESH_MesherHelper::toCheckPosOnShape(int shapeID ) const +{ + map< int,bool >::const_iterator id_ok = myNodePosShapesValidity.find( shapeID ); + return ( id_ok == myNodePosShapesValidity.end() || !id_ok->second ); +} + +//================================================================================ /*! - * \brief Select UV on either of 2 pcurves of a seam edge, closest to the given UV - * \param uv1 - UV on the seam - * \param uv2 - UV within a face - * \retval gp_Pnt2d - selected UV + * \brief Set validity of positions of nodes on the shape. + * Once set, validity is not changed */ +//================================================================================ + +void SMESH_MesherHelper::setPosOnShapeValidity(int shapeID, bool ok ) const +{ + std::map< int,bool >::iterator sh_ok = + ((SMESH_MesherHelper*)this)->myNodePosShapesValidity.insert( make_pair( shapeID, ok)).first; + if ( !ok ) + sh_ok->second = ok; +} + +//======================================================================= +//function : ToFixNodeParameters +//purpose : Enables fixing node parameters on EDGEs and FACEs in +// GetNodeU(...,check=true), GetNodeUV(...,check=true), CheckNodeUV() and +// CheckNodeU() in case if a node lies on a shape set via SetSubShape(). +// Default is False +//======================================================================= + +void SMESH_MesherHelper::ToFixNodeParameters(bool toFix) +{ + myFixNodeParameters = toFix; +} + + +//======================================================================= +//function : getUVOnSeam +//purpose : Select UV on either of 2 pcurves of a seam edge, closest to the given UV //======================================================================= -gp_Pnt2d SMESH_MesherHelper::GetUVOnSeam( const gp_Pnt2d& uv1, const gp_Pnt2d& uv2 ) const +gp_Pnt2d SMESH_MesherHelper::getUVOnSeam( const gp_Pnt2d& uv1, const gp_Pnt2d& uv2 ) const { - double p1 = uv1.Coord( myParIndex ); - double p2 = uv2.Coord( myParIndex ); - double p3 = ( Abs( p1 - myPar1 ) < Abs( p1 - myPar2 )) ? myPar2 : myPar1; - if ( Abs( p2 - p1 ) > Abs( p2 - p3 )) - p1 = p3; gp_Pnt2d result = uv1; - result.SetCoord( myParIndex, p1 ); + for ( int i = U_periodic; i <= V_periodic ; ++i ) + { + if ( myParIndex & i ) + { + double p1 = uv1.Coord( i ); + double dp1 = Abs( p1-myPar1[i-1]), dp2 = Abs( p1-myPar2[i-1]); + if ( myParIndex == i || + dp1 < ( myPar2[i-1] - myPar1[i-1] ) / 100. || + dp2 < ( myPar2[i-1] - myPar1[i-1] ) / 100. ) + { + double p2 = uv2.Coord( i ); + double p1Alt = ( dp1 < dp2 ) ? myPar2[i-1] : myPar1[i-1]; + if ( Abs( p2 - p1 ) > Abs( p2 - p1Alt )) + result.SetCoord( i, p1Alt ); + } + } + } return result; } //======================================================================= -/*! - * \brief Return node UV on face - * \param F - the face - * \param n - the node - * \param n2 - a node of element being created located inside a face - * \retval gp_XY - resulting UV - * - * Auxilary function called form GetMediumNode() - */ +//function : GetNodeUV +//purpose : Return node UV on face //======================================================================= gp_XY SMESH_MesherHelper::GetNodeUV(const TopoDS_Face& F, const SMDS_MeshNode* n, - const SMDS_MeshNode* n2) const + const SMDS_MeshNode* n2, + bool* check) const { - gp_Pnt2d uv( 1e100, 1e100 ); + gp_Pnt2d uv( Precision::Infinite(), Precision::Infinite() ); + const SMDS_PositionPtr Pos = n->GetPosition(); - if(Pos->GetTypeOfPosition()==SMDS_TOP_FACE) + bool uvOK = false; + if ( Pos->GetTypeOfPosition() == SMDS_TOP_FACE ) { // node has position on face - const SMDS_FacePosition* fpos = - static_cast(n->GetPosition().get()); - uv = gp_Pnt2d(fpos->GetUParameter(),fpos->GetVParameter()); - } - else if(Pos->GetTypeOfPosition()==SMDS_TOP_EDGE) - { - // node has position on edge => it is needed to find - // corresponding edge from face, get pcurve for this - // edge and recieve value from this pcurve - const SMDS_EdgePosition* epos = - static_cast(n->GetPosition().get()); - SMESHDS_Mesh* meshDS = GetMeshDS(); - int edgeID = Pos->GetShapeId(); - TopoDS_Edge E = TopoDS::Edge(meshDS->IndexToShape(edgeID)); - double f, l; - Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, F, f, l); - uv = C2d->Value( epos->GetUParameter() ); - // for a node on a seam edge select one of UVs on 2 pcurves - if ( n2 && IsSeamShape( edgeID ) ) - uv = GetUVOnSeam( uv, GetNodeUV( F, n2, 0 )); - } - else if(Pos->GetTypeOfPosition()==SMDS_TOP_VERTEX) - { - if ( int vertexID = n->GetPosition()->GetShapeId() ) { - bool ok = true; + const SMDS_FacePosition* fpos = static_cast( Pos ); + uv.SetCoord( fpos->GetUParameter(), fpos->GetVParameter() ); + if ( check ) + uvOK = CheckNodeUV( F, n, uv.ChangeCoord(), 2.*getFaceMaxTol( F )); // 2. from 22830 + } + else if ( Pos->GetTypeOfPosition() == SMDS_TOP_EDGE ) + { + // node has position on EDGE => it is needed to find + // corresponding EDGE from FACE, get pcurve for this + // EDGE and retrieve value from this pcurve + const SMDS_EdgePosition* epos = static_cast( Pos ); + const int edgeID = n->getshapeId(); + const TopoDS_Edge& E = TopoDS::Edge( GetMeshDS()->IndexToShape( edgeID )); + double f, l, u = epos->GetUParameter(); + Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( E, F, f, l ); + bool validU = ( !C2d.IsNull() && ( f < u ) && ( u < l )); + if ( validU ) uv = C2d->Value( u ); + else uv.SetCoord( Precision::Infinite(),0.); + if ( check || !validU ) + uvOK = CheckNodeUV( F, n, uv.ChangeCoord(), 2.*getFaceMaxTol( F ),/*force=*/ !validU ); + + // for a node on a seam EDGE select one of UVs on 2 pcurves + if ( n2 && IsSeamShape( edgeID )) + { + uv = getUVOnSeam( uv, GetNodeUV( F, n2, 0, check )); + } + else + { // adjust uv to period + TopLoc_Location loc; + Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc); + Standard_Boolean isUPeriodic = S->IsUPeriodic(); + Standard_Boolean isVPeriodic = S->IsVPeriodic(); + gp_Pnt2d newUV = uv; + if ( isUPeriodic || isVPeriodic ) { + Standard_Real UF,UL,VF,VL; + S->Bounds(UF,UL,VF,VL); + if ( isUPeriodic ) newUV.SetX( uv.X() + ShapeAnalysis::AdjustToPeriod(uv.X(),UF,UL)); + if ( isVPeriodic ) newUV.SetY( uv.Y() + ShapeAnalysis::AdjustToPeriod(uv.Y(),VF,VL)); + + if ( n2 ) + { + gp_Pnt2d uv2 = GetNodeUV( F, n2, 0, check ); + if ( isUPeriodic && Abs( uv.X()-uv2.X() ) < Abs( newUV.X()-uv2.X() )) + newUV.SetX( uv.X() ); + if ( isVPeriodic && Abs( uv.Y()-uv2.Y() ) < Abs( newUV.Y()-uv2.Y() )) + newUV.SetY( uv.Y() ); + } + } + uv = newUV; + } + } + else if ( Pos->GetTypeOfPosition() == SMDS_TOP_VERTEX ) + { + if ( int vertexID = n->getshapeId() ) { const TopoDS_Vertex& V = TopoDS::Vertex(GetMeshDS()->IndexToShape(vertexID)); try { uv = BRep_Tool::Parameters( V, F ); + uvOK = true; } catch (Standard_Failure& exc) { - ok = false; } - if ( !ok ) { - for ( TopExp_Explorer vert(F,TopAbs_VERTEX); !ok && vert.More(); vert.Next() ) - ok = ( V == vert.Current() ); - if ( !ok ) { -#ifdef _DEBUG_ + if ( !uvOK ) + { + if ( !IsSubShape( V, F )) + { MESSAGE ( "SMESH_MesherHelper::GetNodeUV(); Vertex " << vertexID - << " not in face " << GetMeshDS()->ShapeToIndex( F ) ); -#endif + << " not in face " << GetMeshDS()->ShapeToIndex( F ) ); // get UV of a vertex closest to the node double dist = 1e100; - gp_Pnt pn ( n->X(),n->Y(),n->Z() ); - for ( TopExp_Explorer vert(F,TopAbs_VERTEX); !ok && vert.More(); vert.Next() ) { + gp_Pnt pn = XYZ( n ); + for ( TopExp_Explorer vert( F,TopAbs_VERTEX ); !uvOK && vert.More(); vert.Next() ) { TopoDS_Vertex curV = TopoDS::Vertex( vert.Current() ); gp_Pnt p = BRep_Tool::Pnt( curV ); double curDist = p.SquareDistance( pn ); if ( curDist < dist ) { dist = curDist; uv = BRep_Tool::Parameters( curV, F ); - if ( dist < DBL_MIN ) break; + uvOK = ( dist < DBL_MIN ); } } } - else { + else + { + uvOK = false; TopTools_ListIteratorOfListOfShape it( myMesh->GetAncestors( V )); for ( ; it.More(); it.Next() ) { if ( it.Value().ShapeType() == TopAbs_EDGE ) { @@ -369,851 +679,4641 @@ gp_XY SMESH_MesherHelper::GetNodeUV(const TopoDS_Face& F, double f,l; Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(edge, F, f, l); if ( !C2d.IsNull() ) { - double u = ( V == TopExp::FirstVertex( edge ) ) ? f : l; + double u = ( V == IthVertex( 0, edge )) ? f : l; uv = C2d->Value( u ); + uvOK = true; break; } } } + if ( !uvOK && V.Orientation() == TopAbs_INTERNAL ) + { + Handle(ShapeAnalysis_Surface) projector = GetSurface( F ); + if ( n2 ) uv = GetNodeUV( F, n2 ); + if ( Precision::IsInfinite( uv.X() )) + uv = projector->NextValueOfUV( uv, BRep_Tool::Pnt( V ), BRep_Tool::Tolerance( F )); + else + uv = projector->ValueOfUV( BRep_Tool::Pnt( V ), BRep_Tool::Tolerance( F )); + uvOK = ( projector->Gap() < getFaceMaxTol( F )); + } + } + } + if ( n2 && IsSeamShape( vertexID )) + { + bool isSeam = ( myShape.IsSame( F )); + if ( !isSeam ) { + SMESH_MesherHelper h( *myMesh ); + h.SetSubShape( F ); + isSeam = IsSeamShape( vertexID ); } + + if ( isSeam ) + uv = getUVOnSeam( uv, GetNodeUV( F, n2, 0 )); } - if ( n2 && IsSeamShape( vertexID ) ) - uv = GetUVOnSeam( uv, GetNodeUV( F, n2, 0 )); } } - return uv.XY(); -} + else + { + uvOK = CheckNodeUV( F, n, uv.ChangeCoord(), 2.*getFaceMaxTol( F )); + } -//======================================================================= -/*! - * \brief Return node U on edge - * \param E - the Edge - * \param n - the node - * \retval double - resulting U - * - * Auxilary function called form GetMediumNode() - */ -//======================================================================= + if ( check && !uvOK ) + *check = uvOK; -double SMESH_MesherHelper::GetNodeU(const TopoDS_Edge& E, - const SMDS_MeshNode* n) -{ - double param = 0; - const SMDS_PositionPtr Pos = n->GetPosition(); - if(Pos->GetTypeOfPosition()==SMDS_TOP_EDGE) { - const SMDS_EdgePosition* epos = - static_cast(n->GetPosition().get()); - param = epos->GetUParameter(); - } - else if(Pos->GetTypeOfPosition()==SMDS_TOP_VERTEX) { - SMESHDS_Mesh * meshDS = GetMeshDS(); - int vertexID = n->GetPosition()->GetShapeId(); - const TopoDS_Vertex& V = TopoDS::Vertex(meshDS->IndexToShape(vertexID)); - param = BRep_Tool::Parameter( V, E ); - } - return param; + return uv.XY(); } //======================================================================= -//function : GetMediumNode -//purpose : +//function : CheckNodeUV +//purpose : Check and fix node UV on a face //======================================================================= -/*! - * Special function for search or creation medium node - */ -const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1, - const SMDS_MeshNode* n2, - bool force3d) -{ - TopAbs_ShapeEnum shapeType = myShape.IsNull() ? TopAbs_SHAPE : myShape.ShapeType(); - NLink link(( n1 < n2 ? n1 : n2 ), ( n1 < n2 ? n2 : n1 )); - ItNLinkNode itLN = myNLinkNodeMap.find( link ); - if ( itLN != myNLinkNodeMap.end() ) { - return (*itLN).second; - } - else { - // create medium node - SMDS_MeshNode* n12; - SMESHDS_Mesh* meshDS = GetMeshDS(); - int faceID = -1, edgeID = -1; - const SMDS_PositionPtr Pos1 = n1->GetPosition(); - const SMDS_PositionPtr Pos2 = n2->GetPosition(); - - if( myShape.IsNull() ) +bool SMESH_MesherHelper::CheckNodeUV(const TopoDS_Face& F, + const SMDS_MeshNode* n, + gp_XY& uv, + const double tol, + const bool force, + double distXYZ[4]) const +{ + int shapeID = n->getshapeId(); + bool infinit; + if (( infinit = ( Precision::IsInfinite( uv.X() ) || Precision::IsInfinite( uv.Y() ))) || + ( force ) || + ( uv.X() == 0. && uv.Y() == 0. ) || + ( toCheckPosOnShape( shapeID ))) + { + // check that uv is correct + TopLoc_Location loc; + Handle(Geom_Surface) surface = BRep_Tool::Surface( F,loc ); + gp_Pnt nodePnt = XYZ( n ), surfPnt(0,0,0); + double dist = 0; + if ( !loc.IsIdentity() ) nodePnt.Transform( loc.Transformation().Inverted() ); + if ( infinit || + (dist = nodePnt.Distance( surfPnt = surface->Value( uv.X(), uv.Y() ))) > tol ) { - if( Pos1->GetTypeOfPosition()==SMDS_TOP_FACE ) { - faceID = Pos1->GetShapeId(); + setPosOnShapeValidity( shapeID, false ); + if ( !infinit && distXYZ ) { + surfPnt.Transform( loc ); + distXYZ[0] = dist; + distXYZ[1] = surfPnt.X(); distXYZ[2] = surfPnt.Y(); distXYZ[3]=surfPnt.Z(); } - else if( Pos2->GetTypeOfPosition()==SMDS_TOP_FACE ) { - faceID = Pos2->GetShapeId(); + // uv incorrect, project the node to surface + GeomAPI_ProjectPointOnSurf& projector = GetProjector( F, loc, tol ); + projector.Perform( nodePnt ); + if ( !projector.IsDone() || projector.NbPoints() < 1 ) + { + MESSAGE( "SMESH_MesherHelper::CheckNodeUV() failed to project" ); + return false; } - - if( Pos1->GetTypeOfPosition()==SMDS_TOP_EDGE ) { - edgeID = Pos1->GetShapeId(); + Quantity_Parameter U,V; + projector.LowerDistanceParameters(U,V); + uv.SetCoord( U,V ); + surfPnt = surface->Value( U, V ); + dist = nodePnt.Distance( surfPnt ); + if ( distXYZ ) { + surfPnt.Transform( loc ); + distXYZ[0] = dist; + distXYZ[1] = surfPnt.X(); distXYZ[2] = surfPnt.Y(); distXYZ[3]=surfPnt.Z(); } - if( Pos2->GetTypeOfPosition()==SMDS_TOP_EDGE ) { - edgeID = Pos2->GetShapeId(); + if ( dist > tol ) + { + MESSAGE( "SMESH_MesherHelper::CheckNodeUV(), invalid projection" ); + return false; } + // store the fixed UV on the face + if ( myShape.IsSame(F) && shapeID == myShapeID && myFixNodeParameters ) + const_cast(n)->SetPosition + ( SMDS_PositionPtr( new SMDS_FacePosition( U, V ))); } + else if ( myShape.IsSame(F) && uv.Modulus() > numeric_limits::min() ) + { + setPosOnShapeValidity( shapeID, true ); + } + } + return true; +} - if(!force3d) { - // we try to create medium node using UV parameters of - // nodes, else - medium between corresponding 3d points - if(faceID>-1 || shapeType == TopAbs_FACE) { - // obtaining a face and 2d points for nodes - TopoDS_Face F; - if( myShape.IsNull() ) - F = TopoDS::Face(meshDS->IndexToShape(faceID)); - else { - F = TopoDS::Face(myShape); - faceID = myShapeID; - } - - gp_XY p1 = GetNodeUV(F,n1,n2); - gp_XY p2 = GetNodeUV(F,n2,n1); - - if ( IsDegenShape( Pos1->GetShapeId() )) - p1.SetCoord( myParIndex, p2.Coord( myParIndex )); - else if ( IsDegenShape( Pos2->GetShapeId() )) - p2.SetCoord( myParIndex, p1.Coord( myParIndex )); - - //checking if surface is periodic - Handle(Geom_Surface) S = BRep_Tool::Surface(F); - Standard_Real UF,UL,VF,VL; - S->Bounds(UF,UL,VF,VL); - - Standard_Real u,v; - Standard_Boolean isUPeriodic = S->IsUPeriodic(); - if(isUPeriodic) { - Standard_Real UPeriod = S->UPeriod(); - Standard_Real p2x = p2.X()+ShapeAnalysis::AdjustByPeriod(p2.X(),p1.X(),UPeriod); - Standard_Real pmid = (p1.X()+p2x)/2.; - u = pmid+ShapeAnalysis::AdjustToPeriod(pmid,UF,UL); - } - else - u= (p1.X()+p2.X())/2.; - - Standard_Boolean isVPeriodic = S->IsVPeriodic(); - if(isVPeriodic) { - Standard_Real VPeriod = S->VPeriod(); - Standard_Real p2y = p2.Y()+ShapeAnalysis::AdjustByPeriod(p2.Y(),p1.Y(),VPeriod); - Standard_Real pmid = (p1.Y()+p2y)/2.; - v = pmid+ShapeAnalysis::AdjustToPeriod(pmid,VF,VL); - } - else - v = (p1.Y()+p2.Y())/2.; - - gp_Pnt P = S->Value(u, v); - n12 = meshDS->AddNode(P.X(), P.Y(), P.Z()); - meshDS->SetNodeOnFace(n12, faceID, u, v); - myNLinkNodeMap.insert(NLinkNodeMap::value_type(link,n12)); - return n12; - } - if (edgeID>-1 || shapeType == TopAbs_EDGE) { - - TopoDS_Edge E; - if( myShape.IsNull() ) - E = TopoDS::Edge(meshDS->IndexToShape(edgeID)); - else { - E = TopoDS::Edge(myShape); - edgeID = myShapeID; - } +//======================================================================= +//function : GetProjector +//purpose : Return projector intitialized by given face without location, which is returned +//======================================================================= - double p1 = GetNodeU(E,n1); - double p2 = GetNodeU(E,n2); - - double f,l; - Handle(Geom_Curve) C = BRep_Tool::Curve(E, f, l); - if(!C.IsNull()) { - - Standard_Boolean isPeriodic = C->IsPeriodic(); - double u; - if(isPeriodic) { - Standard_Real Period = C->Period(); - Standard_Real p = p2+ShapeAnalysis::AdjustByPeriod(p2,p1,Period); - Standard_Real pmid = (p1+p)/2.; - u = pmid+ShapeAnalysis::AdjustToPeriod(pmid,C->FirstParameter(),C->LastParameter()); - } - else - u = (p1+p2)/2.; - - gp_Pnt P = C->Value( u ); - n12 = meshDS->AddNode(P.X(), P.Y(), P.Z()); - meshDS->SetNodeOnEdge(n12, edgeID, u); - myNLinkNodeMap.insert(NLinkNodeMap::value_type(link,n12)); - return n12; - } - } - } - // 3d variant - double x = ( n1->X() + n2->X() )/2.; - double y = ( n1->Y() + n2->Y() )/2.; - double z = ( n1->Z() + n2->Z() )/2.; - n12 = meshDS->AddNode(x,y,z); - if(edgeID>-1) - meshDS->SetNodeOnEdge(n12, edgeID); - else if(faceID>-1) - meshDS->SetNodeOnFace(n12, faceID); - else - meshDS->SetNodeInVolume(n12, myShapeID); - myNLinkNodeMap.insert(NLinkNodeMap::value_type(link,n12)); - return n12; +GeomAPI_ProjectPointOnSurf& SMESH_MesherHelper::GetProjector(const TopoDS_Face& F, + TopLoc_Location& loc, + double tol ) const +{ + Handle(Geom_Surface) surface = BRep_Tool::Surface( F,loc ); + int faceID = GetMeshDS()->ShapeToIndex( F ); + TID2ProjectorOnSurf& i2proj = const_cast< TID2ProjectorOnSurf&>( myFace2Projector ); + TID2ProjectorOnSurf::iterator i_proj = i2proj.find( faceID ); + if ( i_proj == i2proj.end() ) + { + if ( tol == 0 ) tol = BRep_Tool::Tolerance( F ); + double U1, U2, V1, V2; + surface->Bounds(U1, U2, V1, V2); + GeomAPI_ProjectPointOnSurf* proj = new GeomAPI_ProjectPointOnSurf(); + proj->Init( surface, U1, U2, V1, V2, tol ); + i_proj = i2proj.insert( make_pair( faceID, proj )).first; } + return *( i_proj->second ); } //======================================================================= -/*! - * Creates a node - */ +//function : GetSurface +//purpose : Return a cached ShapeAnalysis_Surface of a FACE //======================================================================= -SMDS_MeshNode* SMESH_MesherHelper::AddNode(double x, double y, double z, int ID) +Handle(ShapeAnalysis_Surface) SMESH_MesherHelper::GetSurface(const TopoDS_Face& F ) const { - SMESHDS_Mesh * meshDS = GetMeshDS(); - SMDS_MeshNode* node = 0; - if ( ID ) - node = meshDS->AddNodeWithID( x, y, z, ID ); - else - node = meshDS->AddNode( x, y, z ); - if ( mySetElemOnShape && myShapeID > 0 ) { - switch ( myShape.ShapeType() ) { - case TopAbs_SOLID: meshDS->SetNodeInVolume( node, myShapeID); break; - case TopAbs_SHELL: meshDS->SetNodeInVolume( node, myShapeID); break; - case TopAbs_FACE: meshDS->SetNodeOnFace( node, myShapeID); break; - case TopAbs_EDGE: meshDS->SetNodeOnEdge( node, myShapeID); break; - case TopAbs_VERTEX: meshDS->SetNodeOnVertex( node, myShapeID); break; - default: ; - } + Handle(Geom_Surface) surface = BRep_Tool::Surface( F ); + int faceID = GetMeshDS()->ShapeToIndex( F ); + TID2Surface::iterator i_surf = myFace2Surface.find( faceID ); + if ( i_surf == myFace2Surface.end() && faceID ) + { + Handle(ShapeAnalysis_Surface) surf( new ShapeAnalysis_Surface( surface )); + i_surf = myFace2Surface.insert( make_pair( faceID, surf )).first; } - return node; + return i_surf->second; +} + +namespace +{ + gp_XY AverageUV(const gp_XY& uv1, const gp_XY& uv2) { return ( uv1 + uv2 ) / 2.; } + gp_XY_FunPtr(Added); // define gp_XY_Added pointer to function calling gp_XY::Added(gp_XY) + gp_XY_FunPtr(Subtracted); } //======================================================================= -/*! - * Creates quadratic or linear edge - */ +//function : ApplyIn2D +//purpose : Perform given operation on two 2d points in parameric space of given surface. +// It takes into account period of the surface. Use gp_XY_FunPtr macro +// to easily define pointer to function of gp_XY class. //======================================================================= -SMDS_MeshEdge* SMESH_MesherHelper::AddEdge(const SMDS_MeshNode* n1, - const SMDS_MeshNode* n2, - const int id, - const bool force3d) +gp_XY SMESH_MesherHelper::ApplyIn2D(Handle(Geom_Surface) surface, + const gp_XY& uv1, + const gp_XY& uv2, + xyFunPtr fun, + const bool resultInPeriod) { - SMESHDS_Mesh * meshDS = GetMeshDS(); - - SMDS_MeshEdge* edge = 0; - if (myCreateQuadratic) { - const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d); - if(id) - edge = meshDS->AddEdgeWithID(n1, n2, n12, id); - else - edge = meshDS->AddEdge(n1, n2, n12); - } - else { - if(id) - edge = meshDS->AddEdgeWithID(n1, n2, id); - else - edge = meshDS->AddEdge(n1, n2); - } - - if ( mySetElemOnShape && myShapeID > 0 ) - meshDS->SetMeshElementOnShape( edge, myShapeID ); - - return edge; -} + if ( surface->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface ))) + surface = Handle(Geom_RectangularTrimmedSurface)::DownCast( surface )->BasisSurface(); + Standard_Boolean isUPeriodic = surface.IsNull() ? false : surface->IsUPeriodic(); + Standard_Boolean isVPeriodic = surface.IsNull() ? false : surface->IsVPeriodic(); + if ( !isUPeriodic && !isVPeriodic ) + return fun(uv1,uv2); -//======================================================================= -/*! - * Creates quadratic or linear triangle - */ -//======================================================================= + // move uv2 not far than half-period from uv1 + double u2 = + uv2.X()+(isUPeriodic ? ShapeAnalysis::AdjustByPeriod(uv2.X(),uv1.X(),surface->UPeriod()) :0); + double v2 = + uv2.Y()+(isVPeriodic ? ShapeAnalysis::AdjustByPeriod(uv2.Y(),uv1.Y(),surface->VPeriod()) :0); -SMDS_MeshFace* SMESH_MesherHelper::AddFace(const SMDS_MeshNode* n1, - const SMDS_MeshNode* n2, - const SMDS_MeshNode* n3, - const int id, - const bool force3d) -{ - SMESHDS_Mesh * meshDS = GetMeshDS(); - SMDS_MeshFace* elem = 0; - if(!myCreateQuadratic) { - if(id) - elem = meshDS->AddFaceWithID(n1, n2, n3, id); - else - elem = meshDS->AddFace(n1, n2, n3); - } - else { - const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d); - const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d); - const SMDS_MeshNode* n31 = GetMediumNode(n3,n1,force3d); + // execute operation + gp_XY res = fun( uv1, gp_XY(u2,v2) ); - if(id) - elem = meshDS->AddFaceWithID(n1, n2, n3, n12, n23, n31, id); - else - elem = meshDS->AddFace(n1, n2, n3, n12, n23, n31); + // move result within period + if ( resultInPeriod ) + { + Standard_Real UF,UL,VF,VL; + surface->Bounds(UF,UL,VF,VL); + if ( isUPeriodic ) + res.SetX( res.X() + ShapeAnalysis::AdjustToPeriod(res.X(),UF,UL)); + if ( isVPeriodic ) + res.SetY( res.Y() + ShapeAnalysis::AdjustToPeriod(res.Y(),VF,VL)); } - if ( mySetElemOnShape && myShapeID > 0 ) - meshDS->SetMeshElementOnShape( elem, myShapeID ); - return elem; + return res; } //======================================================================= -/*! - * Creates quadratic or linear quadrangle - */ +//function : AdjustByPeriod +//purpose : Move node positions on a FACE within surface period //======================================================================= -SMDS_MeshFace* SMESH_MesherHelper::AddFace(const SMDS_MeshNode* n1, - const SMDS_MeshNode* n2, - const SMDS_MeshNode* n3, - const SMDS_MeshNode* n4, - const int id, - const bool force3d) +void SMESH_MesherHelper::AdjustByPeriod( const TopoDS_Face& face, gp_XY uv[], const int nbUV ) { - SMESHDS_Mesh * meshDS = GetMeshDS(); - SMDS_MeshFace* elem = 0; - if(!myCreateQuadratic) { - if(id) - elem = meshDS->AddFaceWithID(n1, n2, n3, n4, id); - else - elem = meshDS->AddFace(n1, n2, n3, n4); - } - else { - const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d); - const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d); - const SMDS_MeshNode* n34 = GetMediumNode(n3,n4,force3d); - const SMDS_MeshNode* n41 = GetMediumNode(n4,n1,force3d); - - if(id) - elem = meshDS->AddFaceWithID(n1, n2, n3, n4, n12, n23, n34, n41, id); - else - elem = meshDS->AddFace(n1, n2, n3, n4, n12, n23, n34, n41); - } - if ( mySetElemOnShape && myShapeID > 0 ) - meshDS->SetMeshElementOnShape( elem, myShapeID ); + SMESH_MesherHelper h( *myMesh ), *ph = face.IsSame( myShape ) ? this : &h; + ph->SetSubShape( face ); - return elem; + for ( int iCoo = U_periodic; iCoo <= V_periodic; ++iCoo ) + if ( ph->GetPeriodicIndex() & iCoo ) + { + const double period = ( ph->myPar2[iCoo-1] - ph->myPar1[iCoo-1] ); + const double xRef = uv[0].Coord( iCoo ); + for ( int i = 1; i < nbUV; ++i ) + { + double x = uv[i].Coord( iCoo ); + double dx = ShapeAnalysis::AdjustByPeriod( x, xRef, period ); + uv[i].SetCoord( iCoo, x + dx ); + } + } } //======================================================================= -/*! - * Creates quadratic or linear volume - */ +//function : GetMiddleUV +//purpose : Return middle UV taking in account surface period //======================================================================= -SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1, - const SMDS_MeshNode* n2, - const SMDS_MeshNode* n3, - const SMDS_MeshNode* n4, - const SMDS_MeshNode* n5, - const SMDS_MeshNode* n6, - const int id, - const bool force3d) +gp_XY SMESH_MesherHelper::GetMiddleUV(const Handle(Geom_Surface)& surface, + const gp_XY& p1, + const gp_XY& p2) { - SMESHDS_Mesh * meshDS = GetMeshDS(); - SMDS_MeshVolume* elem = 0; - if(!myCreateQuadratic) { - if(id) - elem = meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, id); - else - elem = meshDS->AddVolume(n1, n2, n3, n4, n5, n6); - } - else { - const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d); - const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d); - const SMDS_MeshNode* n31 = GetMediumNode(n3,n1,force3d); - - const SMDS_MeshNode* n45 = GetMediumNode(n4,n5,force3d); - const SMDS_MeshNode* n56 = GetMediumNode(n5,n6,force3d); - const SMDS_MeshNode* n64 = GetMediumNode(n6,n4,force3d); - - const SMDS_MeshNode* n14 = GetMediumNode(n1,n4,force3d); - const SMDS_MeshNode* n25 = GetMediumNode(n2,n5,force3d); - const SMDS_MeshNode* n36 = GetMediumNode(n3,n6,force3d); - - if(id) - elem = meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, - n12, n23, n31, n45, n56, n64, n14, n25, n36, id); - else - elem = meshDS->AddVolume(n1, n2, n3, n4, n5, n6, - n12, n23, n31, n45, n56, n64, n14, n25, n36); - } - if ( mySetElemOnShape && myShapeID > 0 ) - meshDS->SetMeshElementOnShape( elem, myShapeID ); + // NOTE: + // the proper place of getting basic surface seems to be in ApplyIn2D() + // but we put it here to decrease a risk of regressions just before releasing a version + // Handle(Geom_Surface) surf = surface; + // while ( !surf.IsNull() && surf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface ))) + // surf = Handle(Geom_RectangularTrimmedSurface)::DownCast( surf )->BasisSurface(); - return elem; + return ApplyIn2D( surface, p1, p2, & AverageUV ); } //======================================================================= -/*! - * Creates quadratic or linear volume - */ +//function : GetCenterUV +//purpose : Return UV for the central node of a biquadratic triangle //======================================================================= -SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1, - const SMDS_MeshNode* n2, - const SMDS_MeshNode* n3, - const SMDS_MeshNode* n4, - const int id, - const bool force3d) +gp_XY SMESH_MesherHelper::GetCenterUV(const gp_XY& uv1, + const gp_XY& uv2, + const gp_XY& uv3, + const gp_XY& uv12, + const gp_XY& uv23, + const gp_XY& uv31, + bool * isBadTria/*=0*/) { - SMESHDS_Mesh * meshDS = GetMeshDS(); - SMDS_MeshVolume* elem = 0; - if(!myCreateQuadratic) { - if(id) - elem = meshDS->AddVolumeWithID(n1, n2, n3, n4, id); - else - elem = meshDS->AddVolume(n1, n2, n3, n4); - } - else { - const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d); - const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d); - const SMDS_MeshNode* n31 = GetMediumNode(n3,n1,force3d); - - const SMDS_MeshNode* n14 = GetMediumNode(n1,n4,force3d); - const SMDS_MeshNode* n24 = GetMediumNode(n2,n4,force3d); - const SMDS_MeshNode* n34 = GetMediumNode(n3,n4,force3d); + bool badTria; + gp_XY uvAvg = ( uv12 + uv23 + uv31 ) / 3.; - if(id) - elem = meshDS->AddVolumeWithID(n1, n2, n3, n4, n12, n23, n31, n14, n24, n34, id); - else - elem = meshDS->AddVolume(n1, n2, n3, n4, n12, n23, n31, n14, n24, n34); - } - if ( mySetElemOnShape && myShapeID > 0 ) - meshDS->SetMeshElementOnShape( elem, myShapeID ); + if (( badTria = (( uvAvg - uv1 ) * ( uvAvg - uv23 ) > 0 ))) + uvAvg = ( uv1 + uv23 ) / 2.; + else if (( badTria = (( uvAvg - uv2 ) * ( uvAvg - uv31 ) > 0 ))) + uvAvg = ( uv2 + uv31 ) / 2.; + else if (( badTria = (( uvAvg - uv3 ) * ( uvAvg - uv12 ) > 0 ))) + uvAvg = ( uv3 + uv12 ) / 2.; - return elem; + if ( isBadTria ) + *isBadTria = badTria; + return uvAvg; } //======================================================================= -/*! - * Creates quadratic or linear pyramid - */ +//function : GetNodeU +//purpose : Return node U on edge //======================================================================= -SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1, - const SMDS_MeshNode* n2, - const SMDS_MeshNode* n3, - const SMDS_MeshNode* n4, - const SMDS_MeshNode* n5, - const int id, - const bool force3d) +double SMESH_MesherHelper::GetNodeU(const TopoDS_Edge& E, + const SMDS_MeshNode* n, + const SMDS_MeshNode* inEdgeNode, + bool* check) const { - SMDS_MeshVolume* elem = 0; - if(!myCreateQuadratic) { - if(id) - elem = GetMeshDS()->AddVolumeWithID(n1, n2, n3, n4, n5, id); - else - elem = GetMeshDS()->AddVolume(n1, n2, n3, n4, n5); - } - else { - const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d); - const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d); - const SMDS_MeshNode* n34 = GetMediumNode(n3,n4,force3d); - const SMDS_MeshNode* n41 = GetMediumNode(n4,n1,force3d); - - const SMDS_MeshNode* n15 = GetMediumNode(n1,n5,force3d); - const SMDS_MeshNode* n25 = GetMediumNode(n2,n5,force3d); - const SMDS_MeshNode* n35 = GetMediumNode(n3,n5,force3d); - const SMDS_MeshNode* n45 = GetMediumNode(n4,n5,force3d); + double param = Precision::Infinite(); - if(id) - elem = GetMeshDS()->AddVolumeWithID ( n1, n2, n3, n4, n5, - n12, n23, n34, n41, - n15, n25, n35, n45, - id); - else - elem = GetMeshDS()->AddVolume( n1, n2, n3, n4, n5, - n12, n23, n34, n41, - n15, n25, n35, n45); + const SMDS_PositionPtr pos = n->GetPosition(); + if ( pos->GetTypeOfPosition()==SMDS_TOP_EDGE ) + { + const SMDS_EdgePosition* epos = static_cast( pos ); + param = epos->GetUParameter(); } - if ( mySetElemOnShape && myShapeID > 0 ) - GetMeshDS()->SetMeshElementOnShape( elem, myShapeID ); - - return elem; -} - -//======================================================================= -/*! - * Creates quadratic or linear hexahedron - */ -//======================================================================= - -SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1, - const SMDS_MeshNode* n2, - const SMDS_MeshNode* n3, - const SMDS_MeshNode* n4, - const SMDS_MeshNode* n5, - const SMDS_MeshNode* n6, - const SMDS_MeshNode* n7, - const SMDS_MeshNode* n8, - const int id, - const bool force3d) -{ - SMESHDS_Mesh * meshDS = GetMeshDS(); - SMDS_MeshVolume* elem = 0; - if(!myCreateQuadratic) { - if(id) - elem = meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, n7, n8, id); + else if( pos->GetTypeOfPosition() == SMDS_TOP_VERTEX ) + { + if ( inEdgeNode && TopExp::FirstVertex( E ).IsSame( TopExp::LastVertex( E ))) // issue 0020128 + { + Standard_Real f,l; + BRep_Tool::Range( E, f,l ); + double uInEdge = GetNodeU( E, inEdgeNode ); + param = ( fabs( uInEdge - f ) < fabs( l - uInEdge )) ? f : l; + } else - elem = meshDS->AddVolume(n1, n2, n3, n4, n5, n6, n7, n8); + { + SMESHDS_Mesh * meshDS = GetMeshDS(); + int vertexID = n->getshapeId(); + const TopoDS_Vertex& V = TopoDS::Vertex(meshDS->IndexToShape(vertexID)); + param = BRep_Tool::Parameter( V, E ); + } } - else { - const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d); - const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d); - const SMDS_MeshNode* n34 = GetMediumNode(n3,n4,force3d); - const SMDS_MeshNode* n41 = GetMediumNode(n4,n1,force3d); - - const SMDS_MeshNode* n56 = GetMediumNode(n5,n6,force3d); - const SMDS_MeshNode* n67 = GetMediumNode(n6,n7,force3d); - const SMDS_MeshNode* n78 = GetMediumNode(n7,n8,force3d); - const SMDS_MeshNode* n85 = GetMediumNode(n8,n5,force3d); - - const SMDS_MeshNode* n15 = GetMediumNode(n1,n5,force3d); - const SMDS_MeshNode* n26 = GetMediumNode(n2,n6,force3d); - const SMDS_MeshNode* n37 = GetMediumNode(n3,n7,force3d); - const SMDS_MeshNode* n48 = GetMediumNode(n4,n8,force3d); + if ( check ) + { + double tol = BRep_Tool::Tolerance( E ); + double f,l; BRep_Tool::Range( E, f,l ); + bool force = ( param < f-tol || param > l+tol ); + if ( !force && pos->GetTypeOfPosition()==SMDS_TOP_EDGE ) + force = ( GetMeshDS()->ShapeToIndex( E ) != n->getshapeId() ); - if(id) - elem = meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, n7, n8, - n12, n23, n34, n41, n56, n67, - n78, n85, n15, n26, n37, n48, id); - else - elem = meshDS->AddVolume(n1, n2, n3, n4, n5, n6, n7, n8, - n12, n23, n34, n41, n56, n67, - n78, n85, n15, n26, n37, n48); + *check = CheckNodeU( E, n, param, 2*tol, force ); } - if ( mySetElemOnShape && myShapeID > 0 ) - meshDS->SetMeshElementOnShape( elem, myShapeID ); - - return elem; + return param; } //======================================================================= -/*! - * \brief Load nodes bound to face into a map of node columns - * \param theParam2ColumnMap - map of node columns to fill - * \param theFace - the face on which nodes are searched for - * \param theBaseEdge - the edge nodes of which are columns' bases - * \param theMesh - the mesh containing nodes - * \retval bool - false if something is wrong - * - * The key of the map is a normalized parameter of each - * base node on theBaseEdge. - * This method works in supposition that nodes on the face - * forms a rectangular grid and elements can be quardrangles or triangles - */ +//function : CheckNodeU +//purpose : Check and fix node U on an edge +// Return false if U is bad and could not be fixed //======================================================================= -bool SMESH_MesherHelper::LoadNodeColumns(TParam2ColumnMap & theParam2ColumnMap, - const TopoDS_Face& theFace, - const TopoDS_Edge& theBaseEdge, - SMESHDS_Mesh* theMesh) +bool SMESH_MesherHelper::CheckNodeU(const TopoDS_Edge& E, + const SMDS_MeshNode* n, + double& u, + const double tol, + const bool force, + double distXYZ[4]) const { - // get vertices of theBaseEdge - TopoDS_Vertex vfb, vlb, vft; // first and last, bottom and top vertices - TopoDS_Edge eFrw = TopoDS::Edge( theBaseEdge.Oriented( TopAbs_FORWARD )); - TopExp::Vertices( eFrw, vfb, vlb ); - - // find the other edges of theFace and orientation of e1 - TopoDS_Edge e1, e2, eTop; - bool rev1, CumOri = false; - TopExp_Explorer exp( theFace, TopAbs_EDGE ); - int nbEdges = 0; - for ( ; exp.More(); exp.Next() ) { - if ( ++nbEdges > 4 ) { - return false; // more than 4 edges in theFace - } - TopoDS_Edge e = TopoDS::Edge( exp.Current() ); - if ( theBaseEdge.IsSame( e )) - continue; - TopoDS_Vertex vCommon; - if ( !TopExp::CommonVertex( theBaseEdge, e, vCommon )) - eTop = e; - else if ( vCommon.IsSame( vfb )) { - e1 = e; - vft = TopExp::LastVertex( e1, CumOri ); - rev1 = vfb.IsSame( vft ); - if ( rev1 ) - vft = TopExp::FirstVertex( e1, CumOri ); + int shapeID = n->getshapeId(); + bool infinit; + if (( infinit = Precision::IsInfinite( u )) || + ( force ) || + ( u == 0. ) || + ( toCheckPosOnShape( shapeID ))) + { + TopLoc_Location loc; double f,l; + Handle(Geom_Curve) curve = BRep_Tool::Curve( E,loc,f,l ); + if ( curve.IsNull() ) // degenerated edge + { + if ( u+tol < f || u-tol > l ) + { + double r = Max( 0.5, 1 - tol*n->GetID()); // to get a unique u on edge + u = f*r + l*(1-r); + } } else - e2 = e; - } - if ( nbEdges < 4 ) { - return false; // less than 4 edges in theFace - } - if ( e2.IsNull() && vfb.IsSame( vlb )) - e2 = e1; - - // submeshes corresponding to shapes - SMESHDS_SubMesh* smFace = theMesh->MeshElements( theFace ); - SMESHDS_SubMesh* smb = theMesh->MeshElements( theBaseEdge ); - SMESHDS_SubMesh* smt = theMesh->MeshElements( eTop ); - SMESHDS_SubMesh* sm1 = theMesh->MeshElements( e1 ); - SMESHDS_SubMesh* sm2 = theMesh->MeshElements( e2 ); - SMESHDS_SubMesh* smVfb = theMesh->MeshElements( vfb ); - SMESHDS_SubMesh* smVlb = theMesh->MeshElements( vlb ); - SMESHDS_SubMesh* smVft = theMesh->MeshElements( vft ); - if (!smFace || !smb || !smt || !sm1 || !sm2 || !smVfb || !smVlb || !smVft ) { - RETURN_BAD_RESULT( "NULL submesh " <NbNodes() != smt->NbNodes() || sm1->NbNodes() != sm2->NbNodes() ) { - RETURN_BAD_RESULT(" Diff nb of nodes on opposite edges" ); - } - if (smVfb->NbNodes() != 1 || smVlb->NbNodes() != 1 || smVft->NbNodes() != 1) { - RETURN_BAD_RESULT("Empty submesh of vertex"); - } - // define whether mesh is quadratic - bool isQuadraticMesh = false; - SMDS_ElemIteratorPtr eIt = smFace->GetElements(); - if ( !eIt->more() ) { - RETURN_BAD_RESULT("No elements on the face"); - } - const SMDS_MeshElement* e = eIt->next(); - isQuadraticMesh = e->IsQuadratic(); - - if ( sm1->NbNodes() * smb->NbNodes() != smFace->NbNodes() ) { - // check quadratic case - if ( isQuadraticMesh ) { - // what if there are quadrangles and triangles mixed? -// int n1 = sm1->NbNodes()/2; -// int n2 = smb->NbNodes()/2; -// int n3 = sm1->NbNodes() - n1; -// int n4 = smb->NbNodes() - n2; -// int nf = sm1->NbNodes()*smb->NbNodes() - n3*n4; -// if( nf != smFace->NbNodes() ) { -// MESSAGE( "Wrong nb face nodes: " << -// sm1->NbNodes()<<" "<NbNodes()<<" "<NbNodes()); -// return false; -// } - } - else { - RETURN_BAD_RESULT( "Wrong nb face nodes: " << - sm1->NbNodes()<<" "<NbNodes()<<" "<NbNodes()); - } - } - // IJ size - int vsize = sm1->NbNodes() + 2; - int hsize = smb->NbNodes() + 2; - if(isQuadraticMesh) { - vsize = vsize - sm1->NbNodes()/2 -1; - hsize = hsize - smb->NbNodes()/2 -1; - } - - // load nodes from theBaseEdge - - std::set loadedNodes; - const SMDS_MeshNode* nullNode = 0; - - std::vector & nVecf = theParam2ColumnMap[ 0.]; - nVecf.resize( vsize, nullNode ); - loadedNodes.insert( nVecf[ 0 ] = smVfb->GetNodes()->next() ); - - std::vector & nVecl = theParam2ColumnMap[ 1.]; - nVecl.resize( vsize, nullNode ); - loadedNodes.insert( nVecl[ 0 ] = smVlb->GetNodes()->next() ); - - double f, l; - BRep_Tool::Range( eFrw, f, l ); - double range = l - f; - SMDS_NodeIteratorPtr nIt = smb->GetNodes(); - const SMDS_MeshNode* node; - while ( nIt->more() ) { - node = nIt->next(); - if(IsMedium(node, SMDSAbs_Edge)) - continue; - const SMDS_EdgePosition* pos = - dynamic_cast( node->GetPosition().get() ); - if ( !pos ) { - return false; - } - double u = ( pos->GetUParameter() - f ) / range; - std::vector & nVec = theParam2ColumnMap[ u ]; - nVec.resize( vsize, nullNode ); - loadedNodes.insert( nVec[ 0 ] = node ); - } - if ( theParam2ColumnMap.size() != hsize ) { - RETURN_BAD_RESULT( "Wrong node positions on theBaseEdge" ); - } - - // load nodes from e1 - - std::map< double, const SMDS_MeshNode*> sortedNodes; // sort by param on edge - nIt = sm1->GetNodes(); - while ( nIt->more() ) { - node = nIt->next(); - if(IsMedium(node)) - continue; - const SMDS_EdgePosition* pos = - dynamic_cast( node->GetPosition().get() ); - if ( !pos ) { - return false; - } - sortedNodes.insert( std::make_pair( pos->GetUParameter(), node )); - } - loadedNodes.insert( nVecf[ vsize - 1 ] = smVft->GetNodes()->next() ); - std::map< double, const SMDS_MeshNode*>::iterator u_n = sortedNodes.begin(); - int row = rev1 ? vsize - 1 : 0; - int dRow = rev1 ? -1 : +1; - for ( ; u_n != sortedNodes.end(); u_n++ ) { - row += dRow; - loadedNodes.insert( nVecf[ row ] = u_n->second ); - } - - // try to load the rest nodes - - // get all faces from theFace - TIDSortedElemSet allFaces, foundFaces; - eIt = smFace->GetElements(); - while ( eIt->more() ) { - const SMDS_MeshElement* e = eIt->next(); - if ( e->GetType() == SMDSAbs_Face ) - allFaces.insert( e ); - } - // Starting from 2 neighbour nodes on theBaseEdge, look for a face - // the nodes belong to, and between the nodes of the found face, - // look for a not loaded node considering this node to be the next - // in a column of the starting second node. Repeat, starting - // from nodes next to the previous starting nodes in their columns, - // and so on while a face can be found. Then go the the next pair - // of nodes on theBaseEdge. - TParam2ColumnMap::iterator par_nVec_1 = theParam2ColumnMap.begin(); - TParam2ColumnMap::iterator par_nVec_2 = par_nVec_1; - // loop on columns - int col = 0; - for ( par_nVec_2++; par_nVec_2 != theParam2ColumnMap.end(); par_nVec_1++, par_nVec_2++ ) { - col++; - row = 0; - const SMDS_MeshNode* n1 = par_nVec_1->second[ row ]; - const SMDS_MeshNode* n2 = par_nVec_2->second[ row ]; - const SMDS_MeshElement* face = 0; - bool lastColOnClosedFace = ( nVecf[ row ] == n2 ); - do { - // look for a face by 2 nodes - face = SMESH_MeshEditor::FindFaceInSet( n1, n2, allFaces, foundFaces ); - if ( face ) { - int nbFaceNodes = face->NbNodes(); - if ( face->IsQuadratic() ) - nbFaceNodes /= 2; - if ( nbFaceNodes>4 ) { - RETURN_BAD_RESULT(" Too many nodes in a face: " << nbFaceNodes ); + { + gp_Pnt nodePnt = SMESH_TNodeXYZ( n ); + if ( !loc.IsIdentity() ) nodePnt.Transform( loc.Transformation().Inverted() ); + gp_Pnt curvPnt; + double dist = 2*tol; + if ( !infinit ) + { + curvPnt = curve->Value( u ); + dist = nodePnt.Distance( curvPnt ); + if ( distXYZ ) { + curvPnt.Transform( loc ); + distXYZ[0] = dist; + distXYZ[1] = curvPnt.X(); distXYZ[2] = curvPnt.Y(); distXYZ[3]=curvPnt.Z(); } - // look for a not loaded node of the - bool found = false; - const SMDS_MeshNode* n3 = 0; // a node defferent from n1 and n2 - for ( int i = 0; i < nbFaceNodes && !found; ++i ) { - node = face->GetNode( i ); - found = loadedNodes.insert( node ).second; - if ( !found && node != n1 && node != n2 ) - n3 = node; + } + if ( dist > tol ) + { + setPosOnShapeValidity( shapeID, false ); + // u incorrect, project the node to the curve + int edgeID = GetMeshDS()->ShapeToIndex( E ); + TID2ProjectorOnCurve& i2proj = const_cast< TID2ProjectorOnCurve&>( myEdge2Projector ); + TID2ProjectorOnCurve::iterator i_proj = + i2proj.insert( make_pair( edgeID, (GeomAPI_ProjectPointOnCurve*) 0 )).first; + if ( !i_proj->second ) + { + i_proj->second = new GeomAPI_ProjectPointOnCurve(); + i_proj->second->Init( curve, f, l ); } - if ( lastColOnClosedFace && row + 1 < vsize ) { - node = nVecf[ row + 1 ]; - found = ( face->GetNodeIndex( node ) >= 0 ); + GeomAPI_ProjectPointOnCurve* projector = i_proj->second; + projector->Perform( nodePnt ); + if ( projector->NbPoints() < 1 ) + { + MESSAGE( "SMESH_MesherHelper::CheckNodeU() failed to project" ); + return false; } - if ( found ) { - if ( ++row > vsize - 1 ) { - RETURN_BAD_RESULT( "Too many nodes in column "<< col <<": "<< row+1); - } - par_nVec_2->second[ row ] = node; - foundFaces.insert( face ); - n2 = node; - if ( nbFaceNodes==4 ) { - n1 = par_nVec_1->second[ row ]; - } + Quantity_Parameter U = projector->LowerDistanceParameter(); + u = double( U ); + MESSAGE(" f " << f << " l " << l << " u " << u); + curvPnt = curve->Value( u ); + dist = nodePnt.Distance( curvPnt ); + if ( distXYZ ) { + curvPnt.Transform( loc ); + distXYZ[0] = dist; + distXYZ[1] = curvPnt.X(); distXYZ[2] = curvPnt.Y(); distXYZ[3]=curvPnt.Z(); + } + if ( dist > tol ) + { + MESSAGE( "SMESH_MesherHelper::CheckNodeU(), invalid projection" ); + MESSAGE("distance " << dist << " " << tol ); + return false; } - else if ( nbFaceNodes==3 && n3 == par_nVec_1->second[ row + 1 ] ) { - n1 = n3; + // store the fixed U on the edge + if ( myShape.IsSame(E) && shapeID == myShapeID && myFixNodeParameters ) + const_cast(n)->SetPosition + ( SMDS_PositionPtr( new SMDS_EdgePosition( U ))); + } + else if ( fabs( u ) > numeric_limits::min() ) + { + setPosOnShapeValidity( shapeID, true ); + } + if (( u < f-tol || u > l+tol ) && force ) + { + MESSAGE("u < f-tol || u > l+tol ; u " << u << " f " << f << " l " << l); + // node is on vertex but is set on periodic but trimmed edge (issue 0020890) + try + { + // do not use IsPeriodic() as Geom_TrimmedCurve::IsPeriodic () returns false + double period = curve->Period(); + u = ( u < f ) ? u + period : u - period; } - else { - RETURN_BAD_RESULT( "Not quad mesh, column "<< col ); + catch (Standard_Failure& exc) + { + return false; } } } - while ( face && n1 && n2 ); - - if ( row < vsize - 1 ) { - MESSAGE( "Too few nodes in column "<< col <<": "<< row+1); - MESSAGE( "Base node 1: "<< par_nVec_1->second[0]); - MESSAGE( "Base node 2: "<< par_nVec_2->second[0]); - if ( n1 ) { MESSAGE( "Current node 1: "<< n1); } - else { MESSAGE( "Current node 1: NULL"); } - if ( n2 ) { MESSAGE( "Current node 2: "<< n2); } - else { MESSAGE( "Current node 2: NULL"); } - MESSAGE( "first base node: "<< theParam2ColumnMap.begin()->second[0]); - MESSAGE( "last base node: "<< theParam2ColumnMap.rbegin()->second[0]); - return false; - } - } // loop on columns - + } return true; } //======================================================================= -/*! - * \brief Return number of unique ancestors of the shape - */ +//function : GetMediumPos +//purpose : Return index and type of the shape (EDGE or FACE only) to +// set a medium node on +//param : useCurSubShape - if true, returns the shape set via SetSubShape() +// if any +//param : expectedSupport - shape type corresponding to element being created, +// e.g TopAbs_EDGE if SMDSAbs_Edge is created +// basing on \a n1 and \a n2 +// Calling GetMediumPos() with useCurSubShape=true is OK only for the +// case where the lower dim mesh is already constructed and converted to quadratic, +// else, nodes on EDGEs are assigned to FACE, for example. //======================================================================= -int SMESH_MesherHelper::NbAncestors(const TopoDS_Shape& shape, - const SMESH_Mesh& mesh, - TopAbs_ShapeEnum ancestorType/*=TopAbs_SHAPE*/) +std::pair +SMESH_MesherHelper::GetMediumPos(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const bool useCurSubShape, + TopAbs_ShapeEnum expectedSupport) { - TopTools_MapOfShape ancestors; - TopTools_ListIteratorOfListOfShape ansIt( mesh.GetAncestors(shape) ); - for ( ; ansIt.More(); ansIt.Next() ) { - if ( ancestorType == TopAbs_SHAPE || ansIt.Value().ShapeType() == ancestorType ) - ancestors.Add( ansIt.Value() ); - } - return ancestors.Extent(); -} + if ( useCurSubShape && !myShape.IsNull() ) + return std::make_pair( myShapeID, myShape.ShapeType() ); + + TopAbs_ShapeEnum shapeType = TopAbs_SHAPE; + int shapeID = -1; + TopoDS_Shape shape; + + if (( myShapeID == n1->getshapeId() || myShapeID == n2->getshapeId() ) && myShapeID > 0 ) + { + shapeType = myShape.ShapeType(); + shapeID = myShapeID; + } + else if ( n1->getshapeId() == n2->getshapeId() ) + { + shapeID = n2->getshapeId(); + shape = GetSubShapeByNode( n1, GetMeshDS() ); + } + else // 2 different shapes + { + const SMDS_TypeOfPosition Pos1 = n1->GetPosition()->GetTypeOfPosition(); + const SMDS_TypeOfPosition Pos2 = n2->GetPosition()->GetTypeOfPosition(); + + if ( Pos1 == SMDS_TOP_3DSPACE || Pos2 == SMDS_TOP_3DSPACE ) + { + // in SOLID + } + else if ( Pos1 == SMDS_TOP_FACE || Pos2 == SMDS_TOP_FACE ) + { + // in FACE or SOLID + if ( Pos1 != SMDS_TOP_FACE || Pos2 != SMDS_TOP_FACE ) // not 2 FACEs + { + if ( Pos1 != SMDS_TOP_FACE ) std::swap( n1,n2 ); + TopoDS_Shape F = GetSubShapeByNode( n1, GetMeshDS() ); + TopoDS_Shape S = GetSubShapeByNode( n2, GetMeshDS() ); + if ( IsSubShape( S, F )) + { + shapeType = TopAbs_FACE; + shapeID = n1->getshapeId(); + } + } + } + else if ( Pos1 == SMDS_TOP_EDGE && Pos2 == SMDS_TOP_EDGE ) + { + TopoDS_Shape E1 = GetSubShapeByNode( n1, GetMeshDS() ); + TopoDS_Shape E2 = GetSubShapeByNode( n2, GetMeshDS() ); + shape = GetCommonAncestor( E1, E2, *myMesh, TopAbs_FACE ); + } + else if ( Pos1 == SMDS_TOP_VERTEX && Pos2 == SMDS_TOP_VERTEX ) + { + TopoDS_Shape V1 = GetSubShapeByNode( n1, GetMeshDS() ); + TopoDS_Shape V2 = GetSubShapeByNode( n2, GetMeshDS() ); + shape = GetCommonAncestor( V1, V2, *myMesh, TopAbs_EDGE ); + if ( shape.IsNull() ) shape = GetCommonAncestor( V1, V2, *myMesh, TopAbs_FACE ); + } + else // on VERTEX and EDGE + { + if ( Pos1 != SMDS_TOP_VERTEX ) std::swap( n1,n2 ); + TopoDS_Shape V = GetSubShapeByNode( n1, GetMeshDS() ); + TopoDS_Shape E = GetSubShapeByNode( n2, GetMeshDS() ); + if ( IsSubShape( V, E )) + shape = E; + else + shape = GetCommonAncestor( V, E, *myMesh, TopAbs_FACE ); + } + } + + if ( !shape.IsNull() ) + { + if ( shapeID < 1 ) + shapeID = GetMeshDS()->ShapeToIndex( shape ); + shapeType = shape.ShapeType(); // EDGE or FACE + + if ( expectedSupport < shapeType && + expectedSupport != TopAbs_SHAPE && + !myShape.IsNull() && + myShape.ShapeType() == expectedSupport ) + { + // e.g. a side of triangle connects nodes on the same EDGE but does not + // lie on this EDGE (an arc with a coarse mesh) + // => shapeType == TopAbs_EDGE, expectedSupport == TopAbs_FACE; + // hope that myShape is a right shape, return it if the found shape + // has converted elements of corresponding dim (segments in our example) + int nbConvertedElems = 0; + SMDSAbs_ElementType type = ( shapeType == TopAbs_FACE ? SMDSAbs_Face : SMDSAbs_Edge ); + for ( int iN = 0; iN < 2; ++iN ) + { + const SMDS_MeshNode* n = iN ? n2 : n1; + SMDS_ElemIteratorPtr it = n->GetInverseElementIterator( type ); + while ( it->more() ) + { + const SMDS_MeshElement* elem = it->next(); + if ( elem->getshapeId() == shapeID && + elem->IsQuadratic() ) + { + ++nbConvertedElems; + break; + } + } + } + if ( nbConvertedElems == 2 ) + { + shapeType = myShape.ShapeType(); + shapeID = myShapeID; + } + } + } + return make_pair( shapeID, shapeType ); +} //======================================================================= -/** - * Check mesh without geometry for: if all elements on this shape are quadratic, - * quadratic elements will be created. - * Used then generated 3D mesh without geometry. - */ +//function : GetCentralNode +//purpose : Return existing or create a new central node for a quardilateral +// quadratic face given its 8 nodes. +//@param : force3d - true means node creation in between the given nodes, +// else node position is found on a geometrical face if any. //======================================================================= -SMESH_MesherHelper:: MType SMESH_MesherHelper::IsQuadraticMesh() +const SMDS_MeshNode* SMESH_MesherHelper::GetCentralNode(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n3, + const SMDS_MeshNode* n4, + const SMDS_MeshNode* n12, + const SMDS_MeshNode* n23, + const SMDS_MeshNode* n34, + const SMDS_MeshNode* n41, + bool force3d) { - int NbAllEdgsAndFaces=0; - int NbQuadFacesAndEdgs=0; - int NbFacesAndEdges=0; - //All faces and edges - NbAllEdgsAndFaces = myMesh->NbEdges() + myMesh->NbFaces(); + SMDS_MeshNode *centralNode = 0; // central node to return + + // Find an existing central node + + TBiQuad keyOfMap(n1,n2,n3,n4); + std::map::iterator itMapCentralNode; + itMapCentralNode = myMapWithCentralNode.find( keyOfMap ); + if ( itMapCentralNode != myMapWithCentralNode.end() ) + { + return (*itMapCentralNode).second; + } + + // Get type of shape for the new central node + + TopAbs_ShapeEnum shapeType = TopAbs_SHAPE; + int solidID = -1; + int faceID = -1; + TopoDS_Shape shape; + TopTools_ListIteratorOfListOfShape it; + + std::map< int, int > faceId2nbNodes; + std::map< int, int > ::iterator itMapWithIdFace; - //Quadratic faces and edges - NbQuadFacesAndEdgs = myMesh->NbEdges(ORDER_QUADRATIC) + myMesh->NbFaces(ORDER_QUADRATIC); + SMESHDS_Mesh* meshDS = GetMeshDS(); + + // check if a face lies on a FACE, i.e. its all corner nodes lie either on the FACE or + // on sub-shapes of the FACE + if ( GetMesh()->HasShapeToMesh() ) + { + const SMDS_MeshNode* nodes[] = { n1, n2, n3, n4 }; + for(int i = 0; i < 4; i++) + { + shape = GetSubShapeByNode( nodes[i], meshDS ); + if ( shape.IsNull() ) break; + if ( shape.ShapeType() == TopAbs_SOLID ) + { + solidID = nodes[i]->getshapeId(); + shapeType = TopAbs_SOLID; + break; + } + if ( shape.ShapeType() == TopAbs_FACE ) + { + faceID = nodes[i]->getshapeId(); + itMapWithIdFace = faceId2nbNodes.insert( std::make_pair( faceID, 0 ) ).first; + itMapWithIdFace->second++; + } + else + { + PShapeIteratorPtr it = GetAncestors( shape, *GetMesh(), TopAbs_FACE ); + while ( const TopoDS_Shape* face = it->next() ) + { + faceID = meshDS->ShapeToIndex( *face ); + itMapWithIdFace = faceId2nbNodes.insert( std::make_pair( faceID, 0 )).first; + itMapWithIdFace->second++; + } + } + } + } + if ( solidID < 1 && !faceId2nbNodes.empty() ) // SOLID not found + { + // find ID of the FACE the four corner nodes belong to + itMapWithIdFace = faceId2nbNodes.find( myShapeID ); // IPAL52698 + if ( itMapWithIdFace != faceId2nbNodes.end() && + itMapWithIdFace->second == 4 ) + { + shapeType = TopAbs_FACE; + faceID = myShapeID; + } + else + { + itMapWithIdFace = faceId2nbNodes.begin(); + for ( ; itMapWithIdFace != faceId2nbNodes.end(); ++itMapWithIdFace) + { + if ( itMapWithIdFace->second == 4 ) + { + shapeType = TopAbs_FACE; + faceID = (*itMapWithIdFace).first; + break; + } + } + } + } - //Linear faces and edges - NbFacesAndEdges = myMesh->NbEdges(ORDER_LINEAR) + myMesh->NbFaces(ORDER_LINEAR); + TopoDS_Face F; + if ( shapeType == TopAbs_FACE ) + { + F = TopoDS::Face( meshDS->IndexToShape( faceID )); + } + + // Create a node + + gp_XY uvAvg; + gp_Pnt P; + bool toCheck = true; + if ( !F.IsNull() && !force3d ) + { + Handle(ShapeAnalysis_Surface) surface = GetSurface( F ); + if ( HasDegeneratedEdges() || surface->HasSingularities( 1e-7 )) + { + gp_Pnt center = calcTFI (0.5, 0.5, // IPAL0052863 + SMESH_TNodeXYZ(n1), SMESH_TNodeXYZ(n2), + SMESH_TNodeXYZ(n3), SMESH_TNodeXYZ(n4), + SMESH_TNodeXYZ(n12), SMESH_TNodeXYZ(n23), + SMESH_TNodeXYZ(n34), SMESH_TNodeXYZ(n41)); + gp_Pnt2d uv12 = GetNodeUV( F, n12, n3, &toCheck ); + uvAvg = surface->NextValueOfUV( uv12, center, BRep_Tool::Tolerance( F )).XY(); + } + else + { + gp_XY uv[8] = { + GetNodeUV( F,n1, n3, &toCheck ), + GetNodeUV( F,n2, n4, &toCheck ), + GetNodeUV( F,n3, n1, &toCheck ), + GetNodeUV( F,n4, n2, &toCheck ), + GetNodeUV( F,n12, n3 ), + GetNodeUV( F,n23, n4 ), + GetNodeUV( F,n34, n2 ), + GetNodeUV( F,n41, n2 ) + }; + AdjustByPeriod( F, uv, 8 ); // put uv[] within a period (IPAL52698) + + uvAvg = calcTFI (0.5, 0.5, uv[0],uv[1],uv[2],uv[3], uv[4],uv[5],uv[6],uv[7] ); + } + P = surface->Value( uvAvg ); + centralNode = meshDS->AddNode( P.X(), P.Y(), P.Z() ); + // if ( mySetElemOnShape ) node is not elem! + meshDS->SetNodeOnFace( centralNode, faceID, uvAvg.X(), uvAvg.Y() ); + } + else // ( force3d || F.IsNull() ) + { + P = calcTFI (0.5, 0.5, + SMESH_TNodeXYZ(n1), SMESH_TNodeXYZ(n2), + SMESH_TNodeXYZ(n3), SMESH_TNodeXYZ(n4), + SMESH_TNodeXYZ(n12), SMESH_TNodeXYZ(n23), + SMESH_TNodeXYZ(n34), SMESH_TNodeXYZ(n41)); + centralNode = meshDS->AddNode( P.X(), P.Y(), P.Z() ); + + if ( !F.IsNull() ) // force3d + { + uvAvg = (GetNodeUV(F,n1,n3,&toCheck) + + GetNodeUV(F,n2,n4,&toCheck) + + GetNodeUV(F,n3,n1,&toCheck) + + GetNodeUV(F,n4,n2,&toCheck)) / 4; + //CheckNodeUV( F, centralNode, uvAvg, 2*BRep_Tool::Tolerance( F ), /*force=*/true); + meshDS->SetNodeOnFace( centralNode, faceID, uvAvg.X(), uvAvg.Y() ); + } + else if ( solidID > 0 ) + { + meshDS->SetNodeInVolume( centralNode, solidID ); + } + else if ( myShapeID > 0 && mySetElemOnShape ) + { + meshDS->SetMeshElementOnShape( centralNode, myShapeID ); + } + } + myMapWithCentralNode.insert( std::make_pair( keyOfMap, centralNode ) ); + return centralNode; +} + +//======================================================================= +//function : GetCentralNode +//purpose : Return existing or create a new central node for a +// quadratic triangle given its 6 nodes. +//@param : force3d - true means node creation in between the given nodes, +// else node position is found on a geometrical face if any. +//======================================================================= + +const SMDS_MeshNode* SMESH_MesherHelper::GetCentralNode(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n3, + const SMDS_MeshNode* n12, + const SMDS_MeshNode* n23, + const SMDS_MeshNode* n31, + bool force3d) +{ + SMDS_MeshNode *centralNode = 0; // central node to return + + // Find an existing central node + + TBiQuad keyOfMap(n1,n2,n3); + std::map::iterator itMapCentralNode; + itMapCentralNode = myMapWithCentralNode.find( keyOfMap ); + if ( itMapCentralNode != myMapWithCentralNode.end() ) + { + return (*itMapCentralNode).second; + } + + // Get type of shape for the new central node + + TopAbs_ShapeEnum shapeType = TopAbs_SHAPE; + int solidID = -1; + int faceID = -1; + TopoDS_Shape shape; + TopTools_ListIteratorOfListOfShape it; + + std::map< int, int > faceId2nbNodes; + std::map< int, int > ::iterator itMapWithIdFace; - if (NbAllEdgsAndFaces == NbQuadFacesAndEdgs) { - //Quadratic mesh - return SMESH_MesherHelper::QUADRATIC; + SMESHDS_Mesh* meshDS = GetMeshDS(); + + // check if a face lies on a FACE, i.e. its all corner nodes lie either on the FACE or + // on sub-shapes of the FACE + if ( GetMesh()->HasShapeToMesh() ) + { + const SMDS_MeshNode* nodes[] = { n1, n2, n3 }; + for(int i = 0; i < 3; i++) + { + shape = GetSubShapeByNode( nodes[i], meshDS ); + if ( shape.IsNull() ) break; + if ( shape.ShapeType() == TopAbs_SOLID ) + { + solidID = nodes[i]->getshapeId(); + shapeType = TopAbs_SOLID; + break; + } + if ( shape.ShapeType() == TopAbs_FACE ) + { + faceID = nodes[i]->getshapeId(); + itMapWithIdFace = faceId2nbNodes.insert( std::make_pair( faceID, 0 ) ).first; + itMapWithIdFace->second++; + } + else + { + PShapeIteratorPtr it = GetAncestors(shape, *GetMesh(), TopAbs_FACE ); + while ( const TopoDS_Shape* face = it->next() ) + { + faceID = meshDS->ShapeToIndex( *face ); + itMapWithIdFace = faceId2nbNodes.insert( std::make_pair( faceID, 0 ) ).first; + itMapWithIdFace->second++; + } + } + } } - else if (NbAllEdgsAndFaces == NbFacesAndEdges) { - //Linear mesh - return SMESH_MesherHelper::LINEAR; + if ( solidID < 1 && !faceId2nbNodes.empty() ) // SOLID not found + { + // find ID of the FACE the four corner nodes belong to + itMapWithIdFace = faceId2nbNodes.find( myShapeID ); // IPAL52698 + if ( itMapWithIdFace != faceId2nbNodes.end() && + itMapWithIdFace->second == 4 ) + { + shapeType = TopAbs_FACE; + faceID = myShapeID; + } + else + { + itMapWithIdFace = faceId2nbNodes.begin(); + for ( ; itMapWithIdFace != faceId2nbNodes.end(); ++itMapWithIdFace) + { + if ( itMapWithIdFace->second == 3 ) + { + shapeType = TopAbs_FACE; + faceID = (*itMapWithIdFace).first; + break; + } + } + } } - else - //Mesh with both type of elements - return SMESH_MesherHelper::COMP; + + TopoDS_Face F; + gp_XY uvAvg; + + if ( shapeType == TopAbs_FACE ) + { + F = TopoDS::Face( meshDS->IndexToShape( faceID )); + bool checkOK = true, badTria = false; + gp_XY uv[6] = { + GetNodeUV( F, n1, n23, &checkOK ), + GetNodeUV( F, n2, n31, &checkOK ), + GetNodeUV( F, n3, n12, &checkOK ), + GetNodeUV( F, n12, n3, &checkOK ), + GetNodeUV( F, n23, n1, &checkOK ), + GetNodeUV( F, n31, n2, &checkOK ) + }; + AdjustByPeriod( F, uv, 6 ); // put uv[] within a period (IPAL52698) + + uvAvg = GetCenterUV( uv[0],uv[1],uv[2], uv[3],uv[4],uv[5], &badTria ); + + if ( badTria || !checkOK ) + force3d = true; + } + + // Create a central node + + gp_Pnt P; + if ( !F.IsNull() && !force3d ) + { + TopLoc_Location loc; + Handle( Geom_Surface ) S = BRep_Tool::Surface( F, loc ); + P = S->Value( uvAvg.X(), uvAvg.Y() ).Transformed( loc ); + centralNode = meshDS->AddNode( P.X(), P.Y(), P.Z() ); + // if ( mySetElemOnShape ) node is not elem! + meshDS->SetNodeOnFace( centralNode, faceID, uvAvg.X(), uvAvg.Y() ); + } + else // ( force3d || F.IsNull() ) + { + P = ( SMESH_TNodeXYZ( n12 ) + + SMESH_TNodeXYZ( n23 ) + + SMESH_TNodeXYZ( n31 ) ) / 3; + centralNode = meshDS->AddNode( P.X(), P.Y(), P.Z() ); + + if ( !F.IsNull() ) // force3d + { + meshDS->SetNodeOnFace( centralNode, faceID, uvAvg.X(), uvAvg.Y() ); + } + else if ( solidID > 0 ) + { + meshDS->SetNodeInVolume( centralNode, solidID ); + } + else if ( myShapeID > 0 && mySetElemOnShape ) + { + meshDS->SetMeshElementOnShape( centralNode, myShapeID ); + } + } + myMapWithCentralNode.insert( std::make_pair( keyOfMap, centralNode ) ); + return centralNode; } //======================================================================= +//function : GetMediumNode +//purpose : Return existing or create a new medium node between given ones +//======================================================================= + +const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + bool force3d, + TopAbs_ShapeEnum expectedSupport) +{ + // Find existing node + + SMESH_TLink link(n1,n2); + ItTLinkNode itLN = myTLinkNodeMap.find( link ); + if ( itLN != myTLinkNodeMap.end() ) { + return (*itLN).second; + } + + // Create medium node + + SMDS_MeshNode* n12; + SMESHDS_Mesh* meshDS = GetMeshDS(); + + if ( IsSeamShape( n1->getshapeId() )) + // to get a correct UV of a node on seam, the second node must have checked UV + std::swap( n1, n2 ); + + // get type of shape for the new medium node + int faceID = -1, edgeID = -1; + TopoDS_Edge E; double u [2]; + TopoDS_Face F; gp_XY uv[2]; + bool uvOK[2] = { true, true }; + const bool useCurSubShape = ( !myShape.IsNull() && myShape.ShapeType() == TopAbs_EDGE ); + + pair pos = GetMediumPos( n1, n2, useCurSubShape, expectedSupport ); + + // get positions of the given nodes on shapes + if ( pos.second == TopAbs_FACE ) + { + F = TopoDS::Face(meshDS->IndexToShape( faceID = pos.first )); + uv[0] = GetNodeUV(F,n1,n2, force3d ? 0 : &uvOK[0]); + if (( !force3d ) && + ( HasDegeneratedEdges() || GetSurface( F )->HasSingularities( 1e-7 ))) + { + // IPAL52850 (degen VERTEX not at singularity) + // project middle point to a surface + SMESH_TNodeXYZ p1( n1 ), p2( n2 ); + gp_Pnt pMid = 0.5 * ( p1 + p2 ); + Handle(ShapeAnalysis_Surface) projector = GetSurface( F ); + gp_Pnt2d uvMid; + if ( uvOK[0] ) + uvMid = projector->NextValueOfUV( uv[0], pMid, BRep_Tool::Tolerance( F )); + else + uvMid = projector->ValueOfUV( pMid, getFaceMaxTol( F )); + if ( projector->Gap() * projector->Gap() < ( p1 - p2 ).SquareModulus() / 4 ) + { + gp_Pnt pProj = projector->Value( uvMid ); + n12 = meshDS->AddNode( pProj.X(), pProj.Y(), pProj.Z() ); + meshDS->SetNodeOnFace( n12, faceID, uvMid.X(), uvMid.Y() ); + myTLinkNodeMap.insert( make_pair ( link, n12 )); + return n12; + } + } + uv[1] = GetNodeUV(F,n2,n1, force3d ? 0 : &uvOK[1]); + } + else if ( pos.second == TopAbs_EDGE ) + { + const SMDS_PositionPtr Pos1 = n1->GetPosition(); + const SMDS_PositionPtr Pos2 = n2->GetPosition(); + if ( Pos1->GetTypeOfPosition()==SMDS_TOP_EDGE && + Pos2->GetTypeOfPosition()==SMDS_TOP_EDGE && + n1->getshapeId() != n2->getshapeId() ) + { + // issue 0021006 + return getMediumNodeOnComposedWire(n1,n2,force3d); + } + E = TopoDS::Edge(meshDS->IndexToShape( edgeID = pos.first )); + try { + u[0] = GetNodeU(E,n1,n2, force3d ? 0 : &uvOK[0]); + u[1] = GetNodeU(E,n2,n1, force3d ? 0 : &uvOK[1]); + } + catch ( Standard_Failure& f ) + { + // issue 22502 / a node is on VERTEX not belonging to E + // issue 22568 / both nodes are on non-connected VERTEXes + return getMediumNodeOnComposedWire(n1,n2,force3d); + } + } + + if ( !force3d & uvOK[0] && uvOK[1] ) + { + // we try to create medium node using UV parameters of + // nodes, else - medium between corresponding 3d points + if( ! F.IsNull() ) + { + //if ( uvOK[0] && uvOK[1] ) + { + if ( IsDegenShape( n1->getshapeId() )) { + if ( myParIndex & U_periodic ) uv[0].SetCoord( 1, uv[1].Coord( 1 )); + else uv[0].SetCoord( 2, uv[1].Coord( 2 )); + } + else if ( IsDegenShape( n2->getshapeId() )) { + if ( myParIndex & U_periodic ) uv[1].SetCoord( 1, uv[0].Coord( 1 )); + else uv[1].SetCoord( 2, uv[0].Coord( 2 )); + } + TopLoc_Location loc; + Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc); + gp_XY UV = GetMiddleUV( S, uv[0], uv[1] ); + gp_Pnt P = S->Value( UV.X(), UV.Y() ).Transformed(loc); + n12 = meshDS->AddNode(P.X(), P.Y(), P.Z()); + // if ( mySetElemOnShape ) node is not elem! + meshDS->SetNodeOnFace(n12, faceID, UV.X(), UV.Y()); + myTLinkNodeMap.insert(make_pair(link,n12)); + return n12; + } + } + else if ( !E.IsNull() ) + { + double f,l; + Handle(Geom_Curve) C = BRep_Tool::Curve(E, f, l); + if(!C.IsNull()) + { + Standard_Boolean isPeriodic = C->IsPeriodic(); + double U; + if(isPeriodic) { + Standard_Real Period = C->Period(); + Standard_Real p = u[1]+ShapeAnalysis::AdjustByPeriod(u[1],u[0],Period); + Standard_Real pmid = (u[0]+p)/2.; + U = pmid+ShapeAnalysis::AdjustToPeriod(pmid,C->FirstParameter(),C->LastParameter()); + } + else + U = (u[0]+u[1])/2.; + + gp_Pnt P = C->Value( U ); + n12 = meshDS->AddNode(P.X(), P.Y(), P.Z()); + //if ( mySetElemOnShape ) node is not elem! + meshDS->SetNodeOnEdge(n12, edgeID, U); + myTLinkNodeMap.insert(make_pair(link,n12)); + return n12; + } + } + } + + // 3d variant + double x = ( n1->X() + n2->X() )/2.; + double y = ( n1->Y() + n2->Y() )/2.; + double z = ( n1->Z() + n2->Z() )/2.; + n12 = meshDS->AddNode(x,y,z); + + //if ( mySetElemOnShape ) node is not elem! + { + if ( !F.IsNull() ) + { + gp_XY UV = ( uv[0] + uv[1] ) / 2.; + CheckNodeUV( F, n12, UV, 2 * BRep_Tool::Tolerance( F ), /*force=*/true); + meshDS->SetNodeOnFace(n12, faceID, UV.X(), UV.Y() ); + } + else if ( !E.IsNull() ) + { + double U = ( u[0] + u[1] ) / 2.; + CheckNodeU( E, n12, U, 2 * BRep_Tool::Tolerance( E ), /*force=*/true); + meshDS->SetNodeOnEdge(n12, edgeID, U); + } + else if ( myShapeID > 0 && mySetElemOnShape ) + { + meshDS->SetMeshElementOnShape(n12, myShapeID); + } + } + + myTLinkNodeMap.insert( make_pair( link, n12 )); + return n12; +} + +//================================================================================ /*! - * \brief Return an alternative parameter for a node on seam + * \brief Makes a medium node if nodes reside different edges */ -//======================================================================= +//================================================================================ -double SMESH_MesherHelper::GetOtherParam(const double param) const +const SMDS_MeshNode* SMESH_MesherHelper::getMediumNodeOnComposedWire(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + bool force3d) { - return fabs(param-myPar1) < fabs(param-myPar2) ? myPar2 : myPar1; + SMESH_TNodeXYZ p1( n1 ), p2( n2 ); + gp_Pnt middle = 0.5 * p1 + 0.5 * p2; + SMDS_MeshNode* n12 = AddNode( middle.X(), middle.Y(), middle.Z() ); + + // To find position on edge and 3D position for n12, + // project to 2 edges and select projection most close to + + TopoDS_Edge bestEdge; + double u = 0, distMiddleProj = Precision::Infinite(), distXYZ[4], f,l; + + // get shapes under the nodes + TopoDS_Shape shape[2]; + int nbShapes = 0; + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + const SMDS_MeshNode* n = is2nd ? n2 : n1; + TopoDS_Shape S = GetSubShapeByNode( n, GetMeshDS() ); + if ( !S.IsNull() ) + shape[ nbShapes++ ] = S; + } + // get EDGEs + vector< TopoDS_Shape > edges; + for ( int iS = 0; iS < nbShapes; ++iS ) + { + switch ( shape[iS].ShapeType() ) { + case TopAbs_EDGE: + { + edges.push_back( shape[iS] ); + break; + } + case TopAbs_VERTEX: + { + TopoDS_Shape edge; + if ( nbShapes == 2 && iS==0 && shape[1-iS].ShapeType() == TopAbs_VERTEX ) + edge = GetCommonAncestor( shape[iS], shape[1-iS], *myMesh, TopAbs_EDGE ); + + if ( edge.IsNull() ) + { + PShapeIteratorPtr eIt = GetAncestors( shape[iS], *myMesh, TopAbs_EDGE ); + while( const TopoDS_Shape* e = eIt->next() ) + edges.push_back( *e ); + } + break; + } + case TopAbs_FACE: + { + if ( nbShapes == 1 || shape[1-iS].ShapeType() < TopAbs_EDGE ) + for ( TopExp_Explorer e( shape[iS], TopAbs_EDGE ); e.More(); e.Next() ) + edges.push_back( e.Current() ); + break; + } + default: + continue; + } + } + // project to get U of projection and distance from middle to projection + for ( size_t iE = 0; iE < edges.size(); ++iE ) + { + const TopoDS_Edge& edge = TopoDS::Edge( edges[ iE ]); + distXYZ[0] = distMiddleProj; + double testU = 0; + CheckNodeU( edge, n12, testU, 2 * BRep_Tool::Tolerance(edge), /*force=*/true, distXYZ ); + if ( distXYZ[0] < distMiddleProj ) + { + distMiddleProj = distXYZ[0]; + u = testU; + bestEdge = edge; + } + } + // { + // // both projections failed; set n12 on the edge of n1 with U of a common vertex + // TopoDS_Vertex vCommon; + // if ( TopExp::CommonVertex( edges[0], edges[1], vCommon )) + // u = BRep_Tool::Parameter( vCommon, edges[0] ); + // else + // { + // double f,l, u0 = GetNodeU( edges[0], n1 ); + // BRep_Tool::Range( edges[0],f,l ); + // u = ( fabs(u0-f) < fabs(u0-l) ) ? f : l; + // } + // iOkEdge = 0; + // distMiddleProj = 0; + // } + + if ( !bestEdge.IsNull() ) + { + // move n12 to position of a successfull projection + //double tol = BRep_Tool::Tolerance(edges[ iOkEdge ]); + if ( !force3d /*&& distMiddleProj > 2*tol*/ ) + { + TopLoc_Location loc; + Handle(Geom_Curve) curve = BRep_Tool::Curve( bestEdge,loc,f,l ); + gp_Pnt p = curve->Value( u ).Transformed( loc ); + GetMeshDS()->MoveNode( n12, p.X(), p.Y(), p.Z() ); + } + //if ( mySetElemOnShape ) node is not elem! + { + int edgeID = GetMeshDS()->ShapeToIndex( bestEdge ); + if ( edgeID != n12->getshapeId() ) + GetMeshDS()->UnSetNodeOnShape( n12 ); + GetMeshDS()->SetNodeOnEdge(n12, edgeID, u); + } + } + myTLinkNodeMap.insert( make_pair( SMESH_TLink(n1,n2), n12 )); + + return n12; +} + +//======================================================================= +//function : AddNode +//purpose : Creates a node +//======================================================================= + +SMDS_MeshNode* SMESH_MesherHelper::AddNode(double x, double y, double z, int ID, + double u, double v) +{ + SMESHDS_Mesh * meshDS = GetMeshDS(); + SMDS_MeshNode* node = 0; + if ( ID ) + node = meshDS->AddNodeWithID( x, y, z, ID ); + else + node = meshDS->AddNode( x, y, z ); + if ( mySetElemOnShape && myShapeID > 0 ) { // node is not elem ? + switch ( myShape.ShapeType() ) { + case TopAbs_SOLID: meshDS->SetNodeInVolume( node, myShapeID); break; + case TopAbs_SHELL: meshDS->SetNodeInVolume( node, myShapeID); break; + case TopAbs_FACE: meshDS->SetNodeOnFace( node, myShapeID, u, v); break; + case TopAbs_EDGE: meshDS->SetNodeOnEdge( node, myShapeID, u); break; + case TopAbs_VERTEX: meshDS->SetNodeOnVertex( node, myShapeID); break; + default: ; + } + } + return node; +} + +//======================================================================= +//function : AddEdge +//purpose : Creates quadratic or linear edge +//======================================================================= + +SMDS_MeshEdge* SMESH_MesherHelper::AddEdge(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const int id, + const bool force3d) +{ + SMESHDS_Mesh * meshDS = GetMeshDS(); + + SMDS_MeshEdge* edge = 0; + if (myCreateQuadratic) { + const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d); + if(id) + edge = meshDS->AddEdgeWithID(n1, n2, n12, id); + else + edge = meshDS->AddEdge(n1, n2, n12); + } + else { + if(id) + edge = meshDS->AddEdgeWithID(n1, n2, id); + else + edge = meshDS->AddEdge(n1, n2); + } + + if ( mySetElemOnShape && myShapeID > 0 ) + meshDS->SetMeshElementOnShape( edge, myShapeID ); + + return edge; +} + +//======================================================================= +//function : AddFace +//purpose : Creates quadratic or linear triangle +//======================================================================= + +SMDS_MeshFace* SMESH_MesherHelper::AddFace(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n3, + const int id, + const bool force3d) +{ + SMESHDS_Mesh * meshDS = GetMeshDS(); + SMDS_MeshFace* elem = 0; + + if( n1==n2 || n2==n3 || n3==n1 ) + return elem; + + if(!myCreateQuadratic) { + if(id) + elem = meshDS->AddFaceWithID(n1, n2, n3, id); + else + elem = meshDS->AddFace(n1, n2, n3); + } + else { + const SMDS_MeshNode* n12 = GetMediumNode( n1, n2, force3d, TopAbs_FACE ); + const SMDS_MeshNode* n23 = GetMediumNode( n2, n3, force3d, TopAbs_FACE ); + const SMDS_MeshNode* n31 = GetMediumNode( n3, n1, force3d, TopAbs_FACE ); + if(myCreateBiQuadratic) + { + const SMDS_MeshNode* nCenter = GetCentralNode(n1, n2, n3, n12, n23, n31, force3d); + if(id) + elem = meshDS->AddFaceWithID(n1, n2, n3, n12, n23, n31, nCenter, id); + else + elem = meshDS->AddFace(n1, n2, n3, n12, n23, n31, nCenter); + } + else + { + if(id) + elem = meshDS->AddFaceWithID(n1, n2, n3, n12, n23, n31, id); + else + elem = meshDS->AddFace(n1, n2, n3, n12, n23, n31); + } + } + if ( mySetElemOnShape && myShapeID > 0 ) + meshDS->SetMeshElementOnShape( elem, myShapeID ); + + return elem; +} + +//======================================================================= +//function : AddFace +//purpose : Creates bi-quadratic, quadratic or linear quadrangle +//======================================================================= + +SMDS_MeshFace* SMESH_MesherHelper::AddFace(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n3, + const SMDS_MeshNode* n4, + const int id, + const bool force3d) +{ + SMESHDS_Mesh * meshDS = GetMeshDS(); + SMDS_MeshFace* elem = 0; + + if( n1==n2 ) { + return AddFace(n1,n3,n4,id,force3d); + } + if( n1==n3 ) { + return AddFace(n1,n2,n4,id,force3d); + } + if( n1==n4 ) { + return AddFace(n1,n2,n3,id,force3d); + } + if( n2==n3 ) { + return AddFace(n1,n2,n4,id,force3d); + } + if( n2==n4 ) { + return AddFace(n1,n2,n3,id,force3d); + } + if( n3==n4 ) { + return AddFace(n1,n2,n3,id,force3d); + } + + if(!myCreateQuadratic) { + if(id) + elem = meshDS->AddFaceWithID(n1, n2, n3, n4, id); + else + elem = meshDS->AddFace(n1, n2, n3, n4); + } + else { + const SMDS_MeshNode* n12 = GetMediumNode( n1, n2, force3d, TopAbs_FACE ); + const SMDS_MeshNode* n23 = GetMediumNode( n2, n3, force3d, TopAbs_FACE ); + const SMDS_MeshNode* n34 = GetMediumNode( n3, n4, force3d, TopAbs_FACE ); + const SMDS_MeshNode* n41 = GetMediumNode( n4, n1, force3d, TopAbs_FACE ); + if(myCreateBiQuadratic) + { + const SMDS_MeshNode* nCenter = GetCentralNode(n1, n2, n3, n4, n12, n23, n34, n41, force3d); + if(id) + elem = meshDS->AddFaceWithID(n1, n2, n3, n4, n12, n23, n34, n41, nCenter, id); + else + elem = meshDS->AddFace(n1, n2, n3, n4, n12, n23, n34, n41, nCenter); + } + else + { + if(id) + elem = meshDS->AddFaceWithID(n1, n2, n3, n4, n12, n23, n34, n41, id); + else + elem = meshDS->AddFace(n1, n2, n3, n4, n12, n23, n34, n41); + } + } + if ( mySetElemOnShape && myShapeID > 0 ) + meshDS->SetMeshElementOnShape( elem, myShapeID ); + + return elem; +} + +//======================================================================= +//function : AddPolygonalFace +//purpose : Creates polygon, with additional nodes in quadratic mesh +//======================================================================= + +SMDS_MeshFace* SMESH_MesherHelper::AddPolygonalFace (const vector& nodes, + const int id, + const bool force3d) +{ + SMESHDS_Mesh * meshDS = GetMeshDS(); + SMDS_MeshFace* elem = 0; + + if(!myCreateQuadratic) + { + if(id) + elem = meshDS->AddPolygonalFaceWithID(nodes, id); + else + elem = meshDS->AddPolygonalFace(nodes); + } + else + { + vector newNodes( nodes.size() * 2 ); + newNodes = nodes; + for ( int i = 0; i < nodes.size(); ++i ) + { + const SMDS_MeshNode* n1 = nodes[i]; + const SMDS_MeshNode* n2 = nodes[(i+1)%nodes.size()]; + const SMDS_MeshNode* n12 = GetMediumNode( n1, n2, force3d, TopAbs_FACE ); + newNodes.push_back( n12 ); + } + if(id) + elem = meshDS->AddQuadPolygonalFaceWithID(newNodes, id); + else + elem = meshDS->AddQuadPolygonalFace(newNodes); + } + if ( mySetElemOnShape && myShapeID > 0 ) + meshDS->SetMeshElementOnShape( elem, myShapeID ); + + return elem; +} + +//======================================================================= +//function : AddVolume +//purpose : Creates quadratic or linear prism +//======================================================================= + +SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n3, + const SMDS_MeshNode* n4, + const SMDS_MeshNode* n5, + const SMDS_MeshNode* n6, + const int id, + const bool force3d) +{ + SMESHDS_Mesh * meshDS = GetMeshDS(); + SMDS_MeshVolume* elem = 0; + if(!myCreateQuadratic) { + if(id) + elem = meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, id); + else + elem = meshDS->AddVolume(n1, n2, n3, n4, n5, n6); + } + else { + const SMDS_MeshNode* n12 = GetMediumNode( n1, n2, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n23 = GetMediumNode( n2, n3, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n31 = GetMediumNode( n3, n1, force3d, TopAbs_SOLID ); + + const SMDS_MeshNode* n45 = GetMediumNode( n4, n5, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n56 = GetMediumNode( n5, n6, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n64 = GetMediumNode( n6, n4, force3d, TopAbs_SOLID ); + + const SMDS_MeshNode* n14 = GetMediumNode( n1, n4, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n25 = GetMediumNode( n2, n5, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n36 = GetMediumNode( n3, n6, force3d, TopAbs_SOLID ); + + if(id) + elem = meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, + n12, n23, n31, n45, n56, n64, n14, n25, n36, id); + else + elem = meshDS->AddVolume(n1, n2, n3, n4, n5, n6, + n12, n23, n31, n45, n56, n64, n14, n25, n36); + } + if ( mySetElemOnShape && myShapeID > 0 ) + meshDS->SetMeshElementOnShape( elem, myShapeID ); + + return elem; +} + +//======================================================================= +//function : AddVolume +//purpose : Creates quadratic or linear tetrahedron +//======================================================================= + +SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n3, + const SMDS_MeshNode* n4, + const int id, + const bool force3d) +{ + SMESHDS_Mesh * meshDS = GetMeshDS(); + SMDS_MeshVolume* elem = 0; + if(!myCreateQuadratic) { + if(id) + elem = meshDS->AddVolumeWithID(n1, n2, n3, n4, id); + else + elem = meshDS->AddVolume(n1, n2, n3, n4); + } + else { + const SMDS_MeshNode* n12 = GetMediumNode( n1, n2, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n23 = GetMediumNode( n2, n3, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n31 = GetMediumNode( n3, n1, force3d, TopAbs_SOLID ); + + const SMDS_MeshNode* n14 = GetMediumNode( n1, n4, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n24 = GetMediumNode( n2, n4, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n34 = GetMediumNode( n3, n4, force3d, TopAbs_SOLID ); + + if(id) + elem = meshDS->AddVolumeWithID(n1, n2, n3, n4, n12, n23, n31, n14, n24, n34, id); + else + elem = meshDS->AddVolume(n1, n2, n3, n4, n12, n23, n31, n14, n24, n34); + } + if ( mySetElemOnShape && myShapeID > 0 ) + meshDS->SetMeshElementOnShape( elem, myShapeID ); + + return elem; +} + +//======================================================================= +//function : AddVolume +//purpose : Creates quadratic or linear pyramid +//======================================================================= + +SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n3, + const SMDS_MeshNode* n4, + const SMDS_MeshNode* n5, + const int id, + const bool force3d) +{ + SMDS_MeshVolume* elem = 0; + if(!myCreateQuadratic) { + if(id) + elem = GetMeshDS()->AddVolumeWithID(n1, n2, n3, n4, n5, id); + else + elem = GetMeshDS()->AddVolume(n1, n2, n3, n4, n5); + } + else { + const SMDS_MeshNode* n12 = GetMediumNode( n1, n2, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n23 = GetMediumNode( n2, n3, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n34 = GetMediumNode( n3, n4, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n41 = GetMediumNode( n4, n1, force3d, TopAbs_SOLID ); + + const SMDS_MeshNode* n15 = GetMediumNode( n1, n5, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n25 = GetMediumNode( n2, n5, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n35 = GetMediumNode( n3, n5, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n45 = GetMediumNode( n4, n5, force3d, TopAbs_SOLID ); + + if(id) + elem = GetMeshDS()->AddVolumeWithID ( n1, n2, n3, n4, n5, + n12, n23, n34, n41, + n15, n25, n35, n45, + id); + else + elem = GetMeshDS()->AddVolume( n1, n2, n3, n4, n5, + n12, n23, n34, n41, + n15, n25, n35, n45); + } + if ( mySetElemOnShape && myShapeID > 0 ) + GetMeshDS()->SetMeshElementOnShape( elem, myShapeID ); + + return elem; +} + +//======================================================================= +//function : AddVolume +//purpose : Creates tri-quadratic, quadratic or linear hexahedron +//======================================================================= + +SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n3, + const SMDS_MeshNode* n4, + const SMDS_MeshNode* n5, + const SMDS_MeshNode* n6, + const SMDS_MeshNode* n7, + const SMDS_MeshNode* n8, + const int id, + const bool force3d) +{ + SMESHDS_Mesh * meshDS = GetMeshDS(); + SMDS_MeshVolume* elem = 0; + if(!myCreateQuadratic) { + if(id) + elem = meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, n7, n8, id); + else + elem = meshDS->AddVolume(n1, n2, n3, n4, n5, n6, n7, n8); + } + else { + const SMDS_MeshNode* n12 = GetMediumNode( n1, n2, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n23 = GetMediumNode( n2, n3, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n34 = GetMediumNode( n3, n4, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n41 = GetMediumNode( n4, n1, force3d, TopAbs_SOLID ); + + const SMDS_MeshNode* n56 = GetMediumNode( n5, n6, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n67 = GetMediumNode( n6, n7, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n78 = GetMediumNode( n7, n8, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n85 = GetMediumNode( n8, n5, force3d, TopAbs_SOLID ); + + const SMDS_MeshNode* n15 = GetMediumNode( n1, n5, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n26 = GetMediumNode( n2, n6, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n37 = GetMediumNode( n3, n7, force3d, TopAbs_SOLID ); + const SMDS_MeshNode* n48 = GetMediumNode( n4, n8, force3d, TopAbs_SOLID ); + if ( myCreateBiQuadratic ) + { + const SMDS_MeshNode* n1234 = GetCentralNode( n1,n2,n3,n4,n12,n23,n34,n41,force3d ); + const SMDS_MeshNode* n1256 = GetCentralNode( n1,n2,n5,n6,n12,n26,n56,n15,force3d ); + const SMDS_MeshNode* n2367 = GetCentralNode( n2,n3,n6,n7,n23,n37,n67,n26,force3d ); + const SMDS_MeshNode* n3478 = GetCentralNode( n3,n4,n7,n8,n34,n48,n78,n37,force3d ); + const SMDS_MeshNode* n1458 = GetCentralNode( n1,n4,n5,n8,n41,n48,n15,n85,force3d ); + const SMDS_MeshNode* n5678 = GetCentralNode( n5,n6,n7,n8,n56,n67,n78,n85,force3d ); + + vector pointsOnShapes( SMESH_Block::ID_Shell ); + + pointsOnShapes[ SMESH_Block::ID_V000 ] = SMESH_TNodeXYZ( n4 ); + pointsOnShapes[ SMESH_Block::ID_V100 ] = SMESH_TNodeXYZ( n8 ); + pointsOnShapes[ SMESH_Block::ID_V010 ] = SMESH_TNodeXYZ( n3 ); + pointsOnShapes[ SMESH_Block::ID_V110 ] = SMESH_TNodeXYZ( n7 ); + pointsOnShapes[ SMESH_Block::ID_V001 ] = SMESH_TNodeXYZ( n1 ); + pointsOnShapes[ SMESH_Block::ID_V101 ] = SMESH_TNodeXYZ( n5 ); + pointsOnShapes[ SMESH_Block::ID_V011 ] = SMESH_TNodeXYZ( n2 ); + pointsOnShapes[ SMESH_Block::ID_V111 ] = SMESH_TNodeXYZ( n6 ); + + pointsOnShapes[ SMESH_Block::ID_Ex00 ] = SMESH_TNodeXYZ( n48 ); + pointsOnShapes[ SMESH_Block::ID_Ex10 ] = SMESH_TNodeXYZ( n37 ); + pointsOnShapes[ SMESH_Block::ID_E0y0 ] = SMESH_TNodeXYZ( n15 ); + pointsOnShapes[ SMESH_Block::ID_E1y0 ] = SMESH_TNodeXYZ( n26 ); + pointsOnShapes[ SMESH_Block::ID_Ex01 ] = SMESH_TNodeXYZ( n34 ); + pointsOnShapes[ SMESH_Block::ID_Ex11 ] = SMESH_TNodeXYZ( n78 ); + pointsOnShapes[ SMESH_Block::ID_E0y1 ] = SMESH_TNodeXYZ( n12 ); + pointsOnShapes[ SMESH_Block::ID_E1y1 ] = SMESH_TNodeXYZ( n56 ); + pointsOnShapes[ SMESH_Block::ID_E00z ] = SMESH_TNodeXYZ( n41 ); + pointsOnShapes[ SMESH_Block::ID_E10z ] = SMESH_TNodeXYZ( n85 ); + pointsOnShapes[ SMESH_Block::ID_E01z ] = SMESH_TNodeXYZ( n23 ); + pointsOnShapes[ SMESH_Block::ID_E11z ] = SMESH_TNodeXYZ( n67 ); + + pointsOnShapes[ SMESH_Block::ID_Fxy0 ] = SMESH_TNodeXYZ( n3478 ); + pointsOnShapes[ SMESH_Block::ID_Fxy1 ] = SMESH_TNodeXYZ( n1256 ); + pointsOnShapes[ SMESH_Block::ID_Fx0z ] = SMESH_TNodeXYZ( n1458 ); + pointsOnShapes[ SMESH_Block::ID_Fx1z ] = SMESH_TNodeXYZ( n2367 ); + pointsOnShapes[ SMESH_Block::ID_F0yz ] = SMESH_TNodeXYZ( n1234 ); + pointsOnShapes[ SMESH_Block::ID_F1yz ] = SMESH_TNodeXYZ( n5678 ); + + gp_XYZ centerCube(0.5, 0.5, 0.5); + gp_XYZ nCenterElem; + SMESH_Block::ShellPoint( centerCube, pointsOnShapes, nCenterElem ); + const SMDS_MeshNode* nCenter = + meshDS->AddNode( nCenterElem.X(), nCenterElem.Y(), nCenterElem.Z() ); + meshDS->SetNodeInVolume( nCenter, myShapeID ); + + if(id) + elem = meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, n7, n8, + n12, n23, n34, n41, n56, n67, + n78, n85, n15, n26, n37, n48, + n1234, n1256, n2367, n3478, n1458, n5678, nCenter, id); + else + elem = meshDS->AddVolume(n1, n2, n3, n4, n5, n6, n7, n8, + n12, n23, n34, n41, n56, n67, + n78, n85, n15, n26, n37, n48, + n1234, n1256, n2367, n3478, n1458, n5678, nCenter); + } + else + { + if(id) + elem = meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, n7, n8, + n12, n23, n34, n41, n56, n67, + n78, n85, n15, n26, n37, n48, id); + else + elem = meshDS->AddVolume(n1, n2, n3, n4, n5, n6, n7, n8, + n12, n23, n34, n41, n56, n67, + n78, n85, n15, n26, n37, n48); + } + } + if ( mySetElemOnShape && myShapeID > 0 ) + meshDS->SetMeshElementOnShape( elem, myShapeID ); + + return elem; +} + +//======================================================================= +//function : AddVolume +//purpose : Creates LINEAR!!!!!!!!! octahedron +//======================================================================= + +SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* n3, + const SMDS_MeshNode* n4, + const SMDS_MeshNode* n5, + const SMDS_MeshNode* n6, + const SMDS_MeshNode* n7, + const SMDS_MeshNode* n8, + const SMDS_MeshNode* n9, + const SMDS_MeshNode* n10, + const SMDS_MeshNode* n11, + const SMDS_MeshNode* n12, + const int id, + bool force3d) +{ + SMESHDS_Mesh * meshDS = GetMeshDS(); + SMDS_MeshVolume* elem = 0; + if(id) + elem = meshDS->AddVolumeWithID(n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,id); + else + elem = meshDS->AddVolume(n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12); + if ( mySetElemOnShape && myShapeID > 0 ) + meshDS->SetMeshElementOnShape( elem, myShapeID ); + return elem; +} + +//======================================================================= +//function : AddPolyhedralVolume +//purpose : Creates polyhedron. In quadratic mesh, adds medium nodes +//======================================================================= + +SMDS_MeshVolume* +SMESH_MesherHelper::AddPolyhedralVolume (const std::vector& nodes, + const std::vector& quantities, + const int id, + const bool force3d) +{ + SMESHDS_Mesh * meshDS = GetMeshDS(); + SMDS_MeshVolume* elem = 0; + if(!myCreateQuadratic) + { + if(id) + elem = meshDS->AddPolyhedralVolumeWithID(nodes, quantities, id); + else + elem = meshDS->AddPolyhedralVolume(nodes, quantities); + } + else + { + vector newNodes; + vector newQuantities; + for ( int iFace=0, iN=0; iFace < quantities.size(); ++iFace) + { + int nbNodesInFace = quantities[iFace]; + newQuantities.push_back(0); + for ( int i = 0; i < nbNodesInFace; ++i ) + { + const SMDS_MeshNode* n1 = nodes[ iN + i ]; + newNodes.push_back( n1 ); + newQuantities.back()++; + + const SMDS_MeshNode* n2 = nodes[ iN + ( i+1==nbNodesInFace ? 0 : i+1 )]; +// if ( n1->GetPosition()->GetTypeOfPosition() != SMDS_TOP_3DSPACE && +// n2->GetPosition()->GetTypeOfPosition() != SMDS_TOP_3DSPACE ) + { + const SMDS_MeshNode* n12 = GetMediumNode( n1, n2, force3d, TopAbs_SOLID ); + newNodes.push_back( n12 ); + newQuantities.back()++; + } + } + iN += nbNodesInFace; + } + if(id) + elem = meshDS->AddPolyhedralVolumeWithID( newNodes, newQuantities, id ); + else + elem = meshDS->AddPolyhedralVolume( newNodes, newQuantities ); + } + if ( mySetElemOnShape && myShapeID > 0 ) + meshDS->SetMeshElementOnShape( elem, myShapeID ); + + return elem; +} + +namespace +{ + //================================================================================ + /*! + * \brief Check if a node belongs to any face of sub-mesh + */ + //================================================================================ + + bool isNodeInSubMesh( const SMDS_MeshNode* n, const SMESHDS_SubMesh* sm ) + { + SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator( SMDSAbs_Face ); + while ( fIt->more() ) + if ( sm->Contains( fIt->next() )) + return true; + return false; + } +} + +//======================================================================= +//function : IsSameElemGeometry +//purpose : Returns true if all elements of a sub-mesh are of same shape +//======================================================================= + +bool SMESH_MesherHelper::IsSameElemGeometry(const SMESHDS_SubMesh* smDS, + SMDSAbs_GeometryType shape, + const bool nullSubMeshRes) +{ + if ( !smDS ) return nullSubMeshRes; + + SMDS_ElemIteratorPtr elemIt = smDS->GetElements(); + while ( elemIt->more() ) { + const SMDS_MeshElement* e = elemIt->next(); + if ( e->GetGeomType() != shape ) + return false; + } + return true; +} + +//======================================================================= +//function : LoadNodeColumns +//purpose : Load nodes bound to face into a map of node columns +//======================================================================= + +bool SMESH_MesherHelper::LoadNodeColumns(TParam2ColumnMap & theParam2ColumnMap, + const TopoDS_Face& theFace, + const TopoDS_Edge& theBaseEdge, + SMESHDS_Mesh* theMesh, + SMESH_ProxyMesh* theProxyMesh) +{ + return LoadNodeColumns(theParam2ColumnMap, + theFace, + std::list(1,theBaseEdge), + theMesh, + theProxyMesh); +} + +//======================================================================= +//function : LoadNodeColumns +//purpose : Load nodes bound to face into a map of node columns +//======================================================================= + +bool SMESH_MesherHelper::LoadNodeColumns(TParam2ColumnMap & theParam2ColumnMap, + const TopoDS_Face& theFace, + const std::list& theBaseSide, + SMESHDS_Mesh* theMesh, + SMESH_ProxyMesh* theProxyMesh) +{ + // get a right sub-mesh of theFace + + const SMESHDS_SubMesh* faceSubMesh = 0; + if ( theProxyMesh ) + { + faceSubMesh = theProxyMesh->GetSubMesh( theFace ); + if ( !faceSubMesh || + faceSubMesh->NbElements() == 0 || + theProxyMesh->IsTemporary( faceSubMesh->GetElements()->next() )) + { + // can use a proxy sub-mesh with not temporary elements only + faceSubMesh = 0; + theProxyMesh = 0; + } + } + if ( !faceSubMesh ) + faceSubMesh = theMesh->MeshElements( theFace ); + if ( !faceSubMesh || faceSubMesh->NbElements() == 0 ) + return false; + + if ( theParam2ColumnMap.empty() ) + { + // get data of edges for normalization of params + vector< double > length; + double fullLen = 0; + list::const_iterator edge; + { + for ( edge = theBaseSide.begin(); edge != theBaseSide.end(); ++edge ) + { + double len = std::max( 1e-10, SMESH_Algo::EdgeLength( *edge )); + fullLen += len; + length.push_back( len ); + } + } + + // get nodes on theBaseEdge sorted by param on edge and initialize theParam2ColumnMap with them + edge = theBaseSide.begin(); + for ( int iE = 0; edge != theBaseSide.end(); ++edge, ++iE ) + { + map< double, const SMDS_MeshNode*> sortedBaseNN; + SMESH_Algo::GetSortedNodesOnEdge( theMesh, *edge,/*noMedium=*/true, sortedBaseNN ); + + map< double, const SMDS_MeshNode*>::iterator u_n; + // pb with mesh_Projection_2D_00/A1 fixed by adding expectedSupport arg to GetMediumPos() + // so the following solution is commented (hope forever :) + // + // SMESH_Algo::GetSortedNodesOnEdge( theMesh, *edge,/*noMedium=*/true, sortedBaseNN, + // // SMDSAbs_Edge here is needed to be coherent with + // // StdMeshers_FaceSide used by Quadrangle to get nodes + // // on EDGE; else pb in mesh_Projection_2D_00/A1 where a + // // medium node on EDGE is medium in a triangle but not + // // in a segment + // SMDSAbs_Edge ); + // if ( faceSubMesh->GetElements()->next()->IsQuadratic() ) + // // filter off nodes medium in faces on theFace (same pb with mesh_Projection_2D_00/A1) + // for ( u_n = sortedBaseNN.begin(); u_n != sortedBaseNN.end() ; ) + // { + // const SMDS_MeshNode* node = u_n->second; + // SMDS_ElemIteratorPtr faceIt = node->GetInverseElementIterator( SMDSAbs_Face ); + // if ( faceIt->more() && node ) { + // const SMDS_MeshElement* face = faceIt->next(); + // if ( faceSubMesh->Contains( face ) && face->IsMediumNode( node )) + // node = 0; + // } + // if ( !node ) + // sortedBaseNN.erase( u_n++ ); + // else + // ++u_n; + // } + if ( sortedBaseNN.empty() ) continue; + + u_n = sortedBaseNN.begin(); + if ( theProxyMesh ) // from sortedBaseNN remove nodes not shared by faces of faceSubMesh + { + const SMDS_MeshNode* n1 = (++sortedBaseNN.begin())->second; + const SMDS_MeshNode* n2 = (++sortedBaseNN.rbegin())->second; + bool allNodesAreProxy = ( n1 != theProxyMesh->GetProxyNode( n1 ) && + n2 != theProxyMesh->GetProxyNode( n2 )); + if ( allNodesAreProxy ) + for ( u_n = sortedBaseNN.begin(); u_n != sortedBaseNN.end(); u_n++ ) + u_n->second = theProxyMesh->GetProxyNode( u_n->second ); + + if ( u_n = sortedBaseNN.begin(), !isNodeInSubMesh( u_n->second, faceSubMesh )) + { + while ( ++u_n != sortedBaseNN.end() && !isNodeInSubMesh( u_n->second, faceSubMesh )); + sortedBaseNN.erase( sortedBaseNN.begin(), u_n ); + } + if ( !sortedBaseNN.empty() ) + if ( u_n = --sortedBaseNN.end(), !isNodeInSubMesh( u_n->second, faceSubMesh )) + { + while ( u_n != sortedBaseNN.begin() && !isNodeInSubMesh( (--u_n)->second, faceSubMesh )); + sortedBaseNN.erase( ++u_n, sortedBaseNN.end() ); + } + if ( sortedBaseNN.empty() ) continue; + } + + double f, l; + BRep_Tool::Range( *edge, f, l ); + if ( edge->Orientation() == TopAbs_REVERSED ) std::swap( f, l ); + const double coeff = 1. / ( l - f ) * length[iE] / fullLen; + const double prevPar = theParam2ColumnMap.empty() ? 0 : theParam2ColumnMap.rbegin()->first; + for ( u_n = sortedBaseNN.begin(); u_n != sortedBaseNN.end(); u_n++ ) + { + double par = prevPar + coeff * ( u_n->first - f ); + TParam2ColumnMap::iterator u2nn = + theParam2ColumnMap.insert( theParam2ColumnMap.end(), make_pair( par, TNodeColumn())); + u2nn->second.push_back( u_n->second ); + } + } + if ( theParam2ColumnMap.size() < 2 ) + return false; + } + + // nb rows of nodes + int prevNbRows = theParam2ColumnMap.begin()->second.size(); // current, at least 1 here + int expectedNbRows = faceSubMesh->NbElements() / ( theParam2ColumnMap.size()-1 ); // to be added + + // fill theParam2ColumnMap column by column by passing from nodes on + // theBaseEdge up via mesh faces on theFace + + TParam2ColumnMap::iterator par_nVec_1, par_nVec_2; + par_nVec_2 = theParam2ColumnMap.begin(); + par_nVec_1 = par_nVec_2++; + TIDSortedElemSet emptySet, avoidSet; + for ( ; par_nVec_2 != theParam2ColumnMap.end(); ++par_nVec_1, ++par_nVec_2 ) + { + vector& nCol1 = par_nVec_1->second; + vector& nCol2 = par_nVec_2->second; + nCol1.resize( prevNbRows + expectedNbRows ); + nCol2.resize( prevNbRows + expectedNbRows ); + + int i1, i2, foundNbRows = 0; + const SMDS_MeshNode *n1 = nCol1[ prevNbRows-1 ]; + const SMDS_MeshNode *n2 = nCol2[ prevNbRows-1 ]; + // find face sharing node n1 and n2 and belonging to faceSubMesh + while ( const SMDS_MeshElement* face = + SMESH_MeshAlgos::FindFaceInSet( n1, n2, emptySet, avoidSet, &i1, &i2)) + { + if ( faceSubMesh->Contains( face )) + { + int nbNodes = face->NbCornerNodes(); + if ( nbNodes != 4 ) + return false; + if ( foundNbRows + 1 > expectedNbRows ) + return false; + n1 = face->GetNode( (i2+2) % 4 ); // opposite corner of quadrangle face + n2 = face->GetNode( (i1+2) % 4 ); + nCol1[ prevNbRows + foundNbRows] = n1; + nCol2[ prevNbRows + foundNbRows] = n2; + ++foundNbRows; + } + avoidSet.insert( face ); + } + if ( foundNbRows != expectedNbRows ) + return false; + avoidSet.clear(); + } + return ( theParam2ColumnMap.size() > 1 && + theParam2ColumnMap.begin()->second.size() == prevNbRows + expectedNbRows ); +} + +namespace +{ + //================================================================================ + /*! + * \brief Return true if a node is at a corner of a 2D structured mesh of FACE + */ + //================================================================================ + + bool isCornerOfStructure( const SMDS_MeshNode* n, + const SMESHDS_SubMesh* faceSM, + SMESH_MesherHelper& faceAnalyser ) + { + int nbFacesInSM = 0; + if ( n ) { + SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator( SMDSAbs_Face ); + while ( fIt->more() ) + nbFacesInSM += faceSM->Contains( fIt->next() ); + } + if ( nbFacesInSM == 1 ) + return true; + + if ( nbFacesInSM == 2 && n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX ) + { + return faceAnalyser.IsRealSeam( n->getshapeId() ); + } + return false; + } +} + +//======================================================================= +//function : IsStructured +//purpose : Return true if 2D mesh on FACE is a structured rectangle +//======================================================================= + +bool SMESH_MesherHelper::IsStructured( SMESH_subMesh* faceSM ) +{ + SMESHDS_SubMesh* fSM = faceSM->GetSubMeshDS(); + if ( !fSM || fSM->NbElements() == 0 ) + return false; + + list< TopoDS_Edge > edges; + list< int > nbEdgesInWires; + int nbWires = SMESH_Block::GetOrderedEdges( TopoDS::Face( faceSM->GetSubShape() ), + edges, nbEdgesInWires ); + if ( nbWires != 1 /*|| nbEdgesInWires.front() != 4*/ ) // allow composite sides + return false; + + // algo: find corners of a structure and then analyze nb of faces and + // length of structure sides + + SMESHDS_Mesh* meshDS = faceSM->GetFather()->GetMeshDS(); + SMESH_MesherHelper faceAnalyser( *faceSM->GetFather() ); + faceAnalyser.SetSubShape( faceSM->GetSubShape() ); + + // rotate edges to get the first node being at corner + // (in principle it's not necessary because so far none SALOME algo can make + // such a structured mesh that all corner nodes are not on VERTEXes) + bool isCorner = false; + int nbRemainEdges = nbEdgesInWires.front(); + do { + TopoDS_Vertex V = IthVertex( 0, edges.front() ); + isCorner = isCornerOfStructure( SMESH_Algo::VertexNode( V, meshDS ), + fSM, faceAnalyser); + if ( !isCorner ) { + edges.splice( edges.end(), edges, edges.begin() ); + --nbRemainEdges; + } + } + while ( !isCorner && nbRemainEdges > 0 ); + + if ( !isCorner ) + return false; + + // get all nodes from EDGEs + list< const SMDS_MeshNode* > nodes; + list< TopoDS_Edge >::iterator edge = edges.begin(); + for ( ; edge != edges.end(); ++edge ) + { + map< double, const SMDS_MeshNode* > u2Nodes; + if ( !SMESH_Algo::GetSortedNodesOnEdge( meshDS, *edge, + /*skipMedium=*/true, u2Nodes )) + return false; + + list< const SMDS_MeshNode* > edgeNodes; + map< double, const SMDS_MeshNode* >::iterator u2n = u2Nodes.begin(); + for ( ; u2n != u2Nodes.end(); ++u2n ) + edgeNodes.push_back( u2n->second ); + if ( edge->Orientation() == TopAbs_REVERSED ) + edgeNodes.reverse(); + + if ( !nodes.empty() && nodes.back() == edgeNodes.front() ) + edgeNodes.pop_front(); + nodes.splice( nodes.end(), edgeNodes, edgeNodes.begin(), edgeNodes.end() ); + } + + // get length of structured sides + vector nbEdgesInSide; + int nbEdges = 0; + list< const SMDS_MeshNode* >::iterator n = ++nodes.begin(); + for ( ; n != nodes.end(); ++n ) + { + ++nbEdges; + if ( isCornerOfStructure( *n, fSM, faceAnalyser )) { + nbEdgesInSide.push_back( nbEdges ); + nbEdges = 0; + } + } + + // checks + if ( nbEdgesInSide.size() != 4 ) + return false; + if ( nbEdgesInSide[0] != nbEdgesInSide[2] ) + return false; + if ( nbEdgesInSide[1] != nbEdgesInSide[3] ) + return false; + if ( nbEdgesInSide[0] * nbEdgesInSide[1] != fSM->NbElements() ) + return false; + + return true; +} + +//======================================================================= +//function : IsDistorted2D +//purpose : Return true if 2D mesh on FACE is ditorted +//======================================================================= + +bool SMESH_MesherHelper::IsDistorted2D( SMESH_subMesh* faceSM, + bool checkUV) +{ + if ( !faceSM || faceSM->GetSubShape().ShapeType() != TopAbs_FACE ) + return false; + + bool haveBadFaces = false; + + SMESH_MesherHelper helper( *faceSM->GetFather() ); + helper.SetSubShape( faceSM->GetSubShape() ); + + const TopoDS_Face& F = TopoDS::Face( faceSM->GetSubShape() ); + SMESHDS_SubMesh* smDS = helper.GetMeshDS()->MeshElements( F ); + if ( !smDS || smDS->NbElements() == 0 ) return false; + + SMDS_ElemIteratorPtr faceIt = smDS->GetElements(); + double prevArea = 0; + vector< const SMDS_MeshNode* > nodes; + vector< gp_XY > uv; + bool* toCheckUV = checkUV ? & checkUV : 0; + while ( faceIt->more() && !haveBadFaces ) + { + const SMDS_MeshElement* face = faceIt->next(); + + // get nodes + nodes.resize( face->NbCornerNodes() ); + SMDS_MeshElement::iterator n = face->begin_nodes(); + for ( size_t i = 0; i < nodes.size(); ++n, ++i ) + nodes[ i ] = *n; + + // avoid elems on degenarate shapes as UV on them can be wrong + if ( helper.HasDegeneratedEdges() ) + { + bool isOnDegen = false; + for ( size_t i = 0; ( i < nodes.size() && !isOnDegen ); ++i ) + isOnDegen = helper.IsDegenShape( nodes[ i ]->getshapeId() ); + if ( isOnDegen ) + continue; + } + // prepare to getting UVs + const SMDS_MeshNode* inFaceNode = 0; + if ( helper.HasSeam() ) { + for ( size_t i = 0; ( i < nodes.size() && !inFaceNode ); ++i ) + if ( !helper.IsSeamShape( nodes[ i ]->getshapeId() )) + inFaceNode = nodes[ i ]; + if ( !inFaceNode ) + continue; + } + // get UVs + uv.resize( nodes.size() ); + for ( size_t i = 0; i < nodes.size(); ++i ) + uv[ i ] = helper.GetNodeUV( F, nodes[ i ], inFaceNode, toCheckUV ); + + // compare orientation of triangles + double faceArea = 0; + for ( int iT = 0, nbT = nodes.size()-2; iT < nbT; ++iT ) + { + gp_XY v1 = uv[ iT+1 ] - uv[ 0 ]; + gp_XY v2 = uv[ iT+2 ] - uv[ 0 ]; + faceArea += v2 ^ v1; + } + haveBadFaces = ( faceArea * prevArea < 0 ); + prevArea = faceArea; + } + + return haveBadFaces; +} + +//================================================================================ +/*! + * \brief Find out elements orientation on a geometrical face + * \param theFace - The face correctly oriented in the shape being meshed + * \retval bool - true if the face normal and the normal of first element + * in the correspoding submesh point in different directions + */ +//================================================================================ + +bool SMESH_MesherHelper::IsReversedSubMesh (const TopoDS_Face& theFace) +{ + if ( theFace.IsNull() ) + return false; + + // find out orientation of a meshed face + int faceID = GetMeshDS()->ShapeToIndex( theFace ); + TopoDS_Shape aMeshedFace = GetMeshDS()->IndexToShape( faceID ); + bool isReversed = ( theFace.Orientation() != aMeshedFace.Orientation() ); + + const SMESHDS_SubMesh * aSubMeshDSFace = GetMeshDS()->MeshElements( faceID ); + if ( !aSubMeshDSFace ) + return isReversed; + + // find an element on a bounday of theFace + SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements(); + const SMDS_MeshNode* nn[2]; + while ( iteratorElem->more() ) // loop on elements on theFace + { + const SMDS_MeshElement* elem = iteratorElem->next(); + if ( ! elem ) continue; + + // look for 2 nodes on EDGE + int nbNodes = elem->NbCornerNodes(); + nn[0] = elem->GetNode( nbNodes-1 ); + for ( int iN = 0; iN < nbNodes; ++iN ) + { + nn[1] = elem->GetNode( iN ); + if ( nn[0]->GetPosition()->GetDim() < 2 && + nn[1]->GetPosition()->GetDim() < 2 ) + { + TopoDS_Shape s0 = GetSubShapeByNode( nn[0], GetMeshDS() ); + TopoDS_Shape s1 = GetSubShapeByNode( nn[1], GetMeshDS() ); + TopoDS_Shape E = GetCommonAncestor( s0, s1, *myMesh, TopAbs_EDGE ); + if ( !E.IsNull() && !s0.IsSame( s1 )) + { + // is E seam edge? + int nb = 0; + for ( TopExp_Explorer exp( theFace, TopAbs_EDGE ); exp.More(); exp.Next() ) + if ( E.IsSame( exp.Current() )) { + ++nb; + E = exp.Current(); // to know orientation + } + if ( nb == 1 ) + { + bool ok = true; + double u0 = GetNodeU( TopoDS::Edge( E ), nn[0], nn[1], &ok ); + double u1 = GetNodeU( TopoDS::Edge( E ), nn[1], nn[0], &ok ); + if ( ok ) + { + isReversed = ( u0 > u1 ); + if ( E.Orientation() == TopAbs_REVERSED ) + isReversed = !isReversed; + return isReversed; + } + } + } + } + nn[0] = nn[1]; + } + } + + // find an element with a good normal + gp_Vec Ne; + bool normalOK = false; + gp_XY uv; + iteratorElem = aSubMeshDSFace->GetElements(); + while ( !normalOK && iteratorElem->more() ) // loop on elements on theFace + { + const SMDS_MeshElement* elem = iteratorElem->next(); + if ( ! SMESH_MeshAlgos::FaceNormal( elem, const_cast( Ne.XYZ() ), /*normalized=*/0 )) + continue; + normalOK = true; + + // get UV of a node inside theFACE + SMDS_ElemIteratorPtr nodesIt = elem->nodesIterator(); + const SMDS_MeshNode* nInFace = 0; + int iPosDim = SMDS_TOP_VERTEX; + while ( nodesIt->more() ) // loop on nodes + { + const SMDS_MeshNode* n = static_cast( nodesIt->next() ); + if ( n->GetPosition()->GetTypeOfPosition() >= iPosDim ) + { + nInFace = n; + iPosDim = n->GetPosition()->GetTypeOfPosition(); + } + } + uv = GetNodeUV( theFace, nInFace, 0, &normalOK ); + } + if ( !normalOK ) + return isReversed; + + // face normal at node position + TopLoc_Location loc; + Handle(Geom_Surface) surf = BRep_Tool::Surface( theFace, loc ); + // if ( surf.IsNull() || surf->Continuity() < GeomAbs_C1 ) + // some surfaces not detected as GeomAbs_C1 are nevertheless correct for meshing + if ( surf.IsNull() || surf->Continuity() < GeomAbs_C0 ) + return isReversed; + + gp_Vec d1u, d1v; gp_Pnt p; + surf->D1( uv.X(), uv.Y(), p, d1u, d1v ); + gp_Vec Nf = (d1u ^ d1v).Transformed( loc ); + + if ( theFace.Orientation() == TopAbs_REVERSED ) + Nf.Reverse(); + + return Ne * Nf < 0.; +} + +//======================================================================= +//function : Count +//purpose : Count nb of sub-shapes +//======================================================================= + +int SMESH_MesherHelper::Count(const TopoDS_Shape& shape, + const TopAbs_ShapeEnum type, + const bool ignoreSame) +{ + if ( ignoreSame ) { + TopTools_IndexedMapOfShape map; + TopExp::MapShapes( shape, type, map ); + return map.Extent(); + } + else { + int nb = 0; + for ( TopExp_Explorer exp( shape, type ); exp.More(); exp.Next() ) + ++nb; + return nb; + } +} + +//======================================================================= +//function : NbAncestors +//purpose : Return number of unique ancestors of the shape +//======================================================================= + +int SMESH_MesherHelper::NbAncestors(const TopoDS_Shape& shape, + const SMESH_Mesh& mesh, + TopAbs_ShapeEnum ancestorType/*=TopAbs_SHAPE*/) +{ + TopTools_MapOfShape ancestors; + TopTools_ListIteratorOfListOfShape ansIt( mesh.GetAncestors(shape) ); + for ( ; ansIt.More(); ansIt.Next() ) { + if ( ancestorType == TopAbs_SHAPE || ansIt.Value().ShapeType() == ancestorType ) + ancestors.Add( ansIt.Value() ); + } + return ancestors.Extent(); +} + +//======================================================================= +//function : GetSubShapeOri +//purpose : Return orientation of sub-shape in the main shape +//======================================================================= + +TopAbs_Orientation SMESH_MesherHelper::GetSubShapeOri(const TopoDS_Shape& shape, + const TopoDS_Shape& subShape) +{ + TopAbs_Orientation ori = TopAbs_Orientation(-1); + if ( !shape.IsNull() && !subShape.IsNull() ) + { + TopExp_Explorer e( shape, subShape.ShapeType() ); + if ( shape.Orientation() >= TopAbs_INTERNAL ) // TopAbs_INTERNAL or TopAbs_EXTERNAL + e.Init( shape.Oriented(TopAbs_FORWARD), subShape.ShapeType() ); + for ( ; e.More(); e.Next()) + if ( subShape.IsSame( e.Current() )) + break; + if ( e.More() ) + ori = e.Current().Orientation(); + } + return ori; +} + +//======================================================================= +//function : IsSubShape +//purpose : +//======================================================================= + +bool SMESH_MesherHelper::IsSubShape( const TopoDS_Shape& shape, + const TopoDS_Shape& mainShape ) +{ + if ( !shape.IsNull() && !mainShape.IsNull() ) + { + for ( TopExp_Explorer exp( mainShape, shape.ShapeType()); + exp.More(); + exp.Next() ) + if ( shape.IsSame( exp.Current() )) + return true; + } + SCRUTE((shape.IsNull())); + SCRUTE((mainShape.IsNull())); + return false; +} + +//======================================================================= +//function : IsSubShape +//purpose : +//======================================================================= + +bool SMESH_MesherHelper::IsSubShape( const TopoDS_Shape& shape, SMESH_Mesh* aMesh ) +{ + if ( shape.IsNull() || !aMesh ) + return false; + return + aMesh->GetMeshDS()->ShapeToIndex( shape ) || + // PAL16202 + (shape.ShapeType() == TopAbs_COMPOUND && aMesh->GetMeshDS()->IsGroupOfSubShapes( shape )); +} + +//======================================================================= +//function : IsBlock +//purpose : +//======================================================================= + +bool SMESH_MesherHelper::IsBlock( const TopoDS_Shape& shape ) +{ + if ( shape.IsNull() ) + return false; + + TopoDS_Shell shell; + TopExp_Explorer exp( shape, TopAbs_SHELL ); + if ( !exp.More() ) return false; + shell = TopoDS::Shell( exp.Current() ); + if ( exp.Next(), exp.More() ) return false; + + TopoDS_Vertex v; + TopTools_IndexedMapOfOrientedShape map; + return SMESH_Block::FindBlockShapes( shell, v, v, map ); +} + + +//================================================================================ +/*! + * \brief Return maximal tolerance of shape + */ +//================================================================================ + +double SMESH_MesherHelper::MaxTolerance( const TopoDS_Shape& shape ) +{ + double tol = Precision::Confusion(); + TopExp_Explorer exp; + for ( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() ) + tol = Max( tol, BRep_Tool::Tolerance( TopoDS::Face( exp.Current()))); + for ( exp.Init( shape, TopAbs_EDGE ); exp.More(); exp.Next() ) + tol = Max( tol, BRep_Tool::Tolerance( TopoDS::Edge( exp.Current()))); + for ( exp.Init( shape, TopAbs_VERTEX ); exp.More(); exp.Next() ) + tol = Max( tol, BRep_Tool::Tolerance( TopoDS::Vertex( exp.Current()))); + + return tol; +} + +//================================================================================ +/*! + * \brief Return MaxTolerance( face ), probably cached + */ +//================================================================================ + +double SMESH_MesherHelper::getFaceMaxTol( const TopoDS_Shape& face ) const +{ + int faceID = GetMeshDS()->ShapeToIndex( face ); + + SMESH_MesherHelper* me = const_cast< SMESH_MesherHelper* >( this ); + double & tol = me->myFaceMaxTol.insert( make_pair( faceID, -1. )).first->second; + if ( tol < 0 ) + tol = MaxTolerance( face ); + + return tol; +} + +//================================================================================ +/*! + * \brief Return an angle between two EDGEs sharing a common VERTEX with reference + * of the FACE normal + * \return double - the angle (between -Pi and Pi), negative if the angle is concave, + * 1e100 in case of failure + * \waring Care about order of the EDGEs and their orientation to be as they are + * within the FACE! Don't pass degenerated EDGEs neither! + */ +//================================================================================ + +double SMESH_MesherHelper::GetAngle( const TopoDS_Edge & theE1, + const TopoDS_Edge & theE2, + const TopoDS_Face & theFace, + const TopoDS_Vertex & theCommonV, + gp_Vec* theFaceNormal) +{ + double angle = 1e100; + try + { + double f,l; + Handle(Geom_Curve) c1 = BRep_Tool::Curve( theE1, f,l ); + Handle(Geom_Curve) c2 = BRep_Tool::Curve( theE2, f,l ); + Handle(Geom2d_Curve) c2d1 = BRep_Tool::CurveOnSurface( theE1, theFace, f,l ); + Handle(Geom_Surface) surf = BRep_Tool::Surface( theFace ); + double p1 = BRep_Tool::Parameter( theCommonV, theE1 ); + double p2 = BRep_Tool::Parameter( theCommonV, theE2 ); + if ( c1.IsNull() || c2.IsNull() ) + return angle; + gp_XY uv = c2d1->Value( p1 ).XY(); + gp_Vec du, dv; gp_Pnt p; + surf->D1( uv.X(), uv.Y(), p, du, dv ); + gp_Vec vec1, vec2, vecRef = du ^ dv; + int nbLoops = 0; + double p1tmp = p1; + while ( vecRef.SquareMagnitude() < 1e-25 ) + { + double dp = ( l - f ) / 1000.; + p1tmp += dp * (( Abs( p1 - f ) > Abs( p1 - l )) ? -1. : +1.); + uv = c2d1->Value( p1tmp ).XY(); + surf->D1( uv.X(), uv.Y(), p, du, dv ); + vecRef = du ^ dv; + if ( ++nbLoops > 10 ) + { +#ifdef _DEBUG_ + cout << "SMESH_MesherHelper::GetAngle(): Captured in a sigularity" << endl; +#endif + return angle; + } + } + if ( theFace.Orientation() == TopAbs_REVERSED ) + vecRef.Reverse(); + if ( theFaceNormal ) *theFaceNormal = vecRef; + + c1->D1( p1, p, vec1 ); + c2->D1( p2, p, vec2 ); + // TopoDS_Face F = theFace; + // if ( F.Orientation() == TopAbs_INTERNAL ) + // F.Orientation( TopAbs_FORWARD ); + if ( theE1.Orientation() /*GetSubShapeOri( F, theE1 )*/ == TopAbs_REVERSED ) + vec1.Reverse(); + if ( theE2.Orientation() /*GetSubShapeOri( F, theE2 )*/ == TopAbs_REVERSED ) + vec2.Reverse(); + angle = vec1.AngleWithRef( vec2, vecRef ); + + if ( Abs ( angle ) >= 0.99 * M_PI ) + { + BRep_Tool::Range( theE1, f, l ); + p1 += 1e-7 * ( p1-f < l-p1 ? +1. : -1. ); + c1->D1( p1, p, vec1 ); + if ( theE1.Orientation() == TopAbs_REVERSED ) + vec1.Reverse(); + BRep_Tool::Range( theE2, f, l ); + p2 += 1e-7 * ( p2-f < l-p2 ? +1. : -1. ); + c2->D1( p2, p, vec2 ); + if ( theE2.Orientation() == TopAbs_REVERSED ) + vec2.Reverse(); + angle = vec1.AngleWithRef( vec2, vecRef ); + } + } + catch (...) + { + } + return angle; +} + +//================================================================================ +/*! + * \brief Check if the first and last vertices of an edge are the same + * \param anEdge - the edge to check + * \retval bool - true if same + */ +//================================================================================ + +bool SMESH_MesherHelper::IsClosedEdge( const TopoDS_Edge& anEdge ) +{ + if ( anEdge.Orientation() >= TopAbs_INTERNAL ) + return IsClosedEdge( TopoDS::Edge( anEdge.Oriented( TopAbs_FORWARD ))); + return TopExp::FirstVertex( anEdge ).IsSame( TopExp::LastVertex( anEdge )); +} + +//================================================================================ +/*! + * \brief Wrapper over TopExp::FirstVertex() and TopExp::LastVertex() fixing them + * in the case of INTERNAL edge + */ +//================================================================================ + +TopoDS_Vertex SMESH_MesherHelper::IthVertex( const bool is2nd, + TopoDS_Edge anEdge, + const bool CumOri ) +{ + if ( anEdge.Orientation() >= TopAbs_INTERNAL ) + anEdge.Orientation( TopAbs_FORWARD ); + + const TopAbs_Orientation tgtOri = is2nd ? TopAbs_REVERSED : TopAbs_FORWARD; + TopoDS_Iterator vIt( anEdge, CumOri ); + while ( vIt.More() && vIt.Value().Orientation() != tgtOri ) + vIt.Next(); + + return ( vIt.More() ? TopoDS::Vertex(vIt.Value()) : TopoDS_Vertex() ); +} + +//================================================================================ +/*! + * \brief Return type of shape contained in a group + * \param group - a shape of type TopAbs_COMPOUND + * \param avoidCompound - not to return TopAbs_COMPOUND + */ +//================================================================================ + +TopAbs_ShapeEnum SMESH_MesherHelper::GetGroupType(const TopoDS_Shape& group, + const bool avoidCompound) +{ + if ( !group.IsNull() ) + { + if ( group.ShapeType() != TopAbs_COMPOUND ) + return group.ShapeType(); + + // iterate on a compound + TopoDS_Iterator it( group ); + if ( it.More() ) + return avoidCompound ? GetGroupType( it.Value() ) : it.Value().ShapeType(); + } + return TopAbs_SHAPE; +} + +//================================================================================ +/*! + * \brief Returns a shape, to which a hypothesis used to mesh a given shape is assigned + * \param [in] hyp - the hypothesis + * \param [in] shape - the shape, for meshing which the \a hyp is used + * \param [in] mesh - the mesh + * \return TopoDS_Shape - the shape the \a hyp is assigned to + */ +//================================================================================ + +TopoDS_Shape SMESH_MesherHelper::GetShapeOfHypothesis( const SMESHDS_Hypothesis * hyp, + const TopoDS_Shape& shape, + SMESH_Mesh* mesh) +{ + const SMESH_Hypothesis* h = static_cast( hyp ); + SMESH_HypoFilter hypFilter( SMESH_HypoFilter::Is( h )); + + TopoDS_Shape shapeOfHyp; + mesh->GetHypothesis( shape, hypFilter, /*checkAncestors=*/true, &shapeOfHyp ); + return shapeOfHyp; +} + +//======================================================================= +//function : IsQuadraticMesh +//purpose : Check mesh without geometry for: if all elements on this shape are quadratic, +// quadratic elements will be created. +// Used then generated 3D mesh without geometry. +//======================================================================= + +SMESH_MesherHelper:: MType SMESH_MesherHelper::IsQuadraticMesh() +{ + int NbAllEdgsAndFaces=0; + int NbQuadFacesAndEdgs=0; + int NbFacesAndEdges=0; + //All faces and edges + NbAllEdgsAndFaces = myMesh->NbEdges() + myMesh->NbFaces(); + if ( NbAllEdgsAndFaces == 0 ) + return SMESH_MesherHelper::LINEAR; + + //Quadratic faces and edges + NbQuadFacesAndEdgs = myMesh->NbEdges(ORDER_QUADRATIC) + myMesh->NbFaces(ORDER_QUADRATIC); + + //Linear faces and edges + NbFacesAndEdges = myMesh->NbEdges(ORDER_LINEAR) + myMesh->NbFaces(ORDER_LINEAR); + + if (NbAllEdgsAndFaces == NbQuadFacesAndEdgs) { + //Quadratic mesh + return SMESH_MesherHelper::QUADRATIC; + } + else if (NbAllEdgsAndFaces == NbFacesAndEdges) { + //Linear mesh + return SMESH_MesherHelper::LINEAR; + } + else + //Mesh with both type of elements + return SMESH_MesherHelper::COMP; +} + +//======================================================================= +//function : GetOtherParam +//purpose : Return an alternative parameter for a node on seam +//======================================================================= + +double SMESH_MesherHelper::GetOtherParam(const double param) const +{ + int i = myParIndex & U_periodic ? 0 : 1; + return fabs(param-myPar1[i]) < fabs(param-myPar2[i]) ? myPar2[i] : myPar1[i]; +} + +namespace { + + //======================================================================= + /*! + * \brief Iterator on ancestors of the given type + */ + //======================================================================= + + struct TAncestorsIterator : public SMDS_Iterator + { + TopTools_ListIteratorOfListOfShape _ancIter; + TopAbs_ShapeEnum _type; + TopTools_MapOfShape _encountered; + TAncestorsIterator( const TopTools_ListOfShape& ancestors, TopAbs_ShapeEnum type) + : _ancIter( ancestors ), _type( type ) + { + if ( _ancIter.More() ) { + if ( _ancIter.Value().ShapeType() != _type ) next(); + else _encountered.Add( _ancIter.Value() ); + } + } + virtual bool more() + { + return _ancIter.More(); + } + virtual const TopoDS_Shape* next() + { + const TopoDS_Shape* s = _ancIter.More() ? & _ancIter.Value() : 0; + if ( _ancIter.More() ) + for ( _ancIter.Next(); _ancIter.More(); _ancIter.Next()) + if ( _ancIter.Value().ShapeType() == _type && _encountered.Add( _ancIter.Value() )) + break; + return s; + } + }; + +} // namespace + +//======================================================================= +/*! + * \brief Return iterator on ancestors of the given type + */ +//======================================================================= + +PShapeIteratorPtr SMESH_MesherHelper::GetAncestors(const TopoDS_Shape& shape, + const SMESH_Mesh& mesh, + TopAbs_ShapeEnum ancestorType) +{ + return PShapeIteratorPtr( new TAncestorsIterator( mesh.GetAncestors(shape), ancestorType)); +} + +//======================================================================= +//function : GetCommonAncestor +//purpose : Find a common ancestors of two shapes of the given type +//======================================================================= + +TopoDS_Shape SMESH_MesherHelper::GetCommonAncestor(const TopoDS_Shape& shape1, + const TopoDS_Shape& shape2, + const SMESH_Mesh& mesh, + TopAbs_ShapeEnum ancestorType) +{ + TopoDS_Shape commonAnc; + if ( !shape1.IsNull() && !shape2.IsNull() ) + { + if ( shape1.ShapeType() == ancestorType && IsSubShape( shape2, shape1 )) + return shape1; + if ( shape2.ShapeType() == ancestorType && IsSubShape( shape1, shape2 )) + return shape2; + + PShapeIteratorPtr ancIt = GetAncestors( shape1, mesh, ancestorType ); + while ( const TopoDS_Shape* anc = ancIt->next() ) + if ( IsSubShape( shape2, *anc )) + { + commonAnc = *anc; + break; + } + } + return commonAnc; +} + +//#include + +//======================================================================= +namespace { // Structures used by FixQuadraticElements() +//======================================================================= + +#define __DMP__(txt) \ + // cout << txt +#define MSG(txt) __DMP__(txt< < 1/15 * + return middleNodeMove2 < 1/15./15. * linkLen2; + } + + struct QFace; + // --------------------------------------- + /*! + * \brief Quadratic link knowing its faces + */ + struct QLink: public SMESH_TLink + { + const SMDS_MeshNode* _mediumNode; + mutable vector _faces; + mutable gp_Vec _nodeMove; + mutable int _nbMoves; + mutable bool _is2dFixed; // is moved along surface or in 3D + + QLink(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshNode* nm): + SMESH_TLink( n1,n2 ), _mediumNode(nm), _nodeMove(0,0,0), _nbMoves(0) { + _faces.reserve(4); + _nodeMove = MediumPnt() - MiddlePnt(); + _is2dFixed = ( MediumPos() != SMDS_TOP_FACE ); + } + void SetContinuesFaces() const; + const QFace* GetContinuesFace( const QFace* face ) const; + bool OnBoundary() const; + gp_XYZ MiddlePnt() const { return ( XYZ( node1() ) + XYZ( node2() )) / 2.; } + gp_XYZ MediumPnt() const { return XYZ( _mediumNode ); } + + SMDS_TypeOfPosition MediumPos() const + { return _mediumNode->GetPosition()->GetTypeOfPosition(); } + SMDS_TypeOfPosition EndPos(bool isSecond) const + { return (isSecond ? node2() : node1())->GetPosition()->GetTypeOfPosition(); } + const SMDS_MeshNode* EndPosNode(SMDS_TypeOfPosition pos) const + { return EndPos(0) == pos ? node1() : EndPos(1) == pos ? node2() : 0; } + + void Move(const gp_Vec& move, bool sum=false, bool is2dFixed=false) const + { _nodeMove += move; _nbMoves += sum ? (_nbMoves==0) : 1; _is2dFixed |= is2dFixed; } + gp_XYZ Move() const { return _nodeMove.XYZ() / _nbMoves; } + bool IsMoved() const { return (_nbMoves > 0 /*&& !IsStraight()*/); } + bool IsFixedOnSurface() const { return _is2dFixed; } + bool IsStraight() const + { return isStraightLink( (XYZ(node1())-XYZ(node2())).SquareModulus(), + _nodeMove.SquareMagnitude()); + } + bool operator<(const QLink& other) const { + return (node1()->GetID() == other.node1()->GetID() ? + node2()->GetID() < other.node2()->GetID() : + node1()->GetID() < other.node1()->GetID()); + } +// struct PtrComparator { +// bool operator() (const QLink* l1, const QLink* l2 ) const { return *l1 < *l2; } +// }; + }; + // --------------------------------------------------------- + /*! + * \brief Link in the chain of links; it connects two faces + */ + struct TChainLink + { + const QLink* _qlink; + mutable const QFace* _qfaces[2]; + + TChainLink(const QLink* qlink=0):_qlink(qlink) { + _qfaces[0] = _qfaces[1] = 0; + } + void SetFace(const QFace* face) const { int iF = _qfaces[0] ? 1 : 0; _qfaces[iF]=face; } + + bool IsBoundary() const { return !_qfaces[1]; } + + void RemoveFace( const QFace* face ) const + { _qfaces[(face == _qfaces[1])] = 0; if (!_qfaces[0]) std::swap(_qfaces[0],_qfaces[1]); } + + const QFace* NextFace( const QFace* f ) const + { return _qfaces[0]==f ? _qfaces[1] : _qfaces[0]; } + + const SMDS_MeshNode* NextNode( const SMDS_MeshNode* n ) const + { return n == _qlink->node1() ? _qlink->node2() : _qlink->node1(); } + + bool operator<(const TChainLink& other) const { return *_qlink < *other._qlink; } + + operator bool() const { return (_qlink); } + + const QLink* operator->() const { return _qlink; } + + gp_Vec Normal() const; + + bool IsStraight() const; + }; + // -------------------------------------------------------------------- + typedef list< TChainLink > TChain; + typedef set < TChainLink > TLinkSet; + typedef TLinkSet::const_iterator TLinkInSet; + + const int theFirstStep = 5; + + enum { ERR_OK, ERR_TRI, ERR_PRISM, ERR_UNKNOWN }; // errors of QFace::GetLinkChain() + // -------------------------------------------------------------------- + /*! + * \brief Quadratic face shared by two volumes and bound by QLinks + */ + struct QFace: public TIDSortedNodeSet + { + mutable const SMDS_MeshElement* _volumes[2]; + mutable vector< const QLink* > _sides; + mutable bool _sideIsAdded[4]; // added in chain of links + gp_Vec _normal; +#ifdef _DEBUG_ + mutable const SMDS_MeshElement* _face; +#endif + + QFace( const vector< const QLink*>& links, const SMDS_MeshElement* face=0 ); + + void SetVolume(const SMDS_MeshElement* v) const { _volumes[ _volumes[0] ? 1 : 0 ] = v; } + + int NbVolumes() const { return !_volumes[0] ? 0 : !_volumes[1] ? 1 : 2; } + + void AddSelfToLinks() const { + for ( int i = 0; i < _sides.size(); ++i ) + _sides[i]->_faces.push_back( this ); + } + int LinkIndex( const QLink* side ) const { + for (int i=0; i<_sides.size(); ++i ) if ( _sides[i] == side ) return i; + return -1; + } + bool GetLinkChain( int iSide, TChain& chain, SMDS_TypeOfPosition pos, int& err) const; + + bool GetLinkChain( TChainLink& link, TChain& chain, SMDS_TypeOfPosition pos, int& err) const + { + int i = LinkIndex( link._qlink ); + if ( i < 0 ) return true; + _sideIsAdded[i] = true; + link.SetFace( this ); + // continue from opposite link + return GetLinkChain( (i+2)%_sides.size(), chain, pos, err ); + } + bool IsBoundary() const { return !_volumes[1]; } + + bool Contains( const SMDS_MeshNode* node ) const { return count(node); } + + bool IsSpoiled(const QLink* bentLink ) const; + + TLinkInSet GetBoundaryLink( const TLinkSet& links, + const TChainLink& avoidLink, + TLinkInSet * notBoundaryLink = 0, + const SMDS_MeshNode* nodeToContain = 0, + bool * isAdjacentUsed = 0, + int nbRecursionsLeft = -1) const; + + TLinkInSet GetLinkByNode( const TLinkSet& links, + const TChainLink& avoidLink, + const SMDS_MeshNode* nodeToContain) const; + + const SMDS_MeshNode* GetNodeInFace() const { + for ( int iL = 0; iL < _sides.size(); ++iL ) + if ( _sides[iL]->MediumPos() == SMDS_TOP_FACE ) return _sides[iL]->_mediumNode; + return 0; + } + + gp_Vec LinkNorm(const int i, SMESH_MesherHelper* theFaceHelper=0) const; + + double MoveByBoundary( const TChainLink& theLink, + const gp_Vec& theRefVec, + const TLinkSet& theLinks, + SMESH_MesherHelper* theFaceHelper=0, + const double thePrevLen=0, + const int theStep=theFirstStep, + gp_Vec* theLinkNorm=0, + double theSign=1.0) const; + }; + + //================================================================================ + /*! + * \brief Dump QLink and QFace + */ + ostream& operator << (ostream& out, const QLink& l) + { + out <<"QLink nodes: " + << l.node1()->GetID() << " - " + << l._mediumNode->GetID() << " - " + << l.node2()->GetID() << endl; + return out; + } + ostream& operator << (ostream& out, const QFace& f) + { + out <<"QFace nodes: "/*<< &f << " "*/; + for ( TIDSortedNodeSet::const_iterator n = f.begin(); n != f.end(); ++n ) + out << (*n)->GetID() << " "; + out << " \tvolumes: " + << (f._volumes[0] ? f._volumes[0]->GetID() : 0) << " " + << (f._volumes[1] ? f._volumes[1]->GetID() : 0); + out << " \tNormal: "<< f._normal.X() <<", "<& links, const SMDS_MeshElement* face ) + { + _volumes[0] = _volumes[1] = 0; + _sides = links; + _sideIsAdded[0]=_sideIsAdded[1]=_sideIsAdded[2]=_sideIsAdded[3]=false; + _normal.SetCoord(0,0,0); + for ( int i = 1; i < _sides.size(); ++i ) { + const QLink *l1 = _sides[i-1], *l2 = _sides[i]; + insert( l1->node1() ); insert( l1->node2() ); + // compute normal + gp_Vec v1( XYZ( l1->node2()), XYZ( l1->node1())); + gp_Vec v2( XYZ( l2->node1()), XYZ( l2->node2())); + if ( l1->node1() != l2->node1() && l1->node2() != l2->node2() ) + v1.Reverse(); + _normal += v1 ^ v2; + } + double normSqSize = _normal.SquareMagnitude(); + if ( normSqSize > numeric_limits::min() ) + _normal /= sqrt( normSqSize ); + else + _normal.SetCoord(1e-33,0,0); + +#ifdef _DEBUG_ + _face = face; +#endif + } + //================================================================================ + /*! + * \brief Make up a chain of links + * \param iSide - link to add first + * \param chain - chain to fill in + * \param pos - postion of medium nodes the links should have + * \param error - out, specifies what is wrong + * \retval bool - false if valid chain can't be built; "valid" means that links + * of the chain belongs to rectangles bounding hexahedrons + */ + //================================================================================ + + bool QFace::GetLinkChain( int iSide, TChain& chain, SMDS_TypeOfPosition pos, int& error) const + { + if ( iSide >= _sides.size() ) // wrong argument iSide + return false; + if ( _sideIsAdded[ iSide ]) // already in chain + return true; + + if ( _sides.size() != 4 ) { // triangle - visit all my continous faces + MSGBEG( *this ); + TLinkSet links; + list< const QFace* > faces( 1, this ); + while ( !faces.empty() ) { + const QFace* face = faces.front(); + for ( int i = 0; i < face->_sides.size(); ++i ) { + if ( !face->_sideIsAdded[i] && face->_sides[i] ) { + face->_sideIsAdded[i] = true; + // find a face side in the chain + TLinkInSet chLink = links.insert( TChainLink(face->_sides[i])).first; +// TChain::iterator chLink = chain.begin(); +// for ( ; chLink != chain.end(); ++chLink ) +// if ( chLink->_qlink == face->_sides[i] ) +// break; +// if ( chLink == chain.end() ) +// chLink = chain.insert( chain.begin(), TChainLink(face->_sides[i])); + // add a face to a chained link and put a continues face in the queue + chLink->SetFace( face ); + if ( face->_sides[i]->MediumPos() == pos ) + if ( const QFace* contFace = face->_sides[i]->GetContinuesFace( face )) + if ( contFace->_sides.size() == 3 ) + faces.push_back( contFace ); + } + } + faces.pop_front(); + } + if ( error < ERR_TRI ) + error = ERR_TRI; + chain.insert( chain.end(), links.begin(),links.end() ); + return false; + } + _sideIsAdded[iSide] = true; // not to add this link to chain again + const QLink* link = _sides[iSide]; + if ( !link) + return true; + + // add link into chain + TChain::iterator chLink = chain.insert( chain.begin(), TChainLink(link)); + chLink->SetFace( this ); + MSGBEG( *this ); + + // propagate from a quadrangle to neighbour faces + if ( link->MediumPos() >= pos ) { + int nbLinkFaces = link->_faces.size(); + if ( nbLinkFaces == 4 || (/*nbLinkFaces < 4 && */link->OnBoundary())) { + // hexahedral mesh or boundary quadrangles - goto a continous face + if ( const QFace* f = link->GetContinuesFace( this )) + if ( f->_sides.size() == 4 ) + return f->GetLinkChain( *chLink, chain, pos, error ); + } + else { + TChainLink chLink(link); // side face of prismatic mesh - visit all faces of iSide + for ( int i = 0; i < nbLinkFaces; ++i ) + if ( link->_faces[i] ) + link->_faces[i]->GetLinkChain( chLink, chain, pos, error ); + if ( error < ERR_PRISM ) + error = ERR_PRISM; + return false; + } + } + return true; + } + + //================================================================================ + /*! + * \brief Return a boundary link of the triangle face + * \param links - set of all links + * \param avoidLink - link not to return + * \param notBoundaryLink - out, neither the returned link nor avoidLink + * \param nodeToContain - node the returned link must contain; if provided, search + * also performed on adjacent faces + * \param isAdjacentUsed - returns true if link is found in adjacent faces + * \param nbRecursionsLeft - to limit recursion + */ + //================================================================================ + + TLinkInSet QFace::GetBoundaryLink( const TLinkSet& links, + const TChainLink& avoidLink, + TLinkInSet * notBoundaryLink, + const SMDS_MeshNode* nodeToContain, + bool * isAdjacentUsed, + int nbRecursionsLeft) const + { + TLinkInSet linksEnd = links.end(), boundaryLink = linksEnd; + + typedef list< pair< const QFace*, TLinkInSet > > TFaceLinkList; + TFaceLinkList adjacentFaces; + + for ( int iL = 0; iL < _sides.size(); ++iL ) + { + if ( avoidLink._qlink == _sides[iL] ) + continue; + TLinkInSet link = links.find( _sides[iL] ); + if ( link == linksEnd ) continue; + if ( (*link)->MediumPos() > SMDS_TOP_FACE ) + continue; // We work on faces here, don't go inside a solid + + // check link + if ( link->IsBoundary() ) { + if ( !nodeToContain || + (*link)->node1() == nodeToContain || + (*link)->node2() == nodeToContain ) + { + boundaryLink = link; + if ( !notBoundaryLink ) break; + } + } + else if ( notBoundaryLink ) { + *notBoundaryLink = link; + if ( boundaryLink != linksEnd ) break; + } + + if ( boundaryLink == linksEnd && nodeToContain ) // collect adjacent faces + if ( const QFace* adj = link->NextFace( this )) + if ( adj->Contains( nodeToContain )) + adjacentFaces.push_back( make_pair( adj, link )); + } + + if ( isAdjacentUsed ) *isAdjacentUsed = false; + if ( boundaryLink == linksEnd && nodeToContain && nbRecursionsLeft) // check adjacent faces + { + if ( nbRecursionsLeft < 0 ) + nbRecursionsLeft = nodeToContain->NbInverseElements(); + TFaceLinkList::iterator adj = adjacentFaces.begin(); + for ( ; boundaryLink == linksEnd && adj != adjacentFaces.end(); ++adj ) + boundaryLink = adj->first->GetBoundaryLink( links, *(adj->second), 0, nodeToContain, + isAdjacentUsed, nbRecursionsLeft-1); + if ( isAdjacentUsed ) *isAdjacentUsed = true; + } + return boundaryLink; + } + //================================================================================ + /*! + * \brief Return a link ending at the given node but not avoidLink + */ + //================================================================================ + + TLinkInSet QFace::GetLinkByNode( const TLinkSet& links, + const TChainLink& avoidLink, + const SMDS_MeshNode* nodeToContain) const + { + for ( int i = 0; i < _sides.size(); ++i ) + if ( avoidLink._qlink != _sides[i] && + (_sides[i]->node1() == nodeToContain || _sides[i]->node2() == nodeToContain )) + return links.find( _sides[ i ]); + return links.end(); + } + + //================================================================================ + /*! + * \brief Return normal to the i-th side pointing outside the face + */ + //================================================================================ + + gp_Vec QFace::LinkNorm(const int i, SMESH_MesherHelper* /*uvHelper*/) const + { + gp_Vec norm = _normal ^ gp_Vec( XYZ(_sides[i]->node1()), XYZ(_sides[i]->node2())); + gp_XYZ pIn = ( _sides[ (i+1)%3 ]->MiddlePnt() + + _sides[ (i+2)%3 ]->MiddlePnt() ) / 2.; + gp_Vec vecOut = ( _sides[i]->MiddlePnt() - pIn ); + + if ( norm * vecOut < 0 ) + norm.Reverse(); + double mag2 = norm.SquareMagnitude(); + if ( mag2 > numeric_limits::min() ) + norm /= sqrt( mag2 ); + return norm; + } + //================================================================================ + /*! + * \brief Move medium node of theLink according to its distance from boundary + * \param theLink - link to fix + * \param theRefVec - movement of boundary + * \param theLinks - all adjacent links of continous triangles + * \param theFaceHelper - helper is not used so far + * \param thePrevLen - distance from the boundary + * \param theStep - number of steps till movement propagation limit + * \param theLinkNorm - out normal to theLink + * \param theSign - 1 or -1 depending on movement of boundary + * \retval double - distance from boundary to propagation limit or other boundary + */ + //================================================================================ + + double QFace::MoveByBoundary( const TChainLink& theLink, + const gp_Vec& theRefVec, + const TLinkSet& theLinks, + SMESH_MesherHelper* theFaceHelper, + const double thePrevLen, + const int theStep, + gp_Vec* theLinkNorm, + double theSign) const + { + if ( !theStep ) + return thePrevLen; // propagation limit reached + + int iL; // index of theLink + for ( iL = 0; iL < _sides.size(); ++iL ) + if ( theLink._qlink == _sides[ iL ]) + break; + + MSG(string(theStep,'.')<<" Ref( "<NextFace( this ); + f2 = link2->NextFace( this ); + + isBndLink1 = ( theLink->MediumPos() > (*link1)->MediumPos() ); + isBndLink2 = ( theLink->MediumPos() > (*link2)->MediumPos() ); + if ( theStep == theFirstStep ) // (issue 22541) quad-dominant mesh + { + if ( !isBndLink1 && !f1 ) + f1 = (*link1)->GetContinuesFace( this ); // get a quadrangle face + if ( !isBndLink2 && !f2 ) + f2 = (*link2)->GetContinuesFace( this ); + } + } + else if ( _sides.size() < 4 ) + return thePrevLen; + + // propagate to adjacent faces till limit step or boundary + double len1 = thePrevLen + (theLink->MiddlePnt() - _sides[iL1]->MiddlePnt()).Modulus(); + double len2 = thePrevLen + (theLink->MiddlePnt() - _sides[iL2]->MiddlePnt()).Modulus(); + gp_Vec linkDir1(0,0,0); // initialize to avoid valgrind error ("Conditional jump...") + gp_Vec linkDir2(0,0,0); + try { + OCC_CATCH_SIGNALS; + if ( f1 && !isBndLink1 ) + len1 = f1->MoveByBoundary + ( *link1, theRefVec, theLinks, theFaceHelper, len1, theStep-1, &linkDir1, theSign); + else + linkDir1 = LinkNorm( iL1/*, theFaceHelper*/ ); + } catch (...) { + MSG( " --------------- EXCEPTION"); + return thePrevLen; + } + try { + OCC_CATCH_SIGNALS; + if ( f2 && !isBndLink2 ) + len2 = f2->MoveByBoundary + ( *link2, theRefVec, theLinks, theFaceHelper, len2, theStep-1, &linkDir2, theSign); + else + linkDir2 = LinkNorm( iL2/*, theFaceHelper*/ ); + } catch (...) { + MSG( " --------------- EXCEPTION"); + return thePrevLen; + } + + double fullLen = 0; + if ( theStep != theFirstStep ) + { + // choose chain length by direction of propagation most codirected with theRefVec + bool choose1 = ( theRefVec * linkDir1 * theSign > theRefVec * linkDir2 * theSign ); + fullLen = choose1 ? len1 : len2; + double r = thePrevLen / fullLen; + + gp_Vec move = linkNorm * refProj * ( 1 - r ); + theLink->Move( move, /*sum=*/true ); + + MSG(string(theStep,'.')<<" Move "<< theLink->_mediumNode->GetID()<< + " by " << refProj * ( 1 - r ) << " following " << + (choose1 ? *link1->_qlink : *link2->_qlink)); // warning: link1 can be invalid + + if ( theLinkNorm ) *theLinkNorm = linkNorm; + } + return fullLen; + } + + //================================================================================ + /*! + * \brief Checks if the face is distorted due to bentLink + */ + //================================================================================ + + bool QFace::IsSpoiled(const QLink* bentLink ) const + { + // code is valid for convex faces only + gp_XYZ gc(0,0,0); + for ( TIDSortedNodeSet::const_iterator n = begin(); n!=end(); ++n) + gc += XYZ( *n ) / size(); + for (unsigned i = 0; i < _sides.size(); ++i ) + { + if ( _sides[i] == bentLink ) continue; + gp_Vec linkNorm = _normal ^ gp_Vec( XYZ(_sides[i]->node1()), XYZ(_sides[i]->node2())); + gp_Vec vecOut( gc, _sides[i]->MiddlePnt() ); + if ( linkNorm * vecOut < 0 ) + linkNorm.Reverse(); + double mag2 = linkNorm.SquareMagnitude(); + if ( mag2 > numeric_limits::min() ) + linkNorm /= sqrt( mag2 ); + gp_Vec vecBent ( _sides[i]->MiddlePnt(), bentLink->MediumPnt()); + gp_Vec vecStraight( _sides[i]->MiddlePnt(), bentLink->MiddlePnt()); + if ( vecBent * linkNorm > -0.1*vecStraight.Magnitude() ) + return true; + } + return false; + + } + + //================================================================================ + /*! + * \brief Find pairs of continues faces + */ + //================================================================================ + + void QLink::SetContinuesFaces() const + { + // x0 x - QLink, [-|] - QFace, v - volume + // v0 | v1 + // | Between _faces of link x2 two vertical faces are continues + // x1----x2-----x3 and two horizontal faces are continues. We set vertical faces + // | to _faces[0] and _faces[1] and horizontal faces to + // v2 | v3 _faces[2] and _faces[3] (or vise versa). + // x4 + + if ( _faces.empty() ) + return; + int iFaceCont = -1, nbBoundary = 0, iBoundary[2]={-1,-1}; + if ( _faces[0]->IsBoundary() ) + iBoundary[ nbBoundary++ ] = 0; + for ( int iF = 1; iFaceCont < 0 && iF < _faces.size(); ++iF ) + { + // look for a face bounding none of volumes bound by _faces[0] + bool sameVol = false; + int nbVol = _faces[iF]->NbVolumes(); + for ( int iV = 0; !sameVol && iV < nbVol; ++iV ) + sameVol = ( _faces[iF]->_volumes[iV] == _faces[0]->_volumes[0] || + _faces[iF]->_volumes[iV] == _faces[0]->_volumes[1]); + if ( !sameVol ) + iFaceCont = iF; + if ( _faces[iF]->IsBoundary() ) + iBoundary[ nbBoundary++ ] = iF; + } + // Set continues faces: arrange _faces to have + // _faces[0] continues to _faces[1] + // _faces[2] continues to _faces[3] + if ( nbBoundary == 2 ) // bnd faces are continues + { + if (( iBoundary[0] < 2 ) != ( iBoundary[1] < 2 )) + { + int iNear0 = iBoundary[0] < 2 ? 1-iBoundary[0] : 5-iBoundary[0]; + std::swap( _faces[ iBoundary[1] ], _faces[iNear0] ); + } + } + else if ( iFaceCont > 0 ) // continues faces found + { + if ( iFaceCont != 1 ) + std::swap( _faces[1], _faces[iFaceCont] ); + } + else if ( _faces.size() > 1 ) // not found, set NULL by the first face + { + _faces.insert( ++_faces.begin(), (QFace*) 0 ); + } + } + //================================================================================ + /*! + * \brief Return a face continues to the given one + */ + //================================================================================ + + const QFace* QLink::GetContinuesFace( const QFace* face ) const + { + for ( int i = 0; i < _faces.size(); ++i ) { + if ( _faces[i] == face ) { + int iF = i < 2 ? 1-i : 5-i; + return iF < _faces.size() ? _faces[iF] : 0; + } + } + return 0; + } + //================================================================================ + /*! + * \brief True if link is on mesh boundary + */ + //================================================================================ + + bool QLink::OnBoundary() const + { + for ( int i = 0; i < _faces.size(); ++i ) + if (_faces[i] && _faces[i]->IsBoundary()) return true; + return false; + } + //================================================================================ + /*! + * \brief Return normal of link of the chain + */ + //================================================================================ + + gp_Vec TChainLink::Normal() const { + gp_Vec norm; + if (_qfaces[0]) norm = _qfaces[0]->_normal; + if (_qfaces[1]) norm += _qfaces[1]->_normal; + return norm; + } + //================================================================================ + /*! + * \brief Test link curvature taking into account size of faces + */ + //================================================================================ + + bool TChainLink::IsStraight() const + { + bool isStraight = _qlink->IsStraight(); + if ( isStraight && _qfaces[0] && !_qfaces[1] ) + { + int i = _qfaces[0]->LinkIndex( _qlink ); + int iOpp = ( i + 2 ) % _qfaces[0]->_sides.size(); + gp_XYZ mid1 = _qlink->MiddlePnt(); + gp_XYZ mid2 = _qfaces[0]->_sides[ iOpp ]->MiddlePnt(); + double faceSize2 = (mid1-mid2).SquareModulus(); + isStraight = _qlink->_nodeMove.SquareMagnitude() < 1/10./10. * faceSize2; + } + return isStraight; + } + + //================================================================================ + /*! + * \brief Move medium nodes of vertical links of pentahedrons adjacent by side faces + */ + //================================================================================ + + void fixPrism( TChain& allLinks ) + { + // separate boundary links from internal ones + typedef set QLinkSet; + QLinkSet interLinks, bndLinks1, bndLink2; + + bool isCurved = false; + for ( TChain::iterator lnk = allLinks.begin(); lnk != allLinks.end(); ++lnk ) { + if ( (*lnk)->OnBoundary() ) + bndLinks1.insert( lnk->_qlink ); + else + interLinks.insert( lnk->_qlink ); + isCurved = isCurved || !lnk->IsStraight(); + } + if ( !isCurved ) + return; // no need to move + + QLinkSet *curBndLinks = &bndLinks1, *newBndLinks = &bndLink2; + + while ( !interLinks.empty() && !curBndLinks->empty() ) + { + // propagate movement from boundary links to connected internal links + QLinkSet::iterator bnd = curBndLinks->begin(), bndEnd = curBndLinks->end(); + for ( ; bnd != bndEnd; ++bnd ) + { + const QLink* bndLink = *bnd; + for ( int i = 0; i < bndLink->_faces.size(); ++i ) // loop on faces of bndLink + { + const QFace* face = bndLink->_faces[i]; // quadrange lateral face of a prism + if ( !face ) continue; + // find and move internal link opposite to bndLink within the face + int interInd = ( face->LinkIndex( bndLink ) + 2 ) % face->_sides.size(); + const QLink* interLink = face->_sides[ interInd ]; + QLinkSet::iterator pInterLink = interLinks.find( interLink ); + if ( pInterLink == interLinks.end() ) continue; // not internal link + interLink->Move( bndLink->_nodeMove ); + // treated internal links become new boundary ones + interLinks.erase( pInterLink ); + newBndLinks->insert( interLink ); + } + } + curBndLinks->clear(); + std::swap( curBndLinks, newBndLinks ); + } + } + + //================================================================================ + /*! + * \brief Fix links of continues triangles near curved boundary + */ + //================================================================================ + + void fixTriaNearBoundary( TChain & allLinks, SMESH_MesherHelper& /*helper*/) + { + if ( allLinks.empty() ) return; + + TLinkSet linkSet( allLinks.begin(), allLinks.end()); + TLinkInSet linkIt = linkSet.begin(), linksEnd = linkSet.end(); + + for ( linkIt = linkSet.begin(); linkIt != linksEnd; ++linkIt) + { + if ( linkIt->IsBoundary() && !linkIt->IsStraight() && linkIt->_qfaces[0]) + { + // move iff a boundary link is bent towards inside of a face (issue 0021084) + const QFace* face = linkIt->_qfaces[0]; + gp_XYZ pIn = ( face->_sides[0]->MiddlePnt() + + face->_sides[1]->MiddlePnt() + + face->_sides[2]->MiddlePnt() ) / 3.; + gp_XYZ insideDir( pIn - (*linkIt)->MiddlePnt()); + bool linkBentInside = ((*linkIt)->_nodeMove.Dot( insideDir ) > 0 ); + //if ( face->IsSpoiled( linkIt->_qlink )) + if ( linkBentInside ) + face->MoveByBoundary( *linkIt, (*linkIt)->_nodeMove, linkSet ); + } + } + } + + //================================================================================ + /*! + * \brief Detect rectangular structure of links and build chains from them + */ + //================================================================================ + + enum TSplitTriaResult { + _OK, _NO_CORNERS, _FEW_ROWS, _MANY_ROWS, _NO_SIDELINK, _BAD_MIDQUAD, _NOT_RECT, + _NO_MIDQUAD, _NO_UPTRIA, _BAD_SET_SIZE, _BAD_CORNER, _BAD_START, _NO_BOTLINK, _TWISTED_CHAIN }; + + TSplitTriaResult splitTrianglesIntoChains( TChain & allLinks, + vector< TChain> & resultChains, + SMDS_TypeOfPosition pos ) + { + // put links in the set and evalute number of result chains by number of boundary links + TLinkSet linkSet; + int nbBndLinks = 0; + for ( TChain::iterator lnk = allLinks.begin(); lnk != allLinks.end(); ++lnk ) { + linkSet.insert( *lnk ); + nbBndLinks += lnk->IsBoundary(); + } + resultChains.clear(); + resultChains.reserve( nbBndLinks / 2 ); + + TLinkInSet linkIt, linksEnd = linkSet.end(); + + // find a boundary link with corner node; corner node has position pos-2 + // i.e. SMDS_TOP_VERTEX for links on faces and SMDS_TOP_EDGE for + // links in volume + SMDS_TypeOfPosition cornerPos = SMDS_TypeOfPosition(pos-2); + const SMDS_MeshNode* corner = 0; + for ( linkIt = linkSet.begin(); linkIt != linksEnd; ++linkIt ) + if ( linkIt->IsBoundary() && (corner = (*linkIt)->EndPosNode(cornerPos))) + break; + if ( !corner) + return _NO_CORNERS; + + TLinkInSet startLink = linkIt; + const SMDS_MeshNode* startCorner = corner; + vector< TChain* > rowChains; + int iCol = 0; + + while ( startLink != linksEnd) // loop on columns + { + // We suppose we have a rectangular structure like shown here. We have found a + // corner of the rectangle (startCorner) and a boundary link sharing + // |/ |/ | the startCorner (startLink). We are going to loop on rows of the + // --o---o---o structure making several chains at once. One chain (columnChain) + // |\ | /| starts at startLink and continues upward (we look at the structure + // \ | \ | / | from such point that startLink is on the bottom of the structure). + // \| \|/ | While going upward we also fill horizontal chains (rowChains) we + // --o---o---o encounter. + // /|\ |\ | + // / | \ | \ | startCorner + // | \| \|,' + // --o---o---o + // `.startLink + + if ( resultChains.size() == nbBndLinks / 2 ) + return _NOT_RECT; + resultChains.push_back( TChain() ); + TChain& columnChain = resultChains.back(); + + TLinkInSet botLink = startLink; // current horizontal link to go up from + corner = startCorner; // current corner the botLink ends at + int iRow = 0; + while ( botLink != linksEnd ) // loop on rows + { + // add botLink to the columnChain + columnChain.push_back( *botLink ); + + const QFace* botTria = botLink->_qfaces[0]; // bottom triangle bound by botLink + if ( !botTria ) + { // the column ends + if ( botLink == startLink ) + return _TWISTED_CHAIN; // issue 0020951 + linkSet.erase( botLink ); + if ( iRow != rowChains.size() ) + return _FEW_ROWS; // different nb of rows in columns + break; + } + // find the link dividing the quadrangle (midQuadLink) and vertical boundary + // link ending at (sideLink); there are two cases: + // 1) midQuadLink does not end at , then we easily find it by botTria, + // since midQuadLink is not at boundary while sideLink is. + // 2) midQuadLink ends at + bool isCase2; + TLinkInSet midQuadLink = linksEnd; + TLinkInSet sideLink = botTria->GetBoundaryLink( linkSet, *botLink, &midQuadLink, + corner, &isCase2 ); + if ( isCase2 ) { // find midQuadLink among links of botTria + midQuadLink = botTria->GetLinkByNode( linkSet, *botLink, corner ); + if ( midQuadLink->IsBoundary() ) + return _BAD_MIDQUAD; + } + if ( sideLink == linksEnd || midQuadLink == linksEnd || sideLink == midQuadLink ) + return sideLink == linksEnd ? _NO_SIDELINK : _NO_MIDQUAD; + + // fill chains + columnChain.push_back( *midQuadLink ); + if ( iRow >= rowChains.size() ) { + if ( iCol > 0 ) + return _MANY_ROWS; // different nb of rows in columns + if ( resultChains.size() == nbBndLinks / 2 ) + return _NOT_RECT; + resultChains.push_back( TChain() ); + rowChains.push_back( & resultChains.back() ); + } + rowChains[iRow]->push_back( *sideLink ); + rowChains[iRow]->push_back( *midQuadLink ); + + const QFace* upTria = midQuadLink->NextFace( botTria ); // upper tria of the rectangle + if ( !upTria) + return _NO_UPTRIA; + if ( iRow == 0 ) { + // prepare startCorner and startLink for the next column + startCorner = startLink->NextNode( startCorner ); + if (isCase2) + startLink = botTria->GetBoundaryLink( linkSet, *botLink, 0, startCorner ); + else + startLink = upTria->GetBoundaryLink( linkSet, *midQuadLink, 0, startCorner ); + // check if no more columns remains + if ( startLink != linksEnd ) { + const SMDS_MeshNode* botNode = startLink->NextNode( startCorner ); + if ( (isCase2 ? botTria : upTria)->Contains( botNode )) + startLink = linksEnd; // startLink bounds upTria or botTria + else if ( startLink == botLink || startLink == midQuadLink || startLink == sideLink ) + return _BAD_START; + } + } + // find bottom link and corner for the next row + corner = sideLink->NextNode( corner ); + // next bottom link ends at the new corner + linkSet.erase( botLink ); + botLink = upTria->GetLinkByNode( linkSet, (isCase2 ? *sideLink : *midQuadLink), corner ); + if ( botLink == linksEnd || botLink == midQuadLink || botLink == sideLink) + return _NO_BOTLINK; + if ( midQuadLink == startLink || sideLink == startLink ) + return _TWISTED_CHAIN; // issue 0020951 + linkSet.erase( midQuadLink ); + linkSet.erase( sideLink ); + + // make faces neighboring the found ones be boundary + if ( startLink != linksEnd ) { + const QFace* tria = isCase2 ? botTria : upTria; + for ( int iL = 0; iL < 3; ++iL ) { + linkIt = linkSet.find( tria->_sides[iL] ); + if ( linkIt != linksEnd ) + linkIt->RemoveFace( tria ); + } + } + if ( botLink->_qfaces[0] == upTria || botLink->_qfaces[1] == upTria ) + botLink->RemoveFace( upTria ); // make next botTria first in vector + + iRow++; + } // loop on rows + + iCol++; + } + // In the linkSet, there must remain the last links of rowChains; add them + if ( linkSet.size() != rowChains.size() ) + return _BAD_SET_SIZE; + for ( int iRow = 0; iRow < rowChains.size(); ++iRow ) { + // find the link (startLink) ending at startCorner + corner = 0; + for ( startLink = linkSet.begin(); startLink != linksEnd; ++startLink ) { + if ( (*startLink)->node1() == startCorner ) { + corner = (*startLink)->node2(); break; + } + else if ( (*startLink)->node2() == startCorner) { + corner = (*startLink)->node1(); break; + } + } + if ( startLink == linksEnd ) + return _BAD_CORNER; + rowChains[ iRow ]->push_back( *startLink ); + linkSet.erase( startLink ); + startCorner = corner; + } + + return _OK; + } + + //================================================================================ + /*! + * \brief Place medium nodes at the link middle for elements whose corner nodes + * are out of geometrical boundary to prevent distorting elements. + * Issue 0020982, note 0013990 + */ + //================================================================================ + + void force3DOutOfBoundary( SMESH_MesherHelper& theHelper, + SMESH_ComputeErrorPtr& theError) + { + SMESHDS_Mesh* meshDS = theHelper.GetMeshDS(); + TopoDS_Shape shape = theHelper.GetSubShape().Oriented( TopAbs_FORWARD ); + if ( shape.IsNull() ) return; + + if ( !theError ) theError = SMESH_ComputeError::New(); + + gp_XYZ faceNorm; + + if ( shape.ShapeType() == TopAbs_FACE ) // 2D + { + if ( theHelper.GetMesh()->NbTriangles( ORDER_QUADRATIC ) < 1 ) return; + + SMESHDS_SubMesh* faceSM = meshDS->MeshElements( shape ); + if ( !faceSM ) return; + + const TopoDS_Face& face = TopoDS::Face( shape ); + Handle(Geom_Surface) surface = BRep_Tool::Surface( face ); + + TopExp_Explorer edgeIt( face, TopAbs_EDGE ); + for ( ; edgeIt.More(); edgeIt.Next() ) // loop on EDGEs of a FACE + { + // check if the EDGE needs checking + const TopoDS_Edge& edge = TopoDS::Edge( edgeIt.Current() ); + if ( SMESH_Algo::isDegenerated( edge ) ) + continue; + if ( theHelper.IsRealSeam( edge ) && + edge.Orientation() == TopAbs_REVERSED ) + continue; + + SMESHDS_SubMesh* edgeSM = meshDS->MeshElements( edge ); + if ( !edgeSM ) continue; + + double f,l; + Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l ); + BRepAdaptor_Curve curve3D( edge ); + switch ( curve3D.GetType() ) { + case GeomAbs_Line: continue; + case GeomAbs_Circle: + case GeomAbs_Ellipse: + case GeomAbs_Hyperbola: + case GeomAbs_Parabola: + try + { + gp_Vec D1, D2, Du1, Dv1; gp_Pnt p; + curve3D.D2( 0.5 * ( f + l ), p, D1, D2 ); + gp_Pnt2d uv = pcurve->Value( 0.5 * ( f + l ) ); + surface->D1( uv.X(), uv.Y(), p, Du1, Dv1 ); + gp_Vec fNorm = Du1 ^ Dv1; + if ( fNorm.IsParallel( D2, M_PI * 25./180. )) + continue; // face is normal to the curve3D + + gp_Vec curvNorm = fNorm ^ D1; + if ( edge.Orientation() == TopAbs_REVERSED ) curvNorm.Reverse(); + if ( curvNorm * D2 > 0 ) + continue; // convex edge + } + catch ( Standard_Failure ) + { + continue; + } + } + // get nodes shared by faces that may be distorted + SMDS_NodeIteratorPtr nodeIt; + if ( edgeSM->NbNodes() > 0 ) { + nodeIt = edgeSM->GetNodes(); + } + else { + SMESHDS_SubMesh* vertexSM = meshDS->MeshElements( theHelper.IthVertex( 0, edge )); + if ( !vertexSM ) + vertexSM = meshDS->MeshElements( theHelper.IthVertex( 1, edge )); + if ( !vertexSM ) continue; + nodeIt = vertexSM->GetNodes(); + } + + // find suspicious faces + TIDSortedElemSet checkedFaces; + vector< const SMDS_MeshNode* > nOnEdge( 2 ); + const SMDS_MeshNode* nOnFace; + while ( nodeIt->more() ) + { + const SMDS_MeshNode* n = nodeIt->next(); + SMDS_ElemIteratorPtr faceIt = n->GetInverseElementIterator( SMDSAbs_Face ); + while ( faceIt->more() ) + { + const SMDS_MeshElement* f = faceIt->next(); + if ( !faceSM->Contains( f ) || + f->NbNodes() < 6 || // check quadratic triangles only + !checkedFaces.insert( f ).second ) + continue; + + // get nodes on EDGE and on FACE of a suspicious face + nOnEdge.clear(); nOnFace = 0; + SMDS_MeshElement::iterator triNode = f->begin_nodes(); + for ( int nbN = 0; nbN < 3; ++triNode, ++nbN ) + { + n = *triNode; + if ( n->GetPosition()->GetDim() == 2 ) + nOnFace = n; + else + nOnEdge.push_back( n ); + } + + // check if nOnFace is inside the FACE + if ( nOnFace && nOnEdge.size() == 2 ) + { + theHelper.AddTLinks( static_cast< const SMDS_MeshFace* > ( f )); + if ( !SMESH_MeshAlgos::FaceNormal( f, faceNorm, /*normalized=*/false )) + continue; + gp_XYZ edgeDir = SMESH_TNodeXYZ( nOnEdge[0] ) - SMESH_TNodeXYZ( nOnEdge[1] ); + gp_XYZ edgeNorm = faceNorm ^ edgeDir; + n = theHelper.GetMediumNode( nOnEdge[0], nOnEdge[1], true ); // find n, not create + gp_XYZ pN0 = SMESH_TNodeXYZ( nOnEdge[0] ); + gp_XYZ pMedium = SMESH_TNodeXYZ( n ); // on-edge node location + gp_XYZ pFaceN = SMESH_TNodeXYZ( nOnFace ); // on-face node location + double hMedium = edgeNorm * gp_Vec( pN0, pMedium ).XYZ(); + double hFace = edgeNorm * gp_Vec( pN0, pFaceN ).XYZ(); + if ( Abs( hMedium ) > Abs( hFace * 0.6 )) + { + // nOnFace is out of FACE, move a medium on-edge node to the middle + gp_XYZ pMid3D = 0.5 * ( pN0 + SMESH_TNodeXYZ( nOnEdge[1] )); + meshDS->MoveNode( n, pMid3D.X(), pMid3D.Y(), pMid3D.Z() ); + MSG( "move OUT of face " << n ); + theError->myBadElements.push_back( f ); + } + } + } + } + } + if ( !theError->myBadElements.empty() ) + theError->myName = EDITERR_NO_MEDIUM_ON_GEOM; + return; + + } // 2D ============================================================================== + + if ( shape.ShapeType() == TopAbs_SOLID ) // 3D + { + if ( theHelper.GetMesh()->NbTetras ( ORDER_QUADRATIC ) < 1 && + theHelper.GetMesh()->NbPyramids( ORDER_QUADRATIC ) < 1 ) return; + + SMESHDS_SubMesh* solidSM = meshDS->MeshElements( shape ); + if ( !solidSM ) return; + + // check if the SOLID is bound by concave FACEs + vector< TopoDS_Face > concaveFaces; + TopExp_Explorer faceIt( shape, TopAbs_FACE ); + for ( ; faceIt.More(); faceIt.Next() ) // loop on FACEs of a SOLID + { + const TopoDS_Face& face = TopoDS::Face( faceIt.Current() ); + if ( !meshDS->MeshElements( face )) continue; + + BRepAdaptor_Surface surface( face ); + switch ( surface.GetType() ) { + case GeomAbs_Plane: continue; + case GeomAbs_Cylinder: + case GeomAbs_Cone: + case GeomAbs_Sphere: + try + { + double u = 0.5 * ( surface.FirstUParameter() + surface.LastUParameter() ); + double v = 0.5 * ( surface.FirstVParameter() + surface.LastVParameter() ); + gp_Vec Du1, Dv1, Du2, Dv2, Duv2; gp_Pnt p; + surface.D2( u,v, p, Du1, Dv1, Du2, Dv2, Duv2 ); + gp_Vec fNorm = Du1 ^ Dv1; + if ( face.Orientation() == TopAbs_REVERSED ) fNorm.Reverse(); + bool concaveU = ( fNorm * Du2 > 1e-100 ); + bool concaveV = ( fNorm * Dv2 > 1e-100 ); + if ( concaveU || concaveV ) + concaveFaces.push_back( face ); + } + catch ( Standard_Failure ) + { + concaveFaces.push_back( face ); + } + } + } + if ( concaveFaces.empty() ) + return; + + // fix 2D mesh on the SOLID + for ( faceIt.ReInit(); faceIt.More(); faceIt.Next() ) // loop on FACEs of a SOLID + { + SMESH_MesherHelper faceHelper( *theHelper.GetMesh() ); + faceHelper.SetSubShape( faceIt.Current() ); + force3DOutOfBoundary( faceHelper, theError ); + } + + // get an iterator over faces on concaveFaces + vector< SMDS_ElemIteratorPtr > faceIterVec( concaveFaces.size() ); + for ( size_t i = 0; i < concaveFaces.size(); ++i ) + faceIterVec[i] = meshDS->MeshElements( concaveFaces[i] )->GetElements(); + typedef SMDS_IteratorOnIterators + < const SMDS_MeshElement*, vector< SMDS_ElemIteratorPtr > > TIterOnIter; + SMDS_ElemIteratorPtr faceIter( new TIterOnIter( faceIterVec )); + + // a seacher to check if a volume is close to a concave face + std::auto_ptr< SMESH_ElementSearcher > faceSearcher + ( SMESH_MeshAlgos::GetElementSearcher( *theHelper.GetMeshDS(), faceIter )); + + // classifier + //BRepClass3d_SolidClassifier solidClassifier( shape ); + + TIDSortedElemSet checkedVols, movedNodes; + //for ( faceIt.ReInit(); faceIt.More(); faceIt.Next() ) // loop on FACEs of a SOLID + for ( size_t iF = 0; iF < concaveFaces.size(); ++iF ) // loop on concave FACEs + { + //const TopoDS_Shape& face = faceIt.Current(); + const TopoDS_Shape& face = concaveFaces[ iF ]; + SMESHDS_SubMesh* faceSM = meshDS->MeshElements( face ); + if ( !faceSM ) continue; + + // get nodes shared by volumes (tet and pyra) on the FACE that may be distorted + SMDS_NodeIteratorPtr nodeIt; + if ( faceSM->NbNodes() > 0 ) { + nodeIt = faceSM->GetNodes(); + } + else { + TopExp_Explorer vertex( face, TopAbs_VERTEX ); + SMESHDS_SubMesh* vertexSM = meshDS->MeshElements( vertex.Current() ); + if ( !vertexSM ) continue; + nodeIt = vertexSM->GetNodes(); + } + // get ids of sub-shapes of the FACE + set< int > subIDs; + SMESH_subMeshIteratorPtr smIt = + theHelper.GetMesh()->GetSubMesh( face )->getDependsOnIterator(/*includeSelf=*/true); + while ( smIt->more() ) + subIDs.insert( smIt->next()->GetId() ); + + // find suspicious volumes adjacent to the FACE + vector< const SMDS_MeshNode* > nOnFace( 4 ); + const SMDS_MeshNode* nInSolid; + while ( nodeIt->more() ) + { + const SMDS_MeshNode* n = nodeIt->next(); + SMDS_ElemIteratorPtr volIt = n->GetInverseElementIterator( SMDSAbs_Volume ); + while ( volIt->more() ) + { + const SMDS_MeshElement* vol = volIt->next(); + int nbN = vol->NbCornerNodes(); + if ( ( nbN != 4 && nbN != 5 ) || + !solidSM->Contains( vol ) || + !checkedVols.insert( vol ).second ) + continue; + + // get nodes on FACE and in SOLID of a suspicious volume + nOnFace.clear(); nInSolid = 0; + SMDS_MeshElement::iterator volNode = vol->begin_nodes(); + for ( int nb = nbN; nb > 0; ++volNode, --nb ) + { + n = *volNode; + if ( n->GetPosition()->GetDim() == 3 ) + nInSolid = n; + else if ( subIDs.count( n->getshapeId() )) + nOnFace.push_back( n ); + else + nInSolid = n; + } + if ( !nInSolid || nOnFace.size() != nbN - 1 ) + continue; + + // get size of the vol + SMESH_TNodeXYZ pInSolid( nInSolid ), pOnFace0( nOnFace[0] ); + double volLength = pInSolid.SquareDistance( nOnFace[0] ); + for ( size_t i = 1; i < nOnFace.size(); ++i ) + { + volLength = Max( volLength, pOnFace0.SquareDistance( nOnFace[i] )); + } + + // check if vol is close to concaveFaces + const SMDS_MeshElement* closeFace = + faceSearcher->FindClosestTo( pInSolid, SMDSAbs_Face ); + if ( !closeFace || + pInSolid.SquareDistance( closeFace->GetNode(0) ) > 4 * volLength ) + continue; + + // check if vol is distorted, i.e. a medium node is much closer + // to nInSolid than the link middle + bool isDistorted = false; + SMDS_FaceOfNodes onFaceTria( nOnFace[0], nOnFace[1], nOnFace[2] ); + if ( !SMESH_MeshAlgos::FaceNormal( &onFaceTria, faceNorm, /*normalized=*/false )) + continue; + theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* > ( vol )); + vector< pair< SMESH_TLink, const SMDS_MeshNode* > > links; + for ( size_t i = 0; i < nOnFace.size(); ++i ) // loop on links between nOnFace + for ( size_t j = i+1; j < nOnFace.size(); ++j ) + { + SMESH_TLink link( nOnFace[i], nOnFace[j] ); + TLinkNodeMap::const_iterator linkIt = + theHelper.GetTLinkNodeMap().find( link ); + if ( linkIt != theHelper.GetTLinkNodeMap().end() ) + { + links.push_back( make_pair( linkIt->first, linkIt->second )); + if ( !isDistorted ) { + // compare projections of nInSolid and nMedium to face normal + gp_Pnt pMedium = SMESH_TNodeXYZ( linkIt->second ); + double hMedium = faceNorm * gp_Vec( pOnFace0, pMedium ).XYZ(); + double hVol = faceNorm * gp_Vec( pOnFace0, pInSolid ).XYZ(); + isDistorted = ( Abs( hMedium ) > Abs( hVol * 0.5 )); + } + } + } + // move medium nodes to link middle + if ( isDistorted ) + { + for ( size_t i = 0; i < links.size(); ++i ) + { + const SMDS_MeshNode* nMedium = links[i].second; + if ( movedNodes.insert( nMedium ).second ) + { + gp_Pnt pMid3D = 0.5 * ( SMESH_TNodeXYZ( links[i].first.node1() ) + + SMESH_TNodeXYZ( links[i].first.node2() )); + meshDS->MoveNode( nMedium, pMid3D.X(), pMid3D.Y(), pMid3D.Z() ); + MSG( "move OUT of solid " << nMedium ); + } + } + theError->myBadElements.push_back( vol ); + } + } // loop on volumes sharing a node on FACE + } // loop on nodes on FACE + } // loop on FACEs of a SOLID + + if ( !theError->myBadElements.empty() ) + theError->myName = EDITERR_NO_MEDIUM_ON_GEOM; + } // 3D case + } + +} //namespace + +//======================================================================= +/*! + * \brief Move medium nodes of faces and volumes to fix distorted elements + * \param error - container of fixed distorted elements + * \param volumeOnly - to fix nodes on faces or not, if the shape is solid + * + * Issue 0020307: EDF 992 SMESH : Linea/Quadratic with Medium Node on Geometry + */ +//======================================================================= + +void SMESH_MesherHelper::FixQuadraticElements(SMESH_ComputeErrorPtr& compError, + bool volumeOnly) +{ + // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion + if ( getenv("NO_FixQuadraticElements") ) + return; + + // 0. Apply algorithm to SOLIDs or FACEs + // ---------------------------------------------- + if ( myShape.IsNull() ) { + if ( !myMesh->HasShapeToMesh() ) return; + SetSubShape( myMesh->GetShapeToMesh() ); + +#ifdef _DEBUG_ + int nbSolids = 0; + TopTools_IndexedMapOfShape solids; + TopExp::MapShapes(myShape,TopAbs_SOLID,solids); + nbSolids = solids.Extent(); +#endif + TopTools_MapOfShape faces; // faces not in solid or in not meshed solid + for ( TopExp_Explorer f(myShape,TopAbs_FACE,TopAbs_SOLID); f.More(); f.Next() ) { + faces.Add( f.Current() ); // not in solid + } + for ( TopExp_Explorer s(myShape,TopAbs_SOLID); s.More(); s.Next() ) { + if ( myMesh->GetSubMesh( s.Current() )->IsEmpty() ) { // get faces of solid + for ( TopExp_Explorer f( s.Current(), TopAbs_FACE); f.More(); f.Next() ) + faces.Add( f.Current() ); // in not meshed solid + } + else { // fix nodes in the solid and its faces +#ifdef _DEBUG_ + MSG("FIX SOLID " << nbSolids-- << " #" << GetMeshDS()->ShapeToIndex(s.Current())); +#endif + SMESH_MesherHelper h(*myMesh); + h.SetSubShape( s.Current() ); + h.ToFixNodeParameters(true); + h.FixQuadraticElements( compError, false ); + } + } + // fix nodes on geom faces +#ifdef _DEBUG_ + int nbfaces = faces.Extent(); /*avoid "unused varianbles": */ nbfaces++, nbfaces--; +#endif + for ( TopTools_MapIteratorOfMapOfShape fIt( faces ); fIt.More(); fIt.Next() ) { + MSG("FIX FACE " << nbfaces-- << " #" << GetMeshDS()->ShapeToIndex(fIt.Key())); + SMESH_MesherHelper h(*myMesh); + h.SetSubShape( fIt.Key() ); + h.ToFixNodeParameters(true); + h.FixQuadraticElements( compError, true); + } + //perf_print_all_meters(1); + if ( compError && compError->myName == EDITERR_NO_MEDIUM_ON_GEOM ) + compError->myComment = "during conversion to quadratic, " + "some medium nodes were not placed on geometry to avoid distorting elements"; + return; + } + + // 1. Find out type of elements and get iterator on them + // --------------------------------------------------- + + SMDS_ElemIteratorPtr elemIt; + SMDSAbs_ElementType elemType = SMDSAbs_All; + + SMESH_subMesh* submesh = myMesh->GetSubMeshContaining( myShapeID ); + if ( !submesh ) + return; + if ( SMESHDS_SubMesh* smDS = submesh->GetSubMeshDS() ) { + elemIt = smDS->GetElements(); + if ( elemIt->more() ) { + elemType = elemIt->next()->GetType(); + elemIt = smDS->GetElements(); + } + } + if ( !elemIt || !elemIt->more() || elemType < SMDSAbs_Face ) + return; + + // 2. Fill in auxiliary data structures + // ---------------------------------- + + set< QLink > links; + set< QFace > faces; + set< QLink >::iterator pLink; + set< QFace >::iterator pFace; + + bool isCurved = false; + //bool hasRectFaces = false; + //set nbElemNodeSet; + SMDS_VolumeTool volTool; + + TIDSortedNodeSet apexOfPyramid; + const int apexIndex = 4; + + // Issue 0020982 + // Move medium nodes to the link middle for elements whose corner nodes + // are out of geometrical boundary to fix distorted elements. + force3DOutOfBoundary( *this, compError ); + + if ( elemType == SMDSAbs_Volume ) + { + while ( elemIt->more() ) // loop on volumes + { + const SMDS_MeshElement* vol = elemIt->next(); + if ( !vol->IsQuadratic() || !volTool.Set( vol )) + return; + double volMinSize2 = -1.; + for ( int iF = 0; iF < volTool.NbFaces(); ++iF ) // loop on faces of volume + { + int nbN = volTool.NbFaceNodes( iF ); + //nbElemNodeSet.insert( nbN ); + const SMDS_MeshNode** faceNodes = volTool.GetFaceNodes( iF ); + vector< const QLink* > faceLinks( nbN/2 ); + for ( int iN = 0; iN < nbN; iN += 2 ) // loop on links of a face + { + // store QLink + QLink link( faceNodes[iN], faceNodes[iN+2], faceNodes[iN+1] ); + pLink = links.insert( link ).first; + faceLinks[ iN/2 ] = & *pLink; + + if ( link.MediumPos() == SMDS_TOP_3DSPACE ) + { + if ( !link.IsStraight() ) + return; // already fixed + } + else if ( !isCurved ) + { + if ( volMinSize2 < 0 ) volMinSize2 = volTool.MinLinearSize2(); + isCurved = !isStraightLink( volMinSize2, link._nodeMove.SquareMagnitude() ); + } + } + // store QFace + pFace = faces.insert( QFace( faceLinks )).first; + if ( pFace->NbVolumes() == 0 ) + pFace->AddSelfToLinks(); + pFace->SetVolume( vol ); +// hasRectFaces = hasRectFaces || +// ( volTool.GetVolumeType() == SMDS_VolumeTool::QUAD_HEXA || +// volTool.GetVolumeType() == SMDS_VolumeTool::QUAD_PENTA ); +#ifdef _DEBUG_ + if ( nbN == 6 ) + pFace->_face = GetMeshDS()->FindFace(faceNodes[0],faceNodes[2],faceNodes[4]); + else + pFace->_face = GetMeshDS()->FindFace(faceNodes[0],faceNodes[2], + faceNodes[4],faceNodes[6] ); +#endif + } + // collect pyramid apexes for further correction + if ( vol->NbCornerNodes() == 5 ) + apexOfPyramid.insert( vol->GetNode( apexIndex )); + } + set< QLink >::iterator pLink = links.begin(); + for ( ; pLink != links.end(); ++pLink ) + pLink->SetContinuesFaces(); + } + else + { + while ( elemIt->more() ) // loop on faces + { + const SMDS_MeshElement* face = elemIt->next(); + if ( !face->IsQuadratic() ) + continue; + //nbElemNodeSet.insert( face->NbNodes() ); + int nbN = face->NbNodes()/2; + vector< const QLink* > faceLinks( nbN ); + for ( int iN = 0; iN < nbN; ++iN ) // loop on links of a face + { + // store QLink + QLink link( face->GetNode(iN), face->GetNode((iN+1)%nbN), face->GetNode(iN+nbN) ); + pLink = links.insert( link ).first; + faceLinks[ iN ] = & *pLink; + if ( !isCurved && + link.node1()->GetPosition()->GetTypeOfPosition() < 2 && + link.node2()->GetPosition()->GetTypeOfPosition() < 2 ) + isCurved = !link.IsStraight(); + } + // store QFace + pFace = faces.insert( QFace( faceLinks )).first; + pFace->AddSelfToLinks(); + //hasRectFaces = ( hasRectFaces || nbN == 4 ); + } + } + if ( !isCurved ) + return; // no curved edges of faces + + // 3. Compute displacement of medium nodes + // --------------------------------------- + + SMESH_MesherHelper faceHlp(*myMesh); + + // two loops on QFaces: the first is to treat boundary links, the second is for internal ones. + TopLoc_Location loc; + bool checkUV; + // not to treat boundary of volumic sub-mesh. + int isInside = ( elemType == SMDSAbs_Volume && volumeOnly ) ? 1 : 0; + for ( ; isInside < 2; ++isInside ) + { + MSG( "--------------- LOOP (inside=" << isInside << ") ------------------"); + SMDS_TypeOfPosition pos = isInside ? SMDS_TOP_3DSPACE : SMDS_TOP_FACE; + SMDS_TypeOfPosition bndPos = isInside ? SMDS_TOP_FACE : SMDS_TOP_EDGE; + + for ( pFace = faces.begin(); pFace != faces.end(); ++pFace ) { + if ( bool(isInside) == pFace->IsBoundary() ) + continue; + for ( int dir = 0; dir < 2; ++dir ) // 2 directions of propagation from the quadrangle + { + MSG( "CHAIN"); + // make chain of links connected via continues faces + int error = ERR_OK; + TChain rawChain; + if ( !pFace->GetLinkChain( dir, rawChain, pos, error) && error ==ERR_UNKNOWN ) continue; + rawChain.reverse(); + if ( !pFace->GetLinkChain( dir+2, rawChain, pos, error ) && error ==ERR_UNKNOWN ) continue; + + vector< TChain > chains; + if ( error == ERR_OK ) { // chain contains continues rectangles + chains.resize(1); + chains[0].splice( chains[0].begin(), rawChain ); + } + else if ( error == ERR_TRI ) { // chain contains continues triangles + TSplitTriaResult res = splitTrianglesIntoChains( rawChain, chains, pos ); + if ( res != _OK ) { // not 'quadrangles split into triangles' in chain + fixTriaNearBoundary( rawChain, *this ); + break; + } + } + else if ( error == ERR_PRISM ) { // quadrangle side faces of prisms + fixPrism( rawChain ); + break; + } + else { + continue; + } + for ( int iC = 0; iC < chains.size(); ++iC ) + { + TChain& chain = chains[iC]; + if ( chain.empty() ) continue; + if ( chain.front().IsStraight() && chain.back().IsStraight() ) { + MSG("3D straight - ignore"); + continue; + } + if ( chain.front()->MediumPos() > bndPos || + chain.back() ->MediumPos() > bndPos ) { + MSG("Internal chain - ignore"); + continue; + } + // mesure chain length and compute link position along the chain + double chainLen = 0; + vector< double > linkPos; + TChain savedChain; // backup + MSGBEG( "Link medium nodes: "); + TChain::iterator link0 = chain.begin(), link1 = chain.begin(), link2; + for ( ++link1; link1 != chain.end(); ++link1, ++link0 ) { + MSGBEG( (*link0)->_mediumNode->GetID() << "-" <<(*link1)->_mediumNode->GetID()<<" "); + double len = ((*link0)->MiddlePnt() - (*link1)->MiddlePnt()).Modulus(); + while ( len < numeric_limits::min() ) { // remove degenerated link + if ( savedChain.empty() ) savedChain = chain; + link1 = chain.erase( link1 ); + if ( link1 == chain.end() ) + break; + len = ((*link0)->MiddlePnt() - (*link1)->MiddlePnt()).Modulus(); + } + chainLen += len; + linkPos.push_back( chainLen ); + } + MSG(""); + if ( linkPos.size() <= 2 && savedChain.size() > 2 ) { + //continue; + linkPos.clear(); + chainLen = 0; + chain = savedChain; + for ( link1 = chain.begin(); link1 != chain.end(); ++link1 ) { + chainLen += 1; + linkPos.push_back( chainLen ); + } + } + gp_Vec move0 = chain.front()->_nodeMove; + gp_Vec move1 = chain.back ()->_nodeMove; + + TopoDS_Face face; + if ( !isInside ) + { + // compute node displacement of end links of chain in parametric space of FACE + TChainLink& linkOnFace = *(++chain.begin()); + const SMDS_MeshNode* nodeOnFace = linkOnFace->_mediumNode; + TopoDS_Shape f = GetSubShapeByNode( nodeOnFace, GetMeshDS() ); + if ( !f.IsNull() && f.ShapeType() == TopAbs_FACE ) + { + face = TopoDS::Face( f ); + faceHlp.SetSubShape( face ); + Handle(Geom_Surface) surf = BRep_Tool::Surface(face,loc); + //bool isStraight[2]; // commented for issue 0023118 + for ( int is1 = 0; is1 < 2; ++is1 ) // move0 or move1 + { + TChainLink& link = is1 ? chain.back() : chain.front(); + gp_XY uvm = faceHlp.GetNodeUV( face, link->_mediumNode, nodeOnFace, &checkUV ); + gp_XY uv1 = faceHlp.GetNodeUV( face, link->node1(), nodeOnFace, &checkUV ); + gp_XY uv2 = faceHlp.GetNodeUV( face, link->node2(), nodeOnFace, &checkUV ); + gp_XY uv12 = faceHlp.GetMiddleUV( surf, uv1, uv2 ); + // uvMove = uvm - uv12 + gp_XY uvMove = ApplyIn2D(surf, uvm, uv12, gp_XY_Subtracted, /*inPeriod=*/false); + ( is1 ? move1 : move0 ).SetCoord( uvMove.X(), uvMove.Y(), 0 ); + if ( !is1 ) // correct nodeOnFace for move1 (issue 0020919) + nodeOnFace = (*(++chain.rbegin()))->_mediumNode; + // isStraight[is1] = isStraightLink( (uv2-uv1).SquareModulus(), + // 10 * uvMove.SquareModulus()); + } + // if ( isStraight[0] && isStraight[1] ) { + // MSG("2D straight - ignore"); + // continue; // straight - no need to move nodes of internal links + // } + + // check if a chain is already fixed + gp_XY uvm = faceHlp.GetNodeUV( face, linkOnFace->_mediumNode, 0, &checkUV ); + gp_XY uv1 = faceHlp.GetNodeUV( face, linkOnFace->node1(), nodeOnFace, &checkUV ); + gp_XY uv2 = faceHlp.GetNodeUV( face, linkOnFace->node2(), nodeOnFace, &checkUV ); + gp_XY uv12 = faceHlp.GetMiddleUV( surf, uv1, uv2 ); + if (( uvm - uv12 ).SquareModulus() > 1e-10 ) + { + MSG("Already fixed - ignore"); + continue; + } + } + } + gp_Trsf trsf; + if ( isInside || face.IsNull() ) + { + // compute node displacement of end links in their local coord systems + { + TChainLink& ln0 = chain.front(), ln1 = *(++chain.begin()); + trsf.SetTransformation( gp_Ax3( gp::Origin(), ln0.Normal(), + gp_Vec( ln0->MiddlePnt(), ln1->MiddlePnt() ))); + move0.Transform(trsf); + } + { + TChainLink& ln0 = *(++chain.rbegin()), ln1 = chain.back(); + trsf.SetTransformation( gp_Ax3( gp::Origin(), ln1.Normal(), + gp_Vec( ln0->MiddlePnt(), ln1->MiddlePnt() ))); + move1.Transform(trsf); + } + } + // compute displacement of medium nodes + link2 = chain.begin(); + link0 = link2++; + link1 = link2++; + for ( int i = 0; link2 != chain.end(); ++link0, ++link1, ++link2, ++i ) + { + double r = linkPos[i] / chainLen; + // displacement in local coord system + gp_Vec move = (1. - r) * move0 + r * move1; + if ( isInside || face.IsNull()) { + // transform to global + gp_Vec x01( (*link0)->MiddlePnt(), (*link1)->MiddlePnt() ); + gp_Vec x12( (*link1)->MiddlePnt(), (*link2)->MiddlePnt() ); + try { + gp_Vec x = x01.Normalized() + x12.Normalized(); + trsf.SetTransformation( gp_Ax3( gp::Origin(), link1->Normal(), x), gp_Ax3() ); + } catch ( Standard_Failure ) { + trsf.Invert(); + } + move.Transform(trsf); + (*link1)->Move( move, /*sum=*/false, /*is2dFixed=*/false ); + } + else { + // compute 3D displacement by 2D one + Handle(Geom_Surface) s = BRep_Tool::Surface(face,loc); + gp_XY oldUV = faceHlp.GetNodeUV( face, (*link1)->_mediumNode, 0, &checkUV ); + gp_XY newUV = ApplyIn2D( s, oldUV, gp_XY( move.X(),move.Y()), gp_XY_Added ); + gp_Pnt newPnt = s->Value( newUV.X(), newUV.Y()); + move = gp_Vec( XYZ((*link1)->_mediumNode), newPnt.Transformed(loc) ); + if ( SMDS_FacePosition* nPos = + dynamic_cast< SMDS_FacePosition* >((*link1)->_mediumNode->GetPosition())) + nPos->SetParameters( newUV.X(), newUV.Y() ); +#ifdef _DEBUG_ + if ( (XYZ((*link1)->node1()) - XYZ((*link1)->node2())).SquareModulus() < + move.SquareMagnitude()) + { + gp_XY uv0 = faceHlp.GetNodeUV( face, (*link0)->_mediumNode, 0, &checkUV ); + gp_XY uv2 = faceHlp.GetNodeUV( face, (*link2)->_mediumNode, 0, &checkUV ); + MSG( "TOO LONG MOVE \t" << + "uv0: "<Move( move, /*sum=*/false, /*is2dFixed=*/true ); + } + MSG( "Move " << (*link1)->_mediumNode->GetID() << " following " + << chain.front()->_mediumNode->GetID() <<"-" + << chain.back ()->_mediumNode->GetID() << + " by " << move.Magnitude()); + } + } // loop on chains of links + } // loop on 2 directions of propagation from quadrangle + } // loop on faces + } // fix faces and/or volumes + + // 4. Move nodes + // ------------- + + TIDSortedElemSet biQuadQuas, biQuadTris, triQuadHexa; + const SMDS_MeshElement *biQuadQua, *triQuadHex; + const bool toFixCentralNodes = ( myMesh->NbBiQuadQuadrangles() + + myMesh->NbBiQuadTriangles() + + myMesh->NbTriQuadraticHexas() ); + double distXYZ[4]; + faceHlp.ToFixNodeParameters( true ); + + for ( pLink = links.begin(); pLink != links.end(); ++pLink ) { + if ( pLink->IsMoved() ) + { + gp_Pnt p = pLink->MiddlePnt() + pLink->Move(); + + // put on surface nodes on FACE but moved in 3D (23050) + if ( !pLink->IsFixedOnSurface() ) + { + faceHlp.SetSubShape( pLink->_mediumNode->getshapeId() ); + if ( faceHlp.GetSubShape().ShapeType() == TopAbs_FACE ) + { + const_cast( pLink->_mediumNode )->setXYZ( p.X(), p.Y(), p.Z()); + p.Coord( distXYZ[1], distXYZ[2], distXYZ[3] ); + gp_XY uv( Precision::Infinite(), 0 ); + if ( faceHlp.CheckNodeUV( TopoDS::Face( faceHlp.GetSubShape() ), pLink->_mediumNode, + uv, /*tol=*/pLink->Move().Modulus(), /*force=*/true, distXYZ )) + p.SetCoord( distXYZ[1], distXYZ[2], distXYZ[3] ); + } + } + GetMeshDS()->MoveNode( pLink->_mediumNode, p.X(), p.Y(), p.Z()); + + // collect bi-quadratic elements + if ( toFixCentralNodes ) + { + biQuadQua = triQuadHex = 0; + SMDS_ElemIteratorPtr eIt = pLink->_mediumNode->GetInverseElementIterator(); + while ( eIt->more() ) + { + const SMDS_MeshElement* e = eIt->next(); + switch( e->GetEntityType() ) { + case SMDSEntity_BiQuad_Quadrangle: biQuadQuas.insert( e ); break; + case SMDSEntity_BiQuad_Triangle: biQuadTris.insert( e ); break; + case SMDSEntity_TriQuad_Hexa: triQuadHexa.insert( e ); break; + default:; + } + } + } + } + } + // Fix positions of central nodes of bi-tri-quadratic elements + + // treat bi-quad quadrangles + { + vector< const SMDS_MeshNode* > nodes( 9 ); + gp_XY uv[ 9 ]; + TIDSortedElemSet::iterator quadIt = biQuadQuas.begin(); + for ( ; quadIt != biQuadQuas.end(); ++quadIt ) + { + const SMDS_MeshElement* quad = *quadIt; + // nodes + nodes.clear(); + nodes.assign( quad->begin_nodes(), quad->end_nodes() ); + // FACE + TopoDS_Shape S = GetSubShapeByNode( nodes.back(), GetMeshDS() ); + if ( S.IsNull() || S.ShapeType() != TopAbs_FACE ) continue; + const TopoDS_Face& F = TopoDS::Face( S ); + Handle( Geom_Surface ) surf = BRep_Tool::Surface( F, loc ); + const double tol = BRep_Tool::Tolerance( F ); + // UV + for ( int i = 0; i < 8; ++i ) + { + uv[ i ] = GetNodeUV( F, nodes[i], nodes[8], &checkUV ); + // as this method is used after mesh generation, UV of nodes is not + // updated according to bending links, so we update + if ( i > 3 && nodes[i]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) + CheckNodeUV( F, nodes[i], uv[ i ], 2*tol, /*force=*/true ); + } + AdjustByPeriod( F, uv, 8 ); // put uv[] within a period (IPAL52698) + // move the central node + gp_XY uvCent = calcTFI (0.5, 0.5, uv[0],uv[1],uv[2],uv[3],uv[4],uv[5],uv[6],uv[7] ); + gp_Pnt p = surf->Value( uvCent.X(), uvCent.Y() ).Transformed( loc ); + GetMeshDS()->MoveNode( nodes[8], p.X(), p.Y(), p.Z()); + } + } + + // treat bi-quad triangles + { + vector< const SMDS_MeshNode* > nodes; + gp_XY uv[ 6 ]; + TIDSortedElemSet::iterator triIt = biQuadTris.begin(); + for ( ; triIt != biQuadTris.end(); ++triIt ) + { + const SMDS_MeshElement* tria = *triIt; + // FACE + const TopoDS_Shape& S = GetMeshDS()->IndexToShape( tria->getshapeId() ); + if ( S.IsNull() || S.ShapeType() != TopAbs_FACE ) continue; + const TopoDS_Face& F = TopoDS::Face( S ); + Handle( Geom_Surface ) surf = BRep_Tool::Surface( F, loc ); + const double tol = BRep_Tool::Tolerance( F ); + + // nodes + nodes.assign( tria->begin_nodes(), tria->end_nodes() ); + // UV + bool uvOK = true, badTria = false; + for ( int i = 0; i < 6; ++i ) + { + uv[ i ] = GetNodeUV( F, nodes[i], nodes[(i+1)%3], &uvOK ); + // as this method is used after mesh generation, UV of nodes is not + // updated according to bending links, so we update + if ( nodes[i]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) + CheckNodeUV( F, nodes[i], uv[ i ], 2*tol, /*force=*/true ); + } + + // move the central node + gp_Pnt p; + if ( !uvOK || badTria ) + { + p = ( SMESH_TNodeXYZ( nodes[3] ) + + SMESH_TNodeXYZ( nodes[4] ) + + SMESH_TNodeXYZ( nodes[5] )) / 3; + } + else + { + AdjustByPeriod( F, uv, 6 ); // put uv[] within a period (IPAL52698) + gp_XY uvCent = GetCenterUV( uv[0], uv[1], uv[2], uv[3], uv[4], uv[5], &badTria ); + p = surf->Value( uvCent.X(), uvCent.Y() ).Transformed( loc ); + } + GetMeshDS()->MoveNode( tria->GetNode(6), p.X(), p.Y(), p.Z() ); + } + } + + // treat tri-quadratic hexahedra + { + SMDS_VolumeTool volExp; + TIDSortedElemSet::iterator hexIt = triQuadHexa.begin(); + for ( ; hexIt != triQuadHexa.end(); ++hexIt ) + { + volExp.Set( *hexIt, /*ignoreCentralNodes=*/false ); + + // fix nodes central in sides + for ( int iQuad = 0; iQuad < volExp.NbFaces(); ++iQuad ) + { + const SMDS_MeshNode** quadNodes = volExp.GetFaceNodes( iQuad ); + if ( quadNodes[8]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE ) + { + gp_XYZ p = calcTFI( 0.5, 0.5, + SMESH_TNodeXYZ( quadNodes[0] ), SMESH_TNodeXYZ( quadNodes[2] ), + SMESH_TNodeXYZ( quadNodes[4] ), SMESH_TNodeXYZ( quadNodes[6] ), + SMESH_TNodeXYZ( quadNodes[1] ), SMESH_TNodeXYZ( quadNodes[3] ), + SMESH_TNodeXYZ( quadNodes[5] ), SMESH_TNodeXYZ( quadNodes[7] )); + GetMeshDS()->MoveNode( quadNodes[8], p.X(), p.Y(), p.Z()); + } + } + + // fix the volume central node + vector pointsOnShapes( SMESH_Block::ID_Shell ); + const SMDS_MeshNode** hexNodes = volExp.GetNodes(); + + pointsOnShapes[ SMESH_Block::ID_V000 ] = SMESH_TNodeXYZ( hexNodes[ 0 ] ); + pointsOnShapes[ SMESH_Block::ID_V100 ] = SMESH_TNodeXYZ( hexNodes[ 3 ] ); + pointsOnShapes[ SMESH_Block::ID_V010 ] = SMESH_TNodeXYZ( hexNodes[ 1 ] ); + pointsOnShapes[ SMESH_Block::ID_V110 ] = SMESH_TNodeXYZ( hexNodes[ 2 ] ); + pointsOnShapes[ SMESH_Block::ID_V001 ] = SMESH_TNodeXYZ( hexNodes[ 4 ] ); + pointsOnShapes[ SMESH_Block::ID_V101 ] = SMESH_TNodeXYZ( hexNodes[ 7 ] ); + pointsOnShapes[ SMESH_Block::ID_V011 ] = SMESH_TNodeXYZ( hexNodes[ 5 ] ); + pointsOnShapes[ SMESH_Block::ID_V111 ] = SMESH_TNodeXYZ( hexNodes[ 6 ] ); + + pointsOnShapes[ SMESH_Block::ID_Ex00 ] = SMESH_TNodeXYZ( hexNodes[ 11 ] ); + pointsOnShapes[ SMESH_Block::ID_Ex10 ] = SMESH_TNodeXYZ( hexNodes[ 9 ] ); + pointsOnShapes[ SMESH_Block::ID_E0y0 ] = SMESH_TNodeXYZ( hexNodes[ 8 ] ); + pointsOnShapes[ SMESH_Block::ID_E1y0 ] = SMESH_TNodeXYZ( hexNodes[ 10 ] ); + pointsOnShapes[ SMESH_Block::ID_Ex01 ] = SMESH_TNodeXYZ( hexNodes[ 15 ] ); + pointsOnShapes[ SMESH_Block::ID_Ex11 ] = SMESH_TNodeXYZ( hexNodes[ 13 ] ); + pointsOnShapes[ SMESH_Block::ID_E0y1 ] = SMESH_TNodeXYZ( hexNodes[ 12 ] ); + pointsOnShapes[ SMESH_Block::ID_E1y1 ] = SMESH_TNodeXYZ( hexNodes[ 14 ] ); + pointsOnShapes[ SMESH_Block::ID_E00z ] = SMESH_TNodeXYZ( hexNodes[ 16 ] ); + pointsOnShapes[ SMESH_Block::ID_E10z ] = SMESH_TNodeXYZ( hexNodes[ 19 ] ); + pointsOnShapes[ SMESH_Block::ID_E01z ] = SMESH_TNodeXYZ( hexNodes[ 17 ] ); + pointsOnShapes[ SMESH_Block::ID_E11z ] = SMESH_TNodeXYZ( hexNodes[ 18 ] ); + + pointsOnShapes[ SMESH_Block::ID_Fxy0 ] = SMESH_TNodeXYZ( hexNodes[ 20 ] ); + pointsOnShapes[ SMESH_Block::ID_Fxy1 ] = SMESH_TNodeXYZ( hexNodes[ 25 ] ); + pointsOnShapes[ SMESH_Block::ID_Fx0z ] = SMESH_TNodeXYZ( hexNodes[ 21 ] ); + pointsOnShapes[ SMESH_Block::ID_Fx1z ] = SMESH_TNodeXYZ( hexNodes[ 23 ] ); + pointsOnShapes[ SMESH_Block::ID_F0yz ] = SMESH_TNodeXYZ( hexNodes[ 24 ] ); + pointsOnShapes[ SMESH_Block::ID_F1yz ] = SMESH_TNodeXYZ( hexNodes[ 22 ] ); + + gp_XYZ nCenterParams(0.5, 0.5, 0.5), nCenterCoords; + SMESH_Block::ShellPoint( nCenterParams, pointsOnShapes, nCenterCoords ); + GetMeshDS()->MoveNode( hexNodes[26], + nCenterCoords.X(), nCenterCoords.Y(), nCenterCoords.Z()); + } + } } diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Octree.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Octree.cpp index 01fde5160e4b..e7b049722399 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Octree.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Octree.cpp @@ -1,183 +1,79 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMESH_Octree : global Octree implementation -// File : SMESH_Octree.cxx -// Created : Tue Jan 16 16:00:00 2007 -// Author : Nicolas Geimer & Aurélien Motteux(OCC) -// Module : SMESH + +// SMESH SMESH_Octree : Octree implementation +// File : SMESH_Octree.cxx +// Created : Tue Jan 16 16:00:00 2007 +// Author : Nicolas Geimer & Aurélien Motteux(OCC) +// Module : SMESH // #include "SMESH_Octree.hxx" //=========================================================================== /*! - * \brief SMESH_Octree Constructor - * \param maxLevel - The level max the octree can reach (If <0 unlimited) + * Constructor. limit must be provided at tree root construction. + * limit will be deleted by SMESH_Octree. */ //=========================================================================== -SMESH_Octree::SMESH_Octree (const int maxLevel, const double minBoxSize): - myChildren(NULL), - myFather(NULL), - myLevel(0), - myMaxLevel(maxLevel), - myMinBoxSize(minBoxSize), - myIsLeaf(-1) -{ - myBox = new Bnd_B3d(); -} -//====================================== -/*! - * \brief SMESH_Octree Destructor - */ -//====================================== -SMESH_Octree::~SMESH_Octree () +SMESH_Octree::SMESH_Octree (SMESH_TreeLimit* limit): TBaseTree( limit ) { - if(myChildren != NULL) - { - if(!myIsLeaf) - { - for(int i = 0; i<8; i++) - delete myChildren[i]; - delete[] myChildren ; - } - } - delete myBox; } -//=========================================================================== +//================================================================= /*! - * \brief Set the bounding box of the Octree - * \param box - 3d Bounding Box of the Octree + * \brief Allocate a bndbox according to childIndex. childIndex is zero based */ -//=========================================================================== -void SMESH_Octree::setBox(const Bnd_B3d* box) -{ -// delete myBox; -// myBox=new Bnd_B3d(*box); - *myBox = *box; -} +//================================================================= -//=========================================================================== -/*! - * \brief Set box to the 3d Bounding Box of the Octree - * \param box - Set box to the 3d Bounding Box of the Octree - */ -//=========================================================================== -void SMESH_Octree::getBox(Bnd_B3d& box) +Bnd_B3d* SMESH_Octree::newChildBox(int childIndex) const { -// if(box != NULL) -// delete box; -// box = new Bnd_B3d (*myBox); - box = *myBox; -} + gp_XYZ min = getBox()->CornerMin(); + gp_XYZ max = getBox()->CornerMax(); + gp_XYZ HSize = (max - min)/2.; + gp_XYZ childHsize = HSize/2.; -//=========================================================================== -/*! - * \brief Set the max level of the Octree - * \param maxLevel - The level max the octree can reach (If <0 unlimited) - */ -//=========================================================================== -void SMESH_Octree::setMaxLevel(const int maxLevel) -{myMaxLevel = maxLevel;} + gp_XYZ minChild( min.X() + childIndex%2 * HSize.X(), + min.Y() + (childIndex%4)/2 * HSize.Y(), + min.Z() + ( childIndex>=4 ) * HSize.Z()); + return new Bnd_B3d(minChild+childHsize,childHsize); +} //=========================================================================== /*! - * \brief Compute the bigger dimension of the box - * \param box - 3d Box - * \retval double - bigger dimension of the box + * \brief Compute the bigger dimension of my box */ //=========================================================================== -double SMESH_Octree::maxSize(const Bnd_B3d* box) -{ - if(box ==NULL) - return 0; - gp_XYZ min = box->CornerMin(); - gp_XYZ max = box->CornerMax(); - gp_XYZ Size = (max - min); - double returnVal = (Size.X()>Size.Y())?Size.X():Size.Y(); - return (returnVal>Size.Z())?returnVal:Size.Z(); -} -//============================= -/*! - * \brief Compute the Octree - */ -//============================= -void SMESH_Octree::Compute() -{ - // As soon as the Octree is a Leaf, I stop building his children - if(!isLeaf()) - buildChildren(); -} - -//================================================================= -/*! - * \brief Build the 8 children boxes and call buildChildrenData() - */ -//================================================================= -void SMESH_Octree::buildChildren() +double SMESH_Octree::maxSize() const { - myChildren = new SMESH_Octree*[8]; - - gp_XYZ min = myBox->CornerMin(); - gp_XYZ max = myBox->CornerMax(); - gp_XYZ HSize = (max - min)/2.; - gp_XYZ mid = min + HSize; - gp_XYZ childHsize = HSize/2.; - - Standard_Real XminChild, YminChild, ZminChild; - Bnd_B3d* box; - gp_XYZ minChild; - for (int i =0; i<8; i++) + if ( getBox() && !getBox()->IsVoid() ) { - // We build the eight boxes, we need 2 points to do that. - // Min, and Mid - // In binary, we can write i from 0 to 7 - // For instance : - // 5 is 101, it corresponds here in coordinates to ZYX - // If coordinate is 0 in Y-> box from Ymin to Ymid - // If coordinate is 1 in Y-> box from Ymid to Ymax - // Same scheme for X and Z - // I need the minChild to build the Bnd_B3d box. - - XminChild= (i%2==0)?min.X():mid.X(); - YminChild= ((i%4)/2==0)?min.Y():mid.Y(); - ZminChild= (i<4)?min.Z():mid.Z(); - minChild.SetCoord(XminChild, YminChild, ZminChild); - - box = new Bnd_B3d(minChild+childHsize,childHsize); - // The child is of the same type than its father (For instance, a SMESH_OctreeNode) - // We allocate the memory we need fot the child - myChildren[i] = allocateOctreeChild(); - // and we assign to him its box. - myChildren[i]->setBox(box); - delete box; + gp_XYZ min = getBox()->CornerMin(); + gp_XYZ max = getBox()->CornerMax(); + gp_XYZ Size = (max - min); + double returnVal = (Size.X()>Size.Y())?Size.X():Size.Y(); + return (returnVal>Size.Z())?returnVal:Size.Z(); } - - // After building the 8 boxes, we put the data into the children.. - buildChildrenData(); - - //After we pass to the next level of the Octree - for (int i =0; i<8; i++) - myChildren[i]->Compute(); + return 0.; } diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_OctreeNode.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_OctreeNode.cpp index 926b387ff110..e55128eb86c8 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_OctreeNode.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_OctreeNode.cpp @@ -1,36 +1,36 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH_OctreeNode : Octree with Nodes set -// inherites global class SMESH_Octree -// +// inherites class SMESH_Octree // File : SMESH_OctreeNode.cxx // Created : Tue Jan 16 16:00:00 2007 -// Author : Nicolas Geimer & Aurélien Motteux (OCC) +// Author : Nicolas Geimer & Aurelien Motteux (OCC) // Module : SMESH - +// #include "SMESH_OctreeNode.hxx" -#include "SMDS_MeshNode.hxx" #include "SMDS_SetIterator.hxx" +#include "SMESH_TypeDefs.hxx" #include using namespace std; @@ -44,20 +44,34 @@ using namespace std; * \param minBoxSize - Minimal size of the Octree Box */ //================================================================ -SMESH_OctreeNode::SMESH_OctreeNode (const set & theNodes, const int maxLevel, + +SMESH_OctreeNode::SMESH_OctreeNode (const TIDSortedNodeSet & theNodes, const int maxLevel, const int maxNbNodes , const double minBoxSize ) - :SMESH_Octree(maxLevel,minBoxSize), - myMaxNbNodes(maxNbNodes), - myNodes(theNodes) + :SMESH_Octree( new Limit( maxLevel,minBoxSize,maxNbNodes)), + myNodes(theNodes) +{ + compute(); +} + +//================================================================================ +/*! + * \brief Constructor used to allocate a child + */ +//================================================================================ + +SMESH_OctreeNode::SMESH_OctreeNode ():SMESH_Octree() +{ +} + +//================================================================================ +/*! + * \brief Return max number of nodes in a tree leaf + */ +//================================================================================ + +int SMESH_OctreeNode::getMaxNbNodes() const { - // We need to compute the first bounding box via a special method - computeBoxForFather(); - myNbNodes = myNodes.size(); - myIsLeaf = ((myLevel == myMaxLevel) || - (myNbNodes <= myMaxNbNodes) || - (maxSize(myBox) <= myMinBoxSize)); - // All the children (Boxes and Data) are computed in Compute() - Compute(); + return ((Limit*)myLimit)->myMaxNbNodes; } //================================================================================== @@ -65,16 +79,10 @@ SMESH_OctreeNode::SMESH_OctreeNode (const set & theNodes, * \brief Construct an empty SMESH_OctreeNode used by SMESH_Octree::buildChildren() */ //================================================================================== -SMESH_Octree* SMESH_OctreeNode::allocateOctreeChild() + +SMESH_Octree* SMESH_OctreeNode::newChild() const { - SMESH_OctreeNode * theOctree = new SMESH_OctreeNode(); - theOctree->myFather = this; - theOctree->myLevel = myLevel + 1; - theOctree->myMaxLevel = myMaxLevel; - theOctree->myMaxNbNodes = myMaxNbNodes; - theOctree->myMinBoxSize = myMinBoxSize; - theOctree->myNbNodes = 0; - return theOctree; + return new SMESH_OctreeNode(); } //====================================== @@ -84,25 +92,20 @@ SMESH_Octree* SMESH_OctreeNode::allocateOctreeChild() * We take the max/min coord of the nodes */ //====================================== -void SMESH_OctreeNode::computeBoxForFather() + +Bnd_B3d* SMESH_OctreeNode::buildRootBox() { - set::iterator it = myNodes.begin(); + Bnd_B3d* box = new Bnd_B3d; + TIDSortedNodeSet::iterator it = myNodes.begin(); for (; it != myNodes.end(); it++) { const SMDS_MeshNode* n1 = *it; gp_XYZ p1( n1->X(), n1->Y(), n1->Z() ); - myBox->Add(p1); + box->Add(p1); } -} + if ( myNodes.size() <= getMaxNbNodes() ) + myIsLeaf = true; -//==================================================================================== -/*! - * \brief Tell if Octree is a leaf or not (has to be implemented in inherited classes) - * \retval - True if the Octree is a leaf - */ -//==================================================================================== -const bool SMESH_OctreeNode::isLeaf() -{ - return myIsLeaf; + return box; } //==================================================================================== @@ -113,19 +116,14 @@ const bool SMESH_OctreeNode::isLeaf() * \retval bool - True if Node is in the box within precision */ //==================================================================================== -const bool SMESH_OctreeNode::isInside (const SMDS_MeshNode * Node, const double precision) + +const bool SMESH_OctreeNode::isInside (const gp_XYZ& p, const double precision) { - double X = Node->X(); - double Y = Node->Y(); - double Z = Node->Z(); - bool Out = 1 ; if (precision <= 0.) - return !(myBox->IsOut(gp_XYZ(X,Y,Z))); - Bnd_B3d BoxWithPrecision; - getBox(BoxWithPrecision); + return !(getBox()->IsOut(p)); + Bnd_B3d BoxWithPrecision = *getBox(); BoxWithPrecision.Enlarge(precision); - Out = BoxWithPrecision.IsOut(gp_XYZ(X,Y,Z)); - return !(Out); + return ! BoxWithPrecision.IsOut(p); } //================================================ @@ -136,16 +134,15 @@ const bool SMESH_OctreeNode::isInside (const SMDS_MeshNode * Node, const double //================================================ void SMESH_OctreeNode::buildChildrenData() { - gp_XYZ min = myBox->CornerMin(); - gp_XYZ max = myBox->CornerMax(); + gp_XYZ min = getBox()->CornerMin(); + gp_XYZ max = getBox()->CornerMax(); gp_XYZ mid = (min + max)/2.; - set::iterator it = myNodes.begin(); - int ChildBoxNum; + TIDSortedNodeSet::iterator it = myNodes.begin(); while (it != myNodes.end()) { const SMDS_MeshNode* n1 = *it; - ChildBoxNum = (n1->X() > mid.X()) + (n1->Y() > mid.Y())*2 + (n1->Z() > mid.Z())*4; + int ChildBoxNum = getChildIndex( n1->X(), n1->Y(), n1->Z(), mid ); SMESH_OctreeNode* myChild = dynamic_cast (myChildren[ChildBoxNum]); myChild->myNodes.insert(myChild->myNodes.end(),n1); myNodes.erase( it ); @@ -154,10 +151,8 @@ void SMESH_OctreeNode::buildChildrenData() for (int i = 0; i < 8; i++) { SMESH_OctreeNode* myChild = dynamic_cast (myChildren[i]); - myChild->myNbNodes = (myChild->myNodes).size(); - myChild->myIsLeaf = ((myChild->myLevel == myMaxLevel) || - (myChild->myNbNodes <= myMaxNbNodes) || - (maxSize(myChild->myBox) <= myMinBoxSize)); + if ( myChild->myNodes.size() <= getMaxNbNodes() ) + myChild->myIsLeaf = true; } } @@ -173,9 +168,10 @@ void SMESH_OctreeNode::NodesAround (const SMDS_MeshNode * Node, list* Result, const double precision) { - if (isInside(Node,precision)) + SMESH_TNodeXYZ p(Node); + if (isInside(p, precision)) { - if (myIsLeaf) + if (isLeaf()) { Result->insert(Result->end(), myNodes.begin(), myNodes.end()); } @@ -190,6 +186,100 @@ void SMESH_OctreeNode::NodesAround (const SMDS_MeshNode * Node, } } +//================================================================================ +/*! + * \brief Return in dist2Nodes nodes mapped to their square distance from Node + * Tries to find a closest node. + * \param node - node to find nodes closest to + * \param dist2Nodes - map of found nodes and their distances + * \param precision - radius of a sphere to check nodes inside + * \retval bool - true if an exact overlapping found !!! + */ +//================================================================================ + +bool SMESH_OctreeNode::NodesAround(const gp_XYZ &node, + map& dist2Nodes, + double precision) +{ + if ( !dist2Nodes.empty() ) + precision = min ( precision, sqrt( dist2Nodes.begin()->first )); + else if ( precision == 0. ) + precision = maxSize() / 2; + + if (isInside(node, precision)) + { + if (!isLeaf()) + { + // first check a child containing node + gp_XYZ mid = (getBox()->CornerMin() + getBox()->CornerMax()) / 2.; + int nodeChild = getChildIndex( node.X(), node.Y(), node.Z(), mid ); + if ( ((SMESH_OctreeNode*) myChildren[nodeChild])->NodesAround(node, dist2Nodes, precision)) + return true; + + for (int i = 0; i < 8; i++) + if ( i != nodeChild ) + if (((SMESH_OctreeNode*) myChildren[i])->NodesAround(node, dist2Nodes, precision)) + return true; + } + else if ( NbNodes() > 0 ) + { + double minDist = precision * precision; + TIDSortedNodeSet::iterator nIt = myNodes.begin(); + for ( ; nIt != myNodes.end(); ++nIt ) + { + SMESH_TNodeXYZ p2( *nIt ); + double dist2 = ( node - p2 ).SquareModulus(); + if ( dist2 < minDist ) + dist2Nodes.insert( make_pair( minDist = dist2, p2._node )); + } +// if ( dist2Nodes.size() > 1 ) // leave only closest node in dist2Nodes +// dist2Nodes.erase( ++dist2Nodes.begin(), dist2Nodes.end()); + + // true if an exact overlapping found + return ( sqrt( minDist ) <= precision * 1e-12 ); + } + } + return false; +} + +//================================================================================ +/*! + * \brief Return a list of nodes close to a point + * \param [in] point - point + * \param [out] nodes - found nodes + * \param [in] precision - allowed distance from \a point + */ +//================================================================================ + +void SMESH_OctreeNode::NodesAround(const gp_XYZ& point, + std::vector& nodes, + double precision) +{ + if ( isInside( point, precision )) + { + if ( isLeaf() && NbNodes() ) + { + double minDist2 = precision * precision; + TIDSortedNodeSet::iterator nIt = myNodes.begin(); + for ( ; nIt != myNodes.end(); ++nIt ) + { + SMESH_TNodeXYZ p2( *nIt ); + double dist2 = ( point - p2 ).SquareModulus(); + if ( dist2 <= minDist2 ) + nodes.push_back( p2._node ); + } + } + else if ( myChildren ) + { + for (int i = 0; i < 8; i++) + { + SMESH_OctreeNode* myChild = dynamic_cast (myChildren[i]); + myChild->NodesAround( point, nodes, precision); + } + } + } +} + //============================= /*! * \brief Return in theGroupsOfNodes a list of group of nodes close to each other within theTolerance @@ -202,15 +292,16 @@ void SMESH_OctreeNode::NodesAround (const SMDS_MeshNode * Node, * \param maxNbNodes - maximum Nodes in a Leaf of the SMESH_OctreeNode constructed, default value is 5 */ //============================= -void SMESH_OctreeNode::FindCoincidentNodes (set theSetOfNodes, +void SMESH_OctreeNode::FindCoincidentNodes (TIDSortedNodeSet& theSetOfNodes, list< list< const SMDS_MeshNode*> >* theGroupsOfNodes, const double theTolerance, const int maxLevel, const int maxNbNodes) { - SMESH_OctreeNode* theOctreeNode = new SMESH_OctreeNode(theSetOfNodes, maxLevel, maxNbNodes, theTolerance); - theOctreeNode->FindCoincidentNodes (&theSetOfNodes, theTolerance, theGroupsOfNodes); - delete theOctreeNode; + // VSR 14/10/2011: limit max number of the levels in order to avoid endless recursing + const int MAX_LEVEL = 10; + SMESH_OctreeNode theOctreeNode(theSetOfNodes, maxLevel < 0 ? MAX_LEVEL : maxLevel, maxNbNodes, theTolerance); + theOctreeNode.FindCoincidentNodes (&theSetOfNodes, theTolerance, theGroupsOfNodes); } //============================= @@ -223,42 +314,33 @@ void SMESH_OctreeNode::FindCoincidentNodes (set theSetOfNo * \param theGroupsOfNodes - list of nodes closed to each other returned */ //============================= -void SMESH_OctreeNode::FindCoincidentNodes ( set* theSetOfNodes, - const double theTolerance, +void SMESH_OctreeNode::FindCoincidentNodes ( TIDSortedNodeSet* theSetOfNodes, + const double theTolerance, list< list< const SMDS_MeshNode*> >* theGroupsOfNodes) { - set::iterator it1 = theSetOfNodes->begin(); + TIDSortedNodeSet::iterator it1 = theSetOfNodes->begin(); list::iterator it2; + list ListOfCoincidentNodes; + TIDCompare idLess; + while (it1 != theSetOfNodes->end()) { const SMDS_MeshNode * n1 = *it1; - list ListOfCoincidentNodes;// Initialize the lists via a declaration, it's enough - - list * groupPtr = 0; - // Searching for Nodes around n1 and put them in ListofCoincidentNodes. // Found nodes are also erased from theSetOfNodes FindCoincidentNodes(n1, theSetOfNodes, &ListOfCoincidentNodes, theTolerance); - // We build a list {n1 + his neigbours} and add this list in theGroupsOfNodes - for (it2 = ListOfCoincidentNodes.begin(); it2 != ListOfCoincidentNodes.end(); it2++) + if ( !ListOfCoincidentNodes.empty() ) { - const SMDS_MeshNode* n2 = *it2; - if ( !groupPtr ) - { - theGroupsOfNodes->push_back( list() ); - groupPtr = & theGroupsOfNodes->back(); - groupPtr->push_back( n1 ); - } - if (groupPtr->front() > n2) - groupPtr->push_front( n2 ); - else - groupPtr->push_back( n2 ); + // We build a list {n1 + his neigbours} and add this list in theGroupsOfNodes + if ( idLess( n1, ListOfCoincidentNodes.front() )) ListOfCoincidentNodes.push_front( n1 ); + else ListOfCoincidentNodes.push_back ( n1 ); + ListOfCoincidentNodes.sort( idLess ); + theGroupsOfNodes->push_back( list() ); + theGroupsOfNodes->back().splice( theGroupsOfNodes->back().end(), ListOfCoincidentNodes ); } - if (groupPtr != 0) - groupPtr->sort(); theSetOfNodes->erase(it1); it1 = theSetOfNodes->begin(); @@ -275,28 +357,27 @@ void SMESH_OctreeNode::FindCoincidentNodes ( set* theSetOf * \param precision - Precision used */ //====================================================================================== -void SMESH_OctreeNode::FindCoincidentNodes (const SMDS_MeshNode * Node, - set* SetOfNodes, +void SMESH_OctreeNode::FindCoincidentNodes (const SMDS_MeshNode * Node, + TIDSortedNodeSet* SetOfNodes, list* Result, - const double precision) + const double precision) { - bool isInsideBool = isInside(Node,precision); + gp_Pnt p1 (Node->X(), Node->Y(), Node->Z()); + bool isInsideBool = isInside( p1.XYZ(), precision ); if (isInsideBool) { // I'm only looking in the leaves, since all the nodes are stored there. - if (myIsLeaf) + if (isLeaf()) { - gp_Pnt p1 (Node->X(), Node->Y(), Node->Z()); - - set myNodesCopy = myNodes; - set::iterator it = myNodesCopy.begin(); - double tol2 = precision * precision; + TIDSortedNodeSet::iterator it = myNodes.begin(); + const double tol2 = precision * precision; bool squareBool; - while (it != myNodesCopy.end()) + while (it != myNodes.end()) { const SMDS_MeshNode* n2 = *it; + squareBool = false; // We're only looking at nodes with a superior Id. // JFA: Why? //if (Node->GetID() < n2->GetID()) @@ -311,14 +392,13 @@ void SMESH_OctreeNode::FindCoincidentNodes (const SMDS_MeshNode * Node, { Result->insert(Result->begin(), n2); SetOfNodes->erase( n2 ); - myNodes.erase( n2 ); + myNodes.erase( *it++ ); // it++ goes forward and returns it's previous position } } - //myNodesCopy.erase( it ); - //it = myNodesCopy.begin(); - it++; + if ( !squareBool ) + it++; } - if (Result->size() > 0) + if ( !Result->empty() ) myNodes.erase(Node); // JFA: for bug 0020185 } else @@ -333,6 +413,42 @@ void SMESH_OctreeNode::FindCoincidentNodes (const SMDS_MeshNode * Node, } } +//================================================================================ +/*! + * \brief Update data according to node movement + */ +//================================================================================ + +void SMESH_OctreeNode::UpdateByMoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt ) +{ + if ( isLeaf() ) + { + TIDSortedNodeSet::iterator pNode = myNodes.find( node ); + bool nodeInMe = ( pNode != myNodes.end() ); + + bool pointInMe = isInside( toPnt.Coord(), 1e-10 ); + + if ( pointInMe != nodeInMe ) + { + if ( pointInMe ) + myNodes.insert( node ); + else + myNodes.erase( node ); + } + } + else if ( myChildren ) + { + gp_XYZ mid = (getBox()->CornerMin() + getBox()->CornerMax()) / 2.; + int nodeChild = getChildIndex( node->X(), node->Y(), node->Z(), mid ); + int pointChild = getChildIndex( toPnt.X(), toPnt.Y(), toPnt.Z(), mid ); + if ( nodeChild != pointChild ) + { + ((SMESH_OctreeNode*) myChildren[ nodeChild ])->UpdateByMoveNode( node, toPnt ); + ((SMESH_OctreeNode*) myChildren[ pointChild ])->UpdateByMoveNode( node, toPnt ); + } + } +} + //================================================================================ /*! * \brief Return iterator over children @@ -341,8 +457,8 @@ void SMESH_OctreeNode::FindCoincidentNodes (const SMDS_MeshNode * Node, SMESH_OctreeNodeIteratorPtr SMESH_OctreeNode::GetChildrenIterator() { return SMESH_OctreeNodeIteratorPtr - ( new SMDS_SetIterator< SMESH_OctreeNode*, SMESH_Octree** > - ( myChildren, ( isLeaf() ? myChildren : &myChildren[ 8 ] ))); + ( new SMDS_SetIterator< SMESH_OctreeNode*, TBaseTree** > + ( myChildren, (( isLeaf() || !myChildren ) ? myChildren : &myChildren[ 8 ] ))); } //================================================================================ @@ -353,6 +469,6 @@ SMESH_OctreeNodeIteratorPtr SMESH_OctreeNode::GetChildrenIterator() SMDS_NodeIteratorPtr SMESH_OctreeNode::GetNodeIterator() { return SMDS_NodeIteratorPtr - ( new SMDS_SetIterator< SMDS_pNode, set< SMDS_pNode >::const_iterator > - ( myNodes.begin(), myNodes.end() )); + ( new SMDS_SetIterator< SMDS_pNode, TIDSortedNodeSet::const_iterator > + ( myNodes.begin(), myNodes.size() ? myNodes.end() : myNodes.begin())); } diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Pattern.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Pattern.cpp index aa02c183b357..eae5aee77376 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Pattern.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Pattern.cpp @@ -1,35 +1,46 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File : SMESH_Pattern.hxx // Created : Mon Aug 2 10:30:00 2004 // Author : Edward AGAPOV (eap) -// -#ifdef _MSC_VER -#define _USE_MATH_DEFINES -#endif // _MSC_VER -#include #include "SMESH_Pattern.hxx" +#include "SMDS_EdgePosition.hxx" +#include "SMDS_FacePosition.hxx" +#include "SMDS_MeshElement.hxx" +#include "SMDS_MeshFace.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMDS_VolumeTool.hxx" +#include "SMESHDS_Group.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESHDS_SubMesh.hxx" +#include "SMESH_Block.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MeshAlgos.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_subMesh.hxx" + #include #include #include @@ -44,7 +55,7 @@ #include #include #include -#include +#include #include #include #include @@ -64,46 +75,26 @@ #include #include -#include "SMDS_EdgePosition.hxx" -#include "SMDS_FacePosition.hxx" -#include "SMDS_MeshElement.hxx" -#include "SMDS_MeshFace.hxx" -#include "SMDS_MeshNode.hxx" -#include "SMDS_VolumeTool.hxx" -#include "SMESHDS_Group.hxx" -#include "SMESHDS_Mesh.hxx" -#include "SMESHDS_SubMesh.hxx" -#include "SMESH_Block.hxx" -#include "SMESH_Mesh.hxx" -#include "SMESH_MesherHelper.hxx" -#include "SMESH_subMesh.hxx" +#include +#include #include "utilities.h" -#ifndef PI -#define PI M_PI -#endif - using namespace std; typedef map< const SMDS_MeshElement*, int > TNodePointIDMap; #define smdsNode( elem ) static_cast( elem ) -//======================================================================= -//function : SMESH_Pattern -//purpose : -//======================================================================= - -SMESH_Pattern::SMESH_Pattern () +namespace { -} + //======================================================================= //function : getInt //purpose : //======================================================================= -static inline int getInt( const char * theSring ) +inline int getInt( const char * theSring ) { if ( *theSring < '0' || *theSring > '9' ) return -1; @@ -112,7 +103,7 @@ static inline int getInt( const char * theSring ) int val = strtol( theSring, &ptr, 10 ); if ( ptr == theSring || // there must not be neither '.' nor ',' nor 'E' ... - (*ptr != ' ' && *ptr != '\n' && *ptr != '\0')) + (*ptr != ' ' && *ptr != '\n' && *ptr != '\0' && *ptr != '\r')) return -1; return val; @@ -123,7 +114,7 @@ static inline int getInt( const char * theSring ) //purpose : //======================================================================= -static inline double getDouble( const char * theSring ) +inline double getDouble( const char * theSring ) { char *ptr; return strtod( theSring, &ptr ); @@ -135,9 +126,9 @@ static inline double getDouble( const char * theSring ) // Return the number of the found tokens //======================================================================= -static int readLine (list & theFields, - const char* & theLineBeg, - const bool theClearFields ) +int readLine (list & theFields, + const char* & theLineBeg, + const bool theClearFields ) { if ( theClearFields ) theFields.clear(); @@ -210,6 +201,65 @@ static int readLine (list & theFields, return nbRead; } +//======================================================================= +//function : isRealSeam +//purpose : return true if an EDGE encounters twice in a FACE +//======================================================================= + +// bool isRealSeam( const TopoDS_Edge& e, const TopoDS_Face& f ) +// { +// if ( BRep_Tool::IsClosed( e, f )) +// { +// int nb = 0; +// for (TopExp_Explorer exp( f, TopAbs_EDGE ); exp.More(); exp.Next()) +// if ( exp.Current().IsSame( e )) +// if ( ++nb == 2 ) +// return true; +// } +// return false; +// } + +//======================================================================= +//function : loadVE +//purpose : load VERTEXes and EDGEs in a map. Return nb loaded VERTEXes +//======================================================================= + +int loadVE( const list< TopoDS_Edge > & eList, + TopTools_IndexedMapOfOrientedShape & map ) +{ + list< TopoDS_Edge >::const_iterator eIt = eList.begin(); + // vertices + int nbV; + for ( eIt = eList.begin(); eIt != eList.end(); eIt++ ) + { + nbV = map.Extent(); + map.Add( TopExp::FirstVertex( *eIt, true )); + bool added = ( nbV < map.Extent() ); + if ( !added ) { // vertex encountered twice + // a seam vertex have two corresponding key points + map.Add( TopExp::FirstVertex( *eIt, true ).Reversed()); + } + } + nbV = map.Extent(); + + // edges + for ( eIt = eList.begin(); eIt != eList.end(); eIt++ ) + map.Add( *eIt ); + + return nbV; +} + +} // namespace + +//======================================================================= +//function : SMESH_Pattern +//purpose : +//======================================================================= + +SMESH_Pattern::SMESH_Pattern () +{ +} + //======================================================================= //function : Load //purpose : Load a pattern from @@ -219,6 +269,8 @@ bool SMESH_Pattern::Load (const char* theFileContents) { MESSAGE("Load( file ) "); + Kernel_Utils::Localizer loc; + // file structure: // ! This is a comment @@ -362,6 +414,9 @@ bool SMESH_Pattern::Load (const char* theFileContents) bool SMESH_Pattern::Save (ostream& theFile) { MESSAGE(" ::Save(file) " ); + + Kernel_Utils::Localizer loc; + if ( !IsLoaded() ) { MESSAGE(" Pattern not loaded "); return setErrorCode( ERR_SAVE_NOT_LOADED ); @@ -446,13 +501,8 @@ static gp_XY project (const SMDS_MeshNode* theNode, } double u, v, minVal = DBL_MAX; for ( int i = theProjectorPS.NbExt(); i > 0; i-- ) -#if OCC_VERSION_HEX >= 0x060500 - if ( theProjectorPS.SquareDistance( i ) < minVal ) { + if ( theProjectorPS.SquareDistance( i ) < minVal ) { minVal = theProjectorPS.SquareDistance( i ); -#else - if ( theProjectorPS.Value( i ) < minVal ) { - minVal = theProjectorPS.Value( i ); -#endif theProjectorPS.Point( i ).Parameter( u, v ); } return gp_XY( u, v ); @@ -471,8 +521,7 @@ template bool areNodesBound( TFaceIterator & faceItr ) while ( nIt->more() ) { const SMDS_MeshNode* node = smdsNode( nIt->next() ); - SMDS_PositionPtr pos = node->GetPosition(); - if ( !pos || !pos->GetShapeId() ) { + if (node->getshapeId() <1) { return false; } } @@ -491,7 +540,7 @@ static bool isMeshBoundToShape(SMESHDS_Mesh * aMeshDS, SMESHDS_SubMesh * aFaceSubmesh, const bool isMainShape) { - if ( isMainShape ) { + if ( isMainShape && aFaceSubmesh ) { // check that all faces are bound to aFaceSubmesh if ( aMeshDS->NbFaces() != aFaceSubmesh->NbElements() ) return false; @@ -515,7 +564,8 @@ static bool isMeshBoundToShape(SMESHDS_Mesh * aMeshDS, bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, const TopoDS_Face& theFace, - bool theProject) + bool theProject, + TopoDS_Vertex the1stVertex) { MESSAGE(" ::Load(face) " ); Clear(); @@ -523,6 +573,7 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS(); SMESHDS_SubMesh * fSubMesh = aMeshDS->MeshElements( theFace ); + const bool isQuadMesh = aMeshDS->GetMeshInfo().NbFaces( ORDER_QUADRATIC ); SMESH_MesherHelper helper( *theMesh ); helper.SetSubShape( theFace ); @@ -538,10 +589,9 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, // check if face is closed bool isClosed = helper.HasSeam(); - TopoDS_Vertex bidon; list eList; list::iterator elIt; - SMESH_Block::GetOrderedEdges( face, bidon, eList, myNbKeyPntInBoundary ); + SMESH_Block::GetOrderedEdges( face, eList, myNbKeyPntInBoundary, the1stVertex ); // check that requested or needed projection is possible bool isMainShape = theMesh->IsMainShape( face ); @@ -570,39 +620,26 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, // --------------------------------------------------------------- // get all faces - list< const SMDS_MeshElement* > faces; - if ( nbElems > 0 ) { - SMDS_ElemIteratorPtr fIt = fSubMesh->GetElements(); - while ( fIt->more() ) { - const SMDS_MeshElement* f = fIt->next(); - if ( f && f->GetType() == SMDSAbs_Face ) - faces.push_back( f ); - } - } - else { - SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator(); - while ( fIt->more() ) - faces.push_back( fIt->next() ); - } + SMDS_ElemIteratorPtr fIt; + if ( nbElems > 0 ) + fIt = fSubMesh->GetElements(); + else + fIt = aMeshDS->elementsIterator( SMDSAbs_Face ); // put nodes of all faces into the nodePointIDMap and fill myElemPointIDs - list< const SMDS_MeshElement* >::iterator fIt = faces.begin(); - for ( ; fIt != faces.end(); ++fIt ) + while ( fIt->more() ) { + const SMDS_MeshElement* face = fIt->next(); myElemPointIDs.push_back( TElemDef() ); TElemDef& elemPoints = myElemPointIDs.back(); - SMDS_ElemIteratorPtr nIt = (*fIt)->nodesIterator(); - while ( nIt->more() ) + int nbNodes = face->NbCornerNodes(); + for ( int i = 0;i < nbNodes; ++i ) { - const SMDS_MeshElement* node = nIt->next(); - TNodePointIDMap::iterator nIdIt = nodePointIDMap.find( node ); - if ( nIdIt == nodePointIDMap.end() ) - { - elemPoints.push_back( iPoint ); - nodePointIDMap.insert( make_pair( node, iPoint++ )); - } - else - elemPoints.push_back( (*nIdIt).second ); + const SMDS_MeshElement* node = face->GetNode( i ); + TNodePointIDMap::iterator nIdIt = nodePointIDMap.insert( make_pair( node, -1 )).first; + if ( nIdIt->second == -1 ) + nIdIt->second = iPoint++; + elemPoints.push_back( (*nIdIt).second ); } } myPoints.resize( iPoint ); @@ -646,31 +683,34 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, // Load shapes in the consequent order and count nb of points - // vertices - for ( elIt = eList.begin(); elIt != eList.end(); elIt++ ) { - int nbV = myShapeIDMap.Extent(); - myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true )); - bool added = ( nbV < myShapeIDMap.Extent() ); - if ( !added ) { // vertex encountered twice - // a seam vertex have two corresponding key points - myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ).Reversed()); - ++nbNodes; - } + loadVE( eList, myShapeIDMap ); + myShapeIDMap.Add( face ); + + nbNodes += myShapeIDMap.Extent() - 1; + + for ( elIt = eList.begin(); elIt != eList.end(); elIt++ ) if ( SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( *elIt )) nbNodes += eSubMesh->NbNodes() + 1; - } - // edges - for ( elIt = eList.begin(); elIt != eList.end(); elIt++ ) - myShapeIDMap.Add( *elIt ); - // the face - myShapeIDMap.Add( face ); myPoints.resize( nbNodes ); // Load U of points on edges - for ( elIt = eList.begin(); elIt != eList.end(); elIt++ ) + list::iterator nbEinW = myNbKeyPntInBoundary.begin(); + int iE = 0; + vector< TopoDS_Edge > eVec; + for ( elIt = eList.begin(); elIt != eList.end(); elIt++, iE++ ) { + if ( isClosed && ( iE == 0 || iE == *nbEinW )) + { + // new wire begins; put wire EDGEs in eVec + list::iterator eEnd = elIt; + if ( iE == *nbEinW ) + ++nbEinW; + std::advance( eEnd, *nbEinW ); + eVec.assign( elIt, eEnd ); + iE = 0; + } TopoDS_Edge & edge = *elIt; list< TPoint* > & ePoints = getShapePoints( edge ); double f, l; @@ -680,7 +720,7 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, TopoDS_Shape v1 = TopExp::FirstVertex( edge, true ); // always FORWARD TopoDS_Shape v2 = TopExp::LastVertex( edge, true ); // always REVERSED // to make adjacent edges share key-point, we make v2 FORWARD too - // (as we have different points for same shape with different orienation) + // (as we have different points for same shape with different orientation) v2.Reverse(); // on closed face we must have REVERSED some of seam vertices @@ -692,18 +732,13 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, v2.Reverse(); } } - else { // on CLOSED edge (i.e. having one vertex with different orienations) + else { // on CLOSED edge (i.e. having one vertex with different orientations) for ( int is2 = 0; is2 < 2; ++is2 ) { TopoDS_Shape & v = is2 ? v2 : v1; if ( helper.IsRealSeam( v ) ) { // reverse or not depending on orientation of adjacent seam - TopoDS_Edge seam; - list::iterator eIt2 = elIt; - if ( is2 ) - seam = ( ++eIt2 == eList.end() ? eList.front() : *eIt2 ); - else - seam = ( eIt2 == eList.begin() ? eList.back() : *(--eIt2) ); - if ( seam.Orientation() == TopAbs_REVERSED ) + int iSeam = helper.WrapIndex( iE + ( is2 ? +1 : -1 ), eVec.size() ); + if ( eVec[ iSeam ].Orientation() == TopAbs_REVERSED ) v.Reverse(); } } @@ -743,12 +778,17 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, // loop on nodes of an edge: sort them by param on edge typedef map < double, const SMDS_MeshNode* > TParamNodeMap; TParamNodeMap paramNodeMap; + int nbMeduimNodes = 0; SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes(); while ( nIt->more() ) { - const SMDS_MeshNode* node = smdsNode( nIt->next() ); + const SMDS_MeshNode* node = nIt->next(); + if ( isQuadMesh && helper.IsMedium( node, SMDSAbs_Face )) { + ++nbMeduimNodes; + continue; + } const SMDS_EdgePosition* epos = - static_cast(node->GetPosition().get()); + static_cast(node->GetPosition()); double u = epos->GetUParameter(); paramNodeMap.insert( make_pair( u, node )); } @@ -760,7 +800,9 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, paramNodeMap.clear(); nIt = eSubMesh->GetNodes(); for ( int iNode = 0; nIt->more(); ++iNode ) { - const SMDS_MeshNode* node = smdsNode( nIt->next() ); + const SMDS_MeshNode* node = nIt->next(); + if ( isQuadMesh && helper.IsMedium( node, SMDSAbs_Face )) + continue; proj.Perform( gp_Pnt( node->X(), node->Y(), node->Z())); double u = 0; if ( proj.IsDone() ) { @@ -774,7 +816,12 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, } paramNodeMap.insert( make_pair( u, node )); } + + //rnv : To fix the bug IPAL21999 Pattern Mapping - New - collapse of pattern mesh + if ( paramNodeMap.size() != eSubMesh->NbNodes() - nbMeduimNodes ) + return setErrorCode(ERR_UNEXPECTED); } + // put U in [0,1] so that the first key-point has U==0 bool isSeam = helper.IsRealSeam( edge ); double du = l - f; @@ -857,7 +904,9 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, SMDS_NodeIteratorPtr nIt = fSubMesh->GetNodes(); while ( nIt->more() ) { - const SMDS_MeshNode* node = smdsNode( nIt->next() ); + const SMDS_MeshNode* node = nIt->next(); + if ( isQuadMesh && helper.IsMedium( node, SMDSAbs_Face )) + continue; nodePointIDMap.insert( make_pair( node, iPoint )); TPoint* p = &myPoints[ iPoint++ ]; fPoints.push_back( p ); @@ -865,7 +914,7 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, p->myInitUV = project( node, projector ); else { const SMDS_FacePosition* pos = - static_cast(node->GetPosition().get()); + static_cast(node->GetPosition()); p->myInitUV.SetCoord( pos->GetUParameter(), pos->GetVParameter() ); } p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 ); @@ -883,9 +932,12 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, while ( nIt->more() ) { const SMDS_MeshNode* node = smdsNode( nIt->next() ); - iPoint = nodePointIDMap[ node ]; // point index of interest + n_id = nodePointIDMap.find( node ); + if ( n_id == nodePointIDMap.end() ) + continue; // medium node + iPoint = n_id->second; // point index of interest // for a node on a seam edge there are two points - if ( helper.IsRealSeam( node->GetPosition()->GetShapeId() ) && + if ( helper.IsRealSeam( node->getshapeId() ) && ( n_id = closeNodePointIDMap.find( node )) != not_found ) { TPoint & p1 = myPoints[ iPoint ]; @@ -896,7 +948,7 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, // find node not on a seam edge while ( nIt2->more() && !notSeamNode ) { const SMDS_MeshNode* n = smdsNode( nIt2->next() ); - if ( !helper.IsSeamShape( n->GetPosition()->GetShapeId() )) + if ( !helper.IsSeamShape( n->getshapeId() )) notSeamNode = n; } gp_Pnt2d uv = helper.GetNodeUV( theFace, node, notSeamNode ); @@ -909,6 +961,7 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, } } } + myPoints.resize( nodePointIDMap.size() + closeNodePointIDMap.size() ); myIsBoundaryPointsFound = true; } @@ -980,6 +1033,7 @@ void SMESH_Pattern::computeUVOnEdge (const TopoDS_Edge& theEdge, BRep_Tool::CurveOnSurface( theEdge, TopoDS::Face( myShape ), f, l ); ePoints.back()->myInitU = 1.0; + //ePoints.front()->myInitU = 0.0; //myUV = C2d->Value( isForward ? f : l ).XY(); list< TPoint* >::const_iterator pIt = ePoints.begin(); for ( pIt++; pIt != ePoints.end(); pIt++ ) { @@ -1243,7 +1297,7 @@ static bool checkQuads (const TIsoNode* node, maxLen2 = Max( maxLen2, ( n[1]->myUV - n[2]->myUV ).SquareModulus() ); } maxLen2 = Max( maxLen2, ( n[2]->myUV - node->myUV ).SquareModulus() ); - minDiag = sqrt( maxLen2 ) * PI / 60.; // ~ maxLen * Sin( 3 deg ) + minDiag = sqrt( maxLen2 ) * M_PI / 60.; // ~ maxLen * Sin( 3 deg ) } // check if newUV is behind 3 dirs: n[0]-n[1], n[1]-n[2] and n[0]-n[2] @@ -1794,7 +1848,7 @@ bool SMESH_Pattern:: double initAngle = initTgt1.Angle( initTgt2 ); double angle = node->myDir[0].Angle( node->myDir[1] ); if ( reversed ) angle = -angle; - if ( initAngle > angle && initAngle - angle > PI / 2.1 ) { + if ( initAngle > angle && initAngle - angle > M_PI / 2.1 ) { // find a close internal node TIsoNode* nClose = 0; list< TIsoNode* > testNodes; @@ -1888,7 +1942,7 @@ bool SMESH_Pattern:: for ( nIt = startNodes.begin(); nIt != startNodes.end(); nIt++ ) { - TIsoNode* prevN[2], *node = *nIt; + TIsoNode *node = *nIt; if ( node->IsUVComputed() || !node->IsMovable() ) continue; gp_XY newUV( 0, 0 ), sumDir( 0, 0 ); @@ -1949,7 +2003,6 @@ bool SMESH_Pattern:: newUV += prevNode1->myUV + dir * step[ iDir ]; } sumDir += dir; - prevN[ iDir ] = prevNode1; nbComp++; } } @@ -2011,7 +2064,7 @@ bool SMESH_Pattern:: } // define ratio bool ok = true; // <- stupid fix TO AVOID PB OF NODES WITH NULL BND NODES - double locR[2] = { 0, 0 }; +// double locR[2] = { 0, 0 }; for ( iDir = 0; iDir < 2; iDir++ ) { const int iCoord = 2 - iDir; // coord changing along an isoline @@ -2025,7 +2078,7 @@ bool SMESH_Pattern:: double par3 = bndNode2->myInitUV.Coord( iCoord ); double r = ( par2 - par1 ) / ( par3 - par1 ); r = Abs ( r - 0.5 ) * 2.0; // [0,1] - distance from the middle - locR[ iDir ] = ( 1 - r * r ) * 0.25; +// locR[ iDir ] = ( 1 - r * r ) * 0.25; } //locR[0] = locR[1] = 0.25; // intersect the 2 lines and move a node @@ -2353,7 +2406,7 @@ bool SMESH_Pattern::Apply (const TopoDS_Face& theFace, list< TopoDS_Edge > eList; list< int > nbVertexInWires; - int nbWires = SMESH_Block::GetOrderedEdges( face, theVertexOnKeyPoint1, eList, nbVertexInWires); + int nbWires = SMESH_Block::GetOrderedEdges( face, eList, nbVertexInWires, theVertexOnKeyPoint1); if ( !theVertexOnKeyPoint1.IsSame( TopExp::FirstVertex( eList.front(), true ))) { MESSAGE( " theVertexOnKeyPoint1 not found in the outer wire "); @@ -2369,33 +2422,7 @@ bool SMESH_Pattern::Apply (const TopoDS_Face& theFace, } // here shapes get IDs, for the outer wire IDs are OK - list::iterator elIt = eList.begin(); - for ( ; elIt != eList.end(); elIt++ ) { - myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true )); - bool isClosed1 = BRep_Tool::IsClosed( *elIt, theFace ); - // BEGIN: jfa for bug 0019943 - if (isClosed1) { - isClosed1 = false; - for (TopExp_Explorer expw (theFace, TopAbs_WIRE); expw.More() && !isClosed1; expw.Next()) { - const TopoDS_Wire& wire = TopoDS::Wire(expw.Current()); - int nbe = 0; - for (BRepTools_WireExplorer we (wire, theFace); we.More() && !isClosed1; we.Next()) { - if (we.Current().IsSame(*elIt)) { - nbe++; - if (nbe == 2) isClosed1 = true; - } - } - } - } - // END: jfa for bug 0019943 - if (isClosed1) - myShapeIDMap.Add( TopExp::LastVertex( *elIt, true ));// vertex orienation is REVERSED - } - int nbVertices = myShapeIDMap.Extent(); - - for ( elIt = eList.begin(); elIt != eList.end(); elIt++ ) - myShapeIDMap.Add( *elIt ); - + int nbVertices = loadVE( eList, myShapeIDMap ); myShapeIDMap.Add( face ); if ( myShapeIDToPointsMap.size() != myShapeIDMap.Extent() ) { @@ -2407,10 +2434,11 @@ bool SMESH_Pattern::Apply (const TopoDS_Face& theFace, list< list< TPoint* > > edgesPointsList; edgesPointsList.push_back( list< TPoint* >() ); list< TPoint* > * edgesPoints = & edgesPointsList.back(); - list< TPoint* >::iterator pIt; + list< TPoint* >::iterator pIt, pEnd; // compute UV of points on the outer wire int iE, nbEdgesInOuterWire = nbVertexInWires.front(); + list< TopoDS_Edge >::iterator elIt; for (iE = 0, elIt = eList.begin(); iE < nbEdgesInOuterWire && elIt != eList.end(); iE++, elIt++ ) @@ -2475,7 +2503,7 @@ bool SMESH_Pattern::Apply (const TopoDS_Face& theFace, list< TopoDS_Edge >& wire = (*wlIt); int nbEdges = wire.size(); wlIt++; - if ( wlIt == wireList.end() || (*wlIt).size() != nbEdges ) // a unique size wire + if ( wlIt != wireList.end() && (*wlIt).size() != nbEdges ) // a unique size wire { // choose the best first edge of a wire setFirstEdge( wire, id1 ); @@ -2525,14 +2553,24 @@ bool SMESH_Pattern::Apply (const TopoDS_Face& theFace, // re-fill myShapeIDMap - all shapes get good IDs myShapeIDMap.Clear(); - for ( elIt = eList.begin(); elIt != eList.end(); elIt++ ) - myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true )); - for ( elIt = eList.begin(); elIt != eList.end(); elIt++ ) - myShapeIDMap.Add( *elIt ); + nbVertices = loadVE( eList, myShapeIDMap ); myShapeIDMap.Add( face ); } // there are inner wires + // Set XYZ of on-vertex points + + // for ( int iV = 1; iV <= nbVertices; ++iV ) + // { + // const TopoDS_Vertex& V = TopoDS::Vertex( myShapeIDMap( iV )); + // list< TPoint* > & vPoints = getShapePoints( iV ); + // if ( !vPoints.empty() ) + // { + // //vPoints.front()->myUV = BRep_Tool::Parameters( V, theFace ).XY(); + // vPoints.front()->myXYZ = BRep_Tool::Pnt( V ); + // } + // } + // Compute XYZ of on-edge points TopLoc_Location loc; @@ -2540,8 +2578,7 @@ bool SMESH_Pattern::Apply (const TopoDS_Face& theFace, { BRepAdaptor_Curve C3d( *elIt ); list< TPoint* > & ePoints = getShapePoints( iE++ ); - pIt = ePoints.begin(); - for ( pIt++; pIt != ePoints.end(); pIt++ ) + for ( pIt = ++ePoints.begin(), pEnd = ePoints.end(); pIt != pEnd; pIt++ ) { TPoint* point = *pIt; point->myXYZ = C3d.Value( point->myU ); @@ -2604,8 +2641,9 @@ bool SMESH_Pattern::Apply (const SMDS_MeshFace* theFace, } // check nb of nodes - if (theFace->NbNodes() != myNbKeyPntInBoundary.front() ) { - MESSAGE( myKeyPointIDs.size() << " != " << theFace->NbNodes() ); + const int nbFaceNodes = theFace->NbCornerNodes(); + if ( nbFaceNodes != myNbKeyPntInBoundary.front() ) { + MESSAGE( myKeyPointIDs.size() << " != " << nbFaceNodes ); return setErrorCode( ERR_APPL_BAD_NB_VERTICES ); } @@ -2622,10 +2660,10 @@ bool SMESH_Pattern::Apply (const SMDS_MeshFace* theFace, list< const SMDS_MeshNode* > nodes; list< const SMDS_MeshNode* >::iterator n = nodes.end(); - SMDS_ElemIteratorPtr noIt = theFace->nodesIterator(); + SMDS_NodeIteratorPtr noIt = theFace->nodeIterator(); int iSub = 0; - while ( noIt->more() ) { - const SMDS_MeshNode* node = smdsNode( noIt->next() ); + while ( noIt->more() && iSub < nbFaceNodes ) { + const SMDS_MeshNode* node = noIt->next(); nodes.push_back( node ); if ( iSub++ == theNodeIndexOnKeyPoint1 ) n = --nodes.end(); @@ -2640,9 +2678,9 @@ bool SMESH_Pattern::Apply (const SMDS_MeshFace* theFace, nodes.splice( nodes.end(), nodes, nodes.begin(), n ); } list< gp_XYZ > xyzList; - myOrderedNodes.resize( theFace->NbNodes() ); + myOrderedNodes.resize( nbFaceNodes ); for ( iSub = 0, n = nodes.begin(); n != nodes.end(); ++n ) { - xyzList.push_back( gp_XYZ( (*n)->X(), (*n)->Y(), (*n)->Z() )); + xyzList.push_back( SMESH_TNodeXYZ( *n )); myOrderedNodes[ iSub++] = *n; } @@ -2944,11 +2982,6 @@ bool SMESH_Pattern::Apply (SMESH_Mesh* theMesh, myXYZ.resize( myPoints.size() * theFaces.size(), undefinedXYZ() ); myElements.reserve( theFaces.size() ); - // to find point index - map< TPoint*, int > pointIndex; - for ( int i = 0; i < myPoints.size(); i++ ) - pointIndex.insert( make_pair( & myPoints[ i ], i )); - int ind1 = 0; // lowest point index for a face // meshed geometry @@ -2995,12 +3028,12 @@ bool SMESH_Pattern::Apply (SMESH_Mesh* theMesh, } // put points on links to myIdsOnBoundary, // they will be used to sew new elements on adjacent refined elements - int nbNodes = (*face)->NbNodes(), eID = nbNodes + 1; + int nbNodes = (*face)->NbCornerNodes(), eID = nbNodes + 1; for ( int i = 0; i < nbNodes; i++ ) { list< TPoint* > & linkPoints = getShapePoints( eID++ ); const SMDS_MeshNode* n1 = myOrderedNodes[ i ]; - const SMDS_MeshNode* n2 = myOrderedNodes[ i + 1 == nbNodes ? 0 : i + 1 ]; + const SMDS_MeshNode* n2 = myOrderedNodes[( i+1 ) % nbNodes ]; // make a link and a node set TNodeSet linkSet, node1Set; linkSet.insert( n1 ); @@ -3009,7 +3042,7 @@ bool SMESH_Pattern::Apply (SMESH_Mesh* theMesh, list< TPoint* >::iterator p = linkPoints.begin(); { // map the first link point to n1 - int nId = pointIndex[ *p ] + ind1; + int nId = ( *p - &myPoints[0] ) + ind1; myXYZIdToNodeMap[ nId ] = n1; list< list< int > >& groups = myIdsOnBoundary[ node1Set ]; groups.push_back(list< int > ()); @@ -3021,7 +3054,7 @@ bool SMESH_Pattern::Apply (SMESH_Mesh* theMesh, list< int >& indList = groups.back(); // add points to the map excluding the end points for ( p++; *p != linkPoints.back(); p++ ) - indList.push_back( pointIndex[ *p ] + ind1 ); + indList.push_back( ( *p - &myPoints[0] ) + ind1 ); } ind1 += myPoints.size(); } @@ -3155,6 +3188,8 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, myIs2D = false; SMESHDS_SubMesh * aSubMesh; + const bool isQuadMesh = theMesh->NbVolumes( ORDER_QUADRATIC ); + // load shapes in myShapeIDMap SMESH_Block block; TopoDS_Vertex v1, v2; @@ -3187,6 +3222,8 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, // store a node and a point while ( nIt->more() ) { const SMDS_MeshNode* node = smdsNode( nIt->next() ); + if ( isQuadMesh && SMESH_MeshEditor::IsMedium( node, SMDSAbs_Volume )) + continue; nodePointIDMap.insert( make_pair( node, iPoint )); if ( block.IsVertexID( shapeID )) myKeyPointIDs.push_back( iPoint ); @@ -3221,9 +3258,11 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, nIt = aSubMesh->GetNodes(); for ( ; nIt->more(); pIt++ ) { - const SMDS_MeshNode* node = smdsNode( nIt->next() ); + const SMDS_MeshNode* node = nIt->next(); + if ( isQuadMesh && SMESH_MeshEditor::IsMedium( node, SMDSAbs_Edge )) + continue; const SMDS_EdgePosition* epos = - static_cast(node->GetPosition().get()); + static_cast(node->GetPosition()); double u = ( epos->GetUParameter() - f ) / ( l - f ); (*pIt)->myInitXYZ.SetCoord( iCoord, isForward ? u : 1 - u ); } @@ -3247,11 +3286,12 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, { SMDS_ElemIteratorPtr elemIt = aSubMesh->GetElements(); while ( elemIt->more() ) { - SMDS_ElemIteratorPtr nIt = elemIt->next()->nodesIterator(); + const SMDS_MeshElement* elem = elemIt->next(); myElemPointIDs.push_back( TElemDef() ); TElemDef& elemPoints = myElemPointIDs.back(); - while ( nIt->more() ) - elemPoints.push_back( nodePointIDMap[ nIt->next() ]); + int nbNodes = elem->NbCornerNodes(); + for ( int i = 0;i < nbNodes; ++i ) + elemPoints.push_back( nodePointIDMap[ elem->GetNode( i )]); } } @@ -3417,7 +3457,7 @@ void SMESH_Pattern::mergePoints (const bool uniteGroups) Bnd_Box box; TNodeSet::const_iterator n = nodes.begin(); for ( ; n != nodes.end(); ++n ) - box.Add( gp_Pnt( (*n)->X(), (*n)->Y(), (*n)->Z() )); + box.Add( gp_Pnt( SMESH_TNodeXYZ( *n ))); double x, y, z, X, Y, Z; box.Get( x, y, z, X, Y, Z ); gp_Pnt p( x, y, z ), P( X, Y, Z ); @@ -3428,7 +3468,7 @@ void SMESH_Pattern::mergePoints (const bool uniteGroups) bool unite = ( uniteGroups && nodes.size() == 2 ); map< double, int > distIndMap; const SMDS_MeshNode* node = *nodes.begin(); - gp_Pnt P( node->X(), node->Y(), node->Z() ); + gp_Pnt P = SMESH_TNodeXYZ( node ); // compare points, replace indices @@ -3501,13 +3541,7 @@ void SMESH_Pattern:: myPolyElems.reserve( myIdsOnBoundary.size() ); // make a set of refined elements - TIDSortedElemSet avoidSet, elemSet; - std::vector::iterator itv = myElements.begin(); - for(; itv!=myElements.end(); itv++) { - const SMDS_MeshElement* el = (*itv); - avoidSet.insert( el ); - } - //avoidSet.insert( myElements.begin(), myElements.end() ); + TIDSortedElemSet elemSet, avoidSet( myElements.begin(), myElements.end() ); map< TNodeSet, list< list< int > > >::iterator indListIt, nn_IdList; @@ -3534,7 +3568,7 @@ void SMESH_Pattern:: while (true) { const SMDS_MeshElement* face = - SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet ); + SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet ); if ( face ) { avoidSet.insert ( face ); @@ -3699,13 +3733,8 @@ bool SMESH_Pattern:: vector& theQuantity) { bool makePoly = false; -// cout << "FROM FACE NODES: " < bndNodeSet; - for ( int i = 0; i < theNbBndNodes; ++i ) - bndNodeSet.insert( theBndNodes[ i ]); + set< const SMDS_MeshNode* > bndNodeSet( theBndNodes, theBndNodes + theNbBndNodes); map< TNodeSet, list< list< int > > >::iterator nn_IdList; @@ -3714,12 +3743,13 @@ bool SMESH_Pattern:: if ( !myIs2D ) { // for 2D, merge only edges nn_IdList = myIdsOnBoundary.find( bndNodeSet ); if ( nn_IdList != myIdsOnBoundary.end() ) { - makePoly = true; list< int > & faceIds = nn_IdList->second.front(); - ids.insert( faceIds.begin(), faceIds.end() ); + if ( !faceIds.empty() ) { + makePoly = true; + ids.insert( faceIds.begin(), faceIds.end() ); + } } } - //bool hasIdsInFace = !ids.empty(); // add ids on links and bnd nodes int lastFreeId = Max( myXYZIdToNodeMap.rbegin()->first, theNodes.size() ); @@ -3735,22 +3765,26 @@ bool SMESH_Pattern:: bndId = nn_IdList->second.front().front(); ids.insert( bndId ); } - else + else { myXYZIdToNodeMap.insert( make_pair( bndId, theBndNodes[ iN ] )); + } faceDef.push_back( bndId ); // add ids on a link TNodeSet linkNodes; linkNodes.insert( theBndNodes[ iN ]); - linkNodes.insert( theBndNodes[ iN + 1 == theNbBndNodes ? 0 : iN + 1 ]); + linkNodes.insert( theBndNodes[ (iN + 1) % theNbBndNodes] ); nn_IdList = myIdsOnBoundary.find( linkNodes ); if ( nn_IdList != myIdsOnBoundary.end() ) { - makePoly = true; list< int > & linkIds = nn_IdList->second.front(); - ids.insert( linkIds.begin(), linkIds.end() ); - if ( isReversed( theBndNodes[ iN ], linkIds )) - faceDef.insert( faceDef.end(), linkIds.begin(), linkIds.end() ); - else - faceDef.insert( faceDef.end(), linkIds.rbegin(), linkIds.rend() ); + if ( !linkIds.empty() ) + { + makePoly = true; + ids.insert( linkIds.begin(), linkIds.end() ); + if ( isReversed( theBndNodes[ iN ], linkIds )) + faceDef.insert( faceDef.end(), linkIds.begin(), linkIds.end() ); + else + faceDef.insert( faceDef.end(), linkIds.rbegin(), linkIds.rend() ); + } } } @@ -3772,9 +3806,7 @@ bool SMESH_Pattern:: { if ( !checkedVolDefs.insert( *pIdList ).second ) continue; // skip already checked volume definition - vector< int > idVec; - idVec.reserve( (*pIdList)->size() ); - idVec.insert( idVec.begin(), (*pIdList)->begin(), (*pIdList)->end() ); + vector< int > idVec( (*pIdList)->begin(), (*pIdList)->end() ); // loop on face defs of a volume SMDS_VolumeTool::VolumeType volType = vol.GetType( idVec.size() ); if ( volType == SMDS_VolumeTool::UNKNOWN ) @@ -3804,7 +3836,7 @@ bool SMESH_Pattern:: } if ( !defsAdded ) { theQuantity.push_back( faceDef.size() ); - theFaceDefs.splice( theFaceDefs.end(), faceDef, faceDef.begin(), faceDef.end() ); + theFaceDefs.splice( theFaceDefs.end(), faceDef ); } return makePoly; @@ -3862,13 +3894,97 @@ void SMESH_Pattern::clearMesh(SMESH_Mesh* theMesh) const } } +//======================================================================= +//function : findExistingNodes +//purpose : fills nodes vector with nodes existing on a given shape (IMP 22368) +// Returns true if all nodes for all points on S are found +//======================================================================= + +bool SMESH_Pattern::findExistingNodes( SMESH_Mesh* mesh, + const TopoDS_Shape& S, + const std::list< TPoint* > & points, + vector< const SMDS_MeshNode* > & nodesVector) +{ + if ( S.IsNull() || points.empty() ) + return false; + + SMESHDS_Mesh* aMeshDS = mesh->GetMeshDS(); + + switch ( S.ShapeType() ) + { + case TopAbs_VERTEX: + { + int pIndex = points.back() - &myPoints[0]; + if ( !nodesVector[ pIndex ] ) + nodesVector[ pIndex ] = SMESH_Algo::VertexNode( TopoDS::Vertex( S ), aMeshDS ); + return nodesVector[ pIndex ]; + } + case TopAbs_EDGE: + { + const TopoDS_Edge& edge = TopoDS::Edge( S ); + map< double, const SMDS_MeshNode* > paramsOfNodes; + if ( !SMESH_Algo::GetSortedNodesOnEdge( aMeshDS, edge, + /*ignoreMediumNodes=*/false, + paramsOfNodes ) + || paramsOfNodes.size() < 3 ) + break; + // points on VERTEXes are included with wrong myU + list< TPoint* >::const_reverse_iterator pItR = ++points.rbegin(); + list< TPoint* >::const_iterator pItF = ++points.begin(); + const bool isForward = ( (*pItF)->myU < (*pItR)->myU ); + map< double, const SMDS_MeshNode* >::iterator u2n = ++paramsOfNodes.begin(); + map< double, const SMDS_MeshNode* >::iterator u2nEnd = --paramsOfNodes.end(); + TPoint* p; + if ( paramsOfNodes.size() == points.size() ) + { + for ( ; u2n != u2nEnd; ++u2n ) + { + p = ( isForward ? *pItF : *pItR ); + int pIndex = p - &myPoints[0]; + if ( !nodesVector [ pIndex ] ) + nodesVector [ pIndex ] = u2n->second; + ++pItF; + ++pItR; + } + return true; + } + else + { + const double tolFact = 0.05; + while ( u2n != u2nEnd && pItF != points.end() ) + { + const double u = u2n->first; + const SMDS_MeshNode* n = u2n->second; + const double tol = ( (++u2n)->first - u ) * tolFact; + do + { + p = ( isForward ? *pItF : *pItR ); + if ( Abs( u - p->myU ) < tol ) + { + int pIndex = p - &myPoints[0]; + if ( !nodesVector [ pIndex ] ) + nodesVector [ pIndex ] = n; + ++pItF; + ++pItR; + break; + } + } + while ( p->myU < u && ( ++pItF, ++pItR != points.rend() )); + } + } + break; + } // case TopAbs_EDGE: + + default:; + } // switch ( S.ShapeType() ) + + return false; +} + //======================================================================= //function : MakeMesh //purpose : Create nodes and elements in using nodes // coordinates computed by either of Apply...() methods -// WARNING : StdMeshers_Projection_... relies on MakeMesh() behavior: that -// it does not care of nodes and elements already existing on -// subshapes. DO NOT MERGE them or modify also StdMeshers_Projection_.. //======================================================================= bool SMESH_Pattern::MakeMesh(SMESH_Mesh* theMesh, @@ -3904,32 +4020,83 @@ bool SMESH_Pattern::MakeMesh(SMESH_Mesh* theMesh, myXYZ[ i ].Y(), myXYZ[ i ].Z()); } - } + if ( theMesh->HasShapeToMesh() ) + { + // set nodes on EDGEs (IMP 22368) + SMESH_MesherHelper helper( *theMesh ); + helper.ToFixNodeParameters( true ); + map< TNodeSet, list< list< int > > >::iterator idListIt = myIdsOnBoundary.begin(); + for ( ; idListIt != myIdsOnBoundary.end(); idListIt++ ) + { + list >& groups = idListIt->second; + const TNodeSet& nodes = idListIt->first; + if ( nodes.size() != 2 ) + continue; // not a link + const SMDS_MeshNode* n1 = *nodes.begin(); + const SMDS_MeshNode* n2 = *nodes.rbegin(); + TopoDS_Shape S1 = helper.GetSubShapeByNode( n1, aMeshDS ); + TopoDS_Shape S2 = helper.GetSubShapeByNode( n2, aMeshDS ); + if ( S1.IsNull() || S1.ShapeType() < TopAbs_EDGE || + S2.IsNull() || S2.ShapeType() < TopAbs_EDGE ) + continue; + TopoDS_Shape S; + if ( S1.ShapeType() == TopAbs_EDGE ) + { + if ( S1 == S2 || helper.IsSubShape( S2, S1 )) + S = S1; + } + else if ( S2.ShapeType() == TopAbs_EDGE ) + { + if ( helper.IsSubShape( S1, S2 )) + S = S2; + } + else + { + S = helper.GetCommonAncestor( S1, S2, *theMesh, TopAbs_EDGE ); + } + if ( S.IsNull() ) + continue; + const TopoDS_Edge & E = TopoDS::Edge( S ); + helper.SetSubShape( E ); + list >::iterator g = groups.begin(); + for ( ; g != groups.end(); ++g ) + { + list< int >& ids = *g; + list< int >::iterator id = ids.begin(); + for ( ; id != ids.end(); ++id ) + if ( nodesVector[ *id ] && nodesVector[ *id ]->getshapeId() < 1 ) + { + double u = 1e100; + aMeshDS->SetNodeOnEdge( nodesVector[ *id ], E, u ); + helper.CheckNodeU( E, nodesVector[ *id ], u, 1e-7, true ); + } + } + } + } + } // if ( onMeshElements ) + else { nodesVector.resize( myPoints.size(), 0 ); - // to find point index - map< TPoint*, int > pointIndex; - for ( int i = 0; i < myPoints.size(); i++ ) - pointIndex.insert( make_pair( & myPoints[ i ], i )); - // loop on sub-shapes of myShape: create nodes map< int, list< TPoint* > >::iterator idPointIt = myShapeIDToPointsMap.begin(); for ( ; idPointIt != myShapeIDToPointsMap.end(); idPointIt++ ) { + list< TPoint* > & points = idPointIt->second; TopoDS_Shape S; - //SMESHDS_SubMesh * subMeshDS = 0; - if ( !myShapeIDMap.IsEmpty() ) { + if ( !myShapeIDMap.IsEmpty() ) S = myShapeIDMap( idPointIt->first ); - //subMeshDS = aMeshDS->MeshElements( S ); - } - list< TPoint* > & points = idPointIt->second; + + // find existing nodes on EDGEs and VERTEXes + if ( findExistingNodes( theMesh, S, points, nodesVector )) + continue; + list< TPoint* >::iterator pIt = points.begin(); for ( ; pIt != points.end(); pIt++ ) { TPoint* point = *pIt; - int pIndex = pointIndex[ point ]; + int pIndex = point - &myPoints[0]; if ( nodesVector [ pIndex ] ) continue; SMDS_MeshNode* node = aMeshDS->AddNode (point->myXYZ.X(), @@ -3937,8 +4104,8 @@ bool SMESH_Pattern::MakeMesh(SMESH_Mesh* theMesh, point->myXYZ.Z()); nodesVector [ pIndex ] = node; - if ( true /*subMeshDS*/ ) { - // !!!!! do not merge new nodes with ones existing on submeshes (see method comment) + if ( !S.IsNull() ) { + switch ( S.ShapeType() ) { case TopAbs_VERTEX: { aMeshDS->SetNodeOnVertex( node, TopoDS::Vertex( S )); break; @@ -3975,6 +4142,8 @@ bool SMESH_Pattern::MakeMesh(SMESH_Mesh* theMesh, createElements( theMesh, nodesVector, myElemPointIDs, myElements ); } + aMeshDS->compactMesh(); + // const map& sm = aMeshDS->SubMeshes(); // map::const_iterator i_sm = sm.begin(); // for ( ; i_sm != sm.end(); i_sm++ ) @@ -4122,10 +4291,13 @@ void SMESH_Pattern::createElements(SMESH_Mesh* theMes SMDS_ElemIteratorPtr noIt = elem->nodesIterator(); while ( noIt->more() ) { SMDS_MeshNode* node = const_cast(smdsNode( noIt->next() )); - if (!node->GetPosition()->GetShapeId() && - shellNodes.find( node ) == shellNodes.end() ) { + if ( node->getshapeId() < 1 && + shellNodes.find( node ) == shellNodes.end() ) + { if ( S.ShapeType() == TopAbs_FACE ) - aMeshDS->SetNodeOnFace( node, shapeID ); + aMeshDS->SetNodeOnFace( node, shapeID, + Precision::Infinite(),// <- it's a sign that UV is not set + Precision::Infinite()); else { aMeshDS->SetNodeInVolume( node, shapeID ); shellNodes.insert( node ); @@ -4257,7 +4429,7 @@ void SMESH_Pattern::arrangeBoundaries (list< list< TPoint* > >& boundaryList) } if ( outerBndPos != boundaryList.begin() ) - boundaryList.splice( boundaryList.begin(), boundaryList, outerBndPos, ++outerBndPos ); + boundaryList.splice( boundaryList.begin(), boundaryList, outerBndPos ); } // if nbBoundaries > 1 @@ -4555,6 +4727,29 @@ void SMESH_Pattern::Clear() myShapeIDMap.Clear(); myShape.Nullify(); myNbKeyPntInBoundary.clear(); + + myXYZ.clear(); + myElemXYZIDs.clear(); + myXYZIdToNodeMap.clear(); + myElements.clear(); + myOrderedNodes.clear(); + myPolyElems.clear(); + myPolyElemXYZIDs.clear(); + myPolyhedronQuantities.clear(); + myIdsOnBoundary.clear(); + myReverseConnectivity.clear(); +} + +//================================================================================ +/*! + * \brief set ErrorCode and return true if it is Ok + */ +//================================================================================ + +bool SMESH_Pattern::setErrorCode( const ErrorCode theErrorCode ) +{ + myErrorCode = theErrorCode; + return myErrorCode == ERR_OK; } //======================================================================= @@ -4582,7 +4777,7 @@ bool SMESH_Pattern::setShapeToMesh(const TopoDS_Shape& theShape) TopTools_MapOfShape seamVertices; TopoDS_Face face = TopoDS::Face( theShape ); TopExp_Explorer eExp( theShape, TopAbs_EDGE ); - for ( ; eExp.More() && nbNodeOnSeamEdge == 0; eExp.Next() ) { + for ( ; eExp.More() /*&& nbNodeOnSeamEdge == 0*/; eExp.Next() ) { const TopoDS_Edge& ee = TopoDS::Edge(eExp.Current()); if ( BRep_Tool::IsClosed(ee, face) ) { // seam edge and vertices encounter twice in theFace diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_ProxyMesh.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_ProxyMesh.cpp new file mode 100644 index 000000000000..ed3f6680375a --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_ProxyMesh.cpp @@ -0,0 +1,595 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 : SMESH_ProxyMesh.cxx +// Created : Thu Dec 2 12:32:53 2010 +// Author : Edward AGAPOV (eap) + +#include "SMESH_ProxyMesh.hxx" + +#include "SMDS_IteratorOnIterators.hxx" +#include "SMDS_SetIterator.hxx" +#include "SMESH_MesherHelper.hxx" + +#include +#include +#include + +//================================================================================ +/*! + * \brief Constructor; mesh must be set by a descendant class + */ +//================================================================================ + +SMESH_ProxyMesh::SMESH_ProxyMesh():_mesh(0) +{ +} +//================================================================================ +/*! + * \brief Make a proxy mesh from components. Components become empty + */ +//================================================================================ + +SMESH_ProxyMesh::SMESH_ProxyMesh(std::vector& components): + _mesh(0) +{ + if ( components.empty() ) return; + + for ( unsigned i = 0; i < components.size(); ++i ) + { + SMESH_ProxyMesh* m = components[i].get(); + if ( !m ) continue; + + takeTmpElemsInMesh( m ); + + if ( !_mesh ) _mesh = m->_mesh; + if ( _allowedTypes.empty() ) _allowedTypes = m->_allowedTypes; + + if ( _subMeshes.size() < m->_subMeshes.size() ) + _subMeshes.resize( m->_subMeshes.size(), 0 ); + for ( unsigned j = 0; j < m->_subMeshes.size(); ++j ) + { + if ( !m->_subMeshes[j] ) continue; + if ( _subMeshes[j] ) + { + // unite 2 sub-meshes + std::set < const SMDS_MeshElement* > elems( _subMeshes[j]->_elements.begin(), + _subMeshes[j]->_elements.end()); + elems.insert( m->_subMeshes[j]->_elements.begin(), + m->_subMeshes[j]->_elements.end()); + _subMeshes[j]->_elements.assign( elems.begin(), elems.end() ); + m->_subMeshes[j]->_elements.clear(); + + if ( !_subMeshes[j]->_n2n ) + _subMeshes[j]->_n2n = m->_subMeshes[j]->_n2n, m->_subMeshes[j]->_n2n = 0; + + else if ( _subMeshes[j]->_n2n && m->_subMeshes[j]->_n2n ) + _subMeshes[j]->_n2n->insert( m->_subMeshes[j]->_n2n->begin(), + m->_subMeshes[j]->_n2n->end()); + } + else + { + _subMeshes[j] = m->_subMeshes[j]; + m->_subMeshes[j] = 0; + } + } + } +} + +//================================================================================ +/*! + * \brief Destructor deletes proxy submeshes and tmp elemens + */ +//================================================================================ + +SMESH_ProxyMesh::~SMESH_ProxyMesh() +{ + for ( unsigned i = 0; i < _subMeshes.size(); ++i ) + delete _subMeshes[i]; + _subMeshes.clear(); + + std::set < const SMDS_MeshElement* >::iterator i = _elemsInMesh.begin(); + for ( ; i != _elemsInMesh.end(); ++i ) + GetMeshDS()->RemoveFreeElement( *i, 0 ); + _elemsInMesh.clear(); +} + +//================================================================================ +/*! + * \brief Returns index of a shape + */ +//================================================================================ + +int SMESH_ProxyMesh::shapeIndex(const TopoDS_Shape& shape) const +{ + return ( shape.IsNull() || !_mesh->HasShapeToMesh() ? 0 : GetMeshDS()->ShapeToIndex(shape)); +} + +//================================================================================ +/*! + * \brief Returns the submesh of a shape; it can be a proxy sub-mesh + */ +//================================================================================ + +const SMESHDS_SubMesh* SMESH_ProxyMesh::GetSubMesh(const TopoDS_Shape& shape) const +{ + const SMESHDS_SubMesh* sm = 0; + + int i = shapeIndex(shape); + if ( i < _subMeshes.size() ) + sm = _subMeshes[i]; + if ( !sm ) + sm = GetMeshDS()->MeshElements( i ); + + return sm; +} + +//================================================================================ +/*! + * \brief Returns the proxy sub-mesh of a shape; it can be NULL + */ +//================================================================================ + +const SMESH_ProxyMesh::SubMesh* +SMESH_ProxyMesh::GetProxySubMesh(const TopoDS_Shape& shape) const +{ + int i = shapeIndex(shape); + return i < _subMeshes.size() ? _subMeshes[i] : 0; +} + +//================================================================================ +/*! + * \brief Returns the proxy node of a node; the input node is returned if no proxy exists + */ +//================================================================================ + +const SMDS_MeshNode* SMESH_ProxyMesh::GetProxyNode( const SMDS_MeshNode* node ) const +{ + const SMDS_MeshNode* proxy = node; + if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) + { + if ( const SubMesh* proxySM = findProxySubMesh( node->getshapeId() )) + proxy = proxySM->GetProxyNode( node ); + } + else + { + TopoDS_Shape shape = SMESH_MesherHelper::GetSubShapeByNode( node, GetMeshDS()); + TopTools_ListIteratorOfListOfShape ancIt; + if ( !shape.IsNull() ) ancIt.Initialize( _mesh->GetAncestors( shape )); + for ( ; ancIt.More() && proxy == node; ancIt.Next() ) + if ( const SubMesh* proxySM = findProxySubMesh( shapeIndex(ancIt.Value()))) + proxy = proxySM->GetProxyNode( node ); + } + return proxy; +} + +//================================================================================ +/*! + * \brief Returns number of proxy sub-meshes + */ +//================================================================================ + +int SMESH_ProxyMesh::NbProxySubMeshes() const +{ + int nb = 0; + for ( size_t i = 0; i < _subMeshes.size(); ++i ) + nb += bool( _subMeshes[i] ); + + return nb; +} + +namespace +{ + //================================================================================ + /*! + * \brief Iterator filtering elements by type + */ + //================================================================================ + + class TFilteringIterator : public SMDS_ElemIterator + { + SMDS_ElemIteratorPtr _iter; + const SMDS_MeshElement * _curElem; + std::vector< SMDSAbs_EntityType> _okTypes; + public: + TFilteringIterator( const std::vector< SMDSAbs_EntityType>& okTypes, + const SMDS_ElemIteratorPtr& elemIterator) + :_iter(elemIterator), _curElem(0), _okTypes(okTypes) + { + next(); + } + virtual bool more() + { + return _curElem; + } + virtual const SMDS_MeshElement* next() + { + const SMDS_MeshElement* res = _curElem; + _curElem = 0; + while ( _iter->more() && !_curElem ) + { + _curElem = _iter->next(); + if ( find( _okTypes.begin(), _okTypes.end(), _curElem->GetEntityType()) == _okTypes.end()) + _curElem = 0; + } + return res; + } + }; +} + +//================================================================================ +/*! + * \brief Returns iterator on all faces on the shape taking into account substitutions + */ +//================================================================================ + +SMDS_ElemIteratorPtr SMESH_ProxyMesh::GetFaces(const TopoDS_Shape& shape) const +{ + if ( !_mesh->HasShapeToMesh() ) + return SMDS_ElemIteratorPtr(); + + _subContainer.RemoveAllSubmeshes(); + + TopTools_IndexedMapOfShape FF; + TopExp::MapShapes( shape, TopAbs_FACE, FF ); + for ( int i = 1; i <= FF.Extent(); ++i ) + if ( const SMESHDS_SubMesh* sm = GetSubMesh( FF(i))) + _subContainer.AddSubMesh( sm ); + + return _subContainer.SMESHDS_SubMesh::GetElements(); +} + +//================================================================================ +/*! + * \brief Returns iterator on all faces of the mesh taking into account substitutions + * To be used in case of mesh without shape + */ +//================================================================================ + +SMDS_ElemIteratorPtr SMESH_ProxyMesh::GetFaces() const +{ + if ( _mesh->HasShapeToMesh() ) + return SMDS_ElemIteratorPtr(); + + _subContainer.RemoveAllSubmeshes(); + for ( unsigned i = 0; i < _subMeshes.size(); ++i ) + if ( _subMeshes[i] ) + _subContainer.AddSubMesh( _subMeshes[i] ); + + if ( _subContainer.NbSubMeshes() == 0 ) // no elements substituted + return GetMeshDS()->elementsIterator(SMDSAbs_Face); + + // if _allowedTypes is empty, only elements from _subMeshes are returned,... + SMDS_ElemIteratorPtr proxyIter = _subContainer.SMESHDS_SubMesh::GetElements(); + if ( _allowedTypes.empty() || NbFaces() == _mesh->NbFaces() ) + return proxyIter; + + // ... else elements filtered using allowedTypes are additionally returned + SMDS_ElemIteratorPtr facesIter = GetMeshDS()->elementsIterator(SMDSAbs_Face); + SMDS_ElemIteratorPtr filterIter( new TFilteringIterator( _allowedTypes, facesIter )); + std::vector< SMDS_ElemIteratorPtr > iters(2); + iters[0] = proxyIter; + iters[1] = filterIter; + + typedef std::vector< SMDS_ElemIteratorPtr > TElemIterVector; + typedef SMDS_IteratorOnIterators TItersIter; + return SMDS_ElemIteratorPtr( new TItersIter( iters )); +} + +//================================================================================ +/*! + * \brief Return total nb of faces taking into account substitutions + */ +//================================================================================ + +int SMESH_ProxyMesh::NbFaces() const +{ + int nb = 0; + if ( _mesh->HasShapeToMesh() ) + { + TopTools_IndexedMapOfShape FF; + TopExp::MapShapes( _mesh->GetShapeToMesh(), TopAbs_FACE, FF ); + for ( int i = 1; i <= FF.Extent(); ++i ) + if ( const SMESHDS_SubMesh* sm = GetSubMesh( FF(i))) + nb += sm->NbElements(); + } + else + { + if ( _subMeshes.empty() ) + return GetMeshDS()->NbFaces(); + + for ( unsigned i = 0; i < _subMeshes.size(); ++i ) + if ( _subMeshes[i] ) + nb += _subMeshes[i]->NbElements(); + + // if _allowedTypes is empty, only elements from _subMeshes are returned, + // else elements filtered using allowedTypes are additionally returned + if ( !_allowedTypes.empty() ) + { + for ( int t = SMDSEntity_Triangle; t <= SMDSEntity_Quad_Quadrangle; ++t ) + { + bool allowed = + ( find( _allowedTypes.begin(), _allowedTypes.end(), t ) != _allowedTypes.end() ); + if ( allowed ) + nb += GetMeshDS()->GetMeshInfo().NbEntities( SMDSAbs_EntityType( t )); + } + } + } + return nb; +} + +//================================================================================ +/*! + * \brief Returns a proxy sub-mesh; it is created if not yet exists + */ +//================================================================================ + +SMESH_ProxyMesh::SubMesh* SMESH_ProxyMesh::getProxySubMesh(int index) +{ + if ( int(_subMeshes.size()) <= index ) + _subMeshes.resize( index+1, 0 ); + if ( !_subMeshes[index] ) + _subMeshes[index] = newSubmesh( index ); + return _subMeshes[index]; +} + +//================================================================================ +/*! + * \brief Returns a proxy sub-mesh; it is created if not yet exists + */ +//================================================================================ + +SMESH_ProxyMesh::SubMesh* SMESH_ProxyMesh::getProxySubMesh(const TopoDS_Shape& shape) +{ + return getProxySubMesh( shapeIndex( shape )); +} + +//================================================================================ +/*! + * \brief Returns a proxy sub-mesh + */ +//================================================================================ + +SMESH_ProxyMesh::SubMesh* SMESH_ProxyMesh::findProxySubMesh(int shapeIndex) const +{ + return shapeIndex < int(_subMeshes.size()) ? _subMeshes[shapeIndex] : 0; +} + +//================================================================================ +/*! + * \brief Returns mesh DS + */ +//================================================================================ + +SMESHDS_Mesh* SMESH_ProxyMesh::GetMeshDS() const +{ + return (SMESHDS_Mesh*)( _mesh ? _mesh->GetMeshDS() : 0 ); +} + +//================================================================================ +/*! + * \brief Move proxy sub-mesh from other proxy mesh to this, returns true if sub-mesh found + */ +//================================================================================ + +bool SMESH_ProxyMesh::takeProxySubMesh( const TopoDS_Shape& shape, + SMESH_ProxyMesh* proxyMesh ) +{ + if ( proxyMesh && proxyMesh->_mesh == _mesh ) + { + int iS = shapeIndex( shape ); + if ( SubMesh* sm = proxyMesh->findProxySubMesh( iS )) + { + if ( iS >= int(_subMeshes.size()) ) + _subMeshes.resize( iS + 1, 0 ); + _subMeshes[iS] = sm; + proxyMesh->_subMeshes[iS] = 0; + return true; + } + } + return false; +} + +//================================================================================ +/*! + * \brief Move tmp elements residing the _mesh from other proxy mesh to this + */ +//================================================================================ + +void SMESH_ProxyMesh::takeTmpElemsInMesh( SMESH_ProxyMesh* proxyMesh ) +{ + if ( proxyMesh ) + { + _elemsInMesh.insert( proxyMesh->_elemsInMesh.begin(), + proxyMesh->_elemsInMesh.end()); + proxyMesh->_elemsInMesh.clear(); + } +} + +//================================================================================ +/*! + * \brief Removes tmp elements from the _mesh + */ +//================================================================================ + +void SMESH_ProxyMesh::removeTmpElement( const SMDS_MeshElement* elem ) +{ + if ( elem && elem->GetID() > 0 ) + { + std::set < const SMDS_MeshElement* >::iterator i = _elemsInMesh.find( elem ); + if ( i != _elemsInMesh.end() ) + { + GetMeshDS()->RemoveFreeElement( elem, 0 ); + _elemsInMesh.erase( i ); + } + } + else + { + delete elem; + } +} + +//================================================================================ +/*! + * \brief Stores tmp element residing the _mesh + */ +//================================================================================ + +void SMESH_ProxyMesh::storeTmpElement( const SMDS_MeshElement* elem ) +{ + _elemsInMesh.insert( elem ); +} + +//================================================================================ +/*! + * \brief Set node-node correspondence + */ +//================================================================================ + +void SMESH_ProxyMesh::setNode2Node(const SMDS_MeshNode* srcNode, + const SMDS_MeshNode* proxyNode, + const SubMesh* subMesh) +{ + SubMesh* sm = const_cast( subMesh ); + if ( !subMesh->_n2n ) + sm->_n2n = new TN2NMap; + sm->_n2n->insert( std::make_pair( srcNode, proxyNode )); +} + +//================================================================================ +/*! + * \brief Return true if the element is a temporary one + */ +//================================================================================ + +bool SMESH_ProxyMesh::IsTemporary(const SMDS_MeshElement* elem ) const +{ + return ( elem->GetID() < 1 ) || _elemsInMesh.count( elem ); +} + +//================================================================================ +/*! + * \brief Return a proxy node or an input node + */ +//================================================================================ + +const SMDS_MeshNode* SMESH_ProxyMesh::SubMesh::GetProxyNode( const SMDS_MeshNode* n ) const +{ + TN2NMap::iterator n2n; + if ( _n2n && ( n2n = _n2n->find( n )) != _n2n->end()) + return n2n->second; + return n; +} + +//================================================================================ +/*! + * \brief Deletes temporary elements + */ +//================================================================================ + +void SMESH_ProxyMesh::SubMesh::Clear() +{ + for ( unsigned i = 0; i < _elements.size(); ++i ) + if ( _elements[i]->GetID() < 0 ) + delete _elements[i]; + _elements.clear(); + if ( _n2n ) + delete _n2n, _n2n = 0; +} + +//================================================================================ +/*! + * \brief Return number of elements in a proxy sub-mesh. The method is meaningful + * for a sub-mesh containing tmp faces. + */ +//================================================================================ + +int SMESH_ProxyMesh::SubMesh::NbElements() const +{ + return _uvPtStructVec.empty() ? _elements.size() : _uvPtStructVec.size() - 1; +} + +//================================================================================ +/*! + * \brief Return elements of a proxy sub-mesh. The method is meaningful + * for a sub-mesh containing tmp faces. + */ +//================================================================================ + +SMDS_ElemIteratorPtr SMESH_ProxyMesh::SubMesh::GetElements() const +{ + return SMDS_ElemIteratorPtr + ( new SMDS_ElementVectorIterator( _elements.begin(), _elements.end() )); +} + +//================================================================================ +/*! + * \brief Return number of nodes in a proxy sub-mesh. The method is meaningful + * for a sub-mesh containing nodes of 2D viscous layer. + */ +//================================================================================ + +int SMESH_ProxyMesh::SubMesh::NbNodes() const +{ + return _uvPtStructVec.size(); +} + +//================================================================================ +/*! + * \brief Return nodes of a proxy sub-mesh. The method is meaningful + * for a sub-mesh containing nodes of 2D viscous layer. + */ +//================================================================================ + +SMDS_NodeIteratorPtr SMESH_ProxyMesh::SubMesh::GetNodes() const +{ + if ( !_uvPtStructVec.empty() ) + return SMDS_NodeIteratorPtr ( new SMDS_SetIterator + < SMDS_pNode, + UVPtStructVec::const_iterator, + UVPtStruct::NodeAccessor > + ( _uvPtStructVec.begin(), _uvPtStructVec.end() )); + + return SMDS_NodeIteratorPtr + ( new SMDS_SetIterator< SMDS_pNode, std::vector< SMDS_pElement >::const_iterator> + ( _elements.begin(), _elements.end() )); +} + +//================================================================================ +/*! + * \brief Store an element + */ +//================================================================================ + +void SMESH_ProxyMesh::SubMesh::AddElement(const SMDS_MeshElement * e) +{ + _elements.push_back( e ); +} + +//================================================================================ +/*! + * \brief Check presence of element inside it-self + */ +//================================================================================ + +bool SMESH_ProxyMesh::SubMesh::Contains(const SMDS_MeshElement * ME) const +{ + if ( ME->GetType() != SMDSAbs_Node ) + return find( _elements.begin(), _elements.end(), ME ) != _elements.end(); + return false; +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_TryCatch.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_TryCatch.cpp new file mode 100644 index 000000000000..1f987213a6fd --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_TryCatch.cpp @@ -0,0 +1,82 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// ------------------------------------------------------------------ +#include "SMESH_TryCatch.hxx" + +void SMESH::throwSalomeEx(const char* txt) +{ + throw SALOME_Exception( txt ); +} + +void SMESH::doNothing(const char* txt) +{ + MESSAGE( txt << " " << __FILE__ << ": " << __LINE__ ); +} +// ------------------------------------------------------------------ +#include "SMESH_ComputeError.hxx" + +#define _case2char(err) case err: return #err; + +// Return SMESH_ComputeError::myName as text, to be used to dump errors in terminal +std::string SMESH_ComputeError::CommonName() const +{ + switch( myName ) { + _case2char(COMPERR_OK ); + _case2char(COMPERR_BAD_INPUT_MESH ); + _case2char(COMPERR_STD_EXCEPTION ); + _case2char(COMPERR_OCC_EXCEPTION ); + _case2char(COMPERR_SLM_EXCEPTION ); + _case2char(COMPERR_EXCEPTION ); + _case2char(COMPERR_MEMORY_PB ); + _case2char(COMPERR_ALGO_FAILED ); + _case2char(COMPERR_BAD_SHAPE ); + _case2char(COMPERR_WARNING ); + _case2char(COMPERR_CANCELED ); + _case2char(COMPERR_NO_MESH_ON_SHAPE); + _case2char(COMPERR_BAD_PARMETERS ); + default:; + } + return ""; +} + +// Return the most severe error +SMESH_ComputeErrorPtr SMESH_ComputeError::Worst( SMESH_ComputeErrorPtr er1, + SMESH_ComputeErrorPtr er2 ) +{ + if ( !er1 ) return er2; + if ( !er2 ) return er1; + // both not NULL + if ( er1->IsOK() ) return er2; + if ( er2->IsOK() ) return er1; + // both not OK + if ( !er1->IsKO() ) return er2; + if ( !er2->IsKO() ) return er1; + // both KO + bool hasInfo1 = er1->myComment.size() || !er1->myBadElements.empty(); + bool hasInfo2 = er2->myComment.size() || !er2->myBadElements.empty(); + if ( er1->myName == er2->myName || + hasInfo1 != hasInfo2 ) + return hasInfo1 < hasInfo2 ? er2 : er1; + + return er1->myName == COMPERR_CANCELED ? er2 : er1; +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_subMesh.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_subMesh.cpp index 6de2eaf2016c..f85d1359a712 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_subMesh.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_subMesh.cpp @@ -1,29 +1,31 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : SMESH_subMesh.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// +// vjemarie ISSUE getAlgo + #include "SMESH_subMesh.hxx" #include "SMESH_Algo.hxx" @@ -35,24 +37,31 @@ #include "SMESH_subMeshEventListener.hxx" #include "SMESH_Comment.hxx" #include "SMDS_SetIterator.hxx" +#include "SMDSAbs_ElementType.hxx" + +#include #include "utilities.h" -//#include "OpUtil.hxx" +#include "OpUtil.hxx" +#include "Basics_Utils.hxx" #include #include #include +#include #include #include +#include #include #include -#include -#include #include +#include #include #include +#include + using namespace std; //============================================================================= @@ -81,22 +90,24 @@ SMESH_subMesh::SMESH_subMesh(int Id, SMESHDS_Mesh * meshDS, const TopoDS_Shape & aSubShape) { - _subShape = aSubShape; - _subMeshDS = meshDS->MeshElements(_subShape); // may be null ... - _father = father; - _Id = Id; - _dependenceAnalysed = _alwaysComputed = false; - - if (_subShape.ShapeType() == TopAbs_VERTEX) - { - _algoState = HYP_OK; - _computeState = READY_TO_COMPUTE; - } - else - { - _algoState = NO_ALGO; - _computeState = NOT_READY; - } + _subShape = aSubShape; + _subMeshDS = meshDS->MeshElements(_subShape); // may be null ... + _father = father; + _Id = Id; + _dependenceAnalysed = _alwaysComputed = false; + _algo = 0; + if (_subShape.ShapeType() == TopAbs_VERTEX) + { + _algoState = HYP_OK; + _computeState = READY_TO_COMPUTE; + } + else + { + _algoState = NO_ALGO; + _computeState = NOT_READY; + } + _computeCost = 0; // how costly is to compute this sub-mesh + _realComputeCost = 0; } //============================================================================= @@ -107,9 +118,7 @@ SMESH_subMesh::SMESH_subMesh(int Id, SMESH_subMesh::~SMESH_subMesh() { - //MESSAGE("SMESH_subMesh::~SMESH_subMesh"); - // **** - DeleteOwnListeners(); + deleteOwnListeners(); } //============================================================================= @@ -142,6 +151,17 @@ SMESHDS_SubMesh * SMESH_subMesh::GetSubMeshDS() */ //============================================================================= +const SMESHDS_SubMesh * SMESH_subMesh::GetSubMeshDS() const +{ + return ((SMESH_subMesh*) this )->GetSubMeshDS(); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + SMESHDS_SubMesh* SMESH_subMesh::CreateSubMeshDS() { if ( !GetSubMeshDS() ) { @@ -170,7 +190,23 @@ SMESH_subMesh *SMESH_subMesh::GetFirstToCompute() //================================================================================ /*! - * \brief Allow algo->Compute() if a subshape of lower dim is meshed but + * \brief Returns a current algorithm + */ +//================================================================================ + +SMESH_Algo* SMESH_subMesh::GetAlgo() const +{ + if ( !_algo ) + { + SMESH_subMesh* me = const_cast< SMESH_subMesh* >( this ); + me->_algo = _father->GetGen()->GetAlgo( me ); + } + return _algo; +} + +//================================================================================ +/*! + * \brief Allow algo->Compute() if a sub-shape of lower dim is meshed but * none mesh entity is bound to it (PAL13615, 2nd part) */ //================================================================================ @@ -235,15 +271,16 @@ bool SMESH_subMesh::IsMeshComputed() const //============================================================================= /*! - * + * Return true if all sub-meshes have been meshed */ //============================================================================= -bool SMESH_subMesh::SubMeshesComputed() +bool SMESH_subMesh::SubMeshesComputed(bool * isFailedToCompute/*=0*/) const { int myDim = SMESH_Gen::GetShapeDim( _subShape ); int dimToCheck = myDim - 1; bool subMeshesComputed = true; + if ( isFailedToCompute ) *isFailedToCompute = false; // check subMeshes with upper dimension => reverse iteration SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,true); while ( smIt->more() ) @@ -252,253 +289,232 @@ bool SMESH_subMesh::SubMeshesComputed() if ( sm->_alwaysComputed ) continue; const TopoDS_Shape & ss = sm->GetSubShape(); + // MSV 07.04.2006: restrict checking to myDim-1 only. Ex., there is no sense // in checking of existence of edges if the algo needs only faces. Moreover, // degenerated edges may have no submesh, as after computing NETGEN_2D. - int dim = SMESH_Gen::GetShapeDim( ss ); - if (dim < dimToCheck) - break; // the rest subMeshes are all of less dimension + if ( !_algo || _algo->NeedDiscreteBoundary() ) { + int dim = SMESH_Gen::GetShapeDim( ss ); + if (dim < dimToCheck) + break; // the rest subMeshes are all of less dimension + } SMESHDS_SubMesh * ds = sm->GetSubMeshDS(); bool computeOk = (sm->GetComputeState() == COMPUTE_OK || - (ds && ( ds->NbNodes() || ds->NbElements() ))); + (ds && ( dimToCheck ? ds->NbElements() : ds->NbNodes() ))); if (!computeOk) { - int type = ss.ShapeType(); - subMeshesComputed = false; - - switch (type) - { - case TopAbs_COMPOUND: - { - MESSAGE("The not computed sub mesh is a COMPOUND"); - break; - } - case TopAbs_COMPSOLID: - { - MESSAGE("The not computed sub mesh is a COMPSOLID"); - break; - } - case TopAbs_SHELL: - { - MESSAGE("The not computed sub mesh is a SHEL"); - break; - } - case TopAbs_WIRE: - { - MESSAGE("The not computed sub mesh is a WIRE"); - break; - } - case TopAbs_SOLID: - { - MESSAGE("The not computed sub mesh is a SOLID"); - break; - } - case TopAbs_FACE: - { - MESSAGE("The not computed sub mesh is a FACE"); - break; - } - case TopAbs_EDGE: - { - MESSAGE("The not computed sub mesh is a EDGE"); - break; - } - default: - { - MESSAGE("The not computed sub mesh is of unknown type"); - break; - } - } - - break; + if ( isFailedToCompute && !(*isFailedToCompute) ) + *isFailedToCompute = ( sm->GetComputeState() == FAILED_TO_COMPUTE ); + + // int type = ss.ShapeType(); + + // switch (type) + // { + // case TopAbs_COMPOUND: + // { + // MESSAGE("The not computed sub mesh is a COMPOUND"); + // break; + // } + // case TopAbs_COMPSOLID: + // { + // MESSAGE("The not computed sub mesh is a COMPSOLID"); + // break; + // } + // case TopAbs_SHELL: + // { + // MESSAGE("The not computed sub mesh is a SHEL"); + // break; + // } + // case TopAbs_WIRE: + // { + // MESSAGE("The not computed sub mesh is a WIRE"); + // break; + // } + // case TopAbs_SOLID: + // { + // MESSAGE("The not computed sub mesh is a SOLID"); + // break; + // } + // case TopAbs_FACE: + // { + // MESSAGE("The not computed sub mesh is a FACE"); + // break; + // } + // case TopAbs_EDGE: + // { + // MESSAGE("The not computed sub mesh is a EDGE"); + // break; + // } + // default: + // { + // MESSAGE("The not computed sub mesh is of unknown type"); + // break; + // } + // } + + if ( !isFailedToCompute ) + break; } } return subMeshesComputed; } -//============================================================================= +//================================================================================ /*! - * + * \brief Return cost of computing this sub-mesh. If hypotheses are not well defined, + * zero is returned + * \return int - the computation cost in abstract units. */ -//============================================================================= +//================================================================================ -bool SMESH_subMesh::SubMeshesReady() +int SMESH_subMesh::GetComputeCost() const { - bool subMeshesReady = true; - SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,true); - while ( smIt->more() ) { - SMESH_subMesh *sm = smIt->next(); - bool computeOk = (sm->GetComputeState() == COMPUTE_OK || - sm->GetComputeState() == READY_TO_COMPUTE); - if (!computeOk) - { - subMeshesReady = false; - SCRUTE(sm->GetId()); - break; + return _realComputeCost; +} + +//================================================================================ +/*! + * \brief Return cost of computing this sub-mesh. The cost depends on the shape type + * and number of sub-meshes this one DependsOn(). + * \return int - the computation cost in abstract units. + */ +//================================================================================ + +int SMESH_subMesh::computeCost() const +{ + if ( !_computeCost ) + { + int computeCost; + switch ( _subShape.ShapeType() ) { + case TopAbs_SOLID: + case TopAbs_SHELL: computeCost = 5000; break; + case TopAbs_FACE: computeCost = 500; break; + case TopAbs_EDGE: computeCost = 2; break; + default: computeCost = 1; } + SMESH_subMeshIteratorPtr childIt = getDependsOnIterator(/*includeSelf=*/false); + while ( childIt->more() ) + computeCost += childIt->next()->computeCost(); + + ((SMESH_subMesh*)this)->_computeCost = computeCost; } - return subMeshesReady; + return _computeCost; } //============================================================================= /*! - * Construct dependence on first level subMeshes. complex shapes (compsolid, - * shell, wire) are not analysed the same way as simple shapes (solid, face, - * edge). - * For collection shapes (compsolid, shell, wire) prepare a list of submeshes - * with possible multiples occurences. Multiples occurences corresponds to - * internal frontiers within shapes of the collection and must not be keeped. - * See FinalizeDependence. + * Returns all sub-meshes this one depend on */ //============================================================================= const map < int, SMESH_subMesh * >& SMESH_subMesh::DependsOn() { - if (_dependenceAnalysed) + if ( _dependenceAnalysed || !_father->HasShapeToMesh() ) return _mapDepend; - //MESSAGE("SMESH_subMesh::DependsOn"); - int type = _subShape.ShapeType(); - //SCRUTE(type); switch (type) { case TopAbs_COMPOUND: + { + list< TopoDS_Shape > compounds( 1, _subShape ); + list< TopoDS_Shape >::iterator comp = compounds.begin(); + for ( ; comp != compounds.end(); ++comp ) { - //MESSAGE("compound"); - for (TopExp_Explorer exp(_subShape, TopAbs_SOLID); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - for (TopExp_Explorer exp(_subShape, TopAbs_SHELL, TopAbs_SOLID); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); //only shell not in solid - } - for (TopExp_Explorer exp(_subShape, TopAbs_FACE, TopAbs_SHELL); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - for (TopExp_Explorer exp(_subShape, TopAbs_EDGE, TopAbs_FACE); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - break; - } - case TopAbs_COMPSOLID: - { - //MESSAGE("compsolid"); - for (TopExp_Explorer exp(_subShape, TopAbs_SOLID); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - break; - } - case TopAbs_SHELL: - { - //MESSAGE("shell"); - for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - break; - } - case TopAbs_WIRE: - { - //MESSAGE("wire"); - for (TopExp_Explorer exp(_subShape, TopAbs_EDGE); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - break; - } - case TopAbs_SOLID: - { - //MESSAGE("solid"); - if(_father->HasShapeToMesh()) { - for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More(); - exp.Next()) + for ( TopoDS_Iterator sub( *comp ); sub.More(); sub.Next() ) + switch ( sub.Value().ShapeType() ) { - InsertDependence(exp.Current()); + case TopAbs_COMPOUND: compounds.push_back( sub.Value() ); break; + case TopAbs_COMPSOLID: insertDependence( sub.Value(), TopAbs_SOLID ); break; + case TopAbs_SOLID: insertDependence( sub.Value(), TopAbs_SOLID ); break; + case TopAbs_SHELL: insertDependence( sub.Value(), TopAbs_FACE ); break; + case TopAbs_FACE: insertDependence( sub.Value(), TopAbs_FACE ); break; + case TopAbs_WIRE: insertDependence( sub.Value(), TopAbs_EDGE ); break; + case TopAbs_EDGE: insertDependence( sub.Value(), TopAbs_EDGE ); break; + case TopAbs_VERTEX: insertDependence( sub.Value(), TopAbs_VERTEX ); break; + default:; } - } - break; - } - case TopAbs_FACE: - { - //MESSAGE("face"); - for (TopExp_Explorer exp(_subShape, TopAbs_EDGE); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - break; - } - case TopAbs_EDGE: - { - //MESSAGE("edge"); - for (TopExp_Explorer exp(_subShape, TopAbs_VERTEX); exp.More(); - exp.Next()) - { - InsertDependence(exp.Current()); - } - break; - } - case TopAbs_VERTEX: - { - break; - } - default: - { - break; } } + break; + case TopAbs_COMPSOLID: insertDependence( _subShape, TopAbs_SOLID ); break; + case TopAbs_SOLID: insertDependence( _subShape, TopAbs_FACE ); break; + case TopAbs_SHELL: insertDependence( _subShape, TopAbs_FACE ); break; + case TopAbs_FACE: insertDependence( _subShape, TopAbs_EDGE ); break; + case TopAbs_WIRE: insertDependence( _subShape, TopAbs_EDGE ); break; + case TopAbs_EDGE: insertDependence( _subShape, TopAbs_VERTEX ); break; + default:; + } _dependenceAnalysed = true; return _mapDepend; } +//================================================================================ +/*! + * \brief Return a key for SMESH_subMesh::_mapDepend map + */ +//================================================================================ + +namespace +{ + int dependsOnMapKey( const SMESH_subMesh* sm ) + { + int type = sm->GetSubShape().ShapeType(); + int ordType = 9 - type; // 2 = Vertex, 8 = CompSolid + int cle = sm->GetId(); + cle += 10000000 * ordType; // sort map by ordType then index + return cle; + } +} + //============================================================================= /*! - * For simple Shapes (solid, face, edge): add subMesh into dependence list. + * Add sub-meshes on sub-shapes of a given type into the dependence map. */ //============================================================================= -void SMESH_subMesh::InsertDependence(const TopoDS_Shape aSubShape) +void SMESH_subMesh::insertDependence(const TopoDS_Shape aShape, + TopAbs_ShapeEnum aSubType) { - //MESSAGE("SMESH_subMesh::InsertDependence"); - SMESH_subMesh *aSubMesh = _father->GetSubMesh(aSubShape); - int type = aSubShape.ShapeType(); - int ordType = 9 - type; // 2 = Vertex, 8 = CompSolid - int cle = aSubMesh->GetId(); - cle += 10000000 * ordType; // sort map by ordType then index - if ( _mapDepend.find( cle ) == _mapDepend.end()) + TopExp_Explorer sub( aShape, aSubType ); + for ( ; sub.More(); sub.Next() ) { - _mapDepend[cle] = aSubMesh; - const map < int, SMESH_subMesh * > & subMap = aSubMesh->DependsOn(); - _mapDepend.insert( subMap.begin(), subMap.end() ); + SMESH_subMesh *aSubMesh = _father->GetSubMesh( sub.Current() ); + if ( aSubMesh->GetId() == 0 ) + continue; // not a sub-shape of the shape to mesh + int cle = dependsOnMapKey( aSubMesh ); + if ( _mapDepend.find( cle ) == _mapDepend.end()) + { + _mapDepend[cle] = aSubMesh; + const map < int, SMESH_subMesh * > & subMap = aSubMesh->DependsOn(); + _mapDepend.insert( subMap.begin(), subMap.end() ); + } } } +//================================================================================ +/*! + * \brief Return \c true if \a this sub-mesh depends on \a other + */ +//================================================================================ + +bool SMESH_subMesh::DependsOn( const SMESH_subMesh* other ) const +{ + return other ? _mapDepend.count( dependsOnMapKey( other )) : false; +} + //============================================================================= /*! - * + * Return a shape of \a this sub-mesh */ //============================================================================= const TopoDS_Shape & SMESH_subMesh::GetSubShape() const { - //MESSAGE("SMESH_subMesh::GetSubShape"); - return _subShape; + return _subShape; } - //======================================================================= //function : CanAddHypothesis //purpose : return true if theHypothesis can be attached to me: @@ -509,12 +525,13 @@ bool SMESH_subMesh::CanAddHypothesis(const SMESH_Hypothesis* theHypothesis) cons { int aHypDim = theHypothesis->GetDim(); int aShapeDim = SMESH_Gen::GetShapeDim(_subShape); - if (aHypDim == 3 && aShapeDim == 3) { - // check case of open shell - //if (_subShape.ShapeType() == TopAbs_SHELL && !_subShape.Closed()) - if (_subShape.ShapeType() == TopAbs_SHELL && !BRep_Tool::IsClosed(_subShape)) - return false; - } + // issue 21106. Forbid 3D mesh on the SHELL + // if (aHypDim == 3 && aShapeDim == 3) { + // // check case of open shell + // //if (_subShape.ShapeType() == TopAbs_SHELL && !_subShape.Closed()) + // if (_subShape.ShapeType() == TopAbs_SHELL && !BRep_Tool::IsClosed(_subShape)) + // return false; + // } if ( aHypDim <= aShapeDim ) return true; @@ -530,8 +547,14 @@ bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis, const TopAbs_ShapeEnum theShapeType) { if ( theHypothesis->GetType() > SMESHDS_Hypothesis::PARAM_ALGO) + { // algorithm - return ( theHypothesis->GetShapeType() & (1<< theShapeType)); + if ( theHypothesis->GetShapeType() & (1<< theShapeType)) + // issue 21106. Forbid 3D mesh on the SHELL + return !( theHypothesis->GetDim() == 3 && theShapeType == TopAbs_SHELL ); + else + return false; + } // hypothesis switch ( theShapeType ) { @@ -558,28 +581,31 @@ bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis, return false; } -//============================================================================= +//================================================================================ /*! - * + * \brief Treats modification of hypotheses definition + * \param [in] event - what happens + * \param [in] anHyp - a hypothesis + * \return SMESH_Hypothesis::Hypothesis_Status - a treatment result. + * + * Optional description of a problematic situation (if any) can be retrieved + * via GetComputeError(). */ -//============================================================================= +//================================================================================ SMESH_Hypothesis::Hypothesis_Status SMESH_subMesh::AlgoStateEngine(int event, SMESH_Hypothesis * anHyp) { - // MESSAGE("SMESH_subMesh::AlgoStateEngine"); - //SCRUTE(_algoState); - //SCRUTE(event); - // **** les retour des evenement shape sont significatifs // (add ou remove fait ou non) // le retour des evenement father n'indiquent pas que add ou remove fait SMESH_Hypothesis::Hypothesis_Status aux_ret, ret = SMESH_Hypothesis::HYP_OK; + if ( _Id == 0 ) return ret; // not a sub-shape of the shape to mesh SMESHDS_Mesh* meshDS =_father->GetMeshDS(); - SMESH_Gen* gen =_father->GetGen(); SMESH_Algo* algo = 0; + _algo = 0; if (_subShape.ShapeType() == TopAbs_VERTEX ) { @@ -595,7 +621,7 @@ SMESH_Hypothesis::Hypothesis_Status if ( event != REMOVE_FATHER_ALGO ) { _algoState = NO_ALGO; - algo = gen->GetAlgo(*_father, _subShape); + algo = GetAlgo(); if ( algo ) { _algoState = MISSING_HYP; if ( event == REMOVE_FATHER_HYP || @@ -608,7 +634,7 @@ SMESH_Hypothesis::Hypothesis_Status int oldAlgoState = _algoState; bool modifiedHyp = (event == MODIF_HYP); // if set to true, force event MODIF_ALGO_STATE - bool needFullClean = false; + SMESH_Algo* algoRequiringCleaning = 0; bool isApplicableHyp = IsApplicableHypotesis( anHyp ); @@ -631,8 +657,9 @@ SMESH_Hypothesis::Hypothesis_Status SMESH_HypoFilter filter( SMESH_HypoFilter::HasType( algo->GetType() )); filter.Or( SMESH_HypoFilter::HasType( algo->GetType()+1 )); filter.Or( SMESH_HypoFilter::HasType( algo->GetType()+2 )); - if ( SMESH_Algo * curAlgo = (SMESH_Algo*) _father->GetHypothesis( _subShape, filter, true )) - needFullClean = ( !curAlgo->NeedDescretBoundary() ); + if ( SMESH_Algo * curAlgo = (SMESH_Algo*)_father->GetHypothesis( this, filter, true )) + if ( !curAlgo->NeedDiscreteBoundary() ) + algoRequiringCleaning = curAlgo; } } @@ -644,7 +671,7 @@ SMESH_Hypothesis::Hypothesis_Status if ( ! CanAddHypothesis( anHyp )) // check dimension return SMESH_Hypothesis::HYP_BAD_DIM; - if ( /*!anHyp->IsAuxiliary() &&*/ GetSimilarAttached( _subShape, anHyp ) ) + if ( !anHyp->IsAuxiliary() && getSimilarAttached( _subShape, anHyp ) ) return SMESH_Hypothesis::HYP_ALREADY_EXIST; if ( !meshDS->AddHypothesis(_subShape, anHyp)) @@ -662,13 +689,8 @@ SMESH_Hypothesis::Hypothesis_Status if (event == REMOVE_ALGO) { algo = dynamic_cast (anHyp); - if (!algo->NeedDescretBoundary()) - { - // clean all mesh in the tree of the current submesh; - // we must perform it now because later - // we will have no information about the type of the removed algo - needFullClean = true; - } + if (!algo->NeedDiscreteBoundary()) + algoRequiringCleaning = algo; } } @@ -678,6 +700,9 @@ SMESH_Hypothesis::Hypothesis_Status if (!isApplicableHyp) return ret; // not applicable hypotheses do not change algo state + if (( algo = GetAlgo())) + algo->InitComputeError(); + switch (_algoState) { @@ -688,16 +713,16 @@ SMESH_Hypothesis::Hypothesis_Status case ADD_HYP: break; case ADD_ALGO: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if (algo->CheckHypothesis((*_father),_subShape, aux_ret)) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else if ( algo->IsStatusFatal( aux_ret )) { meshDS->RemoveHypothesis(_subShape, anHyp); ret = aux_ret; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); break; } case REMOVE_HYP: @@ -705,26 +730,26 @@ SMESH_Hypothesis::Hypothesis_Status case ADD_FATHER_HYP: break; case ADD_FATHER_ALGO: { // Algo just added in father - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if ( algo == anHyp ) { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret)) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } case REMOVE_FATHER_HYP: break; case REMOVE_FATHER_ALGO: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); if (algo) { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } @@ -741,10 +766,10 @@ SMESH_Hypothesis::Hypothesis_Status switch (event) { case ADD_HYP: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, ret )) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); if (SMESH_Hypothesis::IsStatusFatal( ret )) meshDS->RemoveHypothesis(_subShape, anHyp); else if (!_father->IsUsedHypothesis( anHyp, this )) @@ -755,70 +780,70 @@ SMESH_Hypothesis::Hypothesis_Status break; } case ADD_ALGO: { //already existing algo : on father ? - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))// ignore hyp status - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else if ( algo->IsStatusFatal( aux_ret )) { meshDS->RemoveHypothesis(_subShape, anHyp); ret = aux_ret; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); break; } case REMOVE_HYP: break; case REMOVE_ALGO: { // perhaps a father algo applies ? - algo = gen->GetAlgo((*_father), _subShape); - if (algo == NULL) // no more algo applying on subShape... + algo = GetAlgo(); + if (algo == NULL) // no more algo applying on sub-shape... { - SetAlgoState(NO_ALGO); + setAlgoState(NO_ALGO); } else { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } case MODIF_HYP: // assigned hypothesis value may become good case ADD_FATHER_HYP: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); break; } case ADD_FATHER_ALGO: { // new father algo - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT( algo ); if ( algo == anHyp ) { if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } case REMOVE_FATHER_HYP: // nothing to do break; case REMOVE_FATHER_ALGO: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); if (algo == NULL) // no more applying algo on father { - SetAlgoState(NO_ALGO); + setAlgoState(NO_ALGO); } else { if ( algo->CheckHypothesis((*_father),_subShape , aux_ret )) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } @@ -834,7 +859,7 @@ SMESH_Hypothesis::Hypothesis_Status switch (event) { case ADD_HYP: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if (!algo->CheckHypothesis((*_father),_subShape, ret )) { @@ -842,7 +867,7 @@ SMESH_Hypothesis::Hypothesis_Status // ret should be fatal: anHyp was not added ret = SMESH_Hypothesis::HYP_INCOMPATIBLE; } - else if (!_father->IsUsedHypothesis( anHyp, this )) + else if (!_father->IsUsedHypothesis( anHyp, this )) ret = SMESH_Hypothesis::HYP_INCOMPATIBLE; if (SMESH_Hypothesis::IsStatusFatal( ret )) @@ -857,37 +882,37 @@ SMESH_Hypothesis::Hypothesis_Status break; } case ADD_ALGO: { //already existing algo : on father ? - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) { // check if algo changes SMESH_HypoFilter f; f.Init( SMESH_HypoFilter::IsAlgo() ); f.And( SMESH_HypoFilter::IsApplicableTo( _subShape )); f.AndNot( SMESH_HypoFilter::Is( algo )); - const SMESH_Hypothesis * prevAlgo = _father->GetHypothesis( _subShape, f, true ); + const SMESH_Hypothesis * prevAlgo = _father->GetHypothesis( this, f, true ); if (prevAlgo && - string(algo->GetName()) != string(prevAlgo->GetName()) ) + string( algo->GetName()) != prevAlgo->GetName()) modifiedHyp = true; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); break; } case REMOVE_HYP: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) - SetAlgoState(HYP_OK); + setAlgoState(HYP_OK); else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); modifiedHyp = true; break; } case REMOVE_ALGO: { // perhaps a father algo applies ? - algo = gen->GetAlgo((*_father), _subShape); - if (algo == NULL) // no more algo applying on subShape... + algo = GetAlgo(); + if (algo == NULL) // no more algo applying on sub-shape... { - SetAlgoState(NO_ALGO); + setAlgoState(NO_ALGO); } else { @@ -897,13 +922,13 @@ SMESH_Hypothesis::Hypothesis_Status modifiedHyp = true; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } case MODIF_HYP: // hypothesis value may become bad case ADD_FATHER_HYP: { // new father hypothesis ? - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) { @@ -911,11 +936,11 @@ SMESH_Hypothesis::Hypothesis_Status modifiedHyp = true; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); break; } case ADD_FATHER_ALGO: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); if ( algo == anHyp ) { // a new algo on father if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) { // check if algo changes @@ -923,33 +948,38 @@ SMESH_Hypothesis::Hypothesis_Status f.Init( SMESH_HypoFilter::IsAlgo() ); f.And( SMESH_HypoFilter::IsApplicableTo( _subShape )); f.AndNot( SMESH_HypoFilter::Is( algo )); - const SMESH_Hypothesis* prevAlgo = _father->GetHypothesis( _subShape, f, true ); + const SMESH_Hypothesis* prevAlgo = _father->GetHypothesis( this, f, true ); if (prevAlgo && string(algo->GetName()) != string(prevAlgo->GetName()) ) modifiedHyp = true; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } case REMOVE_FATHER_HYP: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) { // is there the same local hyp or maybe a new father algo applied? - if ( !GetSimilarAttached( _subShape, anHyp ) ) + if ( !getSimilarAttached( _subShape, anHyp ) ) modifiedHyp = true; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); break; } case REMOVE_FATHER_ALGO: { - algo = gen->GetAlgo((*_father), _subShape); + // IPAL21346. Edges not removed when Netgen 1d-2d is removed from a SOLID. + // CLEAN was not called at event REMOVE_ALGO because the algo is not applicable to SOLID. + algo = dynamic_cast (anHyp); + if (!algo->NeedDiscreteBoundary()) + algoRequiringCleaning = algo; + algo = GetAlgo(); if (algo == NULL) // no more applying algo on father { - SetAlgoState(NO_ALGO); + setAlgoState(NO_ALGO); } else { @@ -959,7 +989,7 @@ SMESH_Hypothesis::Hypothesis_Status modifiedHyp = true; } else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; } @@ -978,38 +1008,50 @@ SMESH_Hypothesis::Hypothesis_Status // detect algorithm hiding // - if ( ret == SMESH_Hypothesis::HYP_OK && - ( event == ADD_ALGO || event == ADD_FATHER_ALGO ) && + if ( ret == SMESH_Hypothesis::HYP_OK && + ( event == ADD_ALGO || event == ADD_FATHER_ALGO ) && algo && algo->GetName() == anHyp->GetName() ) { // is algo hidden? SMESH_Gen* gen = _father->GetGen(); - TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape )); - for ( ; ( ret == SMESH_Hypothesis::HYP_OK && it.More()); it.Next() ) { - if ( SMESH_Algo* upperAlgo = gen->GetAlgo( *_father, it.Value() )) - if ( !upperAlgo->NeedDescretBoundary() && !upperAlgo->SupportSubmeshes()) + const std::vector< SMESH_subMesh * > & ancestors = GetAncestors(); + for ( size_t iA = 0; ( ret == SMESH_Hypothesis::HYP_OK && iA < ancestors.size()); ++iA ) { + if ( SMESH_Algo* upperAlgo = ancestors[ iA ]->GetAlgo() ) + if ( !upperAlgo->NeedDiscreteBoundary() && !upperAlgo->SupportSubmeshes()) ret = SMESH_Hypothesis::HYP_HIDDEN_ALGO; } // is algo hiding? if ( ret == SMESH_Hypothesis::HYP_OK && - !algo->NeedDescretBoundary() && - !algo->SupportSubmeshes()) { + !algo->NeedDiscreteBoundary() && + !algo->SupportSubmeshes()) + { + TopoDS_Shape algoAssignedTo, otherAssignedTo; + gen->GetAlgo( this, &algoAssignedTo ); map::reverse_iterator i_sm = _mapDepend.rbegin(); for ( ; ( ret == SMESH_Hypothesis::HYP_OK && i_sm != _mapDepend.rend()) ; ++i_sm ) - if ( gen->GetAlgo( *_father, i_sm->second->_subShape )) + if ( gen->GetAlgo( i_sm->second, &otherAssignedTo ) && + SMESH_MesherHelper::IsSubShape( /*sub=*/otherAssignedTo, /*main=*/algoAssignedTo )) ret = SMESH_Hypothesis::HYP_HIDING_ALGO; } } + if ( _algo ) { // get an error description set by _algo->CheckHypothesis() + _computeError = _algo->GetComputeError(); + _algo->InitComputeError(); + } + bool stateChange = ( _algoState != oldAlgoState ); if ( stateChange && _algoState == HYP_OK ) // hyp becomes OK algo->SetEventListener( this ); - NotifyListenersOnEvent( event, ALGO_EVENT, anHyp ); + if ( event == REMOVE_ALGO || event == REMOVE_FATHER_ALGO ) + _algo = 0; + + notifyListenersOnEvent( event, ALGO_EVENT, anHyp ); if ( stateChange && oldAlgoState == HYP_OK ) { // hyp becomes KO - DeleteOwnListeners(); + deleteOwnListeners(); SetIsAlwaysComputed( false ); if (_subShape.ShapeType() == TopAbs_VERTEX ) { // restore default states @@ -1018,15 +1060,17 @@ SMESH_Hypothesis::Hypothesis_Status } } - if ( needFullClean ) { + if ( algoRequiringCleaning ) { // added or removed algo is all-dimensional ComputeStateEngine( CLEAN ); - CleanDependsOn(); + cleanDependsOn( algoRequiringCleaning ); ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE ); } - if (stateChange || modifiedHyp) - ComputeStateEngine(MODIF_ALGO_STATE); + if ( stateChange || modifiedHyp ) + ComputeStateEngine( MODIF_ALGO_STATE ); + + _realComputeCost = ( _algoState == HYP_OK ) ? computeCost() : 0; return ret; } @@ -1044,9 +1088,9 @@ bool SMESH_subMesh::IsConform(const SMESH_Algo* theAlgo) // Suppose that theAlgo is applicable to _subShape, do not check it here //if ( !IsApplicableHypotesis( theAlgo )) return false; - // check only algo that doesn't NeedDescretBoundary(): because mesh made + // check only algo that doesn't NeedDiscreteBoundary(): because mesh made // on a sub-shape will be ignored by theAlgo - if ( theAlgo->NeedDescretBoundary() || + if ( theAlgo->NeedDiscreteBoundary() || !theAlgo->OnlyUnaryInput() ) // all adjacent shapes will be meshed by this algo? return true; @@ -1064,18 +1108,18 @@ bool SMESH_subMesh::IsConform(const SMESH_Algo* theAlgo) for (; itsub.More(); itsub.Next()) { // loop on adjacent subShapes - TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( itsub.Value() )); - for (; it.More(); it.Next()) + const std::vector< SMESH_subMesh * > & ancestors = GetAncestors(); + for ( size_t iA = 0; iA < ancestors.size(); ++iA ) { - const TopoDS_Shape& adjacent = it.Value(); + const TopoDS_Shape& adjacent = ancestors[ iA ]->GetSubShape(); if ( _subShape.IsSame( adjacent )) continue; if ( adjacent.ShapeType() != _subShape.ShapeType()) break; // check algo attached to smAdjacent - SMESH_Algo * algo = gen->GetAlgo((*_father), adjacent); + SMESH_Algo * algo = ancestors[ iA ]->GetAlgo(); if (algo && - !algo->NeedDescretBoundary() && + !algo->NeedDiscreteBoundary() && algo->OnlyUnaryInput()) return false; // NOT CONFORM MESH WILL BE PRODUCED } @@ -1090,19 +1134,29 @@ bool SMESH_subMesh::IsConform(const SMESH_Algo* theAlgo) */ //============================================================================= -void SMESH_subMesh::SetAlgoState(int state) +void SMESH_subMesh::setAlgoState(algo_state state) { _algoState = state; } -//============================================================================= +//================================================================================ /*! + * \brief Send an event to sub-meshes + * \param [in] event - the event + * \param [in] anHyp - an hypothesis + * \param [in] exitOnFatal - to stop iteration on sub-meshes if a sub-mesh + * reports a fatal result + * \return SMESH_Hypothesis::Hypothesis_Status - the worst result * + * Optional description of a problematic situation (if any) can be retrieved + * via GetComputeError(). */ -//============================================================================= +//================================================================================ + SMESH_Hypothesis::Hypothesis_Status - SMESH_subMesh::SubMeshesAlgoStateEngine(int event, - SMESH_Hypothesis * anHyp) + SMESH_subMesh::SubMeshesAlgoStateEngine(int event, + SMESH_Hypothesis * anHyp, + bool exitOnFatal) { SMESH_Hypothesis::Hypothesis_Status ret = SMESH_Hypothesis::HYP_OK; //EAP: a wire (dim==1) should notify edges (dim==1) @@ -1111,26 +1165,96 @@ SMESH_Hypothesis::Hypothesis_Status { SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false); while ( smIt->more() ) { - SMESH_Hypothesis::Hypothesis_Status ret2 = - smIt->next()->AlgoStateEngine(event, anHyp); + SMESH_subMesh* sm = smIt->next(); + SMESH_Hypothesis::Hypothesis_Status ret2 = sm->AlgoStateEngine(event, anHyp); if ( ret2 > ret ) + { ret = ret2; + _computeError = sm->_computeError; + sm->_computeError.reset(); + if ( exitOnFatal && SMESH_Hypothesis::IsStatusFatal( ret )) + break; + } } } return ret; } -//============================================================================= +//================================================================================ /*! - * + * \brief Remove elements from sub-meshes. + * \param algoRequiringCleaning - an all-dimensional algorithm whose presence + * causes the cleaning. */ -//============================================================================= +//================================================================================ -void SMESH_subMesh::CleanDependsOn() +void SMESH_subMesh::cleanDependsOn( SMESH_Algo* algoRequiringCleaning/*=0*/ ) { - SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false); - while ( smIt->more() ) - smIt->next()->ComputeStateEngine(CLEAN); + SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false, + /*complexShapeFirst=*/true); + if ( _father->NbNodes() == 0 ) + { + while ( smIt->more() ) + smIt->next()->ComputeStateEngine(CHECK_COMPUTE_STATE); + } + else if ( !algoRequiringCleaning || !algoRequiringCleaning->SupportSubmeshes() ) + { + while ( smIt->more() ) + smIt->next()->ComputeStateEngine(CLEAN); + } + else if ( algoRequiringCleaning && algoRequiringCleaning->SupportSubmeshes() ) + { + SMESHDS_Mesh* meshDS = _father->GetMeshDS(); + + // find sub-meshes to keep elements on + set< SMESH_subMesh* > smToKeep; + TopAbs_ShapeEnum prevShapeType = TopAbs_SHAPE; + bool toKeepPrevShapeType = false; + while ( smIt->more() ) + { + SMESH_subMesh* sm = smIt->next(); + sm->ComputeStateEngine(CHECK_COMPUTE_STATE); + if ( !sm->IsEmpty() ) + { + const bool sameShapeType = ( prevShapeType == sm->GetSubShape().ShapeType() ); + bool keepSubMeshes = ( sameShapeType && toKeepPrevShapeType ); + if ( !sameShapeType ) + { + // check if the algo allows presence of global algos of dimension the algo + // can generate it-self + int shapeDim = SMESH_Gen::GetShapeDim( sm->GetSubShape() ); + keepSubMeshes = algoRequiringCleaning->NeedLowerHyps( shapeDim ); + prevShapeType = sm->GetSubShape().ShapeType(); + toKeepPrevShapeType = keepSubMeshes; + } + if ( !keepSubMeshes ) + { + // look for an algo assigned to sm + bool algoFound = false; + const list& hyps = meshDS->GetHypothesis( sm->_subShape ); + list::const_iterator h = hyps.begin(); + for ( ; ( !algoFound && h != hyps.end() ); ++h ) + algoFound = ((*h)->GetType() != SMESHDS_Hypothesis::PARAM_ALGO ); + keepSubMeshes = algoFound; + } + // remember all sub-meshes of sm + if ( keepSubMeshes ) + { + SMESH_subMeshIteratorPtr smIt2 = getDependsOnIterator(false); + while ( smIt2->more() ) + smToKeep.insert( smIt2->next() ); + } + } + } + // remove elements + SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,true); + while ( smIt->more() ) + { + SMESH_subMesh* sm = smIt->next(); + if ( !smToKeep.count( sm )) + sm->ComputeStateEngine(CLEAN); + } + } } //============================================================================= @@ -1141,48 +1265,32 @@ void SMESH_subMesh::CleanDependsOn() void SMESH_subMesh::DumpAlgoState(bool isMain) { - int dim = SMESH_Gen::GetShapeDim(_subShape); -// if (dim < 1) return; - if (isMain) - { - const map < int, SMESH_subMesh * >&subMeshes = DependsOn(); - - map < int, SMESH_subMesh * >::const_iterator itsub; - for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++) - { - SMESH_subMesh *sm = (*itsub).second; - sm->DumpAlgoState(false); - } - } - int type = _subShape.ShapeType(); - MESSAGE("dim = " << dim << " type of shape " << type); - switch (_algoState) - { - case NO_ALGO: - MESSAGE(" AlgoState = NO_ALGO"); - break; - case MISSING_HYP: - MESSAGE(" AlgoState = MISSING_HYP"); - break; - case HYP_OK: - MESSAGE(" AlgoState = HYP_OK"); - break; - } - switch (_computeState) - { - case NOT_READY: - MESSAGE(" ComputeState = NOT_READY"); - break; - case READY_TO_COMPUTE: - MESSAGE(" ComputeState = READY_TO_COMPUTE"); - break; - case COMPUTE_OK: - MESSAGE(" ComputeState = COMPUTE_OK"); - break; - case FAILED_TO_COMPUTE: - MESSAGE(" ComputeState = FAILED_TO_COMPUTE"); - break; - } + if (isMain) + { + const map < int, SMESH_subMesh * >&subMeshes = DependsOn(); + + map < int, SMESH_subMesh * >::const_iterator itsub; + for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++) + { + SMESH_subMesh *sm = (*itsub).second; + sm->DumpAlgoState(false); + } + } + MESSAGE("dim = " << SMESH_Gen::GetShapeDim(_subShape) << + " type of shape " << _subShape.ShapeType()); + switch (_algoState) + { + case NO_ALGO : MESSAGE(" AlgoState = NO_ALGO"); break; + case MISSING_HYP : MESSAGE(" AlgoState = MISSING_HYP"); break; + case HYP_OK : MESSAGE(" AlgoState = HYP_OK");break; + } + switch (_computeState) + { + case NOT_READY : MESSAGE(" ComputeState = NOT_READY");break; + case READY_TO_COMPUTE : MESSAGE(" ComputeState = READY_TO_COMPUTE");break; + case COMPUTE_OK : MESSAGE(" ComputeState = COMPUTE_OK");break; + case FAILED_TO_COMPUTE: MESSAGE(" ComputeState = FAILED_TO_COMPUTE");break; + } } //================================================================================ @@ -1202,7 +1310,7 @@ static void cleanSubMesh( SMESH_subMesh * subMesh ) const SMDS_MeshElement * elt = ite->next(); //MESSAGE( " RM elt: "<GetID()<<" ( "<NbNodes()<<" )" ); //meshDS->RemoveElement(elt); - meshDS->RemoveFreeElement(elt, subMeshDS); + meshDS->RemoveFreeElement(elt, 0); } SMDS_NodeIteratorPtr itn = subMeshDS->GetNodes(); @@ -1210,10 +1318,11 @@ static void cleanSubMesh( SMESH_subMesh * subMesh ) const SMDS_MeshNode * node = itn->next(); //MESSAGE( " RM node: "<GetID()); if ( node->NbInverseElements() == 0 ) - meshDS->RemoveFreeNode(node, subMeshDS); + meshDS->RemoveFreeNode(node, 0); else // for StdMeshers_CompositeSegment_1D: node in one submesh, edge in another meshDS->RemoveNode(node); } + subMeshDS->Clear(); } } } @@ -1226,25 +1335,40 @@ static void cleanSubMesh( SMESH_subMesh * subMesh ) bool SMESH_subMesh::ComputeStateEngine(int event) { - _computeError.reset(); + switch ( event ) { + case MODIF_ALGO_STATE: + case COMPUTE: + case COMPUTE_SUBMESH: + //case COMPUTE_CANCELED: + case CLEAN: + //case SUBMESH_COMPUTED: + //case SUBMESH_RESTORED: + //case SUBMESH_LOADED: + //case MESH_ENTITY_REMOVED: + //case CHECK_COMPUTE_STATE: + _computeError.reset(); break; + default:; + } - //MESSAGE("SMESH_subMesh::ComputeStateEngine"); - //SCRUTE(_computeState); - //SCRUTE(event); + if ( event == CLEAN ) + _alwaysComputed = false; // Unset 'true' set by MergeNodes() (issue 0022182) if (_subShape.ShapeType() == TopAbs_VERTEX) { _computeState = READY_TO_COMPUTE; SMESHDS_SubMesh* smDS = GetSubMeshDS(); - if ( smDS && smDS->NbNodes() ) { + if ( smDS && smDS->NbNodes() ) + { if ( event == CLEAN ) { - CleanDependants(); + cleanDependants(); cleanSubMesh( this ); } else _computeState = COMPUTE_OK; } - else if ( event == COMPUTE && !_alwaysComputed ) { + else if (( event == COMPUTE || event == COMPUTE_SUBMESH ) + && !_alwaysComputed ) + { const TopoDS_Vertex & V = TopoDS::Vertex( _subShape ); gp_Pnt P = BRep_Tool::Pnt(V); if ( SMDS_MeshNode * n = _father->GetMeshDS()->AddNode(P.X(), P.Y(), P.Z()) ) { @@ -1253,14 +1377,14 @@ bool SMESH_subMesh::ComputeStateEngine(int event) } } if ( event == MODIF_ALGO_STATE ) - CleanDependants(); + cleanDependants(); return true; } SMESH_Gen *gen = _father->GetGen(); SMESH_Algo *algo = 0; bool ret = true; SMESH_Hypothesis::Hypothesis_Status hyp_status; - //algo_state oldAlgoState = (algo_state) GetAlgoState(); + algo_state oldAlgoState = (algo_state) GetAlgoState(); switch (_computeState) { @@ -1271,25 +1395,32 @@ bool SMESH_subMesh::ComputeStateEngine(int event) switch (event) { case MODIF_ALGO_STATE: - algo = gen->GetAlgo((*_father), _subShape); - if (algo && !algo->NeedDescretBoundary()) - CleanDependsOn(); // clean sub-meshes with event CLEAN + algo = GetAlgo(); + if (algo && !algo->NeedDiscreteBoundary()) + cleanDependsOn( algo ); // clean sub-meshes with event CLEAN if ( _algoState == HYP_OK ) _computeState = READY_TO_COMPUTE; break; - case COMPUTE: // nothing to do + case COMPUTE: // nothing to do + case COMPUTE_SUBMESH: + break; + case COMPUTE_CANCELED: // nothing to do break; case CLEAN: - CleanDependants(); - RemoveSubMeshElementsAndNodes(); + cleanDependants(); + removeSubMeshElementsAndNodes(); break; - case SUBMESH_COMPUTED: // nothing to do + case SUBMESH_COMPUTED: // nothing to do break; case SUBMESH_RESTORED: ComputeSubMeshStateEngine( SUBMESH_RESTORED ); break; case MESH_ENTITY_REMOVED: break; + case SUBMESH_LOADED: + loadDependentMeshes(); + ComputeSubMeshStateEngine( SUBMESH_LOADED ); + //break; case CHECK_COMPUTE_STATE: if ( IsMeshComputed() ) _computeState = COMPUTE_OK; @@ -1307,60 +1438,75 @@ bool SMESH_subMesh::ComputeStateEngine(int event) { case MODIF_ALGO_STATE: _computeState = NOT_READY; - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); if (algo) { - if (!algo->NeedDescretBoundary()) - CleanDependsOn(); // clean sub-meshes with event CLEAN + if (!algo->NeedDiscreteBoundary()) + cleanDependsOn( algo ); // clean sub-meshes with event CLEAN if ( _algoState == HYP_OK ) _computeState = READY_TO_COMPUTE; } break; case COMPUTE: + case COMPUTE_SUBMESH: { - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); ASSERT(algo); ret = algo->CheckHypothesis((*_father), _subShape, hyp_status); if (!ret) { MESSAGE("***** verify compute state *****"); _computeState = NOT_READY; - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); break; } TopoDS_Shape shape = _subShape; + algo->SubMeshesToCompute().assign( 1, this ); // check submeshes needed if (_father->HasShapeToMesh() ) { - bool subComputed = false; - if (!algo->OnlyUnaryInput()) - shape = GetCollection( gen, algo, subComputed ); - else + bool subComputed = false, subFailed = false; + if (!algo->OnlyUnaryInput()) { + if ( event == COMPUTE /*&& + ( algo->NeedDiscreteBoundary() || algo->SupportSubmeshes() )*/) + shape = getCollection( gen, algo, subComputed, subFailed, algo->SubMeshesToCompute()); + else + subComputed = SubMeshesComputed( & subFailed ); + } + else { subComputed = SubMeshesComputed(); - ret = ( algo->NeedDescretBoundary() ? subComputed : - algo->SupportSubmeshes() ? true : + } + ret = ( algo->NeedDiscreteBoundary() ? subComputed : + algo->SupportSubmeshes() ? !subFailed : ( !subComputed || _father->IsNotConformAllowed() )); - if (!ret) { + if (!ret) + { _computeState = FAILED_TO_COMPUTE; - if ( !algo->NeedDescretBoundary() ) + if ( !algo->NeedDiscreteBoundary() && !subFailed ) _computeError = SMESH_ComputeError::New(COMPERR_BAD_INPUT_MESH, - "Unexpected computed submesh",algo); - break; + "Unexpected computed sub-mesh",algo); + break; // goto exit } } - // compute -// CleanDependants(); for "UseExisting_*D" algos -// RemoveSubMeshElementsAndNodes(); + // Compute + + // to restore cout that may be redirected by algo + std::streambuf* coutBuffer = std::cout.rdbuf(); + + //cleanDependants(); for "UseExisting_*D" algos + //removeSubMeshElementsAndNodes(); + loadDependentMeshes(); ret = false; _computeState = FAILED_TO_COMPUTE; _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo); try { -#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 OCC_CATCH_SIGNALS; -#endif + algo->InitComputeError(); + MemoryReserve aMemoryReserve; SMDS_Mesh::CheckMemory(); + Kernel_Utils::Localizer loc; if ( !_father->HasShapeToMesh() ) // no shape { SMESH_MesherHelper helper( *_father ); @@ -1372,8 +1518,13 @@ bool SMESH_subMesh::ComputeStateEngine(int event) { ret = algo->Compute((*_father), shape); } - if ( !_computeError || ( !ret && _computeError->IsOK() ) ) // algo can set _computeError of submesh - _computeError = algo->GetComputeError(); + // algo can set _computeError of submesh + _computeError = SMESH_ComputeError::Worst( _computeError, algo->GetComputeError() ); + } + catch ( ::SMESH_ComputeError& comperr ) { + cout << " SMESH_ComputeError caught" << endl; + if ( !_computeError ) _computeError = SMESH_ComputeError::New(); + *_computeError = comperr; } catch ( std::bad_alloc& exc ) { MESSAGE("std::bad_alloc thrown inside algo->Compute()"); @@ -1402,10 +1553,13 @@ bool SMESH_subMesh::ComputeStateEngine(int event) _computeError->myComment += ex.GetMessageString(); } } - catch ( SMESH_Exception& S_ex ) { + catch ( SALOME_Exception& S_ex ) { + const int skipSalomeShift = 7; /* to skip "Salome " of + "Salome Exception" prefix returned + by SALOME_Exception::what() */ if ( !_computeError ) _computeError = SMESH_ComputeError::New(); _computeError->myName = COMPERR_SLM_EXCEPTION; - _computeError->myComment = S_ex.what(); + _computeError->myComment = S_ex.what() + skipSalomeShift; } catch ( std::exception& exc ) { if ( !_computeError ) _computeError = SMESH_ComputeError::New(); @@ -1418,38 +1572,79 @@ bool SMESH_subMesh::ComputeStateEngine(int event) else ret = false; } - if (ret && !_alwaysComputed && shape == _subShape) { // check if anything was built - ret = ( GetSubMeshDS() && ( GetSubMeshDS()->NbElements() || GetSubMeshDS()->NbNodes() )); + std::cout.rdbuf( coutBuffer ); // restore cout that could be redirected by algo + + // check if an error reported on any sub-shape + bool isComputeErrorSet = !checkComputeError( algo, ret, shape ); + if ( isComputeErrorSet ) + ret = false; + // check if anything was built + TopExp_Explorer subS(shape, _subShape.ShapeType()); + if (ret) + { + for (; ret && subS.More(); subS.Next()) + if ( !_father->GetSubMesh( subS.Current() )->IsMeshComputed() && + ( _subShape.ShapeType() != TopAbs_EDGE || + !algo->isDegenerated( TopoDS::Edge( subS.Current() )))) + ret = false; } - bool isComputeErrorSet = !CheckComputeError( algo, shape ); + // Set _computeError if (!ret && !isComputeErrorSet) { - // Set _computeError - if ( !_computeError ) - _computeError = SMESH_ComputeError::New(); - if ( _computeError->IsOK() ) - _computeError->myName = COMPERR_ALGO_FAILED; - _computeState = FAILED_TO_COMPUTE; + for (subS.ReInit(); subS.More(); subS.Next()) + { + SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() ); + if ( !sm->IsMeshComputed() ) + { + if ( !sm->_computeError ) + sm->_computeError = SMESH_ComputeError::New(); + if ( sm->_computeError->IsOK() ) + sm->_computeError->myName = COMPERR_ALGO_FAILED; + sm->_computeState = FAILED_TO_COMPUTE; + sm->_computeError->myAlgo = algo; + } + } } - if (ret) + if (ret && _computeError && _computeError->myName != COMPERR_WARNING ) { _computeError.reset(); } - UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED + + // send event SUBMESH_COMPUTED + if ( ret ) { + if ( !algo->NeedDiscreteBoundary() ) + // send SUBMESH_COMPUTED to dependants of all sub-meshes of shape + for (subS.ReInit(); subS.More(); subS.Next()) + { + SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() ); + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(false,false); + while ( smIt->more() ) { + sm = smIt->next(); + if ( sm->GetSubShape().ShapeType() == TopAbs_VERTEX ) + sm->updateDependantsState( SUBMESH_COMPUTED ); + else + break; + } + } + else + updateDependantsState( SUBMESH_COMPUTED ); + } } break; + case COMPUTE_CANCELED: // nothing to do + break; case CLEAN: - CleanDependants(); - RemoveSubMeshElementsAndNodes(); + cleanDependants(); + removeSubMeshElementsAndNodes(); _computeState = NOT_READY; - algo = gen->GetAlgo((*_father), _subShape); + algo = GetAlgo(); if (algo) { ret = algo->CheckHypothesis((*_father), _subShape, hyp_status); if (ret) _computeState = READY_TO_COMPUTE; else - SetAlgoState(MISSING_HYP); + setAlgoState(MISSING_HYP); } break; case SUBMESH_COMPUTED: // nothing to do @@ -1459,14 +1654,20 @@ bool SMESH_subMesh::ComputeStateEngine(int event) // happen after retrieval from a file ComputeStateEngine( CHECK_COMPUTE_STATE ); ComputeSubMeshStateEngine( SUBMESH_RESTORED ); - algo = gen->GetAlgo(*_father, _subShape); + algo = GetAlgo(); if (algo) algo->SubmeshRestored( this ); break; case MESH_ENTITY_REMOVED: break; + case SUBMESH_LOADED: + loadDependentMeshes(); + ComputeSubMeshStateEngine( SUBMESH_LOADED ); + //break; case CHECK_COMPUTE_STATE: if ( IsMeshComputed() ) _computeState = COMPUTE_OK; + else if ( _computeError && _computeError->IsKO() ) + _computeState = FAILED_TO_COMPUTE; break; default: ASSERT(0); @@ -1481,15 +1682,17 @@ bool SMESH_subMesh::ComputeStateEngine(int event) { case MODIF_ALGO_STATE: ComputeStateEngine( CLEAN ); - algo = gen->GetAlgo((*_father), _subShape); - if (algo && !algo->NeedDescretBoundary()) - CleanDependsOn(); // clean sub-meshes with event CLEAN + algo = GetAlgo(); + if (algo && !algo->NeedDiscreteBoundary()) + cleanDependsOn( algo ); // clean sub-meshes with event CLEAN break; case COMPUTE: // nothing to do break; + case COMPUTE_CANCELED: // nothing to do + break; case CLEAN: - CleanDependants(); // clean sub-meshes, dependant on this one, with event CLEAN - RemoveSubMeshElementsAndNodes(); + cleanDependants(); // clean sub-meshes, dependant on this one, with event CLEAN + removeSubMeshElementsAndNodes(); _computeState = NOT_READY; if ( _algoState == HYP_OK ) _computeState = READY_TO_COMPUTE; @@ -1499,12 +1702,12 @@ bool SMESH_subMesh::ComputeStateEngine(int event) case SUBMESH_RESTORED: ComputeStateEngine( CHECK_COMPUTE_STATE ); ComputeSubMeshStateEngine( SUBMESH_RESTORED ); - algo = gen->GetAlgo(*_father, _subShape); + algo = GetAlgo(); if (algo) algo->SubmeshRestored( this ); break; case MESH_ENTITY_REMOVED: - UpdateDependantsState( CHECK_COMPUTE_STATE ); - ComputeStateEngine( CHECK_COMPUTE_STATE ); + updateDependantsState ( CHECK_COMPUTE_STATE ); + ComputeStateEngine ( CHECK_COMPUTE_STATE ); ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE ); break; case CHECK_COMPUTE_STATE: @@ -1515,6 +1718,9 @@ bool SMESH_subMesh::ComputeStateEngine(int event) _computeState = NOT_READY; } break; + case SUBMESH_LOADED: + // already treated event, thanks to which _computeState == COMPUTE_OK + break; default: ASSERT(0); break; @@ -1527,25 +1733,37 @@ bool SMESH_subMesh::ComputeStateEngine(int event) switch (event) { case MODIF_ALGO_STATE: - algo = gen->GetAlgo((*_father), _subShape); - if (algo && !algo->NeedDescretBoundary()) - CleanDependsOn(); // clean sub-meshes with event CLEAN + if ( !IsEmpty() ) + ComputeStateEngine( CLEAN ); + algo = GetAlgo(); + if (algo && !algo->NeedDiscreteBoundary()) + cleanDependsOn( algo ); // clean sub-meshes with event CLEAN if (_algoState == HYP_OK) _computeState = READY_TO_COMPUTE; else _computeState = NOT_READY; break; - case COMPUTE: // nothing to do + case COMPUTE: // nothing to do + case COMPUTE_SUBMESH: + break; + case COMPUTE_CANCELED: + { + algo = GetAlgo(); + algo->CancelCompute(); + } break; case CLEAN: - CleanDependants(); // submeshes dependent on me should be cleaned as well - RemoveSubMeshElementsAndNodes(); + cleanDependants(); // submeshes dependent on me should be cleaned as well + removeSubMeshElementsAndNodes(); break; case SUBMESH_COMPUTED: // allow retry compute - if (_algoState == HYP_OK) - _computeState = READY_TO_COMPUTE; - else - _computeState = NOT_READY; + if ( IsEmpty() ) // 23061 + { + if (_algoState == HYP_OK) + _computeState = READY_TO_COMPUTE; + else + _computeState = NOT_READY; + } break; case SUBMESH_RESTORED: ComputeSubMeshStateEngine( SUBMESH_RESTORED ); @@ -1561,6 +1779,8 @@ bool SMESH_subMesh::ComputeStateEngine(int event) else _computeState = NOT_READY; break; + // case SUBMESH_LOADED: + // break; default: ASSERT(0); break; @@ -1573,11 +1793,83 @@ bool SMESH_subMesh::ComputeStateEngine(int event) break; } - NotifyListenersOnEvent( event, COMPUTE_EVENT ); + notifyListenersOnEvent( event, COMPUTE_EVENT ); + + return ret; +} + + +//============================================================================= +/*! + * + */ +//============================================================================= + +bool SMESH_subMesh::Evaluate(MapShapeNbElems& aResMap) +{ + _computeError.reset(); + + bool ret = true; + + if (_subShape.ShapeType() == TopAbs_VERTEX) { + vector aVec(SMDSEntity_Last,0); + aVec[SMDSEntity_Node] = 1; + aResMap.insert(make_pair(this,aVec)); + return ret; + } + + //SMESH_Gen *gen = _father->GetGen(); + SMESH_Algo *algo = 0; + SMESH_Hypothesis::Hypothesis_Status hyp_status; + + algo = GetAlgo(); + if( algo && !aResMap.count( this )) + { + ret = algo->CheckHypothesis((*_father), _subShape, hyp_status); + if (!ret) return false; + + if (_father->HasShapeToMesh() && algo->NeedDiscreteBoundary() ) + { + // check submeshes needed + bool subMeshEvaluated = true; + int dimToCheck = SMESH_Gen::GetShapeDim( _subShape ) - 1; + SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,/*complexShapeFirst=*/true); + while ( smIt->more() && subMeshEvaluated ) + { + SMESH_subMesh* sm = smIt->next(); + int dim = SMESH_Gen::GetShapeDim( sm->GetSubShape() ); + if (dim < dimToCheck) break; // the rest subMeshes are all of less dimension + const vector & nbs = aResMap[ sm ]; + subMeshEvaluated = (std::accumulate( nbs.begin(), nbs.end(), 0 ) > 0 ); + } + if ( !subMeshEvaluated ) + return false; + } + _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo); + + if ( IsMeshComputed() ) + { + vector & nbEntities = aResMap[ this ]; + nbEntities.resize( SMDSEntity_Last, 0 ); + if ( SMESHDS_SubMesh* sm = GetSubMeshDS() ) + { + nbEntities[ SMDSEntity_Node ] = sm->NbNodes(); + SMDS_ElemIteratorPtr elemIt = sm->GetElements(); + while ( elemIt->more() ) + nbEntities[ elemIt->next()->GetEntityType() ]++; + } + } + else + { + ret = algo->Evaluate((*_father), _subShape, aResMap); + } + aResMap.insert( make_pair( this,vector(0))); + } return ret; } + //======================================================================= /*! * \brief Update compute_state by _computeError and send proper events to @@ -1586,18 +1878,20 @@ bool SMESH_subMesh::ComputeStateEngine(int event) */ //======================================================================= -bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& theShape) +bool SMESH_subMesh::checkComputeError(SMESH_Algo* theAlgo, + const bool theComputeOK, + const TopoDS_Shape& theShape) { bool noErrors = true; if ( !theShape.IsNull() ) { // Check state of submeshes - if ( !theAlgo->NeedDescretBoundary()) + if ( !theAlgo->NeedDiscreteBoundary()) { SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false); while ( smIt->more() ) - if ( !smIt->next()->CheckComputeError( theAlgo )) + if ( !smIt->next()->checkComputeError( theAlgo, theComputeOK )) noErrors = false; } @@ -1609,27 +1903,39 @@ bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& t for (TopoDS_Iterator subIt( theShape ); subIt.More(); subIt.Next()) { SMESH_subMesh* sm = _father->GetSubMesh( subIt.Value() ); if ( sm != this ) { - if ( !sm->CheckComputeError( theAlgo, sm->GetSubShape() )) + if ( !sm->checkComputeError( theAlgo, theComputeOK, sm->GetSubShape() )) noErrors = false; - UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED + updateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED } } } } { - // Check my state + + // Set my _computeState + if ( !_computeError || _computeError->IsOK() ) { - _computeState = COMPUTE_OK; + // no error description is set to this sub-mesh, check if any mesh is computed + _computeState = IsMeshComputed() ? COMPUTE_OK : FAILED_TO_COMPUTE; + if ( _computeState != COMPUTE_OK ) + { + if ( _subShape.ShapeType() == TopAbs_EDGE && + SMESH_Algo::isDegenerated( TopoDS::Edge( _subShape )) ) + _computeState = COMPUTE_OK; + else if ( theComputeOK ) + _computeError = SMESH_ComputeError::New(COMPERR_NO_MESH_ON_SHAPE,"",theAlgo); + } } - else + + if ( _computeError && !_computeError->IsOK() ) { if ( !_computeError->myAlgo ) _computeError->myAlgo = theAlgo; // Show error SMESH_Comment text; - text << theAlgo->GetName() << " failed on subshape #" << _Id << " with error "; + text << theAlgo->GetName() << " failed on sub-shape #" << _Id << " with error "; if (_computeError->IsCommon() ) text << _computeError->CommonName(); else @@ -1637,73 +1943,22 @@ bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& t if ( _computeError->myComment.size() > 0 ) text << " \"" << _computeError->myComment << "\""; -#ifdef _DEBUG_ - MESSAGE_BEGIN ( text ); - // Show vertices location of a failed shape - TopTools_IndexedMapOfShape vMap; - TopExp::MapShapes( _subShape, TopAbs_VERTEX, vMap ); - MESSAGE_ADD ( "Subshape vertices " << ( vMap.Extent()>10 ? "(first 10):" : ":") ); - for ( int iv = 1; iv <= vMap.Extent() && iv < 11; ++iv ) { - gp_Pnt P( BRep_Tool::Pnt( TopoDS::Vertex( vMap( iv ) ))); - MESSAGE_ADD ( "#" << _father->GetMeshDS()->ShapeToIndex( vMap( iv )) << " " - << P.X() << " " << P.Y() << " " << P.Z() << " " ); - } -#else INFOS( text ); -#endif - _computeState = FAILED_TO_COMPUTE; - noErrors = false; - } - } - return noErrors; -} - -//======================================================================= -//function : ApplyToCollection -//purpose : Apply theAlgo to all subshapes in theCollection -//======================================================================= - -bool SMESH_subMesh::ApplyToCollection (SMESH_Algo* theAlgo, - const TopoDS_Shape& theCollection) -{ - MESSAGE("SMESH_subMesh::ApplyToCollection"); - ASSERT ( !theAlgo->NeedDescretBoundary() ); - - if ( _computeError ) - _computeError->myName = COMPERR_OK; - bool ok = theAlgo->Compute( *_father, theCollection ); + _computeState = _computeError->IsKO() ? FAILED_TO_COMPUTE : COMPUTE_OK; - // set _computeState of subshapes - TopExp_Explorer anExplorer( theCollection, _subShape.ShapeType() ); - for ( ; anExplorer.More(); anExplorer.Next() ) - { - if ( SMESH_subMesh* subMesh = _father->GetSubMeshContaining( anExplorer.Current() )) - { - bool localOK = subMesh->CheckComputeError( theAlgo ); - if ( !ok && localOK && !subMesh->IsMeshComputed() ) - { - subMesh->_computeError = theAlgo->GetComputeError(); - if ( subMesh->_computeError->IsOK() ) - _computeError = SMESH_ComputeError::New(COMPERR_ALGO_FAILED); - localOK = CheckComputeError( theAlgo ); - } - if ( localOK ) - subMesh->UpdateDependantsState( SUBMESH_COMPUTED ); - subMesh->UpdateSubMeshState( localOK ? COMPUTE_OK : FAILED_TO_COMPUTE ); + noErrors = false; } } - - return true; + return noErrors; } - //======================================================================= -//function : UpdateSubMeshState +//function : updateSubMeshState //purpose : //======================================================================= -void SMESH_subMesh::UpdateSubMeshState(const compute_state theState) +void SMESH_subMesh::updateSubMeshState(const compute_state theState) { SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false); while ( smIt->more() ) @@ -1715,68 +1970,58 @@ void SMESH_subMesh::UpdateSubMeshState(const compute_state theState) //purpose : //======================================================================= -void SMESH_subMesh::ComputeSubMeshStateEngine(int event) +void SMESH_subMesh::ComputeSubMeshStateEngine(int event, const bool includeSelf) { - SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false); + SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(includeSelf,false); while ( smIt->more() ) smIt->next()->ComputeStateEngine(event); } //======================================================================= -//function : UpdateDependantsState +//function : updateDependantsState //purpose : //======================================================================= -void SMESH_subMesh::UpdateDependantsState(const compute_event theEvent) +void SMESH_subMesh::updateDependantsState(const compute_event theEvent) { - //MESSAGE("SMESH_subMesh::UpdateDependantsState"); - TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape )); - for (; it.More(); it.Next()) + const std::vector< SMESH_subMesh * > & ancestors = GetAncestors(); + for ( size_t iA = 0; iA < ancestors.size(); ++iA ) { - const TopoDS_Shape& ancestor = it.Value(); - SMESH_subMesh *aSubMesh = - _father->GetSubMeshContaining(ancestor); - if (aSubMesh) - aSubMesh->ComputeStateEngine( theEvent ); + ancestors[ iA ]->ComputeStateEngine( theEvent ); } } -//============================================================================= -/*! - * - */ -//============================================================================= +//======================================================================= +//function : cleanDependants +//purpose : +//======================================================================= -void SMESH_subMesh::CleanDependants() +void SMESH_subMesh::cleanDependants() { int dimToClean = SMESH_Gen::GetShapeDim( _subShape ) + 1; - TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape )); - for (; it.More(); it.Next()) + const std::vector< SMESH_subMesh * > & ancestors = GetAncestors(); + for ( size_t iA = 0; iA < ancestors.size(); ++iA ) { - const TopoDS_Shape& ancestor = it.Value(); - if ( SMESH_Gen::GetShapeDim( ancestor ) == dimToClean ) { + const TopoDS_Shape& ancestor = ancestors[ iA ]->GetSubShape(); + if ( SMESH_Gen::GetShapeDim( ancestor ) == dimToClean ) + { // PAL8021. do not go upper than SOLID, else ComputeStateEngine(CLEAN) // will erase mesh on other shapes in a compound - if ( ancestor.ShapeType() >= TopAbs_SOLID ) { - SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor); - if (aSubMesh) - aSubMesh->ComputeStateEngine(CLEAN); - } + if ( ancestor.ShapeType() >= TopAbs_SOLID && + !ancestors[ iA ]->IsEmpty() ) // prevent infinite CLEAN via event lesteners + ancestors[ iA ]->ComputeStateEngine(CLEAN); } } } -//============================================================================= -/*! - * - */ -//============================================================================= +//======================================================================= +//function : removeSubMeshElementsAndNodes +//purpose : +//======================================================================= -void SMESH_subMesh::RemoveSubMeshElementsAndNodes() +void SMESH_subMesh::removeSubMeshElementsAndNodes() { - //SCRUTE(_subShape.ShapeType()); - cleanSubMesh( this ); // algo may bind a submesh not to _subShape, eg 3D algo @@ -1797,52 +2042,59 @@ void SMESH_subMesh::RemoveSubMeshElementsAndNodes() } //======================================================================= -//function : GetCollection +//function : getCollection //purpose : return a shape containing all sub-shapes of the MainShape that can be // meshed at once along with _subShape //======================================================================= -TopoDS_Shape SMESH_subMesh::GetCollection(SMESH_Gen * theGen, +TopoDS_Shape SMESH_subMesh::getCollection(SMESH_Gen * theGen, SMESH_Algo* theAlgo, - bool & theSubComputed) + bool & theSubComputed, + bool & theSubFailed, + std::vector& theSubs) { - MESSAGE("SMESH_subMesh::GetCollection"); - - theSubComputed = SubMeshesComputed(); + theSubComputed = SubMeshesComputed( & theSubFailed ); TopoDS_Shape mainShape = _father->GetMeshDS()->ShapeToMesh(); if ( mainShape.IsSame( _subShape )) return _subShape; - const bool ignoreAuxiliaryHyps = false; + const bool skipAuxHyps = false; list aUsedHyp = - theAlgo->GetUsedHypothesis( *_father, _subShape, ignoreAuxiliaryHyps ); // copy + theAlgo->GetUsedHypothesis( *_father, _subShape, skipAuxHyps ); // copy // put in a compound all shapes with the same hypothesis assigned - // and a good ComputState + // and a good ComputeState TopoDS_Compound aCompound; BRep_Builder aBuilder; aBuilder.MakeCompound( aCompound ); - TopExp_Explorer anExplorer( mainShape, _subShape.ShapeType() ); - for ( ; anExplorer.More(); anExplorer.Next() ) + theSubs.clear(); + + SMESH_subMeshIteratorPtr smIt = _father->GetSubMesh( mainShape )->getDependsOnIterator(false); + while ( smIt->more() ) { - const TopoDS_Shape& S = anExplorer.Current(); - SMESH_subMesh* subMesh = _father->GetSubMesh( S ); + SMESH_subMesh* subMesh = smIt->next(); + const TopoDS_Shape& S = subMesh->_subShape; + if ( S.ShapeType() != this->_subShape.ShapeType() ) + continue; + theSubs.push_back( subMesh ); if ( subMesh == this ) { aBuilder.Add( aCompound, S ); } else if ( subMesh->GetComputeState() == READY_TO_COMPUTE ) { - SMESH_Algo* anAlgo = theGen->GetAlgo( *_father, S ); - if (strcmp( anAlgo->GetName(), theAlgo->GetName()) == 0 && // same algo - anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp) // same hyps + SMESH_Algo* anAlgo = subMesh->GetAlgo(); + if (( anAlgo->IsSameName( *theAlgo )) && // same algo + ( anAlgo->GetUsedHypothesis( *_father, S, skipAuxHyps ) == aUsedHyp )) // same hyps + { aBuilder.Add( aCompound, S ); - if ( !subMesh->SubMeshesComputed() ) - theSubComputed = false; + if ( !subMesh->SubMeshesComputed() ) + theSubComputed = false; + } } } @@ -1850,14 +2102,14 @@ TopoDS_Shape SMESH_subMesh::GetCollection(SMESH_Gen * theGen, } //======================================================================= -//function : GetSimilarAttached +//function : getSimilarAttached //purpose : return a hypothesis attached to theShape. // If theHyp is provided, similar but not same hypotheses // is returned; else only applicable ones having theHypType // is returned //======================================================================= -const SMESH_Hypothesis* SMESH_subMesh::GetSimilarAttached(const TopoDS_Shape& theShape, +const SMESH_Hypothesis* SMESH_subMesh::getSimilarAttached(const TopoDS_Shape& theShape, const SMESH_Hypothesis * theHyp, const int theHypType) { @@ -1890,7 +2142,7 @@ SMESH_Hypothesis::Hypothesis_Status MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis"); // is there local hypothesis on me? - if ( GetSimilarAttached( _subShape, 0, theHypType ) ) + if ( getSimilarAttached( _subShape, 0, theHypType ) ) return SMESH_Hypothesis::HYP_OK; @@ -1900,7 +2152,7 @@ SMESH_Hypothesis::Hypothesis_Status for (; it.More(); it.Next()) { const TopoDS_Shape& ancestor = it.Value(); - const SMESH_Hypothesis* hyp = GetSimilarAttached( ancestor, 0, theHypType ); + const SMESH_Hypothesis* hyp = getSimilarAttached( ancestor, 0, theHypType ); if ( hyp ) { if ( aPrevWithHyp.IsNull() || aPrevWithHyp.IsSame( ancestor )) @@ -1917,14 +2169,26 @@ SMESH_Hypothesis::Hypothesis_Status return SMESH_Hypothesis::HYP_OK; } +//================================================================================ +/*! + * \brief Constructor of OwnListenerData + */ +//================================================================================ + +SMESH_subMesh::OwnListenerData::OwnListenerData( SMESH_subMesh* sm, EventListener* el): + mySubMesh( sm ), + myMeshID( sm ? sm->GetFather()->GetId() : -1 ), + mySubMeshID( sm ? sm->GetId() : -1 ), + myListener( el ) +{ +} + //================================================================================ /*! * \brief Sets an event listener and its data to a submesh * \param listener - the listener to store * \param data - the listener data to store * \param where - the submesh to store the listener and it's data - * \param deleteListener - if true then the listener will be deleted as - * it is removed from where submesh * * It remembers the submesh where it puts the listener in order to delete * them when HYP_OK algo_state is lost @@ -1937,8 +2201,8 @@ void SMESH_subMesh::SetEventListener(EventListener* listener, SMESH_subMesh* where) { if ( listener && where ) { - where->SetEventListener( listener, data ); - myOwnListeners.push_back( make_pair( where, listener )); + where->setEventListener( listener, data ); + _ownListeners.push_back( OwnListenerData( where, listener )); } } @@ -1952,34 +2216,95 @@ void SMESH_subMesh::SetEventListener(EventListener* listener, */ //================================================================================ -void SMESH_subMesh::SetEventListener(EventListener* listener, EventListenerData* data) +void SMESH_subMesh::setEventListener(EventListener* listener, + EventListenerData* data) { map< EventListener*, EventListenerData* >::iterator l_d = - myEventListeners.find( listener ); - if ( l_d != myEventListeners.end() ) { + _eventListeners.find( listener ); + if ( l_d != _eventListeners.end() ) { EventListenerData* curData = l_d->second; if ( curData && curData != data && curData->IsDeletable() ) delete curData; l_d->second = data; } - else - myEventListeners.insert( make_pair( listener, data )); + else + { + for ( l_d = _eventListeners.begin(); l_d != _eventListeners.end(); ++l_d ) + if ( listener->GetName() == l_d->first->GetName() ) + { + EventListenerData* curData = l_d->second; + if ( curData && curData != data && curData->IsDeletable() ) + delete curData; + if ( l_d->first != listener && l_d->first->IsDeletable() ) + delete l_d->first; + _eventListeners.erase( l_d ); + break; + } + _eventListeners.insert( make_pair( listener, data )); + } } //================================================================================ /*! * \brief Return an event listener data * \param listener - the listener whose data is + * \param myOwn - if \c true, returns a listener set by this sub-mesh, + * else returns a listener listening to events of this sub-mesh * \retval EventListenerData* - found data, maybe NULL */ //================================================================================ -EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener) const +EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener, + const bool myOwn) const { - map< EventListener*, EventListenerData* >::const_iterator l_d = - myEventListeners.find( listener ); - if ( l_d != myEventListeners.end() ) - return l_d->second; + if ( myOwn ) + { + list< OwnListenerData >::const_iterator d; + for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d ) + { + if ( d->myListener == listener && _father->MeshExists( d->myMeshID )) + return d->mySubMesh->GetEventListenerData( listener, !myOwn ); + } + } + else + { + map< EventListener*, EventListenerData* >::const_iterator l_d = + _eventListeners.find( listener ); + if ( l_d != _eventListeners.end() ) + return l_d->second; + } + return 0; +} + +//================================================================================ +/*! + * \brief Return an event listener data + * \param listenerName - the listener name + * \param myOwn - if \c true, returns a listener set by this sub-mesh, + * else returns a listener listening to events of this sub-mesh + * \retval EventListenerData* - found data, maybe NULL + */ +//================================================================================ + +EventListenerData* SMESH_subMesh::GetEventListenerData(const string& listenerName, + const bool myOwn) const +{ + if ( myOwn ) + { + list< OwnListenerData >::const_iterator d; + for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d ) + { + if ( _father->MeshExists( d->myMeshID ) && listenerName == d->myListener->GetName()) + return d->mySubMesh->GetEventListenerData( listenerName, !myOwn ); + } + } + else + { + map< EventListener*, EventListenerData* >::const_iterator l_d = _eventListeners.begin(); + for ( ; l_d != _eventListeners.end(); ++l_d ) + if ( listenerName == l_d->first->GetName() ) + return l_d->second; + } return 0; } @@ -1988,19 +2313,32 @@ EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener) * \brief Notify stored event listeners on the occured event * \param event - algo_event or compute_event itself * \param eventType - algo_event or compute_event - * \param subMesh - the submesh where the event occures - * \param data - listener data stored in the subMesh * \param hyp - hypothesis, if eventType is algo_event */ //================================================================================ -void SMESH_subMesh::NotifyListenersOnEvent( const int event, +void SMESH_subMesh::notifyListenersOnEvent( const int event, const event_type eventType, SMESH_Hypothesis* hyp) { - map< EventListener*, EventListenerData* >::iterator l_d = myEventListeners.begin(); - for ( ; l_d != myEventListeners.end(); ++l_d ) - l_d->first->ProcessEvent( event, eventType, this, l_d->second, hyp ); + list< pair< EventListener*, EventListenerData* > > eventListeners( _eventListeners.begin(), + _eventListeners.end()); + list< pair< EventListener*, EventListenerData* > >::iterator l_d = eventListeners.begin(); + for ( ; l_d != eventListeners.end(); ++l_d ) + { + std::pair< EventListener*, EventListenerData* > li_da = *l_d; + if ( !_eventListeners.count( li_da.first )) continue; + + if ( li_da.first->myBusySM.insert( this ).second ) + { + const bool isDeletable = li_da.first->IsDeletable(); + + li_da.first->ProcessEvent( event, eventType, this, li_da.second, hyp ); + + if ( !isDeletable || _eventListeners.count( li_da.first )) + li_da.first->myBusySM.erase( this ); // a listener is hopefully not dead + } + } } //================================================================================ @@ -2013,11 +2351,20 @@ void SMESH_subMesh::NotifyListenersOnEvent( const int event, void SMESH_subMesh::DeleteEventListener(EventListener* listener) { map< EventListener*, EventListenerData* >::iterator l_d = - myEventListeners.find( listener ); - if ( l_d != myEventListeners.end() ) { - if ( l_d->first && l_d->first->IsDeletable() ) delete l_d->first; - if ( l_d->second && l_d->second->IsDeletable() ) delete l_d->second; - myEventListeners.erase( l_d ); + _eventListeners.find( listener ); + if ( l_d != _eventListeners.end() && l_d->first ) + { + if ( l_d->second && l_d->second->IsDeletable() ) + { + delete l_d->second; + } + l_d->first->myBusySM.erase( this ); + if ( l_d->first->IsDeletable() ) + { + l_d->first->BeforeDelete( this, l_d->second ); + delete l_d->first; + } + _eventListeners.erase( l_d ); } } @@ -2027,12 +2374,41 @@ void SMESH_subMesh::DeleteEventListener(EventListener* listener) */ //================================================================================ -void SMESH_subMesh::DeleteOwnListeners() +void SMESH_subMesh::deleteOwnListeners() +{ + list< OwnListenerData >::iterator d; + for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d ) + { + SMESH_Mesh* mesh = _father->FindMesh( d->myMeshID ); + if ( !mesh || !mesh->GetSubMeshContaining( d->mySubMeshID )) + continue; + d->mySubMesh->DeleteEventListener( d->myListener ); + } + _ownListeners.clear(); +} + +//======================================================================= +//function : loadDependentMeshes +//purpose : loads dependent meshes on SUBMESH_LOADED event +//======================================================================= + +void SMESH_subMesh::loadDependentMeshes() { - list< pair< SMESH_subMesh*, EventListener* > >::iterator sm_l; - for ( sm_l = myOwnListeners.begin(); sm_l != myOwnListeners.end(); ++sm_l) - sm_l->first->DeleteEventListener( sm_l->second ); - myOwnListeners.clear(); + list< OwnListenerData >::iterator d; + for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d ) + if ( _father != d->mySubMesh->_father ) + d->mySubMesh->_father->Load(); + + // map< EventListener*, EventListenerData* >::iterator l_d = _eventListeners.begin(); + // for ( ; l_d != _eventListeners.end(); ++l_d ) + // if ( l_d->second ) + // { + // const list& smList = l_d->second->mySubMeshes; + // list::const_iterator sm = smList.begin(); + // for ( ; sm != smList.end(); ++sm ) + // if ( _father != (*sm)->_father ) + // (*sm)->_father->Load(); + // } } //================================================================================ @@ -2068,6 +2444,7 @@ void SMESH_subMeshEventListener::ProcessEvent(const int event, (*smIt)->ComputeStateEngine( event ); break; case SMESH_subMesh::COMPUTE: + case SMESH_subMesh::COMPUTE_SUBMESH: if ( subMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK ) for ( ; smIt != smEnd; ++ smIt) (*smIt)->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED ); @@ -2125,21 +2502,88 @@ namespace { //================================================================================ SMESH_subMeshIteratorPtr SMESH_subMesh::getDependsOnIterator(const bool includeSelf, - const bool reverse) + const bool reverse) const { + SMESH_subMesh *me = (SMESH_subMesh*) this; SMESH_subMesh *prepend=0, *append=0; if ( includeSelf ) { - if ( reverse ) prepend = this; - else append = this; + if ( reverse ) prepend = me; + else append = me; } typedef map < int, SMESH_subMesh * > TMap; if ( reverse ) { return SMESH_subMeshIteratorPtr - ( new _Iterator( new SMDS_mapReverseIterator( DependsOn() ), prepend, append )); + ( new _Iterator( new SMDS_mapReverseIterator( me->DependsOn() ), prepend, append )); } { return SMESH_subMeshIteratorPtr - ( new _Iterator( new SMDS_mapIterator( DependsOn() ), prepend, append )); + ( new _Iterator( new SMDS_mapIterator( me->DependsOn() ), prepend, append )); } } + +//================================================================================ +/*! + * \brief Returns ancestor sub-meshes. Finds them if not yet found. + */ +//================================================================================ + +const std::vector< SMESH_subMesh * > & SMESH_subMesh::GetAncestors() const +{ + if ( _ancestors.empty() && + !_subShape.IsSame( _father->GetShapeToMesh() )) + { + const TopTools_ListOfShape& ancShapes = _father->GetAncestors( _subShape ); + + SMESH_subMesh* me = const_cast< SMESH_subMesh* >( this ); + me->_ancestors.reserve( ancShapes.Extent() ); + + TopTools_MapOfShape map; + + for ( TopTools_ListIteratorOfListOfShape it( ancShapes ); it.More(); it.Next() ) + if ( SMESH_subMesh* sm = _father->GetSubMeshContaining( it.Value() )) + if ( map.Add( it.Value() )) + me->_ancestors.push_back( sm ); + } + + return _ancestors; +} + +//================================================================================ +/*! + * \brief Clears the vector of ancestor sub-meshes + */ +//================================================================================ + +void SMESH_subMesh::ClearAncestors() +{ + _ancestors.clear(); +} + +//================================================================================ +/*! + * \brief Find common submeshes (based on shared sub-shapes with other + * \param theOther submesh to check + * \param theSetOfCommon set of common submesh + */ +//================================================================================ + +bool SMESH_subMesh::FindIntersection(const SMESH_subMesh* theOther, + std::set& theSetOfCommon ) const +{ + int oldNb = theSetOfCommon.size(); + + // check main submeshes + const map ::const_iterator otherEnd = theOther->_mapDepend.end(); + if ( theOther->_mapDepend.find(this->GetId()) != otherEnd ) + theSetOfCommon.insert( this ); + if ( _mapDepend.find(theOther->GetId()) != _mapDepend.end() ) + theSetOfCommon.insert( theOther ); + + // check common submeshes + map ::const_iterator mapIt = _mapDepend.begin(); + for( ; mapIt != _mapDepend.end(); mapIt++ ) + if ( theOther->_mapDepend.find((*mapIt).first) != otherEnd ) + theSetOfCommon.insert( (*mapIt).second ); + return oldNb < theSetOfCommon.size(); +} diff --git a/src/3rdParty/salomesmesh/src/SMESH/Utils_ExceptHandlers.cpp b/src/3rdParty/salomesmesh/src/SMESH/Utils_ExceptHandlers.cpp new file mode 100644 index 000000000000..97a9d9272891 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/Utils_ExceptHandlers.cpp @@ -0,0 +1,39 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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: Utils_ExceptHandler.cxx +// Created: Mon Mar 15 10:23:41 2004 +// Author: Oksana TCHEBANOVA +// +// +#include "Utils_ExceptHandlers.hxx" +#include "Utils_SALOME_Exception.hxx" + +void SalomeException () +{ + throw SALOME_Exception("Salome Exception"); +} + +void SALOME_SalomeException() { +// THROW_SALOME_CORBA_EXCEPTION("INTERNAL ERROR", SALOME::INTERNAL_ERROR); +} + diff --git a/src/3rdParty/salomesmesh/src/SMESH/libmesh.c b/src/3rdParty/salomesmesh/src/SMESH/libmesh.c new file mode 100644 index 000000000000..288e7a8ea439 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESH/libmesh.c @@ -0,0 +1,1346 @@ + + +/*----------------------------------------------------------*/ +/* */ +/* LIBMESH V 5.46 */ +/* */ +/*----------------------------------------------------------*/ +/* */ +/* Description: handle .meshb file format I/O */ +/* Author: Loic MARECHAL */ +/* Creation date: feb 16 2007 */ +/* Last modification: apr 03 2012 */ +/* */ +/*----------------------------------------------------------*/ + + +/*----------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include +#include "libmesh5.h" + + +/*----------------------------------------------------------*/ +/* Defines */ +/*----------------------------------------------------------*/ + +#define Asc 1 +#define Bin 2 +#define MshFil 4 +#define SolFil 8 +#define MaxMsh 100 +#define InfKwd 1 +#define RegKwd 2 +#define SolKwd 3 +#define WrdSiz 4 +#define BufSiz 10000 + + +/*----------------------------------------------------------*/ +/* Structures */ +/*----------------------------------------------------------*/ + +typedef struct +{ + int typ, SolSiz, NmbWrd, NmbLin, NmbTyp, TypTab[ GmfMaxTyp ]; + long pos; + char fmt[ GmfMaxTyp*9 ]; +}KwdSct; + +typedef struct +{ + int dim, ver, mod, typ, cod, pos; + long NexKwdPos, siz; + KwdSct KwdTab[ GmfMaxKwd + 1 ]; + FILE *hdl; + int *IntBuf; + float *FltBuf; + unsigned char *buf; + char FilNam[ GmfStrSiz ]; + double DblBuf[1000/8]; + unsigned char blk[ BufSiz + 1000 ]; +}GmfMshSct; + + +/*----------------------------------------------------------*/ +/* Global variables */ +/*----------------------------------------------------------*/ + +static int GmfIniFlg=0; +static GmfMshSct *GmfMshTab[ MaxMsh + 1 ]; +static const char *GmfKwdFmt[ GmfMaxKwd + 1 ][4] = +{ {"Reserved", "", "", ""}, + {"MeshVersionFormatted", "", "", "i"}, + {"Reserved", "", "", ""}, + {"Dimension", "", "", "i"}, + {"Vertices", "Vertex", "i", "dri"}, + {"Edges", "Edge", "i", "iii"}, + {"Triangles", "Triangle", "i", "iiii"}, + {"Quadrilaterals", "Quadrilateral", "i", "iiiii"}, + {"Tetrahedra", "Tetrahedron", "i", "iiiii"}, + {"Prisms", "Prism", "i", "iiiiiii"}, + {"Hexahedra", "Hexahedron", "i", "iiiiiiiii"}, + {"IterationsAll", "IterationAll","","i"}, + {"TimesAll", "TimeAll","","r"}, + {"Corners", "Corner", "i", "i"}, + {"Ridges", "Ridge", "i", "i"}, + {"RequiredVertices", "RequiredVertex", "i", "i"}, + {"RequiredEdges", "RequiredEdge", "i", "i"}, + {"RequiredTriangles", "RequiredTriangle", "i", "i"}, + {"RequiredQuadrilaterals", "RequiredQuadrilateral", "i", "i"}, + {"TangentAtEdgeVertices", "TangentAtEdgeVertex", "i", "iii"}, + {"NormalAtVertices", "NormalAtVertex", "i", "ii"}, + {"NormalAtTriangleVertices", "NormalAtTriangleVertex", "i", "iii"}, + {"NormalAtQuadrilateralVertices", "NormalAtQuadrilateralVertex", "i", "iiii"}, + {"AngleOfCornerBound", "", "", "r"}, + {"TrianglesP2", "TriangleP2", "i", "iiiiiii"}, + {"EdgesP2", "EdgeP2", "i", "iiii"}, + {"SolAtPyramids", "SolAtPyramid", "i", "sr"}, + {"QuadrilateralsQ2", "QuadrilateralQ2", "i", "iiiiiiiiii"}, + {"ISolAtPyramids", "ISolAtPyramid", "i", "iiiii"}, + {"SubDomainFromGeom", "SubDomainFromGeom", "i", "iiii"}, + {"TetrahedraP2", "TetrahedronP2", "i", "iiiiiiiiiii"}, + {"Fault_NearTri", "Fault_NearTri", "i", "i"}, + {"Fault_Inter", "Fault_Inter", "i", "i"}, + {"HexahedraQ2", "HexahedronQ2", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiii"}, + {"ExtraVerticesAtEdges", "ExtraVerticesAtEdge", "i", "in"}, + {"ExtraVerticesAtTriangles", "ExtraVerticesAtTriangle", "i", "in"}, + {"ExtraVerticesAtQuadrilaterals", "ExtraVerticesAtQuadrilateral", "i", "in"}, + {"ExtraVerticesAtTetrahedra", "ExtraVerticesAtTetrahedron", "i", "in"}, + {"ExtraVerticesAtPrisms", "ExtraVerticesAtPrism", "i", "in"}, + {"ExtraVerticesAtHexahedra", "ExtraVerticesAtHexahedron", "i", "in"}, + {"VerticesOnGeometricVertices", "VertexOnGeometricVertex", "i", "iir"}, + {"VerticesOnGeometricEdges", "VertexOnGeometricEdge", "i", "iirr"}, + {"VerticesOnGeometricTriangles", "VertexOnGeometricTriangle", "i", "iirrr"}, + {"VerticesOnGeometricQuadrilaterals", "VertexOnGeometricQuadrilateral", "i", "iirrr"}, + {"EdgesOnGeometricEdges", "EdgeOnGeometricEdge", "i", "iir"}, + {"Fault_FreeEdge", "Fault_FreeEdge", "i", "i"}, + {"Polyhedra", "Polyhedron", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"}, + {"Polygons", "Polygon", "", "iiiiiiiii"}, + {"Fault_Overlap", "Fault_Overlap", "i", "i"}, + {"Pyramids", "Pyramid", "i", "iiiiii"}, + {"BoundingBox", "", "", "drdr"}, + {"Body","i", "drdrdrdr"}, + {"PrivateTable", "PrivateTable", "i", "i"}, + {"Fault_BadShape", "Fault_BadShape", "i", "i"}, + {"End", "", "", ""}, + {"TrianglesOnGeometricTriangles", "TriangleOnGeometricTriangle", "i", "iir"}, + {"TrianglesOnGeometricQuadrilaterals", "TriangleOnGeometricQuadrilateral", "i", "iir"}, + {"QuadrilateralsOnGeometricTriangles", "QuadrilateralOnGeometricTriangle", "i", "iir"}, + {"QuadrilateralsOnGeometricQuadrilaterals", "QuadrilateralOnGeometricQuadrilateral", "i", "iir"}, + {"Tangents", "Tangent", "i", "dr"}, + {"Normals", "Normal", "i", "dr"}, + {"TangentAtVertices", "TangentAtVertex", "i", "ii"}, + {"SolAtVertices", "SolAtVertex", "i", "sr"}, + {"SolAtEdges", "SolAtEdge", "i", "sr"}, + {"SolAtTriangles", "SolAtTriangle", "i", "sr"}, + {"SolAtQuadrilaterals", "SolAtQuadrilateral", "i", "sr"}, + {"SolAtTetrahedra", "SolAtTetrahedron", "i", "sr"}, + {"SolAtPrisms", "SolAtPrism", "i", "sr"}, + {"SolAtHexahedra", "SolAtHexahedron", "i", "sr"}, + {"DSolAtVertices", "DSolAtVertex", "i", "sr"}, + {"ISolAtVertices", "ISolAtVertex", "i", "i"}, + {"ISolAtEdges", "ISolAtEdge", "i", "ii"}, + {"ISolAtTriangles", "ISolAtTriangle", "i", "iii"}, + {"ISolAtQuadrilaterals", "ISolAtQuadrilateral", "i", "iiii"}, + {"ISolAtTetrahedra", "ISolAtTetrahedron", "i", "iiii"}, + {"ISolAtPrisms", "ISolAtPrism", "i", "iiiiii"}, + {"ISolAtHexahedra", "ISolAtHexahedron", "i", "iiiiiiii"}, + {"Iterations", "","","i"}, + {"Time", "","","r"}, + {"Fault_SmallTri", "Fault_SmallTri","i","i"}, + {"CoarseHexahedra", "CoarseHexahedron", "i", "i"} + }; + + +/*----------------------------------------------------------*/ +/* Prototypes of local procedures */ +/*----------------------------------------------------------*/ + +static void ScaWrd(GmfMshSct *, unsigned char *); +static void ScaDblWrd(GmfMshSct *, unsigned char *); +static void ScaBlk(GmfMshSct *, unsigned char *, int); +static long GetPos(GmfMshSct *); +static void RecWrd(GmfMshSct *, unsigned char *); +static void RecDblWrd(GmfMshSct *, unsigned char *); +static void RecBlk(GmfMshSct *, unsigned char *, int); +static void SetPos(GmfMshSct *, long); +static int ScaKwdTab(GmfMshSct *); +static void ExpFmt(GmfMshSct *, int); +static void ScaKwdHdr(GmfMshSct *, int); + + +/*----------------------------------------------------------*/ +/* Open a mesh file in read or write mod */ +/*----------------------------------------------------------*/ + +int GmfOpenMesh(const char *FilNam, int mod, ...) +{ + int i, KwdCod, res, *PtrVer, *PtrDim, MshIdx=0; + char str[ GmfStrSiz ]; + va_list VarArg; + GmfMshSct *msh; + char *ptr; + int k; + + if(!GmfIniFlg) + { + for(i=0;i<=MaxMsh;i++) + GmfMshTab[i] = NULL; + + GmfIniFlg = 1; + } + + /*---------------------*/ + /* MESH STRUCTURE INIT */ + /*---------------------*/ + + for(i=1;i<=MaxMsh;i++) + if(!GmfMshTab[i]) + { + MshIdx = i; + break; + } + + if( !MshIdx || !(msh = (GmfMshSct *)calloc(1, sizeof(GmfMshSct))) ) + return(0); + + /* Copy the FilNam into the structure */ + + if(strlen(FilNam) + 7 >= GmfStrSiz) + { + free (msh); + return(0); + } + + strcpy(msh->FilNam, FilNam); + + /* Store the opening mod (read or write) and guess the filetype (binary or ascii) depending on the extension */ + + msh->mod = mod; + msh->buf = (unsigned char *)msh->DblBuf; + msh->FltBuf = (float *)msh->DblBuf; + msh->IntBuf = (int *)msh->DblBuf; + + k = strlen(msh->FilNam) - 6; + if(k < 0) + k = 0; + ptr = msh->FilNam+k; + if(strstr(ptr, ".meshb")) + msh->typ |= (Bin | MshFil); + else if(strstr(ptr, ".mesh")) + msh->typ |= (Asc | MshFil); + else if(strstr(ptr, ".solb")) + msh->typ |= (Bin | SolFil); + else if(strstr(ptr, ".sol")) + msh->typ |= (Asc | SolFil); + else { + free (msh); + return(0); + } + + /* Open the file in the required mod and initialyse the mesh structure */ + + if(msh->mod == GmfRead) + { + + /*-----------------------*/ + /* OPEN FILE FOR READING */ + /*-----------------------*/ + + va_start(VarArg, mod); + PtrVer = va_arg(VarArg, int *); + PtrDim = va_arg(VarArg, int *); + va_end(VarArg); + + /* Create the name string and open the file */ + + if(!(msh->hdl = fopen(msh->FilNam, "rb"))) + { + free (msh); + return(0); + } + + /* Read the endian coding tag, the mesh version and the mesh dimension (mandatory kwd) */ + + if(msh->typ & Bin) + { + fread((unsigned char *)&msh->cod, WrdSiz, 1, msh->hdl); + + if( (msh->cod != 1) && (msh->cod != 16777216) ) + { + free (msh); + return(0); + } + + ScaWrd(msh, (unsigned char *)&msh->ver); + + if( (msh->ver < 1) || (msh->ver > 3) ) + { + free (msh); + return(0); + } + + if( (msh->ver == 3) && (sizeof(long) == 4) ) + { + free (msh); + return(0); + } + + ScaWrd(msh, (unsigned char *)&KwdCod); + + if(KwdCod != GmfDimension) + { + free (msh); + return(0); + } + + GetPos(msh); + ScaWrd(msh, (unsigned char *)&msh->dim); + } + else + { + do + { + res = fscanf(msh->hdl, "%s", str); + }while( (res != EOF) && strcmp(str, "MeshVersionFormatted") ); + + if(res == EOF) + { + free (msh); + return(0); + } + + fscanf(msh->hdl, "%d", &msh->ver); + + if( (msh->ver < 1) || (msh->ver > 3) ) + { + free (msh); + return(0); + } + + do + { + res = fscanf(msh->hdl, "%s", str); + }while( (res != EOF) && strcmp(str, "Dimension") ); + + if(res == EOF) + { + free (msh); + return(0); + } + + fscanf(msh->hdl, "%d", &msh->dim); + } + + if( (msh->dim != 2) && (msh->dim != 3) ) + { + free (msh); + return(0); + } + + (*PtrVer) = msh->ver; + (*PtrDim) = msh->dim; + + /*------------*/ + /* KW READING */ + /*------------*/ + + /* Read the list of kw present in the file */ + + if(!ScaKwdTab(msh)) + { + free (msh); + return(0); + } + + GmfMshTab[ MshIdx ] = msh; + + return(MshIdx); + } + else if(msh->mod == GmfWrite) + { + + /*-----------------------*/ + /* OPEN FILE FOR WRITING */ + /*-----------------------*/ + + msh->cod = 1; + + /* Check if the user provided a valid version number and dimension */ + + va_start(VarArg, mod); + msh->ver = va_arg(VarArg, int); + msh->dim = va_arg(VarArg, int); + va_end(VarArg); + + if( (msh->ver < 1) || (msh->ver > 3) ) + { + free (msh); + return(0); + } + + if( (msh->ver == 3) && (sizeof(long) == 4) ) + { + free (msh); + return(0); + } + + if( (msh->dim != 2) && (msh->dim != 3) ) + { + free (msh); + return(0); + } + + /* Create the mesh file */ + + if(!(msh->hdl = fopen(msh->FilNam, "wb"))) + { + free (msh); + return(0); + } + + GmfMshTab[ MshIdx ] = msh; + + + /*------------*/ + /* KW WRITING */ + /*------------*/ + + /* Write the mesh version and dimension */ + + if(msh->typ & Asc) + { + fprintf(msh->hdl, "%s %d\n\n", GmfKwdFmt[ GmfVersionFormatted ][0], msh->ver); + fprintf(msh->hdl, "%s %d\n", GmfKwdFmt[ GmfDimension ][0], msh->dim); + } + else + { + RecWrd(msh, (unsigned char *)&msh->cod); + RecWrd(msh, (unsigned char *)&msh->ver); + GmfSetKwd(MshIdx, GmfDimension, 0); + RecWrd(msh, (unsigned char *)&msh->dim); + } + + return(MshIdx); + } + else + { + free (msh); + return(0); + } +} + + +/*----------------------------------------------------------*/ +/* Close a meshfile in the right way */ +/*----------------------------------------------------------*/ + +int GmfCloseMesh(int MshIdx) +{ + int res = 1; + GmfMshSct *msh; + + if( (MshIdx < 1) || (MshIdx > MaxMsh) ) + return(0); + + msh = GmfMshTab[ MshIdx ]; + RecBlk(msh, msh->buf, 0); + + /* In write down the "End" kw in write mode */ + + if(msh->mod == GmfWrite){ + if(msh->typ & Asc) + fprintf(msh->hdl, "\n%s\n", GmfKwdFmt[ GmfEnd ][0]); + else + GmfSetKwd(MshIdx, GmfEnd, 0); + } + /* Close the file and free the mesh structure */ + + if(fclose(msh->hdl)) + res = 0; + + free(msh); + GmfMshTab[ MshIdx ] = NULL; + + return(res); +} + + +/*----------------------------------------------------------*/ +/* Read the number of lines and set the position to this kwd*/ +/*----------------------------------------------------------*/ + +int GmfStatKwd(int MshIdx, int KwdCod, ...) +{ + int i, *PtrNmbTyp, *PtrSolSiz, *TypTab; + GmfMshSct *msh; + KwdSct *kwd; + va_list VarArg; + + if( (MshIdx < 1) || (MshIdx > MaxMsh) ) + return(0); + + msh = GmfMshTab[ MshIdx ]; + + if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) ) + return(0); + + kwd = &msh->KwdTab[ KwdCod ]; + + if(!kwd->NmbLin) + return(0); + + /* Read further arguments if this kw is a sol */ + + if(kwd->typ == SolKwd) + { + va_start(VarArg, KwdCod); + + PtrNmbTyp = va_arg(VarArg, int *); + *PtrNmbTyp = kwd->NmbTyp; + + PtrSolSiz = va_arg(VarArg, int *); + *PtrSolSiz = kwd->SolSiz; + + TypTab = va_arg(VarArg, int *); + + for(i=0;iNmbTyp;i++) + TypTab[i] = kwd->TypTab[i]; + + va_end(VarArg); + } + + return(kwd->NmbLin); +} + + +/*----------------------------------------------------------*/ +/* Set the current file position to a given kwd */ +/*----------------------------------------------------------*/ + +int GmfGotoKwd(int MshIdx, int KwdCod) +{ + GmfMshSct *msh; + KwdSct *kwd; + + if( (MshIdx < 1) || (MshIdx > MaxMsh) ) + return(0); + + msh = GmfMshTab[ MshIdx ]; + + if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) ) + return(0); + + kwd = &msh->KwdTab[ KwdCod ]; + + if(!kwd->NmbLin) + return(0); + + return(fseek(msh->hdl, kwd->pos, SEEK_SET)); +} + + +/*----------------------------------------------------------*/ +/* Write the kwd and set the number of lines */ +/*----------------------------------------------------------*/ + +int GmfSetKwd(int MshIdx, int KwdCod, ...) +{ + int i, NmbLin=0, *TypTab; + long CurPos; + va_list VarArg; + GmfMshSct *msh; + KwdSct *kwd; + + if( (MshIdx < 1) || (MshIdx > MaxMsh) ) + return(0); + + msh = GmfMshTab[ MshIdx ]; + RecBlk(msh, msh->buf, 0); + + if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) ) + return(0); + + kwd = &msh->KwdTab[ KwdCod ]; + + /* Read further arguments if this kw has a header */ + + if(strlen(GmfKwdFmt[ KwdCod ][2])) + { + va_start(VarArg, KwdCod); + NmbLin = va_arg(VarArg, int); + + if(!strcmp(GmfKwdFmt[ KwdCod ][3], "sr")) + { + kwd->NmbTyp = va_arg(VarArg, int); + TypTab = va_arg(VarArg, int *); + + for(i=0;iNmbTyp;i++) + kwd->TypTab[i] = TypTab[i]; + } + + va_end(VarArg); + } + + /* Setup the kwd info */ + + ExpFmt(msh, KwdCod); + + if(!kwd->typ) + return(0); + else if(kwd->typ == InfKwd) + kwd->NmbLin = 1; + else + kwd->NmbLin = NmbLin; + + /* Store the next kwd position in binary file */ + + if( (msh->typ & Bin) && msh->NexKwdPos ) + { + CurPos = ftell(msh->hdl); + fseek(msh->hdl, msh->NexKwdPos, SEEK_SET); + SetPos(msh, CurPos); + fseek(msh->hdl, CurPos, SEEK_SET); + } + + /* Write the header */ + + if(msh->typ & Asc) + { + fprintf(msh->hdl, "\n%s\n", GmfKwdFmt[ KwdCod ][0]); + + if(kwd->typ != InfKwd) + fprintf(msh->hdl, "%d\n", kwd->NmbLin); + + /* In case of solution field, write the extended header */ + + if(kwd->typ == SolKwd) + { + fprintf(msh->hdl, "%d ", kwd->NmbTyp); + + for(i=0;iNmbTyp;i++) + fprintf(msh->hdl, "%d ", kwd->TypTab[i]); + + fprintf(msh->hdl, "\n\n"); + } + } + else + { + RecWrd(msh, (unsigned char *)&KwdCod); + msh->NexKwdPos = ftell(msh->hdl); + SetPos(msh, 0); + + if(kwd->typ != InfKwd) + RecWrd(msh, (unsigned char *)&kwd->NmbLin); + + /* In case of solution field, write the extended header at once */ + + if(kwd->typ == SolKwd) + { + RecWrd(msh, (unsigned char *)&kwd->NmbTyp); + + for(i=0;iNmbTyp;i++) + RecWrd(msh, (unsigned char *)&kwd->TypTab[i]); + } + } + + /* Reset write buffer position */ + msh->pos = 0; + + /* Estimate the total file size and check whether it crosses the 2GB threshold */ + + msh->siz += kwd->NmbLin * kwd->NmbWrd * WrdSiz; + + if(msh->siz > 2E9) + return(0); + else + return(kwd->NmbLin); +} + + +/*----------------------------------------------------------*/ +/* Read a full line from the current kwd */ +/*----------------------------------------------------------*/ + +void GmfGetLin(int MshIdx, int KwdCod, ...) +{ + int i, j; + float *FltSolTab; + double *DblSolTab; + va_list VarArg; + GmfMshSct *msh = GmfMshTab[ MshIdx ]; + KwdSct *kwd = &msh->KwdTab[ KwdCod ]; + + /* Start decoding the arguments */ + + va_start(VarArg, KwdCod); + + if(kwd->typ != SolKwd) + { + int k, nb_repeat = 0; + + if(msh->ver == 1) + { + if(msh->typ & Asc) + { + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + fscanf(msh->hdl, "%f", va_arg(VarArg, float *)); + else if(kwd->fmt[i] == 'n') { + fscanf(msh->hdl, "%d", &nb_repeat); + *(va_arg(VarArg, int *)) = nb_repeat; + for(k=0;khdl, "%d", va_arg(VarArg, int *)); + } + else + fscanf(msh->hdl, "%d", va_arg(VarArg, int *)); + } + else + { + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + ScaWrd(msh, (unsigned char *)va_arg(VarArg, float *)); + else if(kwd->fmt[i] == 'n') { + ScaWrd(msh, (unsigned char *)&nb_repeat); + *(va_arg(VarArg, int *)) = nb_repeat; + for(k=0;ktyp & Asc) + { + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + fscanf(msh->hdl, "%lf", va_arg(VarArg, double *)); + else if(kwd->fmt[i] == 'n') { + fscanf(msh->hdl, "%d", &nb_repeat); + *(va_arg(VarArg, int *)) = nb_repeat; + for(k=0;khdl, "%d", va_arg(VarArg, int *)); + } + else + fscanf(msh->hdl, "%d", va_arg(VarArg, int *)); + } + else + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + ScaDblWrd(msh, (unsigned char *)va_arg(VarArg, double *)); + else if(kwd->fmt[i] == 'n') { + ScaWrd(msh, (unsigned char *)&nb_repeat); + *(va_arg(VarArg, int *)) = nb_repeat; + for(k=0;kver == 1) + { + FltSolTab = va_arg(VarArg, float *); + + if(msh->typ & Asc) + for(j=0;jSolSiz;j++) + fscanf(msh->hdl, "%f", &FltSolTab[j]); + else + ScaBlk(msh, (unsigned char *)FltSolTab, kwd->NmbWrd); + } + else + { + DblSolTab = va_arg(VarArg, double *); + + if(msh->typ & Asc) + for(j=0;jSolSiz;j++) + fscanf(msh->hdl, "%lf", &DblSolTab[j]); + else + for(j=0;jSolSiz;j++) + ScaDblWrd(msh, (unsigned char *)&DblSolTab[j]); + } + } + + va_end(VarArg); +} + + +/*----------------------------------------------------------*/ +/* Write a full line from the current kwd */ +/*----------------------------------------------------------*/ + +void GmfSetLin(int MshIdx, int KwdCod, ...) +{ + int i, j, pos, *IntBuf; + float *FltSolTab; + double *DblSolTab, *DblBuf; + va_list VarArg; + GmfMshSct *msh = GmfMshTab[ MshIdx ]; + KwdSct *kwd = &msh->KwdTab[ KwdCod ]; + + /* Start decoding the arguments */ + + va_start(VarArg, KwdCod); + + if(kwd->typ != SolKwd) + { + int k, nb_repeat = 0; + + if(msh->ver == 1) + { + if(msh->typ & Asc) + { + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + fprintf(msh->hdl, "%g ", (float)va_arg(VarArg, double)); + else if(kwd->fmt[i] == 'n') { + nb_repeat = va_arg(VarArg, int); + fprintf(msh->hdl, "%d ", nb_repeat); + for(k=0;khdl, "%d ", va_arg(VarArg, int)); + } + else + fprintf(msh->hdl, "%d ", va_arg(VarArg, int)); + } + else + { + int size_of_block = kwd->SolSiz; + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + msh->FltBuf[i] = va_arg(VarArg, double); + else if(kwd->fmt[i] == 'n') { + nb_repeat = va_arg(VarArg, int); + msh->FltBuf[i] = nb_repeat; + for(k=0;kIntBuf[i+1+k] = va_arg(VarArg, int); + size_of_block ++; + } + } + else + msh->IntBuf[i] = va_arg(VarArg, int); + + RecBlk(msh, msh->buf, size_of_block); + } + } + else + { + if(msh->typ & Asc) + { + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + fprintf(msh->hdl, "%.15lg ", va_arg(VarArg, double)); + else if(kwd->fmt[i] == 'n') { + nb_repeat = va_arg(VarArg, int); + fprintf(msh->hdl, "%d ", nb_repeat); + for(k=0;khdl, "%d ", va_arg(VarArg, int)); + } + else + fprintf(msh->hdl, "%d ", va_arg(VarArg, int)); + } + else + { + pos = 0; + + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + { + DblBuf = (double *)&msh->buf[ pos ]; + *DblBuf = va_arg(VarArg, double); + pos += 8; + } + else if(kwd->fmt[i] == 'n') + { + IntBuf = (int *)&msh->buf[ pos ]; + nb_repeat = va_arg(VarArg, int); + *IntBuf = nb_repeat; + pos += 4; + for(k=0;kbuf[ pos ]; + *IntBuf = va_arg(VarArg, int); + pos += 4; + } + } + else + { + IntBuf = (int *)&msh->buf[ pos ]; + *IntBuf = va_arg(VarArg, int); + pos += 4; + } + RecBlk(msh, msh->buf, pos/4); + } + } + } + else + { + if(msh->ver == 1) + { + FltSolTab = va_arg(VarArg, float *); + + if(msh->typ & Asc) + for(j=0;jSolSiz;j++) + fprintf(msh->hdl, "%g ", FltSolTab[j]); + else + RecBlk(msh, (unsigned char *)FltSolTab, kwd->NmbWrd); + } + else + { + DblSolTab = va_arg(VarArg, double *); + + if(msh->typ & Asc) + for(j=0;jSolSiz;j++) + fprintf(msh->hdl, "%.15lg ", DblSolTab[j]); + else + RecBlk(msh, (unsigned char *)DblSolTab, kwd->NmbWrd); + } + } + + va_end(VarArg); + + if(msh->typ & Asc) + fprintf(msh->hdl, "\n"); +} + + +/*----------------------------------------------------------*/ +/* Private procedure for transmesh : copy a whole line */ +/*----------------------------------------------------------*/ + +void GmfCpyLin(int InpIdx, int OutIdx, int KwdCod) +{ + double d; + float f; + int i, a; + GmfMshSct *InpMsh = GmfMshTab[ InpIdx ], *OutMsh = GmfMshTab[ OutIdx ]; + KwdSct *kwd = &InpMsh->KwdTab[ KwdCod ]; + + for(i=0;iSolSiz;i++) + { + if(kwd->fmt[i] == 'r') + { + if(InpMsh->ver == 1) + { + if(InpMsh->typ & Asc) + fscanf(InpMsh->hdl, "%f", &f); + else + ScaWrd(InpMsh, (unsigned char *)&f); + + d = f; + } + else + { + if(InpMsh->typ & Asc) + fscanf(InpMsh->hdl, "%lf", &d); + else + ScaDblWrd(InpMsh, (unsigned char *)&d); + + f = (float)d; + } + + if(OutMsh->ver == 1) + if(OutMsh->typ & Asc) + fprintf(OutMsh->hdl, "%g ", f); + else + RecWrd(OutMsh, (unsigned char *)&f); + else + if(OutMsh->typ & Asc) + fprintf(OutMsh->hdl, "%.15g ", d); + else + RecDblWrd(OutMsh, (unsigned char *)&d); + } + else if(kwd->fmt[i] == 'n') + { + int k, nb_repeat = 0; + + if(InpMsh->typ & Asc) + fscanf(InpMsh->hdl, "%d", &a); + else + ScaWrd(InpMsh, (unsigned char *)&a); + + nb_repeat = a; + + if(OutMsh->typ & Asc) + fprintf(OutMsh->hdl, "%d ", a); + else + RecWrd(OutMsh, (unsigned char *)&a); + + for(k=0;ktyp & Asc) + fscanf(InpMsh->hdl, "%d", &a); + else + ScaWrd(InpMsh, (unsigned char *)&a); + + if(OutMsh->typ & Asc) + fprintf(OutMsh->hdl, "%d ", a); + else + RecWrd(OutMsh, (unsigned char *)&a); + } + } + else + { + if(InpMsh->typ & Asc) + fscanf(InpMsh->hdl, "%d", &a); + else + ScaWrd(InpMsh, (unsigned char *)&a); + + if(OutMsh->typ & Asc) + fprintf(OutMsh->hdl, "%d ", a); + else + RecWrd(OutMsh, (unsigned char *)&a); + } + } + + if(OutMsh->typ & Asc) + fprintf(OutMsh->hdl, "\n"); +} + + +/*----------------------------------------------------------*/ +/* Find every kw present in a meshfile */ +/*----------------------------------------------------------*/ + +static int ScaKwdTab(GmfMshSct *msh) +{ + int KwdCod; + long NexPos, CurPos, EndPos; + char str[ GmfStrSiz ]; + + if(msh->typ & Asc) + { + /* Scan each string in the file until the end */ + + while(fscanf(msh->hdl, "%s", str) != EOF) + { + /* Fast test in order to reject quickly the numeric values */ + + if(isalpha(str[0])) + { + /* Search which kwd code this string is associated with, + then get its header and save the curent position in file (just before the data) */ + + for(KwdCod=1; KwdCod<= GmfMaxKwd; KwdCod++) + if(!strcmp(str, GmfKwdFmt[ KwdCod ][0])) + { + ScaKwdHdr(msh, KwdCod); + break; + } + } + else if(str[0] == '#') + while(fgetc(msh->hdl) != '\n'); + } + } + else + { + /* Get file size */ + + CurPos = ftell(msh->hdl); + fseek(msh->hdl, 0, SEEK_END); + EndPos = ftell(msh->hdl); + fseek(msh->hdl, CurPos, SEEK_SET); + + /* Jump through kwd positions in the file */ + + do + { + /* Get the kwd code and the next kwd position */ + + ScaWrd(msh, (unsigned char *)&KwdCod); + NexPos = GetPos(msh); + + if(NexPos > EndPos) + return(0); + + /* Check if this kwd belongs to this mesh version */ + + if( (KwdCod >= 1) && (KwdCod <= GmfMaxKwd) ) + ScaKwdHdr(msh, KwdCod); + + /* Go to the next kwd */ + + if(NexPos) + fseek(msh->hdl, NexPos, SEEK_SET); + }while(NexPos && (KwdCod != GmfEnd)); + } + + return(1); +} + + +/*----------------------------------------------------------*/ +/* Read and setup the keyword's header */ +/*----------------------------------------------------------*/ + +static void ScaKwdHdr(GmfMshSct *msh, int KwdCod) +{ + int i; + KwdSct *kwd = &msh->KwdTab[ KwdCod ]; + + if(!strcmp("i", GmfKwdFmt[ KwdCod ][2])) + { + if(msh->typ & Asc) + fscanf(msh->hdl, "%d", &kwd->NmbLin); + else + ScaWrd(msh, (unsigned char *)&kwd->NmbLin); + } + else + kwd->NmbLin = 1; + + if(!strcmp("sr", GmfKwdFmt[ KwdCod ][3])) + { + if(msh->typ & Asc) + { + fscanf(msh->hdl, "%d", &kwd->NmbTyp); + + for(i=0;iNmbTyp;i++) + fscanf(msh->hdl, "%d", &kwd->TypTab[i]); + } + else + { + ScaWrd(msh, (unsigned char *)&kwd->NmbTyp); + + for(i=0;iNmbTyp;i++) + ScaWrd(msh, (unsigned char *)&kwd->TypTab[i]); + } + } + + ExpFmt(msh, KwdCod); + kwd->pos = ftell(msh->hdl); +} + + +/*----------------------------------------------------------*/ +/* Expand the compacted format and compute the line size */ +/*----------------------------------------------------------*/ + +static void ExpFmt(GmfMshSct *msh, int KwdCod) +{ + int i, j, TmpSiz=0; + char chr; + const char *InpFmt = GmfKwdFmt[ KwdCod ][3]; + KwdSct *kwd = &msh->KwdTab[ KwdCod ]; + + /* Set the kwd's type */ + + if(!strlen(GmfKwdFmt[ KwdCod ][2])) + kwd->typ = InfKwd; + else if(!strcmp(InpFmt, "sr")) + kwd->typ = SolKwd; + else + kwd->typ = RegKwd; + + /* Get the solution-field's size */ + + if(kwd->typ == SolKwd) + for(i=0;iNmbTyp;i++) + switch(kwd->TypTab[i]) + { + case GmfSca : TmpSiz += 1; break; + case GmfVec : TmpSiz += msh->dim; break; + case GmfSymMat : TmpSiz += (msh->dim * (msh->dim+1)) / 2; break; + case GmfMat : TmpSiz += msh->dim * msh->dim; break; + } + + /* Scan each character from the format string */ + + i = kwd->SolSiz = kwd->NmbWrd = 0; + + while(i < strlen(InpFmt)) + { + chr = InpFmt[ i++ ]; + + if(chr == 'd') + { + chr = InpFmt[i++]; + + for(j=0;jdim;j++) + kwd->fmt[ kwd->SolSiz++ ] = chr; + } + else if(chr == 's') + { + chr = InpFmt[i++]; + + for(j=0;jfmt[ kwd->SolSiz++ ] = chr; + } + else + kwd->fmt[ kwd->SolSiz++ ] = chr; + } + + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'i') + kwd->NmbWrd++; + else if(msh->ver >= 2) + kwd->NmbWrd += 2; + else + kwd->NmbWrd++; +} + + +/*----------------------------------------------------------*/ +/* Read a four bytes word from a mesh file */ +/*----------------------------------------------------------*/ + +static void ScaWrd(GmfMshSct *msh, unsigned char *wrd) +{ + unsigned char swp; + + fread(wrd, WrdSiz, 1, msh->hdl); + + if(msh->cod == 1) + return; + + swp = wrd[3]; + wrd[3] = wrd[0]; + wrd[0] = swp; + + swp = wrd[2]; + wrd[2] = wrd[1]; + wrd[1] = swp; +} + + +/*----------------------------------------------------------*/ +/* Read an eight bytes word from a mesh file */ +/*----------------------------------------------------------*/ + +static void ScaDblWrd(GmfMshSct *msh, unsigned char *wrd) +{ + int i; + unsigned char swp; + + fread(wrd, WrdSiz, 2, msh->hdl); + + if(msh->cod == 1) + return; + + for(i=0;i<4;i++) + { + swp = wrd[7-i]; + wrd[7-i] = wrd[i]; + wrd[i] = swp; + } +} + + +/*----------------------------------------------------------*/ +/* Read ablock of four bytes word from a mesh file */ +/*----------------------------------------------------------*/ + +static void ScaBlk(GmfMshSct *msh, unsigned char *blk, int siz) +{ + int i, j; + unsigned char swp, *wrd; + + fread(blk, WrdSiz, siz, msh->hdl); + + if(msh->cod == 1) + return; + + for(i=0;iver >= 3) + ScaDblWrd(msh, (unsigned char*)&pos); + else + { + ScaWrd(msh, (unsigned char*)&IntVal); + pos = IntVal; + } + + return(pos); +} + + +/*----------------------------------------------------------*/ +/* Write a four bytes word to a mesh file */ +/*----------------------------------------------------------*/ + +static void RecWrd(GmfMshSct *msh, unsigned char *wrd) +{ + fwrite(wrd, WrdSiz, 1, msh->hdl); +} + + +/*----------------------------------------------------------*/ +/* Write an eight bytes word to a mesh file */ +/*----------------------------------------------------------*/ + +static void RecDblWrd(GmfMshSct *msh, unsigned char *wrd) +{ + fwrite(wrd, WrdSiz, 2, msh->hdl); +} + + +/*----------------------------------------------------------*/ +/* Write a block of four bytes word to a mesh file */ +/*----------------------------------------------------------*/ + +static void RecBlk(GmfMshSct *msh, unsigned char *blk, int siz) +{ + /* Copy this line-block into the main mesh buffer */ + + if(siz) + { + memcpy(&msh->blk[ msh->pos ], blk, siz * WrdSiz); + msh->pos += siz * WrdSiz; + } + + /* When the buffer is full or this procedure is called with a 0 size, flush the cache on disk */ + + if( (msh->pos > BufSiz) || (!siz && msh->pos) ) + { + fwrite(msh->blk, 1, msh->pos, msh->hdl); + msh->pos = 0; + } +} + + +/*----------------------------------------------------------*/ +/* Write a 4 or 8 bytes position in a mesh file */ +/*----------------------------------------------------------*/ + +static void SetPos(GmfMshSct *msh, long pos) +{ + int IntVal; + + if(msh->ver >= 3) + RecDblWrd(msh, (unsigned char*)&pos); + else + { + IntVal = pos; + RecWrd(msh, (unsigned char*)&IntVal); + } +} diff --git a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Command.cpp b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Command.cpp index 26647b68a8c0..05aece9a630d 100644 --- a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Command.cpp +++ b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Command.cpp @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESH_Command.cxx // Author : Yves FRICAUD, OCC // Module : SMESH -// $Header: // #include "SMESHDS_Command.hxx" @@ -54,16 +54,16 @@ SMESHDS_Command::~SMESHDS_Command() //======================================================================= void SMESHDS_Command::AddNode(int NewNodeID, double x, double y, double z) { - if (myType != SMESHDS_AddNode) - { - MESSAGE("SMESHDS_Command::AddNode : Bad Type"); - return; - } - myIntegers.push_back(NewNodeID); - myReals.push_back(x); - myReals.push_back(y); - myReals.push_back(z); - myNumber++; + if ( myType != SMESHDS_AddNode) + { + MESSAGE("SMESHDS_Command::AddNode : Bad Type"); + return; + } + myIntegers.push_back(NewNodeID); + myReals.push_back(x); + myReals.push_back(y); + myReals.push_back(z); + myNumber++; } //======================================================================= @@ -72,16 +72,32 @@ void SMESHDS_Command::AddNode(int NewNodeID, double x, double y, double z) //======================================================================= void SMESHDS_Command::MoveNode(int NodeID, double x, double y, double z) { - if (myType != SMESHDS_MoveNode) - { - MESSAGE("SMESHDS_Command::MoveNode : Bad Type"); - return; - } - myIntegers.push_back(NodeID); - myReals.push_back(x); - myReals.push_back(y); - myReals.push_back(z); - myNumber++; + if ( myType != SMESHDS_MoveNode) + { + MESSAGE("SMESHDS_Command::MoveNode : Bad Type"); + return; + } + myIntegers.push_back(NodeID); + myReals.push_back(x); + myReals.push_back(y); + myReals.push_back(z); + myNumber++; +} + +//======================================================================= +//function : +//purpose : +//======================================================================= +void SMESHDS_Command::Add0DElement(int New0DElementID, int idnode) +{ + if ( myType != SMESHDS_Add0DElement) + { + MESSAGE("SMESHDS_Command::Add0DElement : Bad Type"); + return; + } + myIntegers.push_back(New0DElementID); + myIntegers.push_back(idnode); + myNumber++; } //======================================================================= @@ -90,15 +106,15 @@ void SMESHDS_Command::MoveNode(int NodeID, double x, double y, double z) //======================================================================= void SMESHDS_Command::AddEdge(int NewEdgeID, int idnode1, int idnode2) { - if (myType != SMESHDS_AddEdge) - { - MESSAGE("SMESHDS_Command::AddEdge : Bad Type"); - return; - } - myIntegers.push_back(NewEdgeID); - myIntegers.push_back(idnode1); - myIntegers.push_back(idnode2); - myNumber++; + if ( myType != SMESHDS_AddEdge) + { + MESSAGE("SMESHDS_Command::AddEdge : Bad Type"); + return; + } + myIntegers.push_back(NewEdgeID); + myIntegers.push_back(idnode1); + myIntegers.push_back(idnode2); + myNumber++; } //======================================================================= @@ -106,18 +122,18 @@ void SMESHDS_Command::AddEdge(int NewEdgeID, int idnode1, int idnode2) //purpose : //======================================================================= void SMESHDS_Command::AddFace(int NewFaceID, - int idnode1, int idnode2, int idnode3) + int idnode1, int idnode2, int idnode3) { - if (myType != SMESHDS_AddTriangle) - { - MESSAGE("SMESHDS_Command::AddFace : Bad Type"); - return; - } - myIntegers.push_back(NewFaceID); - myIntegers.push_back(idnode1); - myIntegers.push_back(idnode2); - myIntegers.push_back(idnode3); - myNumber++; + if ( myType != SMESHDS_AddTriangle) + { + MESSAGE("SMESHDS_Command::AddFace : Bad Type"); + return; + } + myIntegers.push_back(NewFaceID); + myIntegers.push_back(idnode1); + myIntegers.push_back(idnode2); + myIntegers.push_back(idnode3); + myNumber++; } //======================================================================= @@ -125,19 +141,19 @@ void SMESHDS_Command::AddFace(int NewFaceID, //purpose : //======================================================================= void SMESHDS_Command::AddFace(int NewFaceID, - int idnode1, int idnode2, int idnode3, int idnode4) + int idnode1, int idnode2, int idnode3, int idnode4) { - if (myType != SMESHDS_AddQuadrangle) - { - MESSAGE("SMESHDS_Command::AddFace : Bad Type"); - return; - } - myIntegers.push_back(NewFaceID); - myIntegers.push_back(idnode1); - myIntegers.push_back(idnode2); - myIntegers.push_back(idnode3); - myIntegers.push_back(idnode4); - myNumber++; + if ( myType != SMESHDS_AddQuadrangle) + { + MESSAGE("SMESHDS_Command::AddFace : Bad Type"); + return; + } + myIntegers.push_back(NewFaceID); + myIntegers.push_back(idnode1); + myIntegers.push_back(idnode2); + myIntegers.push_back(idnode3); + myIntegers.push_back(idnode4); + myNumber++; } //======================================================================= @@ -145,19 +161,19 @@ void SMESHDS_Command::AddFace(int NewFaceID, //purpose : //======================================================================= void SMESHDS_Command::AddVolume(int NewVolID, - int idnode1, int idnode2, int idnode3, int idnode4) + int idnode1, int idnode2, int idnode3, int idnode4) { - if (myType != SMESHDS_AddTetrahedron) - { - MESSAGE("SMESHDS_Command::AddVolume : Bad Type"); - return; - } - myIntegers.push_back(NewVolID); - myIntegers.push_back(idnode1); - myIntegers.push_back(idnode2); - myIntegers.push_back(idnode3); - myIntegers.push_back(idnode4); - myNumber++; + if ( myType != SMESHDS_AddTetrahedron) + { + MESSAGE("SMESHDS_Command::AddVolume : Bad Type"); + return; + } + myIntegers.push_back(NewVolID); + myIntegers.push_back(idnode1); + myIntegers.push_back(idnode2); + myIntegers.push_back(idnode3); + myIntegers.push_back(idnode4); + myNumber++; } //======================================================================= @@ -165,20 +181,20 @@ void SMESHDS_Command::AddVolume(int NewVolID, //purpose : //======================================================================= void SMESHDS_Command::AddVolume(int NewVolID, - int idnode1, int idnode2, int idnode3, int idnode4, int idnode5) + int idnode1, int idnode2, int idnode3, int idnode4, int idnode5) { - if (myType != SMESHDS_AddPyramid) - { - MESSAGE("SMESHDS_Command::AddVolume : Bad Type"); - return; - } - myIntegers.push_back(NewVolID); - myIntegers.push_back(idnode1); - myIntegers.push_back(idnode2); - myIntegers.push_back(idnode3); - myIntegers.push_back(idnode4); - myIntegers.push_back(idnode5); - myNumber++; + if ( myType != SMESHDS_AddPyramid) + { + MESSAGE("SMESHDS_Command::AddVolume : Bad Type"); + return; + } + myIntegers.push_back(NewVolID); + myIntegers.push_back(idnode1); + myIntegers.push_back(idnode2); + myIntegers.push_back(idnode3); + myIntegers.push_back(idnode4); + myIntegers.push_back(idnode5); + myNumber++; } //======================================================================= @@ -186,22 +202,22 @@ void SMESHDS_Command::AddVolume(int NewVolID, //purpose : //======================================================================= void SMESHDS_Command::AddVolume(int NewVolID, - int idnode1, - int idnode2, int idnode3, int idnode4, int idnode5, int idnode6) + int idnode1, + int idnode2, int idnode3, int idnode4, int idnode5, int idnode6) { - if (myType != SMESHDS_AddPrism) - { - MESSAGE("SMESHDS_Command::AddVolume : Bad Type"); - return; - } - myIntegers.push_back(NewVolID); - myIntegers.push_back(idnode1); - myIntegers.push_back(idnode2); - myIntegers.push_back(idnode3); - myIntegers.push_back(idnode4); - myIntegers.push_back(idnode5); - myIntegers.push_back(idnode6); - myNumber++; + if ( myType != SMESHDS_AddPrism) + { + MESSAGE("SMESHDS_Command::AddVolume : Bad Type"); + return; + } + myIntegers.push_back(NewVolID); + myIntegers.push_back(idnode1); + myIntegers.push_back(idnode2); + myIntegers.push_back(idnode3); + myIntegers.push_back(idnode4); + myIntegers.push_back(idnode5); + myIntegers.push_back(idnode6); + myNumber++; } //======================================================================= @@ -209,36 +225,62 @@ void SMESHDS_Command::AddVolume(int NewVolID, //purpose : //======================================================================= void SMESHDS_Command::AddVolume(int NewVolID, - int idnode1, - int idnode2, - int idnode3, - int idnode4, int idnode5, int idnode6, int idnode7, int idnode8) -{ - if (myType != SMESHDS_AddHexahedron) - { - MESSAGE("SMESHDS_Command::AddVolume : Bad Type"); - return; - } - myIntegers.push_back(NewVolID); - myIntegers.push_back(idnode1); - myIntegers.push_back(idnode2); - myIntegers.push_back(idnode3); - myIntegers.push_back(idnode4); - myIntegers.push_back(idnode5); - myIntegers.push_back(idnode6); - myIntegers.push_back(idnode7); - myIntegers.push_back(idnode8); - myNumber++; + int idnode1, + int idnode2, + int idnode3, + int idnode4, int idnode5, int idnode6, int idnode7, int idnode8) +{ + if ( myType != SMESHDS_AddHexahedron) + { + MESSAGE("SMESHDS_Command::AddVolume : Bad Type"); + return; + } + myIntegers.push_back(NewVolID); + myIntegers.push_back(idnode1); + myIntegers.push_back(idnode2); + myIntegers.push_back(idnode3); + myIntegers.push_back(idnode4); + myIntegers.push_back(idnode5); + myIntegers.push_back(idnode6); + myIntegers.push_back(idnode7); + myIntegers.push_back(idnode8); + myNumber++; +} + +void SMESHDS_Command::AddVolume(int NewVolID, + int idnode1,int idnode2,int idnode3,int idnode4, + int idnode5, int idnode6, int idnode7, int idnode8, + int idnode9, int idnode10, int idnode11, int idnode12) +{ + if (myType != SMESHDS_AddHexagonalPrism) + { + MESSAGE("SMESHDS_Command::AddVolume : Bad Type"); + return; + } + myIntegers.push_back(NewVolID); + myIntegers.push_back(idnode1); + myIntegers.push_back(idnode2); + myIntegers.push_back(idnode3); + myIntegers.push_back(idnode4); + myIntegers.push_back(idnode5); + myIntegers.push_back(idnode6); + myIntegers.push_back(idnode7); + myIntegers.push_back(idnode8); + myIntegers.push_back(idnode9); + myIntegers.push_back(idnode10); + myIntegers.push_back(idnode11); + myIntegers.push_back(idnode12); + myNumber++; } //======================================================================= //function : AddPolygonalFace //purpose : //======================================================================= -void SMESHDS_Command::AddPolygonalFace (const int ElementID, - std::vector nodes_ids) +void SMESHDS_Command::AddPolygonalFace (const int ElementID, + const std::vector& nodes_ids) { - if (myType != SMESHDS_AddPolygon) { + if ( myType != SMESHDS_AddPolygon) { MESSAGE("SMESHDS_Command::AddPolygonalFace : Bad Type"); return; } @@ -253,15 +295,37 @@ void SMESHDS_Command::AddPolygonalFace (const int ElementID, myNumber++; } +//======================================================================= +//function : AddQuadPolygonalFace +//purpose : +//======================================================================= +void SMESHDS_Command::AddQuadPolygonalFace (const int ElementID, + const std::vector& nodes_ids) +{ + if ( myType != SMESHDS_AddQuadPolygon) { + MESSAGE("SMESHDS_Command::AddQuadraticPolygonalFace : Bad Type"); + return; + } + myIntegers.push_back(ElementID); + + int i, nbNodes = nodes_ids.size(); + myIntegers.push_back(nbNodes); + for (i = 0; i < nbNodes; i++) { + myIntegers.push_back(nodes_ids[i]); + } + + myNumber++; +} + //======================================================================= //function : AddPolyhedralVolume //purpose : //======================================================================= -void SMESHDS_Command::AddPolyhedralVolume (const int ElementID, - std::vector nodes_ids, - std::vector quantities) +void SMESHDS_Command::AddPolyhedralVolume (const int ElementID, + const std::vector& nodes_ids, + const std::vector& quantities) { - if (myType != SMESHDS_AddPolyhedron) { + if ( myType != SMESHDS_AddPolyhedron) { MESSAGE("SMESHDS_Command::AddPolyhedralVolume : Bad Type"); return; } @@ -288,13 +352,13 @@ void SMESHDS_Command::AddPolyhedralVolume (const int ElementID, //======================================================================= void SMESHDS_Command::RemoveNode(int NodeID) { - if (myType != SMESHDS_RemoveNode) - { - MESSAGE("SMESHDS_Command::RemoveNode : Bad Type"); - return; - } - myIntegers.push_back(NodeID); - myNumber++; + if ( myType != SMESHDS_RemoveNode) + { + MESSAGE("SMESHDS_Command::RemoveNode : Bad Type"); + return; + } + myIntegers.push_back(NodeID); + myNumber++; } //======================================================================= @@ -303,13 +367,13 @@ void SMESHDS_Command::RemoveNode(int NodeID) //======================================================================= void SMESHDS_Command::RemoveElement(int ElementID) { - if (myType != SMESHDS_RemoveElement) - { - MESSAGE("SMESHDS_Command::RemoveElement : Bad Type"); - return; - } - myIntegers.push_back(ElementID); - myNumber++; + if ( myType != SMESHDS_RemoveElement) + { + MESSAGE("SMESHDS_Command::RemoveElement : Bad Type"); + return; + } + myIntegers.push_back(ElementID); + myNumber++; } //======================================================================= @@ -319,7 +383,7 @@ void SMESHDS_Command::RemoveElement(int ElementID) void SMESHDS_Command::ChangeElementNodes(int ElementID, int nodes[], int nbnodes) { - if (myType != SMESHDS_ChangeElementNodes) + if ( myType != SMESHDS_ChangeElementNodes) { MESSAGE("SMESHDS_Command::ChangeElementNodes : Bad Type"); return; @@ -336,9 +400,9 @@ void SMESHDS_Command::ChangeElementNodes(int ElementID, int nodes[], int nbnodes //function : ChangePolyhedronNodes //purpose : //======================================================================= -void SMESHDS_Command::ChangePolyhedronNodes (const int ElementID, - std::vector nodes_ids, - std::vector quantities) +void SMESHDS_Command::ChangePolyhedronNodes (const int ElementID, + const std::vector& nodes_ids, + const std::vector& quantities) { if (myType != SMESHDS_ChangePolyhedronNodes) { @@ -369,7 +433,7 @@ void SMESHDS_Command::ChangePolyhedronNodes (const int ElementID, void SMESHDS_Command::Renumber (const bool isNodes, const int startID, const int deltaID) { - if (myType != SMESHDS_Renumber) + if ( myType != SMESHDS_Renumber) { MESSAGE("SMESHDS_Command::Renumber : Bad Type"); return; @@ -386,7 +450,7 @@ void SMESHDS_Command::Renumber (const bool isNodes, const int startID, const int //======================================================================= SMESHDS_CommandType SMESHDS_Command::GetType() { - return myType; + return myType; } //======================================================================= @@ -395,7 +459,7 @@ SMESHDS_CommandType SMESHDS_Command::GetType() //======================================================================= int SMESHDS_Command::GetNumber() { - return myNumber; + return myNumber; } //======================================================================= @@ -404,7 +468,7 @@ int SMESHDS_Command::GetNumber() //======================================================================= const list < int >&SMESHDS_Command::GetIndexes() { - return myIntegers; + return myIntegers; } //======================================================================= @@ -413,7 +477,7 @@ const list < int >&SMESHDS_Command::GetIndexes() //======================================================================= const list < double >&SMESHDS_Command::GetCoords() { - return myReals; + return myReals; } @@ -427,7 +491,7 @@ const list < double >&SMESHDS_Command::GetCoords() //======================================================================= void SMESHDS_Command::AddEdge(int NewEdgeID, int n1, int n2, int n12) { - if (myType != SMESHDS_AddQuadEdge) { + if ( myType != SMESHDS_AddQuadEdge) { MESSAGE("SMESHDS_Command::AddEdge : Bad Type"); return; } @@ -446,7 +510,7 @@ void SMESHDS_Command::AddFace(int NewFaceID, int n1, int n2, int n3, int n12, int n23, int n31) { - if (myType != SMESHDS_AddQuadTriangle) { + if ( myType != SMESHDS_AddQuadTriangle) { MESSAGE("SMESHDS_Command::AddFace : Bad Type"); return; } @@ -460,6 +524,29 @@ void SMESHDS_Command::AddFace(int NewFaceID, myNumber++; } +//======================================================================= +//function : AddFace +//purpose : +//======================================================================= +void SMESHDS_Command::AddFace(int NewFaceID, + int n1, int n2, int n3, + int n12, int n23, int n31, int nCenter) +{ + if ( myType != SMESHDS_AddBiQuadTriangle) { + MESSAGE("SMESHDS_Command::AddFace : Bad Type"); + return; + } + myIntegers.push_back(NewFaceID); + myIntegers.push_back(n1); + myIntegers.push_back(n2); + myIntegers.push_back(n3); + myIntegers.push_back(n12); + myIntegers.push_back(n23); + myIntegers.push_back(n31); + myIntegers.push_back(nCenter); + myNumber++; +} + //======================================================================= //function : AddFace //purpose : @@ -468,7 +555,31 @@ void SMESHDS_Command::AddFace(int NewFaceID, int n1, int n2, int n3, int n4, int n12, int n23, int n34, int n41) { - if (myType != SMESHDS_AddQuadQuadrangle) { + if ( myType != SMESHDS_AddQuadQuadrangle) { + MESSAGE("SMESHDS_Command::AddFace : Bad Type"); + return; + } + myIntegers.push_back(NewFaceID); + myIntegers.push_back(n1); + myIntegers.push_back(n2); + myIntegers.push_back(n3); + myIntegers.push_back(n4); + myIntegers.push_back(n12); + myIntegers.push_back(n23); + myIntegers.push_back(n34); + myIntegers.push_back(n41); + myNumber++; +} + +//======================================================================= +//function : AddFace +//purpose : +//======================================================================= +void SMESHDS_Command::AddFace(int NewFaceID, + int n1, int n2, int n3, int n4, + int n12, int n23, int n34, int n41, int nCenter) +{ + if (myType != SMESHDS_AddBiQuadQuadrangle) { MESSAGE("SMESHDS_Command::AddFace : Bad Type"); return; } @@ -481,6 +592,7 @@ void SMESHDS_Command::AddFace(int NewFaceID, myIntegers.push_back(n23); myIntegers.push_back(n34); myIntegers.push_back(n41); + myIntegers.push_back(nCenter); myNumber++; } @@ -492,7 +604,7 @@ void SMESHDS_Command::AddVolume(int NewVolID, int n1, int n2, int n3, int n4, int n12, int n23, int n31, int n14, int n24, int n34) { - if (myType != SMESHDS_AddQuadTetrahedron) { + if ( myType != SMESHDS_AddQuadTetrahedron) { MESSAGE("SMESHDS_Command::AddVolume : Bad Type"); return; } @@ -519,7 +631,7 @@ void SMESHDS_Command::AddVolume(int NewVolID, int n1, int n2, int n12, int n23, int n34, int n41, int n15, int n25, int n35, int n45) { - if (myType != SMESHDS_AddQuadPyramid) { + if ( myType != SMESHDS_AddQuadPyramid) { MESSAGE("SMESHDS_Command::AddVolume : Bad Type"); return; } @@ -550,7 +662,7 @@ void SMESHDS_Command::AddVolume(int NewVolID, int n1, int n2, int n45, int n56, int n64, int n14, int n25, int n36) { - if (myType != SMESHDS_AddQuadPentahedron) { + if ( myType != SMESHDS_AddQuadPentahedron) { MESSAGE("SMESHDS_Command::AddVolume : Bad Type"); return; } @@ -583,7 +695,47 @@ void SMESHDS_Command::AddVolume(int NewVolID, int n1, int n2, int n3, int n56, int n67, int n78, int n85, int n15, int n26, int n37, int n48) { - if (myType != SMESHDS_AddQuadHexahedron) { + if ( myType != SMESHDS_AddQuadHexahedron) { + MESSAGE("SMESHDS_Command::AddVolume : Bad Type"); + return; + } + myIntegers.push_back(NewVolID); + myIntegers.push_back(n1); + myIntegers.push_back(n2); + myIntegers.push_back(n3); + myIntegers.push_back(n4); + myIntegers.push_back(n5); + myIntegers.push_back(n6); + myIntegers.push_back(n7); + myIntegers.push_back(n8); + myIntegers.push_back(n12); + myIntegers.push_back(n23); + myIntegers.push_back(n34); + myIntegers.push_back(n41); + myIntegers.push_back(n56); + myIntegers.push_back(n67); + myIntegers.push_back(n78); + myIntegers.push_back(n85); + myIntegers.push_back(n15); + myIntegers.push_back(n26); + myIntegers.push_back(n37); + myIntegers.push_back(n48); + myNumber++; +} + +//======================================================================= +//function : AddVolume +//purpose : +//======================================================================= +void SMESHDS_Command::AddVolume(int NewVolID, int n1, int n2, int n3, + int n4, int n5, int n6, int n7, int n8, + int n12, int n23, int n34, int n41, + int n56, int n67, int n78, int n85, + int n15, int n26, int n37, int n48, + int n1234,int n1256,int n2367,int n3478, + int n1458,int n5678,int nCenter) +{ + if ( myType != SMESHDS_AddQuadHexahedron) { MESSAGE("SMESHDS_Command::AddVolume : Bad Type"); return; } @@ -608,6 +760,31 @@ void SMESHDS_Command::AddVolume(int NewVolID, int n1, int n2, int n3, myIntegers.push_back(n26); myIntegers.push_back(n37); myIntegers.push_back(n48); + myIntegers.push_back(n1234); + myIntegers.push_back(n1256); + myIntegers.push_back(n2367); + myIntegers.push_back(n3478); + myIntegers.push_back(n1458); + myIntegers.push_back(n5678); + myIntegers.push_back(nCenter); myNumber++; } +//================================================================================ +/*! + * \brief Record adding a Ball + */ +//================================================================================ + +void SMESHDS_Command::AddBall(int NewBallID, int node, double diameter) +{ + if ( myType != SMESHDS_AddBall) + { + MESSAGE("SMESHDS_Command::SMESHDS_AddBall : Bad Type"); + return; + } + myIntegers.push_back(NewBallID); + myIntegers.push_back(node); + myReals.push_back(diameter); + myNumber++; +} diff --git a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Document.cpp b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Document.cpp index 9e568e2974ab..4513302d3767 100644 --- a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Document.cpp +++ b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Document.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESHDS_Document.cxx // Author : Yves FRICAUD, OCC @@ -54,40 +55,41 @@ SMESHDS_Document::~SMESHDS_Document() //function : NewMesh //purpose : //======================================================================= -int SMESHDS_Document::NewMesh(bool theIsEmbeddedMode) +SMESHDS_Mesh * SMESHDS_Document::NewMesh(bool theIsEmbeddedMode, int MeshID) { - static int aNewMeshID = 0; - aNewMeshID++; - SMESHDS_Mesh *aNewMesh = new SMESHDS_Mesh(aNewMeshID,theIsEmbeddedMode); - myMeshes[aNewMeshID] = aNewMesh; - return aNewMeshID; + std::map::iterator i_m = + myMeshes.insert( make_pair( MeshID, (SMESHDS_Mesh*)0 )).first; + if ( i_m->second ) + throw SALOME_Exception("SMESHDS_Document::NewMesh(): ID of existing mesh given"); + SMESHDS_Mesh *aNewMesh = new SMESHDS_Mesh(MeshID,theIsEmbeddedMode); + i_m->second = aNewMesh; + return aNewMesh; } //======================================================================= //function : GetMesh -//purpose : +//purpose : //======================================================================= SMESHDS_Mesh *SMESHDS_Document::GetMesh(int MeshID) { - map::iterator it=myMeshes.find(MeshID); - if (it==myMeshes.end()) - { - MESSAGE("SMESHDS_Document::GetMesh : ID not found"); - return NULL; - } - else return (*it).second; + map::iterator it=myMeshes.find(MeshID); + if (it==myMeshes.end()) + { + MESSAGE("SMESHDS_Document::GetMesh : ID not found"); + return NULL; + } + else return (*it).second; } //======================================================================= //function : RemoveMesh -//purpose : +//purpose : //======================================================================= void SMESHDS_Document::RemoveMesh(int MeshID) { - map::iterator it=myMeshes.find(MeshID); - if (it==myMeshes.end()) - MESSAGE("SMESHDS_Document::RemoveMesh : ID not found"); - myMeshes.erase(it); + map::iterator it=myMeshes.find(MeshID); + if (it!=myMeshes.end()) + myMeshes.erase(it); } //======================================================================= @@ -96,7 +98,7 @@ void SMESHDS_Document::RemoveMesh(int MeshID) //======================================================================= void SMESHDS_Document::AddHypothesis(SMESHDS_Hypothesis * H) { - myHypothesis[H->GetID()]=H; + myHypothesis[H->GetID()]=H; } //======================================================================= @@ -105,99 +107,99 @@ void SMESHDS_Document::AddHypothesis(SMESHDS_Hypothesis * H) //======================================================================= SMESHDS_Hypothesis * SMESHDS_Document::GetHypothesis(int HypID) { - map::iterator it=myHypothesis.find(HypID); - if (it==myHypothesis.end()) - { - MESSAGE("SMESHDS_Document::GetHypothesis : ID not found"); - return NULL; - } - else return (*it).second; + map::iterator it=myHypothesis.find(HypID); + if (it==myHypothesis.end()) + { + MESSAGE("SMESHDS_Document::GetHypothesis : ID not found"); + return NULL; + } + else return (*it).second; } //======================================================================= //function : RemoveHypothesis -//purpose : +//purpose : //======================================================================= void SMESHDS_Document::RemoveHypothesis(int HypID) { - map::iterator it=myHypothesis.find(HypID); - if (it==myHypothesis.end()) - MESSAGE("SMESHDS_Document::RemoveHypothesis : ID not found"); - myHypothesis.erase(it); + map::iterator it=myHypothesis.find(HypID); + if (it==myHypothesis.end()) + MESSAGE("SMESHDS_Document::RemoveHypothesis : ID not found"); + myHypothesis.erase(it); } //======================================================================= //function : NbMeshes -//purpose : +//purpose : //======================================================================= int SMESHDS_Document::NbMeshes() { - return myMeshes.size(); + return myMeshes.size(); } //======================================================================= //function : NbHypothesis -//purpose : +//purpose : //======================================================================= int SMESHDS_Document::NbHypothesis() { - return myHypothesis.size(); + return myHypothesis.size(); } //======================================================================= //function : InitMeshesIterator -//purpose : +//purpose : //======================================================================= void SMESHDS_Document::InitMeshesIterator() { - myMeshesIt=myMeshes.begin(); + myMeshesIt=myMeshes.begin(); } //======================================================================= //function : NextMesh -//purpose : +//purpose : //======================================================================= SMESHDS_Mesh * SMESHDS_Document::NextMesh() { - SMESHDS_Mesh * toReturn=(*myMeshesIt).second; - myMeshesIt++; - return toReturn; + SMESHDS_Mesh * toReturn=(*myMeshesIt).second; + myMeshesIt++; + return toReturn; } //======================================================================= //function : MoreMesh -//purpose : +//purpose : //======================================================================= bool SMESHDS_Document::MoreMesh() { - return myMeshesIt!=myMeshes.end(); + return myMeshesIt!=myMeshes.end(); } //======================================================================= //function : InitHypothesisIterator -//purpose : +//purpose : //======================================================================= void SMESHDS_Document::InitHypothesisIterator() { - myHypothesisIt=myHypothesis.begin(); + myHypothesisIt=myHypothesis.begin(); } //======================================================================= //function : NextMesh -//purpose : +//purpose : //======================================================================= SMESHDS_Hypothesis * SMESHDS_Document::NextHypothesis() { - SMESHDS_Hypothesis * toReturn=(*myHypothesisIt).second; - myHypothesisIt++; - return toReturn; + SMESHDS_Hypothesis * toReturn=(*myHypothesisIt).second; + myHypothesisIt++; + return toReturn; } //======================================================================= //function : MoreMesh -//purpose : +//purpose : //======================================================================= bool SMESHDS_Document::MoreHypothesis() { - return myHypothesisIt!=myHypothesis.end(); + return myHypothesisIt!=myHypothesis.end(); } diff --git a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Group.cpp b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Group.cpp index 82ef5eee75d7..6ffa1b19cba4 100644 --- a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Group.cpp +++ b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Group.cpp @@ -1,28 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : idl implementation based on 'SMESH' unit's classes // File : SMESHDS_Group.cxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESHDS/SMESHDS_Group.cxx,v 1.9.2.1 2008/11/27 12:31:37 abd Exp $ +// $Header$ // #include "SMESHDS_Group.hxx" #include "SMESHDS_Mesh.hxx" @@ -48,7 +49,7 @@ SMESHDS_Group::SMESHDS_Group (const int theID, //purpose : //======================================================================= -int SMESHDS_Group::Extent() +int SMESHDS_Group::Extent() const { return myGroup.Extent(); } @@ -97,7 +98,17 @@ bool SMESHDS_Group::Contains (const SMDS_MeshElement* elem) bool SMESHDS_Group::Add (const int theID) { - const SMDS_MeshElement* aElem = findInMesh (theID); + return Add( findInMesh( theID )); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +bool SMESHDS_Group::Add (const SMDS_MeshElement* aElem ) +{ if (!aElem || myGroup.Contains(aElem)) return false; @@ -155,11 +166,22 @@ class MyGroupIterator: public SMDS_ElemIterator //purpose : //======================================================================= -SMDS_ElemIteratorPtr SMESHDS_Group::GetElements() +SMDS_ElemIteratorPtr SMESHDS_Group::GetElements() const { return SMDS_ElemIteratorPtr( new MyGroupIterator ( myGroup )); } +//================================================================================ +/*! + * \brief Return a value allowing to find out if a group has changed or not + */ +//================================================================================ + +int SMESHDS_Group::GetTic() const +{ + return myGroup.Tic(); +} + //======================================================================= //function : SetType //purpose : diff --git a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_GroupBase.cpp b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_GroupBase.cpp index 3cd114a85ff1..818c52009306 100644 --- a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_GroupBase.cpp +++ b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_GroupBase.cpp @@ -1,28 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : idl implementation based on 'SMESH' unit's classes // File : SMESHDS_Group.cxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESHDS/SMESHDS_GroupBase.cxx,v 1.7.2.5 2008/11/27 12:31:37 abd Exp $ +// $Header$ // #include "SMESHDS_GroupBase.hxx" #include "SMESHDS_Mesh.hxx" @@ -31,6 +32,8 @@ using namespace std; +Quantity_Color SMESHDS_GroupBase::myDefaultColor = Quantity_Color( 0.0, 0.0, 0.0, Quantity_TOC_RGB ); + //============================================================================= /*! * @@ -43,7 +46,7 @@ SMESHDS_GroupBase::SMESHDS_GroupBase (const int theID, myID(theID), myMesh(theMesh), myType(theType), myStoreName(""), myCurIndex(0), myCurID(-1) { - myColor = Quantity_Color( 0.0, 0.0, 0.0, Quantity_TOC_RGB ); + myColor = myDefaultColor; } //============================================================================= @@ -104,7 +107,7 @@ void SMESHDS_GroupBase::resetIterator() //purpose : //======================================================================= -int SMESHDS_GroupBase::Extent() +int SMESHDS_GroupBase::Extent() const { SMDS_ElemIteratorPtr it = GetElements(); int nb = 0; diff --git a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_GroupOnFilter.cpp b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_GroupOnFilter.cpp new file mode 100644 index 000000000000..7b24c6278ad9 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_GroupOnFilter.cpp @@ -0,0 +1,415 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SMESHDS_GroupOnFilter.cxx +// Module : SMESH +// +#include "SMESHDS_GroupOnFilter.hxx" + +#include "SMDS_SetIterator.hxx" +#include "SMESHDS_Mesh.hxx" + +#include +#include + +using namespace std; + +//============================================================================= +/*! + * Creates a group based on thePredicate + */ +//============================================================================= + +SMESHDS_GroupOnFilter::SMESHDS_GroupOnFilter (const int theID, + const SMESHDS_Mesh* theMesh, + const SMDSAbs_ElementType theType, + const SMESH_PredicatePtr& thePredicate) + : SMESHDS_GroupBase(theID,theMesh,theType), + myMeshInfo( SMDSEntity_Last, 0 ), + myMeshModifTime(0), + myPredicateTic(0), + myNbElemToSkip(0) +{ + SetPredicate( thePredicate ); +} + +//================================================================================ +/*! + * \brief Sets a new predicate + */ +//================================================================================ + +void SMESHDS_GroupOnFilter::SetPredicate( const SMESH_PredicatePtr& thePredicate ) +{ + myPredicate = thePredicate; + ++myPredicateTic; + setChanged(); + if ( myPredicate ) + myPredicate->SetMesh( GetMesh() ); +} + +//================================================================================ +/*! + * \brief Returns nb of elements + */ +//================================================================================ + +int SMESHDS_GroupOnFilter::Extent() const +{ + update(); + return std::accumulate( myMeshInfo.begin(), myMeshInfo.end(), 0 ); +} + +//================================================================================ +/*! + * \brief Checks emptyness + */ +//================================================================================ + +bool SMESHDS_GroupOnFilter::IsEmpty() +{ + if ( IsUpToDate() ) + { + return ( Extent() == 0 ); + } + else // not up-to-date + { + setChanged(); + SMDS_ElemIteratorPtr okElemIt = GetElements(); + if ( !okElemIt->more() ) + { + // no satisfying elements + setChanged( false ); + } + else + { + return false; + } + } + return true; +} + +//================================================================================ +/*! + * \brief Checks if the element belongs to the group + */ +//================================================================================ + +bool SMESHDS_GroupOnFilter::Contains (const int theID) +{ + return myPredicate && myPredicate->IsSatisfy( theID ); +} + +//================================================================================ +/*! + * \brief Checks if the element belongs to the group + */ +//================================================================================ + +bool SMESHDS_GroupOnFilter::Contains (const SMDS_MeshElement* elem) +{ + return myPredicate && myPredicate->IsSatisfy( elem->GetID() ); +} + +//================================================================================ +namespace // Iterator +{ + struct TIterator : public SMDS_ElemIterator + { + SMESH_PredicatePtr myPredicate; + SMDS_ElemIteratorPtr myElemIt; + const SMDS_MeshElement* myNextElem; + size_t myNbToFind, myNbFound, myTotalNb; + vector< const SMDS_MeshElement*>& myFoundElems; + bool & myFoundElemsOK; + + TIterator( const SMESH_PredicatePtr& filter, + SMDS_ElemIteratorPtr& elems, + size_t nbToFind, + size_t totalNb, + vector< const SMDS_MeshElement*>& foundElems, + bool & foundElemsOK): + myPredicate( filter ), + myElemIt( elems ), + myNextElem( 0 ), + myNbToFind( nbToFind ), + myNbFound( 0 ), + myTotalNb( totalNb ), + myFoundElems( foundElems ), + myFoundElemsOK( foundElemsOK ) + { + myFoundElemsOK = false; + next(); + } + ~TIterator() + { + if ( !myFoundElemsOK ) + clearVector( myFoundElems ); + } + virtual bool more() + { + return myNextElem; + } + virtual const SMDS_MeshElement* next() + { + const SMDS_MeshElement* res = myNextElem; + myNbFound += bool( res ); + myNextElem = 0; + if ( myNbFound < myNbToFind ) + { + while ( myElemIt->more() && !myNextElem ) + { + myNextElem = myElemIt->next(); + if ( !myPredicate->IsSatisfy( myNextElem->GetID() )) + myNextElem = 0; + } + if ( myNextElem ) + myFoundElems.push_back( myNextElem ); + else + keepOrClearElemVec(); + } + else + { + keepOrClearElemVec(); + } + return res; + } + void keepOrClearElemVec() + { + if ( myNbFound == myTotalNb ) + { + myFoundElemsOK = false; // all elems are OK, no need to keep them + } + else + { + // nb of bytes used for myFoundElems + size_t vecMemSize = myFoundElems.size() * sizeof( SMDS_MeshElement* ) / sizeof(char); + size_t aMB = 1024 * 1024; + if ( vecMemSize < aMB ) + { + myFoundElemsOK = true; // < 1 MB - do not clear + } + else + { + int freeRamMB = SMDS_Mesh::CheckMemory( /*doNotRaise=*/true ); + if ( freeRamMB < 0 ) + myFoundElemsOK = true; // hope it's OK + else + myFoundElemsOK = ( freeRamMB * aMB > 10 * vecMemSize ); + } + } + if ( !myFoundElemsOK ) + clearVector( myFoundElems ); + } + }; + + struct TEmptyIterator : public SMDS_ElemIterator + { + virtual bool more() { return false; } + virtual const SMDS_MeshElement* next() { return 0; } + }; +} + +//================================================================================ +/*! + * \brief Return iterator on all elements + */ +//================================================================================ + +SMDS_ElemIteratorPtr SMESHDS_GroupOnFilter::GetElements() const +{ + size_t nbToFind = std::numeric_limits::max(); + size_t totalNb = GetMesh()->GetMeshInfo().NbElements( GetType() ); + + SMDS_ElemIteratorPtr elemIt; // iterator on all elements to initialize TIterator + if ( myPredicate ) + { + myPredicate->SetMesh( GetMesh() ); // hope myPredicate updates self here if necessary + + elemIt = GetMesh()->elementsIterator( GetType() ); + if ( IsUpToDate() ) + { + if ( myElementsOK ) + return SMDS_ElemIteratorPtr( new SMDS_ElementVectorIterator( myElements.begin(), + myElements.end() )); + nbToFind = Extent(); + if ( nbToFind == totalNb ) + return elemIt; // all elements are OK + for ( size_t i = 0; i < myNbElemToSkip; ++i ) + elemIt->next(); // skip w/o check + } + } + else + { + elemIt = SMDS_ElemIteratorPtr( new TEmptyIterator ); + } + + // the iterator fills myElements if all elements are checked + SMESHDS_GroupOnFilter* me = const_cast( this ); + return SMDS_ElemIteratorPtr + ( new TIterator( myPredicate, elemIt, nbToFind, totalNb, me->myElements, me->myElementsOK )); +} + +//================================================================================ +/*! + * \brief Return info on sub-types of elements + */ +//================================================================================ + +std::vector< int > SMESHDS_GroupOnFilter::GetMeshInfo() const +{ + update(); + return myMeshInfo; +} + +//================================================================================ +/*! + * \brief Fill ids of elements. And return their number. + * \a ids must be pre-allocated using nb of elements of type == GetType() + */ +//================================================================================ + +int SMESHDS_GroupOnFilter::getElementIds( void* ids, size_t idSize ) const +{ + SMESHDS_GroupOnFilter* me = const_cast( this ); + + if ( !IsUpToDate() ) + me->setChanged(); + + char* curID = (char*) ids; + SMDS_ElemIteratorPtr elIt = GetElements(); + if ( elIt->more() ) + { + if ( IsUpToDate() ) + { + for ( ; elIt->more(); curID += idSize ) + (*(int*) curID) = elIt->next()->GetID(); + } + else + { + // find out nb of elements to skip w/o check before the 1st OK element + const SMDS_MeshElement* firstOkElem = me->setNbElemToSkip( elIt ); + + me->myMeshInfo.assign( SMDSEntity_Last, 0 ); + me->myMeshInfo[ firstOkElem->GetEntityType() ]++; + + (*(int*) curID) = firstOkElem->GetID(); + for ( curID += idSize; elIt->more(); curID += idSize ) + { + const SMDS_MeshElement* e = elIt->next(); + (*(int*) curID) = e->GetID(); + me->myMeshInfo[ e->GetEntityType() ]++; + } + } + } + me->setChanged( false ); + + return ( curID - (char*)ids ) / idSize; +} + +//================================================================================ +/*! + * \brief Return a value allowing to find out if a group has changed or not + */ +//================================================================================ + +int SMESHDS_GroupOnFilter::GetTic() const +{ + return GetMesh()->GetMTime() * myPredicateTic; +} + +//================================================================================ +/*! + * \brief Return false if update() is needed + */ +//================================================================================ + +bool SMESHDS_GroupOnFilter::IsUpToDate() const +{ + return !( myMeshModifTime < GetMesh()->GetMTime() ); +} + +//================================================================================ +/*! + * \brief Updates myElements if necessary + */ +//================================================================================ + +void SMESHDS_GroupOnFilter::update() const +{ + SMESHDS_GroupOnFilter* me = const_cast( this ); + if ( !IsUpToDate() ) + { + me->setChanged(); + SMDS_ElemIteratorPtr elIt = GetElements(); + if ( elIt->more() ) { + // find out nb of elements to skip w/o check before the 1st OK element + const SMDS_MeshElement* e = me->setNbElemToSkip( elIt ); + ++me->myMeshInfo[ e->GetEntityType() ]; + while ( elIt->more() ) + ++me->myMeshInfo[ elIt->next()->GetEntityType() ]; + } + me->setChanged( false ); + } +} + +//================================================================================ +/*! + * \brief Sets myMeshModifTime and clear fields according to modification state + */ +//================================================================================ + +void SMESHDS_GroupOnFilter::setChanged(bool changed) +{ + myMeshModifTime = GetMesh()->GetMTime(); + if ( changed && myMeshModifTime != 0 ) + --myMeshModifTime; + if ( changed ) { + clearVector( myElements ); + myElementsOK = false; + myNbElemToSkip = 0; + myMeshInfo.assign( SMDSEntity_Last, 0 ); + } +} + +//================================================================================ +/*! + * \brief Sets myNbElemToSkip + * \param okElemIt - iterator on OK elements + * \retval const SMDS_MeshElement* - the first OK element + */ +//================================================================================ + +const SMDS_MeshElement* +SMESHDS_GroupOnFilter::setNbElemToSkip( SMDS_ElemIteratorPtr& okElemIt ) +{ + // find out nb of elements to skip w/o check before the 1st OK element + const SMDS_MeshElement* firstOkElem = okElemIt->next(); + if ( myNbElemToSkip == 0 ) + { + SMDS_ElemIteratorPtr elemIt = GetMesh()->elementsIterator( GetType() ); + myNbElemToSkip = 0; + while ( elemIt->next() != firstOkElem ) + ++myNbElemToSkip; + } + return firstOkElem; +} diff --git a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_GroupOnGeom.cpp b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_GroupOnGeom.cpp index f528c6aacb79..65a39a7bc2ff 100644 --- a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_GroupOnGeom.cpp +++ b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_GroupOnGeom.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : idl implementation based on 'SMESH' unit's classes // File : SMESHDS_GroupOnGeom.cxx // Module : SMESH @@ -72,28 +73,28 @@ class MyIterator: public SMDS_ElemIterator myElemIt = subMesh->GetElements(); next(); } - } + } } bool more() { - if ( myType == SMDSAbs_Node && (myNodeIt!=NULL) ) + if ( myType == SMDSAbs_Node && myNodeIt ) return myNodeIt->more(); return ( myElem != 0 ); } const SMDS_MeshElement* next() { - if ( myType == SMDSAbs_Node && (myNodeIt!=NULL) ) + if ( myType == SMDSAbs_Node && myNodeIt ) return myNodeIt->next(); const SMDS_MeshElement* res = myElem; myElem = 0; - while ( (myElemIt!=NULL) && myElemIt->more() ) { + while ( myElemIt && myElemIt->more() ) { myElem = myElemIt->next(); if ( myElem && myElem->GetType() == myType ) break; else myElem = 0; } - return res; + return res; } }; @@ -102,7 +103,7 @@ class MyIterator: public SMDS_ElemIterator //purpose : //======================================================================= -SMDS_ElemIteratorPtr SMESHDS_GroupOnGeom::GetElements() +SMDS_ElemIteratorPtr SMESHDS_GroupOnGeom::GetElements() const { return SMDS_ElemIteratorPtr( new MyIterator ( GetType(), mySubMesh )); } @@ -127,3 +128,14 @@ bool SMESHDS_GroupOnGeom::Contains (const SMDS_MeshElement* elem) return mySubMesh->Contains( elem ); } +//================================================================================ +/*! + * \brief Return a value allowing to find out if a group has changed or not + */ +//================================================================================ + +int SMESHDS_GroupOnGeom::GetTic() const +{ + return GetMesh()->GetMTime(); +} + diff --git a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Hypothesis.cpp b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Hypothesis.cpp index 22cbb1a1bd0f..571a1946b51d 100644 --- a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Hypothesis.cpp +++ b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Hypothesis.cpp @@ -1,32 +1,34 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESHDS_Hypothesis.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/SMESHDS/SMESHDS_Hypothesis.cxx,v 1.10.2.1 2008/11/27 12:31:37 abd Exp $ // #include "SMESHDS_Hypothesis.hxx" +#include + using namespace std; //============================================================================= @@ -37,11 +39,8 @@ using namespace std; SMESHDS_Hypothesis::SMESHDS_Hypothesis(int hypId) { -// MESSAGE("SMESHDS_Hypothesis::SMESHDS_Hypothesis"); _hypId = hypId; _name = "generic"; -// SCRUTE(_name); -// SCRUTE(_hypId); } //============================================================================= @@ -52,7 +51,6 @@ SMESHDS_Hypothesis::SMESHDS_Hypothesis(int hypId) SMESHDS_Hypothesis::~SMESHDS_Hypothesis() { -// MESSAGE("SMESHDS_Hypothesis::~SMESHDS_Hypothesis"); } //============================================================================= @@ -63,9 +61,6 @@ SMESHDS_Hypothesis::~SMESHDS_Hypothesis() const char* SMESHDS_Hypothesis::GetName() const { -// MESSAGE("SMESHDS_Hypothesis::GetName"); -// SCRUTE(_name); -// SCRUTE(&_name); return _name.c_str(); } @@ -77,8 +72,6 @@ const char* SMESHDS_Hypothesis::GetName() const int SMESHDS_Hypothesis::GetID() const { -// MESSAGE("SMESHDS_Hypothesis::GetId"); -// SCRUTE(_hypId); return _hypId; } @@ -90,8 +83,34 @@ int SMESHDS_Hypothesis::GetID() const int SMESHDS_Hypothesis::GetType() const { -// MESSAGE("SMESHDS_Hypothesis::GetType"); -// SCRUTE(_type); return _type; } +//============================================================================= +/*! + * Equality + */ +//============================================================================= + +bool SMESHDS_Hypothesis::operator==(const SMESHDS_Hypothesis& other) const +{ + if ( this == &other ) + return true; + if ( _name != other._name ) + return false; + ostringstream mySave, otherSave; + ((SMESHDS_Hypothesis*)this )->SaveTo(mySave); + ((SMESHDS_Hypothesis*)&other)->SaveTo(otherSave); + return mySave.str() == otherSave.str(); +} + +//================================================================================ +/*! + * \brief Compare types of hypotheses + */ +//================================================================================ + +bool SMESHDS_Hypothesis::IsSameName( const SMESHDS_Hypothesis& other) const +{ + return _name == other._name; +} diff --git a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Mesh.cpp b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Mesh.cpp index 1233f935513b..79713c80c276 100644 --- a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Mesh.cpp +++ b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Mesh.cpp @@ -1,51 +1,60 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESH_Mesh.cxx // Author : Yves FRICAUD, OCC // Module : SMESH -// $Header: // #include "SMESHDS_Mesh.hxx" -#include "SMESHDS_Group.hxx" -#include "SMDS_VertexPosition.hxx" +#include "SMDS_Downward.hxx" #include "SMDS_EdgePosition.hxx" #include "SMDS_FacePosition.hxx" #include "SMDS_SpacePosition.hxx" +#include "SMDS_VertexPosition.hxx" +#include "SMESHDS_Group.hxx" #include "SMESHDS_GroupOnGeom.hxx" +#include "SMESHDS_Script.hxx" +#include "SMESHDS_TSubMeshHolder.hxx" -#include +#include +#include #include +#include +#include +#include #include +#include +#include +#include #include "utilities.h" using namespace std; -/*Standard_Boolean IsEqual( const TopoDS_Shape& S1, const TopoDS_Shape& S2 ) - { - return S1.IsSame( S2 ); - }*/ +class SMESHDS_Mesh::SubMeshHolder : public SMESHDS_TSubMeshHolder< const SMESHDS_SubMesh > +{ +}; //======================================================================= //function : Create @@ -53,11 +62,11 @@ using namespace std; //======================================================================= SMESHDS_Mesh::SMESHDS_Mesh(int theMeshID, bool theIsEmbeddedMode): myMeshID(theMeshID), - myIsEmbeddedMode(theIsEmbeddedMode), - myCurSubID(-1) + mySubMeshHolder( new SubMeshHolder ), + myIsEmbeddedMode(theIsEmbeddedMode) { myScript = new SMESHDS_Script(theIsEmbeddedMode); - myCurSubMesh = 0; + SetPersistentId(theMeshID); } //======================================================================= @@ -66,6 +75,30 @@ bool SMESHDS_Mesh::IsEmbeddedMode() return myIsEmbeddedMode; } +//================================================================================ +/*! + * \brief Store ID persistent during lifecycle + * + * Initially it was used to have a persistent reference to the mesh from the hypothesis + */ +//================================================================================ + +void SMESHDS_Mesh::SetPersistentId(int id) +{ + if (NbNodes() == 0) + myPersistentID = id; +} +//================================================================================ +/*! + * \brief Return ID persistent during lifecycle + */ +//================================================================================ + +int SMESHDS_Mesh::GetPersistentId() const +{ + return myPersistentID; +} + //======================================================================= //function : ShapeToMesh //purpose : @@ -78,19 +111,17 @@ void SMESHDS_Mesh::ShapeToMesh(const TopoDS_Shape & S) // - hypotheses myShapeToHypothesis.Clear(); // - shape indices in SMDS_Position of nodes - map::iterator i_sub = myShapeIndexToSubMesh.begin(); - for ( ; i_sub != myShapeIndexToSubMesh.end(); i_sub++ ) { - if ( !i_sub->second->IsComplexSubmesh() ) { - SMDS_NodeIteratorPtr nIt = i_sub->second->GetNodes(); + SMESHDS_SubMeshIteratorPtr smIt = SubMeshes(); + while ( SMESHDS_SubMesh* sm = const_cast< SMESHDS_SubMesh* >( smIt->next() )) { + if ( !sm->IsComplexSubmesh() ) { + SMDS_NodeIteratorPtr nIt = sm->GetNodes(); while ( nIt->more() ) - nIt->next()->GetPosition()->SetShapeId( 0 ); + sm->RemoveNode(nIt->next(), false); } } // - sub-meshes - TShapeIndexToSubMesh::iterator i_sm = myShapeIndexToSubMesh.begin(); - for ( ; i_sm != myShapeIndexToSubMesh.end(); ++i_sm ) - delete i_sm->second; - myShapeIndexToSubMesh.clear(); + mySubMeshHolder->DeleteAll(); + myIndexToShape.Clear(); // - groups on geometry set::iterator gr = myGroups.begin(); @@ -116,12 +147,12 @@ void SMESHDS_Mesh::ShapeToMesh(const TopoDS_Shape & S) bool SMESHDS_Mesh::AddHypothesis(const TopoDS_Shape & SS, const SMESHDS_Hypothesis * H) { - if (!myShapeToHypothesis.IsBound(SS.Oriented(TopAbs_FORWARD))) { + if (!myShapeToHypothesis.IsBound(SS/*.Oriented(TopAbs_FORWARD)*/)) { list aList; - myShapeToHypothesis.Bind(SS.Oriented(TopAbs_FORWARD), aList); + myShapeToHypothesis.Bind(SS/*.Oriented(TopAbs_FORWARD)*/, aList); } list& alist = - myShapeToHypothesis(SS.Oriented(TopAbs_FORWARD)); // ignore orientation of SS + myShapeToHypothesis(SS/*.Oriented(TopAbs_FORWARD)*/); // ignore orientation of SS //Check if the Hypothesis is still present list::iterator ith = find(alist.begin(),alist.end(), H ); @@ -140,9 +171,9 @@ bool SMESHDS_Mesh::AddHypothesis(const TopoDS_Shape & SS, bool SMESHDS_Mesh::RemoveHypothesis(const TopoDS_Shape & S, const SMESHDS_Hypothesis * H) { - if( myShapeToHypothesis.IsBound( S.Oriented(TopAbs_FORWARD) ) ) + if( myShapeToHypothesis.IsBound( S/*.Oriented(TopAbs_FORWARD)*/ ) ) { - list& alist=myShapeToHypothesis.ChangeFind( S.Oriented(TopAbs_FORWARD) ); + list& alist=myShapeToHypothesis.ChangeFind( S/*.Oriented(TopAbs_FORWARD)*/ ); list::iterator ith=find(alist.begin(),alist.end(), H ); if (ith != alist.end()) { @@ -173,22 +204,23 @@ SMDS_MeshNode* SMESHDS_Mesh::AddNodeWithID(double x, double y, double z, int ID) //function : MoveNode //purpose : //======================================================================= + void SMESHDS_Mesh::MoveNode(const SMDS_MeshNode *n, double x, double y, double z) { - SMDS_MeshNode * node=const_cast(n); - node->setXYZ(x,y,z); + SMDS_Mesh::MoveNode( n, x, y, z ); myScript->MoveNode(n->GetID(), x, y, z); } //======================================================================= //function : ChangeElementNodes -//purpose : +//purpose : Changed nodes of an element provided that nb of nodes does not change //======================================================================= bool SMESHDS_Mesh::ChangeElementNodes(const SMDS_MeshElement * elem, const SMDS_MeshNode * nodes[], const int nbnodes) { + //MESSAGE("SMESHDS_Mesh::ChangeElementNodes"); if ( ! SMDS_Mesh::ChangeElementNodes( elem, nodes, nbnodes )) return false; @@ -244,14 +276,71 @@ bool SMESHDS_Mesh::ChangePolyhedronNodes void SMESHDS_Mesh::Renumber (const bool isNodes, const int startID, const int deltaID) { - SMDS_Mesh::Renumber( isNodes, startID, deltaID ); - myScript->Renumber( isNodes, startID, deltaID ); + // TODO not possible yet to have node numbers not starting to O and continuous. + if (!this->isCompacted()) + this->compactMesh(); +// SMDS_Mesh::Renumber( isNodes, startID, deltaID ); +// myScript->Renumber( isNodes, startID, deltaID ); +} + +//======================================================================= +//function : Add0DElement +//purpose : +//======================================================================= +SMDS_Mesh0DElement* SMESHDS_Mesh::Add0DElementWithID(int nodeID, int ID) +{ + SMDS_Mesh0DElement* anElem = SMDS_Mesh::Add0DElementWithID(nodeID, ID); + if (anElem) myScript->Add0DElement(ID, nodeID); + return anElem; +} + +SMDS_Mesh0DElement* SMESHDS_Mesh::Add0DElementWithID + (const SMDS_MeshNode * node, int ID) +{ + return Add0DElementWithID(node->GetID(), ID); +} + +SMDS_Mesh0DElement* SMESHDS_Mesh::Add0DElement(const SMDS_MeshNode * node) +{ + SMDS_Mesh0DElement* anElem = SMDS_Mesh::Add0DElement(node); + if (anElem) myScript->Add0DElement(anElem->GetID(), node->GetID()); + return anElem; +} + +//======================================================================= +//function :AddBallWithID +//purpose : +//======================================================================= + +SMDS_BallElement* SMESHDS_Mesh::AddBallWithID(int node, double diameter, int ID) +{ + SMDS_BallElement* anElem = SMDS_Mesh::AddBallWithID(node,diameter,ID); + if (anElem) myScript->AddBall(anElem->GetID(), node, diameter); + return anElem; +} + +SMDS_BallElement* SMESHDS_Mesh::AddBallWithID(const SMDS_MeshNode * node, + double diameter, + int ID) +{ + SMDS_BallElement* anElem = SMDS_Mesh::AddBallWithID(node,diameter,ID); + if (anElem) myScript->AddBall(anElem->GetID(), node->GetID(), diameter); + return anElem; +} + +SMDS_BallElement* SMESHDS_Mesh::AddBall (const SMDS_MeshNode * node, + double diameter) +{ + SMDS_BallElement* anElem = SMDS_Mesh::AddBall(node,diameter); + if (anElem) myScript->AddBall(anElem->GetID(), node->GetID(), diameter); + return anElem; } //======================================================================= //function :AddEdgeWithID //purpose : //======================================================================= + SMDS_MeshEdge* SMESHDS_Mesh::AddEdgeWithID(int n1, int n2, int ID) { SMDS_MeshEdge* anElem = SMDS_Mesh::AddEdgeWithID(n1,n2,ID); @@ -260,21 +349,21 @@ SMDS_MeshEdge* SMESHDS_Mesh::AddEdgeWithID(int n1, int n2, int ID) } SMDS_MeshEdge* SMESHDS_Mesh::AddEdgeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - int ID) + const SMDS_MeshNode * n2, + int ID) { return AddEdgeWithID(n1->GetID(), - n2->GetID(), - ID); + n2->GetID(), + ID); } SMDS_MeshEdge* SMESHDS_Mesh::AddEdge(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2) + const SMDS_MeshNode * n2) { SMDS_MeshEdge* anElem = SMDS_Mesh::AddEdge(n1,n2); if(anElem) myScript->AddEdge(anElem->GetID(), - n1->GetID(), - n2->GetID()); + n1->GetID(), + n2->GetID()); return anElem; } @@ -290,25 +379,25 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(int n1, int n2, int n3, int ID) } SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - int ID) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + int ID) { return AddFaceWithID(n1->GetID(), - n2->GetID(), - n3->GetID(), - ID); + n2->GetID(), + n3->GetID(), + ID); } SMDS_MeshFace* SMESHDS_Mesh::AddFace( const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3) { SMDS_MeshFace *anElem = SMDS_Mesh::AddFace(n1, n2, n3); if(anElem) myScript->AddFace(anElem->GetID(), - n1->GetID(), - n2->GetID(), - n3->GetID()); + n1->GetID(), + n2->GetID(), + n3->GetID()); return anElem; } @@ -324,29 +413,29 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(int n1, int n2, int n3, int n4, int I } SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - int ID) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + int ID) { return AddFaceWithID(n1->GetID(), - n2->GetID(), - n3->GetID(), - n4->GetID(), - ID); + n2->GetID(), + n3->GetID(), + n4->GetID(), + ID); } SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4) { SMDS_MeshFace *anElem = SMDS_Mesh::AddFace(n1, n2, n3, n4); if(anElem) myScript->AddFace(anElem->GetID(), - n1->GetID(), - n2->GetID(), - n3->GetID(), - n4->GetID()); + n1->GetID(), + n2->GetID(), + n3->GetID(), + n4->GetID()); return anElem; } @@ -362,29 +451,29 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, int n4, i } SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - int ID) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + int ID) { return AddVolumeWithID(n1->GetID(), - n2->GetID(), - n3->GetID(), - n4->GetID(), - ID); + n2->GetID(), + n3->GetID(), + n4->GetID(), + ID); } SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddVolume(n1, n2, n3, n4); if(anElem) myScript->AddVolume(anElem->GetID(), - n1->GetID(), - n2->GetID(), - n3->GetID(), - n4->GetID()); + n1->GetID(), + n2->GetID(), + n3->GetID(), + n4->GetID()); return anElem; } @@ -400,33 +489,33 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, int n4, i } SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - int ID) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + int ID) { return AddVolumeWithID(n1->GetID(), - n2->GetID(), - n3->GetID(), - n4->GetID(), - n5->GetID(), - ID); + n2->GetID(), + n3->GetID(), + n4->GetID(), + n5->GetID(), + ID); } SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddVolume(n1, n2, n3, n4, n5); if(anElem) myScript->AddVolume(anElem->GetID(), - n1->GetID(), - n2->GetID(), - n3->GetID(), - n4->GetID(), - n5->GetID()); + n1->GetID(), + n2->GetID(), + n3->GetID(), + n4->GetID(), + n5->GetID()); return anElem; } @@ -442,37 +531,37 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, int n4, i } SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - int ID) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + int ID) { return AddVolumeWithID(n1->GetID(), - n2->GetID(), - n3->GetID(), - n4->GetID(), - n5->GetID(), - n6->GetID(), - ID); + n2->GetID(), + n3->GetID(), + n4->GetID(), + n5->GetID(), + n6->GetID(), + ID); } SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddVolume(n1, n2, n3, n4, n5, n6); if(anElem) myScript->AddVolume(anElem->GetID(), - n1->GetID(), - n2->GetID(), - n3->GetID(), - n4->GetID(), - n5->GetID(), - n6->GetID()); + n1->GetID(), + n2->GetID(), + n3->GetID(), + n4->GetID(), + n5->GetID(), + n6->GetID()); return anElem; } @@ -488,54 +577,129 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, int n4, i } SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, - int ID) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + int ID) { return AddVolumeWithID(n1->GetID(), - n2->GetID(), - n3->GetID(), - n4->GetID(), - n5->GetID(), - n6->GetID(), - n7->GetID(), - n8->GetID(), - ID); + n2->GetID(), + n3->GetID(), + n4->GetID(), + n5->GetID(), + n6->GetID(), + n7->GetID(), + n8->GetID(), + ID); } SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, - const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8) + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddVolume(n1, n2, n3, n4, n5, n6, n7, n8); if(anElem) myScript->AddVolume(anElem->GetID(), - n1->GetID(), - n2->GetID(), - n3->GetID(), - n4->GetID(), - n5->GetID(), - n6->GetID(), - n7->GetID(), - n8->GetID()); + n1->GetID(), + n2->GetID(), + n3->GetID(), + n4->GetID(), + n5->GetID(), + n6->GetID(), + n7->GetID(), + n8->GetID()); return anElem; } + +//======================================================================= +//function :AddVolume +//purpose : add hexagonal prism +//======================================================================= +SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, int n4, + int n5, int n6, int n7, int n8, + int n9, int n10, int n11, int n12, + int ID) +{ + SMDS_MeshVolume *anElem= SMDS_Mesh::AddVolumeWithID(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, ID); + if(anElem) myScript->AddVolume(ID, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12); + return anElem; +} + +SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n9, + const SMDS_MeshNode * n10, + const SMDS_MeshNode * n11, + const SMDS_MeshNode * n12, + int ID) +{ + return AddVolumeWithID(n1->GetID(), + n2->GetID(), + n3->GetID(), + n4->GetID(), + n5->GetID(), + n6->GetID(), + n7->GetID(), + n8->GetID(), + n9->GetID(), + n10->GetID(), + n11->GetID(), + n12->GetID(), + ID); +} + +SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n9, + const SMDS_MeshNode * n10, + const SMDS_MeshNode * n11, + const SMDS_MeshNode * n12) +{ + SMDS_MeshVolume *anElem = SMDS_Mesh::AddVolume(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12); + if(anElem) myScript->AddVolume(anElem->GetID(), + n1->GetID(), + n2->GetID(), + n3->GetID(), + n4->GetID(), + n5->GetID(), + n6->GetID(), + n7->GetID(), + n8->GetID(), + n9->GetID(), + n10->GetID(), + n11->GetID(), + n12->GetID()); + return anElem; +} + + //======================================================================= //function : AddPolygonalFace //purpose : //======================================================================= -SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFaceWithID (std::vector nodes_ids, - const int ID) +SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFaceWithID (const std::vector& nodes_ids, + const int ID) { SMDS_MeshFace *anElem = SMDS_Mesh::AddPolygonalFaceWithID(nodes_ids, ID); if (anElem) { @@ -544,9 +708,9 @@ SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFaceWithID (std::vector nodes_ids, return anElem; } -SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFaceWithID - (std::vector nodes, - const int ID) +SMDS_MeshFace* +SMESHDS_Mesh::AddPolygonalFaceWithID (const std::vector& nodes, + const int ID) { SMDS_MeshFace *anElem = SMDS_Mesh::AddPolygonalFaceWithID(nodes, ID); if (anElem) { @@ -560,8 +724,8 @@ SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFaceWithID return anElem; } -SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFace - (std::vector nodes) +SMDS_MeshFace* +SMESHDS_Mesh::AddPolygonalFace (const std::vector& nodes) { SMDS_MeshFace *anElem = SMDS_Mesh::AddPolygonalFace(nodes); if (anElem) { @@ -575,13 +739,60 @@ SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFace return anElem; } + +//======================================================================= +//function : AddQuadPolygonalFace +//purpose : +//======================================================================= +SMDS_MeshFace* SMESHDS_Mesh::AddQuadPolygonalFaceWithID (const std::vector& nodes_ids, + const int ID) +{ + SMDS_MeshFace *anElem = SMDS_Mesh::AddQuadPolygonalFaceWithID(nodes_ids, ID); + if (anElem) { + myScript->AddQuadPolygonalFace(ID, nodes_ids); + } + return anElem; +} + +SMDS_MeshFace* +SMESHDS_Mesh::AddQuadPolygonalFaceWithID (const std::vector& nodes, + const int ID) +{ + SMDS_MeshFace *anElem = SMDS_Mesh::AddQuadPolygonalFaceWithID(nodes, ID); + if (anElem) { + int i, len = nodes.size(); + std::vector nodes_ids (len); + for (i = 0; i < len; i++) { + nodes_ids[i] = nodes[i]->GetID(); + } + myScript->AddQuadPolygonalFace(ID, nodes_ids); + } + return anElem; +} + +SMDS_MeshFace* +SMESHDS_Mesh::AddQuadPolygonalFace (const std::vector& nodes) +{ + SMDS_MeshFace *anElem = SMDS_Mesh::AddQuadPolygonalFace(nodes); + if (anElem) { + int i, len = nodes.size(); + std::vector nodes_ids (len); + for (i = 0; i < len; i++) { + nodes_ids[i] = nodes[i]->GetID(); + } + myScript->AddQuadPolygonalFace(anElem->GetID(), nodes_ids); + } + return anElem; +} + + //======================================================================= //function : AddPolyhedralVolume //purpose : //======================================================================= -SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolumeWithID (std::vector nodes_ids, - std::vector quantities, - const int ID) +SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolumeWithID (const std::vector& nodes_ids, + const std::vector& quantities, + const int ID) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddPolyhedralVolumeWithID(nodes_ids, quantities, ID); if (anElem) { @@ -591,9 +802,9 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolumeWithID (std::vector nodes } SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolumeWithID - (std::vector nodes, - std::vector quantities, - const int ID) + (const std::vector& nodes, + const std::vector& quantities, + const int ID) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddPolyhedralVolumeWithID(nodes, quantities, ID); if (anElem) { @@ -608,8 +819,8 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolumeWithID } SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolume - (std::vector nodes, - std::vector quantities) + (const std::vector& nodes, + const std::vector& quantities) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddPolyhedralVolume(nodes, quantities); if (anElem) { @@ -628,7 +839,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolume //purpose : //======================================================================= -static void removeFromContainers (map& theSubMeshes, +static void removeFromContainers (SMESHDS_Mesh* theMesh, set& theGroups, list& theElems, const bool isNode) @@ -659,67 +870,43 @@ static void removeFromContainers (map& theSubMeshes, // Rm from sub-meshes // Element should belong to only one sub-mesh - map::iterator SubIt = theSubMeshes.begin(); - for ( ; SubIt != theSubMeshes.end(); SubIt++ ) + if ( theMesh->SubMeshes()->more() ) { - int size = isNode ? (*SubIt).second->NbNodes() : (*SubIt).second->NbElements(); - if ( size == 0 ) continue; - list::iterator elIt = theElems.begin(); - while ( elIt != theElems.end() ) - { - bool removed = false; - if ( isNode ) - removed = (*SubIt).second->RemoveNode( static_cast (*elIt), deleted ); - else - removed = (*SubIt).second->RemoveElement( *elIt, deleted ); - - if (removed) - { - elIt = theElems.erase( elIt ); - if ( theElems.empty() ) - return; // all elements are found and removed - } - else - { - elIt++ ; - } + if ( isNode ) { + for ( ; elIt != theElems.end(); ++elIt ) + if ( SMESHDS_SubMesh* sm = theMesh->MeshElements( (*elIt)->getshapeId() )) + sm->RemoveNode( static_cast (*elIt), deleted ); + } + else { + for ( ; elIt != theElems.end(); ++elIt ) + if ( SMESHDS_SubMesh* sm = theMesh->MeshElements( (*elIt)->getshapeId() )) + sm->RemoveElement( *elIt, deleted ); } } } - + //======================================================================= //function : RemoveNode -//purpose : +//purpose : //======================================================================= void SMESHDS_Mesh::RemoveNode(const SMDS_MeshNode * n) { if ( n->NbInverseElements() == 0 && !(hasConstructionEdges() || hasConstructionFaces())) { - SMESHDS_SubMesh* subMesh=0; - map::iterator SubIt = - myShapeIndexToSubMesh.find( n->GetPosition()->GetShapeId() ); - if ( SubIt != myShapeIndexToSubMesh.end() ) - subMesh = SubIt->second; - else - SubIt = myShapeIndexToSubMesh.begin(); - for ( ; !subMesh && SubIt != myShapeIndexToSubMesh.end(); SubIt++ ) - if (!SubIt->second->IsComplexSubmesh() && SubIt->second->Contains( n )) - subMesh = SubIt->second; - - RemoveFreeNode( n, subMesh, true); + RemoveFreeNode( n, 0, true ); return; } - + myScript->RemoveNode(n->GetID()); - + list removedElems; list removedNodes; SMDS_Mesh::RemoveElement( n, removedElems, removedNodes, true ); - removeFromContainers( myShapeIndexToSubMesh, myGroups, removedElems, false ); - removeFromContainers( myShapeIndexToSubMesh, myGroups, removedNodes, true ); + removeFromContainers( this, myGroups, removedElems, false ); + removeFromContainers( this, myGroups, removedNodes, true ); } //======================================================================= @@ -738,15 +925,16 @@ void SMESHDS_Mesh::RemoveFreeNode(const SMDS_MeshNode * n, set::iterator GrIt = myGroups.begin(); for (; GrIt != myGroups.end(); GrIt++) { SMESHDS_Group* group = dynamic_cast(*GrIt); - if (!group || group->IsEmpty()) continue; - group->SMDSGroup().Remove(n); + if (group && !group->IsEmpty()) + group->SMDSGroup().Remove(n); } } // Rm from sub-mesh // Node should belong to only one sub-mesh - if( subMesh ) - subMesh->RemoveNode(n,/*deleted=*/false); + if ( !subMesh || !subMesh->RemoveNode(n,/*deleted=*/false)) + if (( subMesh = MeshElements( n->getshapeId() ))) + subMesh->RemoveNode(n,/*deleted=*/false ); SMDS_Mesh::RemoveFreeElement(n); } @@ -755,7 +943,7 @@ void SMESHDS_Mesh::RemoveFreeNode(const SMDS_MeshNode * n, //function : RemoveElement //purpose : //======================================================================== -void SMESHDS_Mesh::RemoveElement(const SMDS_MeshElement * elt, bool removenodes) +void SMESHDS_Mesh::RemoveElement(const SMDS_MeshElement * elt) { if (elt->GetType() == SMDSAbs_Node) { @@ -765,12 +953,10 @@ void SMESHDS_Mesh::RemoveElement(const SMDS_MeshElement * elt, bool removenodes) if (!hasConstructionEdges() && !hasConstructionFaces()) { SMESHDS_SubMesh* subMesh=0; - map::iterator SubIt = myShapeIndexToSubMesh.begin(); - for ( ; !subMesh && SubIt != myShapeIndexToSubMesh.end(); SubIt++ ) - if (!SubIt->second->IsComplexSubmesh() && SubIt->second->Contains( elt )) - subMesh = SubIt->second; + if ( elt->getshapeId() > 0 ) + subMesh = MeshElements( elt->getshapeId() ); - RemoveFreeElement( elt, subMesh, true); + RemoveFreeElement( elt, subMesh, true ); return; } @@ -779,18 +965,9 @@ void SMESHDS_Mesh::RemoveElement(const SMDS_MeshElement * elt, bool removenodes) list removedElems; list removedNodes; - SMDS_Mesh::RemoveElement(elt, removedElems, removedNodes, removenodes); + SMDS_Mesh::RemoveElement(elt, removedElems, removedNodes, false ); - removeFromContainers( myShapeIndexToSubMesh, myGroups, removedElems, removenodes ); -} - -//======================================================================= -//function : RemoveFreeElement -//purpose : -//======================================================================= -void SMESHDS_Mesh::RemoveFreeElement(const SMDS_MeshElement * elt) -{ - RemoveFreeElement (elt, 0); + removeFromContainers( this, myGroups, removedElems, false ); } //======================================================================= @@ -801,8 +978,9 @@ void SMESHDS_Mesh::RemoveFreeElement(const SMDS_MeshElement * elt, SMESHDS_SubMesh * subMesh, bool fromGroups) { + //MESSAGE(" --------------------------------> SMESHDS_Mesh::RemoveFreeElement " << subMesh << " " << fromGroups); if (elt->GetType() == SMDSAbs_Node) { - RemoveFreeNode( static_cast(elt), subMesh); + RemoveFreeNode( static_cast(elt), subMesh, fromGroups); return; } @@ -813,7 +991,7 @@ void SMESHDS_Mesh::RemoveFreeElement(const SMDS_MeshElement * elt, myScript->RemoveElement(elt->GetID()); // Rm from group - // Node can belong to several groups + // Element can belong to several groups if ( fromGroups && !myGroups.empty() ) { set::iterator GrIt = myGroups.begin(); for (; GrIt != myGroups.end(); GrIt++) { @@ -825,10 +1003,12 @@ void SMESHDS_Mesh::RemoveFreeElement(const SMDS_MeshElement * elt, // Rm from sub-mesh // Element should belong to only one sub-mesh - if( subMesh ) - subMesh->RemoveElement(elt, /*deleted=*/false); + if ( !subMesh && elt->getshapeId() > 0 ) + subMesh = MeshElements( elt->getshapeId() ); + if ( subMesh ) + subMesh->RemoveElement( elt, /*deleted=*/false ); - SMDS_Mesh::RemoveFreeElement(elt); + SMDS_Mesh::RemoveFreeElement( elt ); } //================================================================================ @@ -843,9 +1023,9 @@ void SMESHDS_Mesh::ClearMesh() SMDS_Mesh::Clear(); // clear submeshes - map::iterator sub, subEnd = myShapeIndexToSubMesh.end(); - for ( sub = myShapeIndexToSubMesh.begin(); sub != subEnd; ++sub ) - sub->second->Clear(); + SMESHDS_SubMeshIteratorPtr smIt = SubMeshes(); + while ( SMESHDS_SubMesh* sm = const_cast< SMESHDS_SubMesh* >( smIt->next() )) + sm->Clear(); // clear groups TGroups::iterator group, groupEnd = myGroups.end(); @@ -855,16 +1035,18 @@ void SMESHDS_Mesh::ClearMesh() g->Clear(); g->SetType( groupType ); } + else + { + (*group)->Extent(); // to free cashed elements in GroupOnFilter's + } } } //================================================================================ /*! * \brief return submesh by shape - * \param shape - the subshape + * \param shape - the sub-shape * \retval SMESHDS_SubMesh* - the found submesh - * - * search of submeshes is optimized */ //================================================================================ @@ -873,35 +1055,7 @@ SMESHDS_SubMesh* SMESHDS_Mesh::getSubmesh( const TopoDS_Shape & shape ) if ( shape.IsNull() ) return 0; - if ( !myCurSubShape.IsNull() && shape.IsSame( myCurSubShape )) - return myCurSubMesh; - - getSubmesh( ShapeToIndex( shape )); - myCurSubShape = shape; - return myCurSubMesh; -} - -//================================================================================ -/*! - * \brief return submesh by subshape index - * \param Index - the subshape index - * \retval SMESHDS_SubMesh* - the found submesh - * search of submeshes is optimized - */ -//================================================================================ - -SMESHDS_SubMesh* SMESHDS_Mesh::getSubmesh( const int Index ) -{ - //Update or build submesh - if ( Index != myCurSubID ) { - map::iterator it = myShapeIndexToSubMesh.find( Index ); - if ( it == myShapeIndexToSubMesh.end() ) - it = myShapeIndexToSubMesh.insert( make_pair(Index, new SMESHDS_SubMesh() )).first; - myCurSubMesh = it->second; - myCurSubID = Index; - myCurSubShape.Nullify(); // myCurSubShape no more corresponds to submesh - } - return myCurSubMesh; + return NewSubMesh( ShapeToIndex( shape )); } //================================================================================ @@ -924,77 +1078,67 @@ bool SMESHDS_Mesh::add(const SMDS_MeshElement* elem, SMESHDS_SubMesh* subMesh ) return false; } -namespace { - - //================================================================================ - /*! - * \brief Creates a node position in volume - */ - //================================================================================ - - inline SMDS_PositionPtr volumePosition(int volId) - { - SMDS_SpacePosition* pos = new SMDS_SpacePosition(); - pos->SetShapeId( volId ); - return SMDS_PositionPtr(pos); - } -} - //======================================================================= //function : SetNodeOnVolume //purpose : //======================================================================= -void SMESHDS_Mesh::SetNodeInVolume(SMDS_MeshNode * aNode, +void SMESHDS_Mesh::SetNodeInVolume(const SMDS_MeshNode* aNode, const TopoDS_Shell & S) { if ( add( aNode, getSubmesh(S) )) - aNode->SetPosition ( volumePosition( myCurSubID )); + const_cast< SMDS_MeshNode* > + ( aNode )->SetPosition( SMDS_SpacePosition::originSpacePosition() ); } + //======================================================================= //function : SetNodeOnVolume //purpose : //======================================================================= -void SMESHDS_Mesh::SetNodeInVolume(SMDS_MeshNode * aNode, +void SMESHDS_Mesh::SetNodeInVolume(const SMDS_MeshNode * aNode, const TopoDS_Solid & S) { if ( add( aNode, getSubmesh(S) )) - aNode->SetPosition ( volumePosition( myCurSubID )); + const_cast< SMDS_MeshNode* > + ( aNode )->SetPosition( SMDS_SpacePosition::originSpacePosition() ); } //======================================================================= //function : SetNodeOnFace //purpose : //======================================================================= -void SMESHDS_Mesh::SetNodeOnFace(SMDS_MeshNode * aNode, +void SMESHDS_Mesh::SetNodeOnFace(const SMDS_MeshNode * aNode, const TopoDS_Face & S, double u, double v) { if ( add( aNode, getSubmesh(S) )) - aNode->SetPosition(SMDS_PositionPtr(new SMDS_FacePosition(myCurSubID, u, v))); + const_cast< SMDS_MeshNode* > + ( aNode )->SetPosition(SMDS_PositionPtr(new SMDS_FacePosition( u, v))); } //======================================================================= //function : SetNodeOnEdge //purpose : //======================================================================= -void SMESHDS_Mesh::SetNodeOnEdge(SMDS_MeshNode * aNode, +void SMESHDS_Mesh::SetNodeOnEdge(const SMDS_MeshNode * aNode, const TopoDS_Edge & S, double u) { if ( add( aNode, getSubmesh(S) )) - aNode->SetPosition(SMDS_PositionPtr(new SMDS_EdgePosition(myCurSubID, u))); + const_cast< SMDS_MeshNode* > + ( aNode )->SetPosition(SMDS_PositionPtr(new SMDS_EdgePosition(u))); } //======================================================================= //function : SetNodeOnVertex //purpose : //======================================================================= -void SMESHDS_Mesh::SetNodeOnVertex(SMDS_MeshNode * aNode, +void SMESHDS_Mesh::SetNodeOnVertex(const SMDS_MeshNode * aNode, const TopoDS_Vertex & S) { if ( add( aNode, getSubmesh(S) )) - aNode->SetPosition(SMDS_PositionPtr(new SMDS_VertexPosition(myCurSubID))); + const_cast< SMDS_MeshNode* > + ( aNode )->SetPosition(SMDS_PositionPtr(new SMDS_VertexPosition())); } //======================================================================= @@ -1003,12 +1147,10 @@ void SMESHDS_Mesh::SetNodeOnVertex(SMDS_MeshNode * aNode, //======================================================================= void SMESHDS_Mesh::UnSetNodeOnShape(const SMDS_MeshNode* aNode) { - if ( (aNode!=NULL) && (aNode->GetPosition()!=NULL) ) { - map::iterator it = - myShapeIndexToSubMesh.find( aNode->GetPosition()->GetShapeId() ); - if ( it != myShapeIndexToSubMesh.end() ) - it->second->RemoveNode( aNode, /*deleted=*/false ); - } + int shapeId = aNode->getshapeId(); + if (shapeId > 0) + if ( SMESHDS_SubMesh* sm = MeshElements( shapeId )) + sm->RemoveNode(aNode, /*deleted=*/false); } //======================================================================= @@ -1028,14 +1170,12 @@ void SMESHDS_Mesh::SetMeshElementOnShape(const SMDS_MeshElement * anElement, void SMESHDS_Mesh::UnSetMeshElementOnShape(const SMDS_MeshElement * elem, const TopoDS_Shape & S) { - int Index = myIndexToShape.FindIndex(S); - - map::iterator it = myShapeIndexToSubMesh.find( Index ); - if ( it != myShapeIndexToSubMesh.end() ) { - if ( elem->GetType() == SMDSAbs_Node ) - it->second->RemoveNode( static_cast( elem ), /*deleted=*/false ); + if ( SMESHDS_SubMesh* sm = MeshElements( S )) + { + if (elem->GetType() == SMDSAbs_Node) + sm->RemoveNode(static_cast (elem), /*deleted=*/false); else - it->second->RemoveElement( elem, /*deleted=*/false ); + sm->RemoveElement(elem, /*deleted=*/false); } } @@ -1045,26 +1185,24 @@ void SMESHDS_Mesh::UnSetMeshElementOnShape(const SMDS_MeshElement * elem, //======================================================================= TopoDS_Shape SMESHDS_Mesh::ShapeToMesh() const { - return myShape; + return myShape; } //======================================================================= //function : IsGroupOfSubShapes -//purpose : return true if at least one subshape of theShape is a subshape +//purpose : return true if at least one sub-shape of theShape is a sub-shape // of myShape or theShape == myShape //======================================================================= bool SMESHDS_Mesh::IsGroupOfSubShapes (const TopoDS_Shape& theShape) const { - if ( myShape.IsSame( theShape )) + if ( myIndexToShape.Contains(theShape) ) return true; - for ( TopoDS_Iterator it( theShape ); it.More(); it.Next() ) { - if (myIndexToShape.Contains( it.Value() ) || - IsGroupOfSubShapes( it.Value() )) + for ( TopoDS_Iterator it( theShape ); it.More(); it.Next() ) + if (IsGroupOfSubShapes( it.Value() )) return true; - } - + return false; } @@ -1075,39 +1213,41 @@ bool SMESHDS_Mesh::IsGroupOfSubShapes (const TopoDS_Shape& theShape) const SMESHDS_SubMesh * SMESHDS_Mesh::MeshElements(const TopoDS_Shape & S) const { int Index = ShapeToIndex(S); - TShapeIndexToSubMesh::const_iterator anIter = myShapeIndexToSubMesh.find(Index); - if (anIter != myShapeIndexToSubMesh.end()) - return anIter->second; - else - return NULL; + return (SMESHDS_SubMesh *) ( Index ? mySubMeshHolder->Get( Index ) : 0 ); } /////////////////////////////////////////////////////////////////////////////// /// Return the sub mesh by Id of shape it is linked to /////////////////////////////////////////////////////////////////////////////// -SMESHDS_SubMesh * SMESHDS_Mesh::MeshElements(const int Index) +SMESHDS_SubMesh * SMESHDS_Mesh::MeshElements(const int Index) const { - TShapeIndexToSubMesh::const_iterator anIter = myShapeIndexToSubMesh.find(Index); - if (anIter != myShapeIndexToSubMesh.end()) - return anIter->second; - else - return NULL; + return const_cast< SMESHDS_SubMesh* >( mySubMeshHolder->Get( Index )); } //======================================================================= //function : SubMeshIndices //purpose : //======================================================================= -list SMESHDS_Mesh::SubMeshIndices() +list SMESHDS_Mesh::SubMeshIndices() const { list anIndices; - std::map::iterator anIter = myShapeIndexToSubMesh.begin(); - for (; anIter != myShapeIndexToSubMesh.end(); anIter++) { - anIndices.push_back((*anIter).first); - } + SMESHDS_SubMeshIteratorPtr smIt = SubMeshes(); + while ( const SMESHDS_SubMesh* sm = smIt->next() ) + anIndices.push_back( sm->GetID() ); + return anIndices; } +//======================================================================= +//function : SubMeshes +//purpose : +//======================================================================= + +SMESHDS_SubMeshIteratorPtr SMESHDS_Mesh::SubMeshes() const +{ + return SMESHDS_SubMeshIteratorPtr( mySubMeshHolder->GetIterator() ); +} + //======================================================================= //function : GetHypothesis //purpose : @@ -1116,20 +1256,35 @@ list SMESHDS_Mesh::SubMeshIndices() const list& SMESHDS_Mesh::GetHypothesis(const TopoDS_Shape & S) const { - if ( myShapeToHypothesis.IsBound( S.Oriented(TopAbs_FORWARD) ) ) // ignore orientation of S - return myShapeToHypothesis.Find( S.Oriented(TopAbs_FORWARD) ); + if ( myShapeToHypothesis.IsBound( S/*.Oriented(TopAbs_FORWARD)*/ ) ) // ignore orientation of S + return myShapeToHypothesis.Find( S/*.Oriented(TopAbs_FORWARD)*/ ); static list empty; return empty; } +//================================================================================ +/*! + * \brief returns true if the hypothesis is assigned to any sub-shape + */ +//================================================================================ + +bool SMESHDS_Mesh::IsUsedHypothesis(const SMESHDS_Hypothesis * H) const +{ + ShapeToHypothesis::Iterator s2h( myShapeToHypothesis ); + for ( ; s2h.More(); s2h.Next() ) + if ( std::find( s2h.Value().begin(), s2h.Value().end(), H ) != s2h.Value().end() ) + return true; + return false; +} + //======================================================================= //function : GetScript //purpose : //======================================================================= SMESHDS_Script* SMESHDS_Mesh::GetScript() { - return myScript; + return myScript; } //======================================================================= @@ -1138,18 +1293,17 @@ SMESHDS_Script* SMESHDS_Mesh::GetScript() //======================================================================= void SMESHDS_Mesh::ClearScript() { - myScript->Clear(); + myScript->Clear(); } //======================================================================= //function : HasMeshElements //purpose : //======================================================================= -bool SMESHDS_Mesh::HasMeshElements(const TopoDS_Shape & S) +bool SMESHDS_Mesh::HasMeshElements(const TopoDS_Shape & S) const { - if (myShape.IsNull()) MESSAGE("myShape is NULL"); - int Index = myIndexToShape.FindIndex(S); - return myShapeIndexToSubMesh.find(Index)!=myShapeIndexToSubMesh.end(); + int Index = myIndexToShape.FindIndex(S); + return mySubMeshHolder->Get( Index ); } //======================================================================= @@ -1158,7 +1312,7 @@ bool SMESHDS_Mesh::HasMeshElements(const TopoDS_Shape & S) //======================================================================= bool SMESHDS_Mesh::HasHypothesis(const TopoDS_Shape & S) { - return myShapeToHypothesis.IsBound(S.Oriented(TopAbs_FORWARD)); + return myShapeToHypothesis.IsBound(S/*.Oriented(TopAbs_FORWARD)*/); } //======================================================================= @@ -1167,15 +1321,12 @@ bool SMESHDS_Mesh::HasHypothesis(const TopoDS_Shape & S) //======================================================================= SMESHDS_SubMesh * SMESHDS_Mesh::NewSubMesh(int Index) { - SMESHDS_SubMesh* SM = 0; - TShapeIndexToSubMesh::iterator anIter = myShapeIndexToSubMesh.find(Index); - if (anIter == myShapeIndexToSubMesh.end()) + SMESHDS_SubMesh* SM = MeshElements( Index ); + if ( !SM ) { - SM = new SMESHDS_SubMesh(); - myShapeIndexToSubMesh[Index]=SM; + SM = new SMESHDS_SubMesh(this, Index); + mySubMeshHolder->Add( Index, SM ); } - else - SM = anIter->second; return SM; } @@ -1188,7 +1339,7 @@ int SMESHDS_Mesh::AddCompoundSubmesh(const TopoDS_Shape& S, TopAbs_ShapeEnum type) { int aMainIndex = 0; - if ( IsGroupOfSubShapes( S ) || (S.ShapeType() == TopAbs_VERTEX && myIndexToShape.Contains(S)) ) + if ( IsGroupOfSubShapes( S )) { aMainIndex = myIndexToShape.Add( S ); bool all = ( type == TopAbs_SHAPE ); @@ -1221,7 +1372,27 @@ int SMESHDS_Mesh::AddCompoundSubmesh(const TopoDS_Shape& S, //======================================================================= const TopoDS_Shape& SMESHDS_Mesh::IndexToShape(int ShapeIndex) const { - return myIndexToShape.FindKey(ShapeIndex); + try + { + if ( ShapeIndex > 0 ) + return myIndexToShape.FindKey(ShapeIndex); + } + catch ( Standard_OutOfRange ) + { + } + static TopoDS_Shape nullShape; + return nullShape; +} + +//================================================================================ +/*! + * \brief Return max index of sub-mesh + */ +//================================================================================ + +int SMESHDS_Mesh::MaxSubMeshIndex() const +{ + return mySubMeshHolder->GetMaxID(); } //======================================================================= @@ -1244,43 +1415,46 @@ int SMESHDS_Mesh::ShapeToIndex(const TopoDS_Shape & S) const //======================================================================= void SMESHDS_Mesh::SetNodeInVolume(const SMDS_MeshNode* aNode, int Index) { - if ( add( aNode, getSubmesh( Index ))) - ((SMDS_MeshNode*) aNode)->SetPosition( volumePosition( Index )); + if ( add( aNode, NewSubMesh( Index ))) + ((SMDS_MeshNode*) aNode)->SetPosition( SMDS_SpacePosition::originSpacePosition()); } //======================================================================= //function : SetNodeOnFace //purpose : //======================================================================= -void SMESHDS_Mesh::SetNodeOnFace(SMDS_MeshNode* aNode, int Index, double u, double v) +void SMESHDS_Mesh::SetNodeOnFace(const SMDS_MeshNode* aNode, int Index, double u, double v) { //Set Position on Node - if ( add( aNode, getSubmesh( Index ))) - aNode->SetPosition(SMDS_PositionPtr(new SMDS_FacePosition(Index, u, v))); + if ( add( aNode, NewSubMesh( Index ))) + const_cast< SMDS_MeshNode* > + ( aNode )->SetPosition(SMDS_PositionPtr(new SMDS_FacePosition( u, v))); } //======================================================================= //function : SetNodeOnEdge //purpose : //======================================================================= -void SMESHDS_Mesh::SetNodeOnEdge(SMDS_MeshNode* aNode, - int Index, - double u) +void SMESHDS_Mesh::SetNodeOnEdge(const SMDS_MeshNode* aNode, + int Index, + double u) { //Set Position on Node - if ( add( aNode, getSubmesh( Index ))) - aNode->SetPosition(SMDS_PositionPtr(new SMDS_EdgePosition(Index, u))); + if ( add( aNode, NewSubMesh( Index ))) + const_cast< SMDS_MeshNode* > + ( aNode )->SetPosition(SMDS_PositionPtr(new SMDS_EdgePosition(u))); } //======================================================================= //function : SetNodeOnVertex //purpose : //======================================================================= -void SMESHDS_Mesh::SetNodeOnVertex(SMDS_MeshNode* aNode, int Index) +void SMESHDS_Mesh::SetNodeOnVertex(const SMDS_MeshNode* aNode, int Index) { //Set Position on Node - if ( add( aNode, getSubmesh( Index ))) - aNode->SetPosition(SMDS_PositionPtr(new SMDS_VertexPosition(Index))); + if ( add( aNode, NewSubMesh( Index ))) + const_cast< SMDS_MeshNode* > + ( aNode )->SetPosition(SMDS_PositionPtr(new SMDS_VertexPosition())); } //======================================================================= @@ -1290,7 +1464,7 @@ void SMESHDS_Mesh::SetNodeOnVertex(SMDS_MeshNode* aNode, int Index) void SMESHDS_Mesh::SetMeshElementOnShape(const SMDS_MeshElement* anElement, int Index) { - add( anElement, getSubmesh( Index )); + add( anElement, NewSubMesh( Index )); } //======================================================================= @@ -1302,9 +1476,7 @@ SMESHDS_Mesh::~SMESHDS_Mesh() // myScript delete myScript; // submeshes - TShapeIndexToSubMesh::iterator i_sm = myShapeIndexToSubMesh.begin(); - for ( ; i_sm != myShapeIndexToSubMesh.end(); ++i_sm ) - delete i_sm->second; + delete mySubMeshHolder; } @@ -1337,8 +1509,8 @@ SMDS_MeshEdge* SMESHDS_Mesh::AddEdge(const SMDS_MeshNode* n1, { SMDS_MeshEdge* anElem = SMDS_Mesh::AddEdge(n1,n2,n12); if(anElem) myScript->AddEdge(anElem->GetID(), - n1->GetID(), - n2->GetID(), + n1->GetID(), + n2->GetID(), n12->GetID()); return anElem; } @@ -1353,9 +1525,9 @@ SMDS_MeshEdge* SMESHDS_Mesh::AddEdgeWithID(const SMDS_MeshNode * n1, int ID) { return AddEdgeWithID(n1->GetID(), - n2->GetID(), + n2->GetID(), n12->GetID(), - ID); + ID); } @@ -1372,7 +1544,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, { SMDS_MeshFace *anElem = SMDS_Mesh::AddFace(n1,n2,n3,n12,n23,n31); if(anElem) myScript->AddFace(anElem->GetID(), - n1->GetID(), n2->GetID(), n3->GetID(), + n1->GetID(), n2->GetID(), n3->GetID(), n12->GetID(), n23->GetID(), n31->GetID()); return anElem; } @@ -1403,7 +1575,57 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, { return AddFaceWithID(n1->GetID(), n2->GetID(), n3->GetID(), n12->GetID(), n23->GetID(), n31->GetID(), - ID); + ID); +} + +//======================================================================= +//function : AddFace +//purpose : +//======================================================================= +SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31, + const SMDS_MeshNode * nCenter) +{ + SMDS_MeshFace *anElem = SMDS_Mesh::AddFace(n1,n2,n3,n12,n23,n31,nCenter); + if(anElem) myScript->AddFace(anElem->GetID(), + n1->GetID(), n2->GetID(), n3->GetID(), + n12->GetID(), n23->GetID(), n31->GetID(), + nCenter->GetID()); + return anElem; +} + +//======================================================================= +//function : AddFaceWithID +//purpose : +//======================================================================= +SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(int n1, int n2, int n3, + int n12,int n23,int n31, int nCenter, int ID) +{ + SMDS_MeshFace *anElem = SMDS_Mesh::AddFaceWithID(n1,n2,n3,n12,n23,n31,nCenter,ID); + if(anElem) myScript->AddFace(ID,n1,n2,n3,n12,n23,n31,nCenter); + return anElem; +} + +//======================================================================= +//function : AddFaceWithID +//purpose : +//======================================================================= +SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n31, + const SMDS_MeshNode * nCenter, + int ID) +{ + return AddFaceWithID(n1->GetID(), n2->GetID(), n3->GetID(), + n12->GetID(), n23->GetID(), n31->GetID(), + nCenter->GetID(), ID); } @@ -1422,7 +1644,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, { SMDS_MeshFace *anElem = SMDS_Mesh::AddFace(n1,n2,n3,n4,n12,n23,n34,n41); if(anElem) myScript->AddFace(anElem->GetID(), - n1->GetID(), n2->GetID(), n3->GetID(), n4->GetID(), + n1->GetID(), n2->GetID(), n3->GetID(), n4->GetID(), n12->GetID(), n23->GetID(), n34->GetID(), n41->GetID()); return anElem; } @@ -1455,7 +1677,63 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, { return AddFaceWithID(n1->GetID(), n2->GetID(), n3->GetID(), n4->GetID(), n12->GetID(), n23->GetID(), n34->GetID(), n41->GetID(), - ID); + ID); +} + + +//======================================================================= +//function : AddFace +//purpose : +//======================================================================= +SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * nCenter) +{ + SMDS_MeshFace *anElem = SMDS_Mesh::AddFace(n1,n2,n3,n4,n12,n23,n34,n41,nCenter); + if(anElem) myScript->AddFace(anElem->GetID(), + n1->GetID(), n2->GetID(), n3->GetID(), n4->GetID(), + n12->GetID(), n23->GetID(), n34->GetID(), n41->GetID(), + nCenter->GetID()); + return anElem; +} + +//======================================================================= +//function : AddFaceWithID +//purpose : +//======================================================================= +SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(int n1, int n2, int n3, int n4, + int n12,int n23,int n34,int n41, + int nCenter, int ID) +{ + SMDS_MeshFace *anElem = SMDS_Mesh::AddFaceWithID(n1,n2,n3,n4,n12,n23,n34,n41,nCenter,ID); + if(anElem) myScript->AddFace(ID,n1,n2,n3,n4,n12,n23,n34,n41,nCenter); + return anElem; +} + +//======================================================================= +//function : AddFaceWithID +//purpose : +//======================================================================= +SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * nCenter, + int ID) +{ + return AddFaceWithID(n1->GetID(), n2->GetID(), n3->GetID(), n4->GetID(), + n12->GetID(), n23->GetID(), n34->GetID(), n41->GetID(), + nCenter->GetID(), ID); } @@ -1476,8 +1754,8 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, { SMDS_MeshVolume *anElem = SMDS_Mesh::AddVolume(n1,n2,n3,n4,n12,n23,n31,n14,n24,n34); if(anElem) myScript->AddVolume(anElem->GetID(), - n1->GetID(), n2->GetID(), n3->GetID(), n4->GetID(), - n12->GetID(), n23->GetID(), n31->GetID(), + n1->GetID(), n2->GetID(), n3->GetID(), n4->GetID(), + n12->GetID(), n23->GetID(), n31->GetID(), n14->GetID(), n24->GetID(), n34->GetID()); return anElem; } @@ -1495,7 +1773,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, int n4, if(anElem) myScript->AddVolume(ID,n1,n2,n3,n4,n12,n23,n31,n14,n24,n34); return anElem; } - + //======================================================================= //function : AddVolumeWithID //purpose : 2d order tetrahedron of 10 nodes @@ -1561,7 +1839,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, int n4, i n15,n25,n35,n45); return anElem; } - + //======================================================================= //function : AddVolumeWithID //purpose : 2d order pyramid of 13 nodes @@ -1638,7 +1916,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, n45,n56,n64,n14,n25,n36); return anElem; } - + //======================================================================= //function : AddVolumeWithID //purpose : 2d order Pentahedron with 15 nodes @@ -1671,7 +1949,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, //======================================================================= //function : AddVolume -//purpose : +//purpose : add quadratic hexahedron //======================================================================= SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, @@ -1726,7 +2004,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, int n4, n56,n67,n78,n85,n15,n26,n37,n48); return anElem; } - + //======================================================================= //function : AddVolumeWithID //purpose : 2d order Hexahedrons with 20 nodes @@ -1761,4 +2039,290 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, ID); } +//======================================================================= +//function : AddVolume +//purpose : add tri-quadratic hexahedron of 27 nodes +//======================================================================= +SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * n56, + const SMDS_MeshNode * n67, + const SMDS_MeshNode * n78, + const SMDS_MeshNode * n85, + const SMDS_MeshNode * n15, + const SMDS_MeshNode * n26, + const SMDS_MeshNode * n37, + const SMDS_MeshNode * n48, + const SMDS_MeshNode * n1234, + const SMDS_MeshNode * n1256, + const SMDS_MeshNode * n2367, + const SMDS_MeshNode * n3478, + const SMDS_MeshNode * n1458, + const SMDS_MeshNode * n5678, + const SMDS_MeshNode * nCenter) +{ + SMDS_MeshVolume *anElem = SMDS_Mesh::AddVolume(n1,n2,n3,n4,n5,n6,n7,n8, + n12,n23,n34,n41, + n56,n67,n78,n85, + n15,n26,n37,n48, + n1234,n1256,n2367,n3478,n1458,n5678,nCenter); + if(anElem) + myScript->AddVolume(anElem->GetID(), n1->GetID(), n2->GetID(), + n3->GetID(), n4->GetID(), n5->GetID(), + n6->GetID(), n7->GetID(), n8->GetID(), + n12->GetID(), n23->GetID(), n34->GetID(), n41->GetID(), + n56->GetID(), n67->GetID(), n78->GetID(), n85->GetID(), + n15->GetID(), n26->GetID(), n37->GetID(), n48->GetID(), + n1234->GetID(),n1256->GetID(),n2367->GetID(),n3478->GetID(), + n1458->GetID(),n5678->GetID(),nCenter->GetID()); + return anElem; +} + +SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(int n1, int n2, int n3, int n4, + int n5, int n6, int n7, int n8, + int n12,int n23,int n34,int n41, + int n56,int n67,int n78,int n85, + int n15,int n26,int n37,int n48, + int n1234,int n1256,int n2367,int n3478, + int n1458,int n5678,int nCenter, + int ID) +{ + SMDS_MeshVolume *anElem = SMDS_Mesh::AddVolumeWithID(n1,n2,n3,n4,n5,n6,n7,n8, + n12,n23,n34,n41, + n56,n67,n78,n85, + n15,n26,n37,n48, + n1234, n1256, n2367, n3478, + n1458, n5678, nCenter, + ID); + if(anElem) myScript->AddVolume(ID,n1,n2,n3,n4,n5,n6,n7,n8,n12,n23,n34,n41, + n56,n67,n78,n85,n15,n26,n37,n48, + n1234, n1256, n2367, n3478, + n1458, n5678, nCenter); + return anElem; +} + +SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n3, + const SMDS_MeshNode * n4, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, + const SMDS_MeshNode * n7, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n12, + const SMDS_MeshNode * n23, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * n56, + const SMDS_MeshNode * n67, + const SMDS_MeshNode * n78, + const SMDS_MeshNode * n85, + const SMDS_MeshNode * n15, + const SMDS_MeshNode * n26, + const SMDS_MeshNode * n37, + const SMDS_MeshNode * n48, + const SMDS_MeshNode * n1234, + const SMDS_MeshNode * n1256, + const SMDS_MeshNode * n2367, + const SMDS_MeshNode * n3478, + const SMDS_MeshNode * n1458, + const SMDS_MeshNode * n5678, + const SMDS_MeshNode * nCenter, + int ID) +{ + return AddVolumeWithID(n1->GetID(), n2->GetID(), n3->GetID(), n4->GetID(), + n5->GetID(), n6->GetID(), n7->GetID(), n8->GetID(), + n12->GetID(), n23->GetID(), n34->GetID(), n41->GetID(), + n56->GetID(), n67->GetID(), n78->GetID(), n85->GetID(), + n15->GetID(), n26->GetID(), n37->GetID(), n48->GetID(), + n1234->GetID(),n1256->GetID(),n2367->GetID(),n3478->GetID(), + n1458->GetID(),n5678->GetID(),nCenter->GetID(), ID); +} + +void SMESHDS_Mesh::compactMesh() +{ + int newNodeSize = 0; + int nbNodes = myNodes.size(); + int nbVtkNodes = myGrid->GetNumberOfPoints(); + MESSAGE("nbNodes=" << nbNodes << " nbVtkNodes=" << nbVtkNodes); + int nbNodeTemp = nbVtkNodes; + if (nbNodes > nbVtkNodes) + nbNodeTemp = nbNodes; + vector idNodesOldToNew; + idNodesOldToNew.clear(); + idNodesOldToNew.resize(nbNodeTemp, -1); // all unused id will be -1 + + for (int i = 0; i < nbNodes; i++) + { + if (myNodes[i]) + { + int vtkid = myNodes[i]->getVtkId(); + idNodesOldToNew[vtkid] = i; // old vtkId --> old smdsId (valid smdsId are >= 0) + newNodeSize++; + } + } + bool areNodesModified = (newNodeSize < nbVtkNodes); + MESSAGE("------------------------- compactMesh Nodes Modified: " << areNodesModified); + areNodesModified = true; + + int newCellSize = 0; + int nbCells = myCells.size(); + int nbVtkCells = myGrid->GetNumberOfCells(); + MESSAGE("nbCells=" << nbCells << " nbVtkCells=" << nbVtkCells); + int nbCellTemp = nbVtkCells; + if (nbCells > nbVtkCells) + nbCellTemp = nbCells; + vector idCellsOldToNew; + idCellsOldToNew.clear(); + idCellsOldToNew.resize(nbCellTemp, -1); // all unused id will be -1 + + for (int i = 0; i < nbCells; i++) + { + if (myCells[i]) + { +// //idCellsOldToNew[i] = myCellIdVtkToSmds[i]; // valid vtk indexes are > = 0 +// int vtkid = myCells[i]->getVtkId(); +// idCellsOldToNew[vtkid] = i; // old vtkId --> old smdsId (not used in input) + newCellSize++; + } + } + if (areNodesModified) + myGrid->compactGrid(idNodesOldToNew, newNodeSize, idCellsOldToNew, newCellSize); + else + myGrid->compactGrid(idNodesOldToNew, 0, idCellsOldToNew, newCellSize); + + int nbVtkPts = myGrid->GetNumberOfPoints(); + nbVtkCells = myGrid->GetNumberOfCells(); + if (nbVtkPts != newNodeSize) + { + MESSAGE("===> nbVtkPts != newNodeSize " << nbVtkPts << " " << newNodeSize); + if (nbVtkPts > newNodeSize) newNodeSize = nbVtkPts; // several points with same SMDS Id + } + if (nbVtkCells != newCellSize) + { + MESSAGE("===> nbVtkCells != newCellSize " << nbVtkCells << " " << newCellSize); + if (nbVtkCells > newCellSize) newCellSize = nbVtkCells; // several cells with same SMDS Id + } + + // --- SMDS_MeshNode and myNodes (id in SMDS and in VTK are the same), myNodeIdFactory + + if (areNodesModified) + { + MESSAGE("-------------- modify myNodes"); + SetOfNodes newNodes; + newNodes.resize(newNodeSize+1,0); // 0 not used, SMDS numbers 1..n + int newSmdsId = 0; + for (int i = 0; i < nbNodes; i++) + { + if (myNodes[i]) + { + newSmdsId++; // SMDS id start to 1 + int oldVtkId = myNodes[i]->getVtkId(); + int newVtkId = idNodesOldToNew[oldVtkId]; + //MESSAGE("myNodes["<< i << "] vtkId " << oldVtkId << " --> " << newVtkId); + myNodes[i]->setVtkId(newVtkId); + myNodes[i]->setId(newSmdsId); + newNodes[newSmdsId] = myNodes[i]; + //MESSAGE("myNodes["<< i << "] --> newNodes[" << newSmdsId << "]"); + } + } + myNodes.swap(newNodes); + this->myNodeIDFactory->emptyPool(newSmdsId); // newSmdsId = number of nodes + MESSAGE("myNodes.size " << myNodes.size()); + } + + // --- SMDS_MeshCell, myCellIdVtkToSmds, myCellIdSmdsToVtk, myCells + + int vtkIndexSize = myCellIdVtkToSmds.size(); + int maxVtkId = -1; + for (int oldVtkId = 0; oldVtkId < vtkIndexSize; oldVtkId++) + { + int oldSmdsId = this->myCellIdVtkToSmds[oldVtkId]; + if (oldSmdsId > 0) + { + int newVtkId = idCellsOldToNew[oldVtkId]; + if (newVtkId > maxVtkId) + maxVtkId = newVtkId; + //MESSAGE("myCells["<< oldSmdsId << "] vtkId " << oldVtkId << " --> " << newVtkId); + myCells[oldSmdsId]->setVtkId(newVtkId); + } + } +// MESSAGE("myCells.size()=" << myCells.size() +// << " myCellIdSmdsToVtk.size()=" << myCellIdSmdsToVtk.size() +// << " myCellIdVtkToSmds.size()=" << myCellIdVtkToSmds.size() ); + + SetOfCells newCells; + //vector newSmdsToVtk; + vector newVtkToSmds; + + assert(maxVtkId < newCellSize); + newCells.resize(newCellSize+1, 0); // 0 not used, SMDS numbers 1..n + //newSmdsToVtk.resize(newCellSize+1, -1); + newVtkToSmds.resize(newCellSize+1, -1); + + int myCellsSize = myCells.size(); + int newSmdsId = 0; + for (int i = 0; i < myCellsSize; i++) + { + if ( myCells[i] ) + { + newSmdsId++; // SMDS id start to 1 + assert(newSmdsId <= newCellSize); + newCells[newSmdsId] = myCells[i]; + newCells[newSmdsId]->setId(newSmdsId); + //MESSAGE("myCells["<< i << "] --> newCells[" << newSmdsId << "]"); + int idvtk = myCells[i]->getVtkId(); + //newSmdsToVtk[newSmdsId] = idvtk; + assert(idvtk < newCellSize); + newVtkToSmds[idvtk] = newSmdsId; + } + } + + myCells.swap(newCells); + //myCellIdSmdsToVtk.swap(newSmdsToVtk); + myCellIdVtkToSmds.swap(newVtkToSmds); + MESSAGE("myCells.size()=" << myCells.size() + << " myCellIdVtkToSmds.size()=" << myCellIdVtkToSmds.size() ); + this->myElementIDFactory->emptyPool(newSmdsId); + + this->myScript->SetModified(true); // notify GUI client for buildPrs when update + + // --- compact list myNodes and myElements in submeshes + + SMESHDS_SubMeshIteratorPtr smIt = SubMeshes(); + while ( SMESHDS_SubMesh* sm = const_cast< SMESHDS_SubMesh* >( smIt->next() )) + sm->compactList(); +} + +void SMESHDS_Mesh::CleanDownWardConnectivity() +{ + myGrid->CleanDownwardConnectivity(); +} + +void SMESHDS_Mesh::BuildDownWardConnectivity(bool withEdges) +{ + myGrid->BuildDownwardConnectivity(withEdges); +} + +/*! change some nodes in cell without modifying type or internal connectivity. + * Nodes inverse connectivity is maintained up to date. + * @param vtkVolId vtk id of the cell. + * @param localClonedNodeIds map old node id to new node id. + * @return ok if success. + */ +bool SMESHDS_Mesh::ModifyCellNodes(int vtkVolId, std::map localClonedNodeIds) +{ + myGrid->ModifyCellNodes(vtkVolId, localClonedNodeIds); + return true; +} diff --git a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Script.cpp b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Script.cpp index 9b6daa8b1a53..f912b7682fbc 100644 --- a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Script.cpp +++ b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_Script.cpp @@ -1,31 +1,32 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESH_Script.cxx // Author : Yves FRICAUD, OCC // Module : SMESH -// $Header: // #include "SMESHDS_Script.hxx" +#include using namespace std; @@ -35,7 +36,9 @@ using namespace std; //======================================================================= SMESHDS_Script::SMESHDS_Script(bool theIsEmbeddedMode): myIsEmbeddedMode(theIsEmbeddedMode) -{} +{ + //cerr << "=========================== myIsEmbeddedMode " << myIsEmbeddedMode << endl; +} //======================================================================= //function : Destructor @@ -95,6 +98,19 @@ void SMESHDS_Script::AddNode(int NewNodeID, double x, double y, double z) getCommand(SMESHDS_AddNode)->AddNode(NewNodeID, x, y, z); } +//======================================================================= +//function : +//purpose : +//======================================================================= +void SMESHDS_Script::Add0DElement (int New0DElementID, int idnode) +{ + if (myIsEmbeddedMode) { + myIsModified = true; + return; + } + getCommand(SMESHDS_Add0DElement)->Add0DElement(New0DElementID, idnode); +} + //======================================================================= //function : //purpose : @@ -208,11 +224,29 @@ void SMESHDS_Script::AddVolume(int NewID, idnode5, idnode6, idnode7, idnode8); } +//======================================================================= +//function : +//purpose : +//======================================================================= +void SMESHDS_Script::AddVolume(int NewVolID, int idnode1, int idnode2, int idnode3, + int idnode4, int idnode5, int idnode6, int idnode7, int idnode8, + int idnode9, int idnode10, int idnode11, int idnode12) +{ + if(myIsEmbeddedMode){ + myIsModified = true; + return; + } + getCommand(SMESHDS_AddHexagonalPrism)->AddVolume(NewVolID, + idnode1, idnode2, idnode3, idnode4, + idnode5, idnode6, idnode7, idnode8, + idnode9, idnode10, idnode11, idnode12); +} + //======================================================================= //function : AddPolygonalFace //purpose : //======================================================================= -void SMESHDS_Script::AddPolygonalFace (int NewFaceID, std::vector nodes_ids) +void SMESHDS_Script::AddPolygonalFace (int NewFaceID, const std::vector& nodes_ids) { if(myIsEmbeddedMode){ myIsModified = true; @@ -221,13 +255,26 @@ void SMESHDS_Script::AddPolygonalFace (int NewFaceID, std::vector nodes_ids getCommand(SMESHDS_AddPolygon)->AddPolygonalFace(NewFaceID, nodes_ids); } +//======================================================================= +//function : AddQuadPolygonalFace +//purpose : +//======================================================================= +void SMESHDS_Script::AddQuadPolygonalFace(int NewFaceID, const std::vector& nodes_ids) +{ + if(myIsEmbeddedMode){ + myIsModified = true; + return; + } + getCommand(SMESHDS_AddQuadPolygon)->AddQuadPolygonalFace(NewFaceID, nodes_ids); +} + //======================================================================= //function : AddPolyhedralVolume //purpose : //======================================================================= -void SMESHDS_Script::AddPolyhedralVolume (int NewID, - std::vector nodes_ids, - std::vector quantities) +void SMESHDS_Script::AddPolyhedralVolume (int NewID, + const std::vector& nodes_ids, + const std::vector& quantities) { if(myIsEmbeddedMode){ myIsModified = true; @@ -237,6 +284,19 @@ void SMESHDS_Script::AddPolyhedralVolume (int NewID, (NewID, nodes_ids, quantities); } +//======================================================================= +//function : AddBall +//purpose : Record adding a Ball +//======================================================================= + +void SMESHDS_Script::AddBall(int NewBallID, int node, double diameter) +{ + if ( myIsEmbeddedMode ) + myIsModified = true; + else + getCommand(SMESHDS_AddBall)->AddBall(NewBallID, node, diameter); +} + //======================================================================= //function : //purpose : @@ -294,9 +354,9 @@ void SMESHDS_Script::ChangeElementNodes(int ElementID, int nodes[], int nbnodes) //function : ChangePolyhedronNodes //purpose : //======================================================================= -void SMESHDS_Script::ChangePolyhedronNodes (const int ElementID, - std::vector nodes_ids, - std::vector quantities) +void SMESHDS_Script::ChangePolyhedronNodes (const int ElementID, + const std::vector& nodes_ids, + const std::vector& quantities) { if(myIsEmbeddedMode){ myIsModified = true; @@ -388,6 +448,21 @@ void SMESHDS_Script::AddFace(int NewFaceID, int n1, int n2, int n3, n12, n23, n31); } +//======================================================================= +//function : AddFace +//purpose : +//======================================================================= +void SMESHDS_Script::AddFace(int NewFaceID, int n1, int n2, int n3, + int n12, int n23, int n31, int nCenter) +{ + if(myIsEmbeddedMode){ + myIsModified = true; + return; + } + getCommand(SMESHDS_AddBiQuadTriangle)->AddFace(NewFaceID, n1, n2, n3, + n12, n23, n31, nCenter); +} + //======================================================================= //function : AddFace //purpose : @@ -403,6 +478,21 @@ void SMESHDS_Script::AddFace(int NewFaceID, int n1, int n2, int n3, int n4, n12, n23, n34, n41); } +//======================================================================= +//function : AddFace +//purpose : +//======================================================================= +void SMESHDS_Script::AddFace(int NewFaceID, int n1, int n2, int n3, int n4, + int n12, int n23, int n34, int n41, int nCenter) +{ + if(myIsEmbeddedMode){ + myIsModified = true; + return; + } + getCommand(SMESHDS_AddBiQuadQuadrangle)->AddFace(NewFaceID, n1, n2, n3, n4, + n12, n23, n34, n41, nCenter); +} + //======================================================================= //function : AddVolume //purpose : @@ -477,3 +567,28 @@ void SMESHDS_Script::AddVolume(int NewVolID, int n1, int n2, int n3, n15, n26, n37, n48); } +//======================================================================= +//function : AddVolume +//purpose : +//======================================================================= +void SMESHDS_Script::AddVolume(int NewVolID, int n1, int n2, int n3, + int n4, int n5, int n6, int n7, int n8, + int n12, int n23, int n34, int n41, + int n56, int n67, int n78, int n85, + int n15, int n26, int n37, int n48, + int n1234,int n1256,int n2367,int n3478, + int n1458,int n5678,int nCenter) +{ + if(myIsEmbeddedMode){ + myIsModified = true; + return; + } + getCommand(SMESHDS_AddTriQuadHexa)->AddVolume(NewVolID, n1, n2, n3, n4, + n5, n6, n7, n8, + n12, n23, n34, n41, + n56, n67, n78, n85, + n15, n26, n37, n48, + n1234, n1256, n2367, n3478, + n1458, n5678, nCenter); +} + diff --git a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_SubMesh.cpp b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_SubMesh.cpp index 0013e54e162e..11dbb124a294 100644 --- a/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_SubMesh.cpp +++ b/src/3rdParty/salomesmesh/src/SMESHDS/SMESHDS_SubMesh.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESHDS : management of mesh data and SMESH document // File : SMESH_SubMesh.cxx // Author : Yves FRICAUD, OCC @@ -26,41 +27,128 @@ // $Header: // #include "SMESHDS_SubMesh.hxx" +#include "SMESHDS_Mesh.hxx" #include "utilities.h" #include "SMDS_SetIterator.hxx" +#include +#include using namespace std; + +//================================================================================ +/*! + * \brief Constructor + */ +//================================================================================ + +SMESHDS_SubMesh::SMESHDS_SubMesh(SMESHDS_Mesh *parent, int index) +{ + myParent = parent; + myIndex = index; + myUnusedIdNodes = 0; + myUnusedIdElements = 0; +} + +//================================================================================ +/*! + * \brief Destructor + */ +//================================================================================ + +SMESHDS_SubMesh::~SMESHDS_SubMesh() +{ +} + //======================================================================= //function : AddElement -//purpose : +//purpose : //======================================================================= + void SMESHDS_SubMesh::AddElement(const SMDS_MeshElement * ME) { - if ( !IsComplexSubmesh() ) - myElements.insert(ME); + if (!IsComplexSubmesh()) + { + if ( ME->GetType() == SMDSAbs_Node ) + { + AddNode( static_cast< const SMDS_MeshNode* >( ME )); + return; + } + int oldShapeId = ME->getshapeId(); + if ( oldShapeId > 0 ) + { + if (oldShapeId != myIndex) + { + throw SALOME_Exception + (LOCALIZED("add element in subshape already belonging to a subshape")); + } + int idInSubShape = ME->getIdInShape(); + if (idInSubShape >= 0) + { + MESSAGE("add element in subshape already belonging to that subshape " + << ME->GetID() << " " << oldShapeId << " " << idInSubShape); + // check if ok: do nothing if ok + if (idInSubShape >= (int)myElements.size()) + { + throw SALOME_Exception(LOCALIZED("out of bounds")); + } + if (ME != myElements[idInSubShape]) + { + throw SALOME_Exception(LOCALIZED("not the same element")); + } + return; + } + } + + SMDS_MeshElement* elem = (SMDS_MeshElement*) (ME); + elem->setShapeId(myIndex); + elem->setIdInShape(myElements.size()); + myElements.push_back(ME); + } } //======================================================================= //function : RemoveElement -//purpose : +//purpose : //======================================================================= + bool SMESHDS_SubMesh::RemoveElement(const SMDS_MeshElement * ME, bool isElemDeleted) { - if ( !IsComplexSubmesh() && NbElements() ) { - - if (!isElemDeleted) // alive element has valid ID and can be found - return myElements.erase(ME); - - TElemSet::iterator e = myElements.begin(), eEnd = myElements.end(); - for ( ; e != eEnd; ++e ) - if ( ME == *e ) { - myElements.erase( e ); - return true; + if (!ME) + { + return false; + } + if (!IsComplexSubmesh()) + { + if ( ME->getshapeId() != myIndex ) // elem not in a pool can loose it's data already + { + if ( isElemDeleted ) + for ( size_t i = 0; i < myElements.size(); ++i ) + if ( myElements[i] == ME ) + { + myElements[i] = 0; + ++myUnusedIdElements; + return true; + } + return false; + } + int idInSubShape = ME->getIdInShape(); + SMDS_MeshElement* elem = (SMDS_MeshElement*) (ME); + elem->setShapeId(0); + elem->setIdInShape(-1); + if ((idInSubShape >= 0) && (idInSubShape < (int) myElements.size())) + { + myElements[idInSubShape] = 0; // this vector entry is no more used + if ( ++myUnusedIdElements == (int) myElements.size() ) + { + clearVector( myElements ); + myUnusedIdElements = 0; } + return true; + } + return false; } - return false; } @@ -68,43 +156,79 @@ bool SMESHDS_SubMesh::RemoveElement(const SMDS_MeshElement * ME, bool isElemDele //function : AddNode //purpose : //======================================================================= + void SMESHDS_SubMesh::AddNode(const SMDS_MeshNode * N) { if ( !IsComplexSubmesh() ) - myNodes.insert(N); + { + const int idInSubShape = N->getIdInShape(); + const int shapeId = N->getshapeId(); + if ((shapeId > 0) && (idInSubShape >= 0)) + { + if ( shapeId != myIndex ) + throw SALOME_Exception + (LOCALIZED("a node being in sub-mesh is added to another sub-mesh")); + if ( idInSubShape >= (int)myNodes.size() || myNodes[ idInSubShape ] != N ) + throw SALOME_Exception + (LOCALIZED("a node with wrong idInSubShape is re-added to the same sub-mesh")); + return; // already in + } + SMDS_MeshNode* node = (SMDS_MeshNode*)(N); + node->setShapeId(myIndex); + node->setIdInShape(myNodes.size()); + myNodes.push_back(N); + } } //======================================================================= //function : RemoveNode -//purpose : +//purpose : //======================================================================= bool SMESHDS_SubMesh::RemoveNode(const SMDS_MeshNode * N, bool isNodeDeleted) { - if ( !IsComplexSubmesh() && NbNodes() ) { - - if (!isNodeDeleted) // alive node has valid ID and can be found - return myNodes.erase(N); - - TElemSet::iterator e = myNodes.begin(), eEnd = myNodes.end(); - for ( ; e != eEnd; ++e ) - if ( N == *e ) { - myNodes.erase( e ); - return true; + if (!IsComplexSubmesh()) + { + if ( N->getshapeId() != myIndex ) + { + if ( isNodeDeleted ) + for ( size_t i = 0; i < myNodes.size(); ++i ) + if ( myNodes[i] == N ) + { + myNodes[i] = 0; + ++myUnusedIdNodes; + return true; + } + return false; + } + int idInSubShape = N->getIdInShape(); + SMDS_MeshNode* node = (SMDS_MeshNode*) (N); + node->setShapeId(0); + node->setIdInShape(-1); + if ((idInSubShape >= 0) && (idInSubShape < (int) myNodes.size())) + { + myNodes[idInSubShape] = 0; // this vector entry is no more used + if ( ++myUnusedIdNodes == (int) myNodes.size() ) + { + clearVector( myNodes ); + myUnusedIdNodes = 0; } + return true; + } + return false; } - return false; } //======================================================================= //function : NbElements -//purpose : +//purpose : //======================================================================= + int SMESHDS_SubMesh::NbElements() const { if ( !IsComplexSubmesh() ) - return myElements.size(); + return myElements.size() - myUnusedIdElements; int nbElems = 0; set::const_iterator it = mySubMeshes.begin(); @@ -121,8 +245,8 @@ int SMESHDS_SubMesh::NbElements() const int SMESHDS_SubMesh::NbNodes() const { - if ( !IsComplexSubmesh() ) - return myNodes.size(); + if ( !IsComplexSubmesh() ) + return myNodes.size() - myUnusedIdNodes; int nbElems = 0; set::const_iterator it = mySubMeshes.begin(); @@ -132,18 +256,41 @@ int SMESHDS_SubMesh::NbNodes() const return nbElems; } -// ===================== -// class MySetIterator -// ===================== - -template class MySetIterator: - public SMDS_SetIterator +/*! + * template class used for iteration on submesh elements. Interface of iterator remains + * unchanged after redesign of SMDS to avoid modification everywhere in SMESH. + * instances are stored in shared_ptr for automatic destruction. + * Container is copied for iteration, because original can be modified + * by addition of elements, for instance, and then reallocated (vector) + */ +template class MySetIterator : public SMDS_Iterator { - typedef SMDS_SetIterator TFather; - public: - MySetIterator(const TSET& s):TFather(s.begin(),s.end()) - { - } +protected: + typename TSET::const_iterator _it, _end; + TSET _table; +public: + MySetIterator(const TSET& table) + { + _table = table; + _it = _table.begin(); + _end = _table.end(); + while ((_it != _end) && (*_it == 0)) + _it++; + } + + virtual bool more() + { + while ((_it != _end) && (*_it == 0)) + _it++; + return (_it != _end); + } + + virtual ELEM next() + { + ELEM e = *_it; + _it++; + return e; + } }; // ===================== @@ -154,7 +301,7 @@ template class MyIterator : public SMDS_Iterator { public: MyIterator (const set& theSubMeshes) - : mySubIt( theSubMeshes.begin() ), mySubEnd( theSubMeshes.end() ), myMore(false) + : myMore(false), mySubIt( theSubMeshes.begin() ), mySubEnd( theSubMeshes.end() ) {} bool more() { @@ -218,8 +365,7 @@ SMDS_ElemIteratorPtr SMESHDS_SubMesh::GetElements() const { if ( IsComplexSubmesh() ) return SMDS_ElemIteratorPtr( new MyElemIterator( mySubMeshes )); - - return SMDS_ElemIteratorPtr(new MySetIterator(myElements)); + return SMDS_ElemIteratorPtr(new MySetIterator >(myElements)); } //======================================================================= @@ -232,7 +378,7 @@ SMDS_NodeIteratorPtr SMESHDS_SubMesh::GetNodes() const if ( IsComplexSubmesh() ) return SMDS_NodeIteratorPtr( new MyNodeIterator( mySubMeshes )); - return SMDS_NodeIteratorPtr(new MySetIterator(myNodes)); + return SMDS_NodeIteratorPtr(new MySetIterator >(myNodes)); } //======================================================================= @@ -244,22 +390,56 @@ bool SMESHDS_SubMesh::Contains(const SMDS_MeshElement * ME) const { // DO NOT TRY TO FIND A REMOVED ELEMENT !! //if ( IsComplexSubmesh() || !ME ) - if (!ME ) + if (!ME) return false; if ( IsComplexSubmesh() ) { set::const_iterator aSubIt = mySubMeshes.begin(); - for ( ; aSubIt != mySubMeshes.end(); aSubIt++ ) - if ( (*aSubIt)->Contains( ME )) + for (; aSubIt != mySubMeshes.end(); aSubIt++) + if ((*aSubIt)->Contains(ME)) return true; return false; } - if ( ME->GetType() == SMDSAbs_Node ) - return ( myNodes.find( ME ) != myNodes.end() ); + if (ME->GetType() == SMDSAbs_Node) + { + int idInShape = ME->getIdInShape(); + if ((idInShape >= 0) && (idInShape < (int) myNodes.size())) + if (myNodes[idInShape] == ME) + return true; + } + else + { + int idInShape = ME->getIdInShape(); + if ((idInShape >= 0) && (idInShape < (int) myElements.size())) + if (myElements[idInShape] == ME) + return true; + } + return false; +} - return ( myElements.find( ME ) != myElements.end() ); +//======================================================================= +//function : IsQuadratic +//purpose : Return true if my 1st element is quadratic +//======================================================================= + +bool SMESHDS_SubMesh::IsQuadratic() const +{ + if ( IsComplexSubmesh() ) + { + set::const_iterator aSubIt = mySubMeshes.begin(); + for (; aSubIt != mySubMeshes.end(); aSubIt++) + if ((*aSubIt)->IsQuadratic()) + return true; + return false; + } + + for ( size_t i = 0; i < myElements.size(); ++i ) + if ( myElements[i] ) + return myElements[i]->IsQuadratic(); + + return false; } //======================================================================= @@ -283,6 +463,16 @@ bool SMESHDS_SubMesh::RemoveSubMesh( const SMESHDS_SubMesh* theSubMesh ) return mySubMeshes.erase( theSubMesh ); } +//======================================================================= +//function : RemoveAllSubmeshes +//purpose : +//======================================================================= + +void SMESHDS_SubMesh::RemoveAllSubmeshes() +{ + mySubMeshes.clear(); +} + //======================================================================= //function : ContainsSubMesh //purpose : @@ -313,11 +503,76 @@ SMESHDS_SubMeshIteratorPtr SMESHDS_SubMesh::GetSubMeshIterator() const void SMESHDS_SubMesh::Clear() { - myElements.clear(); - myNodes.clear(); - SMESHDS_SubMeshIteratorPtr sub = GetSubMeshIterator(); - while ( sub->more() ) { - if ( SMESHDS_SubMesh* sm = (SMESHDS_SubMesh*) sub->next()) - sm->Clear(); + clearVector( myElements ); + clearVector( myNodes ); + myUnusedIdNodes = 0; + myUnusedIdElements = 0; + if ( NbSubMeshes() > 0 ) + { + SMESHDS_SubMeshIteratorPtr sub = GetSubMeshIterator(); + while ( sub->more() ) { + if ( SMESHDS_SubMesh* sm = (SMESHDS_SubMesh*) sub->next()) + sm->Clear(); + } + } +} + +int SMESHDS_SubMesh::getSize() +{ + int c = NbNodes(); + int d = NbElements(); + return c+d; +} + +void SMESHDS_SubMesh::compactList() +{ + if ( myUnusedIdElements > 0 ) + { + std::vector newElems; + newElems.reserve( myElements.size() - myUnusedIdElements ); + for (size_t i = 0; i < myElements.size(); i++) + if (myElements[i]) + { + SMDS_MeshElement* elem = (SMDS_MeshElement*)myElements[i]; + elem->setIdInShape(newElems.size()); + newElems.push_back(elem); + } + myElements.swap(newElems); + myUnusedIdElements = 0; + } + + if ( myUnusedIdNodes > 0 ) + { + std::vector newNodes; + newNodes.reserve( myNodes.size() - myUnusedIdNodes ); + for (size_t i = 0; i < myNodes.size(); i++) + if (myNodes[i]) + { + SMDS_MeshNode* node = (SMDS_MeshNode*)myNodes[i]; + node->setIdInShape(newNodes.size()); + newNodes.push_back(node); + } + myNodes.swap(newNodes); + myUnusedIdNodes = 0; } } + +//======================================================================= +//function : GetElement +//purpose : Return an element by its IdInShape +//======================================================================= + +const SMDS_MeshElement* SMESHDS_SubMesh::GetElement( size_t idInShape ) const +{ + return ( !IsComplexSubmesh() && idInShape < myElements.size() ) ? myElements[idInShape] : 0; +} + +//======================================================================= +//function : GetElement +//purpose : Return a node by its IdInShape +//======================================================================= + +const SMDS_MeshNode* SMESHDS_SubMesh::GetNode( size_t idInShape ) const +{ + return ( !IsComplexSubmesh() && idInShape < myNodes.size() ) ? myNodes[idInShape] : 0; +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/SMESH_MAT2d.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/SMESH_MAT2d.cpp new file mode 100644 index 000000000000..970d560e5f0a --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/SMESH_MAT2d.cpp @@ -0,0 +1,2023 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 : SMESH_MAT2d.cxx +// Created : Thu May 28 17:49:53 2015 +// Author : Edward AGAPOV (eap) + +#include "SMESH_MAT2d.hxx" + +#include + +#include +#include +#include +#include +#include +#include +//#include +#include +// #include +// #include +#include +//#include +#include +#include +#include +#include +#include +#include + +#ifdef _DEBUG_ +#define _MYDEBUG_ +#include "SMESH_File.hxx" +#include "SMESH_Comment.hxx" +#endif + +using namespace std; +using boost::polygon::x; +using boost::polygon::y; +using SMESH_MAT2d::TVD; +using SMESH_MAT2d::TVDEdge; +using SMESH_MAT2d::TVDCell; +using SMESH_MAT2d::TVDVertex; + +namespace +{ + // Input data for construct_voronoi() + // ------------------------------------------------------------------------------------- + + struct InPoint + { + int _a, _b; // coordinates + double _param; // param on EDGE + InPoint(int x, int y, double param) : _a(x), _b(y), _param(param) {} + InPoint() : _a(0), _b(0), _param(0) {} + + // working data + list< const TVDEdge* > _edges; // MA edges of a concave InPoint in CCW order + + size_t index( const vector< InPoint >& inPoints ) const { return this - &inPoints[0]; } + bool operator==( const InPoint& other ) const { return _a == other._a && _b == other._b; } + bool operator==( const TVDVertex* v ) const { return ( Abs( _a - v->x() ) < 1. && + Abs( _b - v->y() ) < 1. ); } + }; + // ------------------------------------------------------------------------------------- + + struct InSegment + { + InPoint * _p0; + InPoint * _p1; + + // working data + size_t _geomEdgeInd; // EDGE index within the FACE + const TVDCell* _cell; + list< const TVDEdge* > _edges; // MA edges in CCW order within _cell + + InSegment( InPoint * p0, InPoint * p1, size_t iE) + : _p0(p0), _p1(p1), _geomEdgeInd(iE) {} + InSegment() : _p0(0), _p1(0), _geomEdgeInd(0) {} + + const InPoint& point0() const { return *_p0; } + const InPoint& point1() const { return *_p1; } + + inline bool isConnected( const TVDEdge* edge ); + + inline bool isExternal( const TVDEdge* edge ); + + static void setGeomEdgeToCell( const TVDCell* cell, size_t eID ) { cell->color( eID ); } + + static size_t getGeomEdge( const TVDCell* cell ) { return cell->color(); } + }; + + // check if a TVDEdge begins at my end or ends at my start + inline bool InSegment::isConnected( const TVDEdge* edge ) + { + return (( edge->vertex0() && edge->vertex1() ) + && + ((Abs( edge->vertex0()->x() - _p1->_a ) < 1.&& + Abs( edge->vertex0()->y() - _p1->_b ) < 1. ) || + (Abs( edge->vertex1()->x() - _p0->_a ) < 1.&& + Abs( edge->vertex1()->y() - _p0->_b ) < 1. ))); + } + + // check if a MA TVDEdge is outside of a domain + inline bool InSegment::isExternal( const TVDEdge* edge ) + { + double dot = // x1*x2 + y1*y2; (x1,y1) - internal normal of InSegment + ( _p0->_b - _p1->_b ) * ( 0.5 * ( edge->vertex0()->x() + edge->vertex1()->x() ) - _p0->_a ) + + ( _p1->_a - _p0->_a ) * ( 0.5 * ( edge->vertex0()->y() + edge->vertex1()->y() ) - _p0->_b ); + return dot < 0.; + } + + // // ------------------------------------------------------------------------------------- + // const size_t theExternMA = 111; // to mark external MA edges + + // bool isExternal( const TVDEdge* edge ) + // { + // return ( SMESH_MAT2d::Branch::getBndSegment( edge ) == theExternMA ); + // } + + // // mark external MA edges + // void markExternalEdges( const TVDEdge* edge ) + // { + // if ( isExternal( edge )) + // return; + // SMESH_MAT2d::Branch::setBndSegment( theExternMA, edge ); + // SMESH_MAT2d::Branch::setBndSegment( theExternMA, edge->twin() ); + // if ( edge->is_primary() && edge->vertex1() ) + // { + // const TVDVertex * v = edge->vertex1(); + // edge = v->incident_edge(); + // do { + // markExternalEdges( edge ); + // edge = edge->rot_next(); + // } while ( edge != v->incident_edge() ); + // } + // } + + // ------------------------------------------------------------------------------------- +#ifdef _MYDEBUG_ + // writes segments into a txt file readable by voronoi_visualizer + void inSegmentsToFile( vector< InSegment>& inSegments) + { + if ( inSegments.size() > 1000 ) + return; + const char* fileName = "/misc/dn25/salome/eap/salome/misc/Code/C++/MAdebug.txt"; + SMESH_File file(fileName, false ); + file.remove(); + file.openForWriting(); + SMESH_Comment text; + text << "0\n"; // nb points + text << inSegments.size() << "\n"; // nb segments + for ( size_t i = 0; i < inSegments.size(); ++i ) + { + text << inSegments[i]._p0->_a << " " + << inSegments[i]._p0->_b << " " + << inSegments[i]._p1->_a << " " + << inSegments[i]._p1->_b << "\n"; + } + text << "\n"; + file.write( text.c_str(), text.size() ); + cout << "Write " << fileName << endl; + } + void dumpEdge( const TVDEdge* edge ) + { + cout << "*Edge_" << edge; + if ( !edge->vertex0() ) + cout << " ( INF, INF"; + else + cout << " ( " << edge->vertex0()->x() << ", " << edge->vertex0()->y(); + if ( !edge->vertex1() ) + cout << ") -> ( INF, INF"; + else + cout << ") -> ( " << edge->vertex1()->x() << ", " << edge->vertex1()->y(); + cout << ")\t cell=" << edge->cell() + << " iBnd=" << edge->color() + << " twin=" << edge->twin() + << " twin_cell=" << edge->twin()->cell() + << " prev=" << edge->prev() << " next=" << edge->next() + << ( edge->is_primary() ? " MA " : " SCND" ) + << ( edge->is_linear() ? " LIN " : " CURV" ) + << endl; + } + void dumpCell( const TVDCell* cell ) + { + cout << "**Cell_" << cell << " GEOM=" << cell->color() << " "; + cout << ( cell->contains_segment() ? " SEG " : " PNT " ); + if ( cell-> is_degenerate() ) + cout << " degen "; + else + { + cout << endl; + const TVDEdge* edge = cell->incident_edge(); + size_t i = 0; + do { + edge = edge->next(); + cout << " - " << ++i << " "; + dumpEdge( edge ); + } while (edge != cell->incident_edge()); + } + } +#else + void inSegmentsToFile( vector< InSegment>& inSegments) {} + void dumpEdge( const TVDEdge* edge ) {} + void dumpCell( const TVDCell* cell ) {} +#endif +} +// ------------------------------------------------------------------------------------- + +namespace boost { + namespace polygon { + + template <> + struct geometry_concept { + typedef point_concept type; + }; + template <> + struct point_traits { + typedef int coordinate_type; + + static inline coordinate_type get(const InPoint& point, orientation_2d orient) { + return (orient == HORIZONTAL) ? point._a : point._b; + } + }; + + template <> + struct geometry_concept { + typedef segment_concept type; + }; + + template <> + struct segment_traits { + typedef int coordinate_type; + typedef InPoint point_type; + + static inline point_type get(const InSegment& segment, direction_1d dir) { + return *(dir.to_int() ? segment._p1 : segment._p0); + } + }; + } // namespace polygon +} // namespace boost + // ------------------------------------------------------------------------------------- + +namespace +{ + const int theNoBrachID = 0; + double theScale[2]; // scale used in bndSegsToMesh() + const size_t theNoEdgeID = std::numeric_limits::max() / 1000; + + // ------------------------------------------------------------------------------------- + /*! + * \brief Intermediate DS to create InPoint's + */ + struct UVU + { + gp_Pnt2d _uv; + double _u; + UVU( gp_Pnt2d uv, double u ): _uv(uv), _u(u) {} + InPoint getInPoint( double scale[2] ) + { + return InPoint( int( _uv.X() * scale[0]), int( _uv.Y() * scale[1]), _u ); + } + }; + // ------------------------------------------------------------------------------------- + /*! + * \brief Segment of EDGE, used to create BndPoints + */ + struct BndSeg + { + InSegment* _inSeg; + const TVDEdge* _edge; + double _uLast; + BndSeg* _prev; // previous BndSeg in FACE boundary + int _branchID; // negative ID means reverse direction + + BndSeg( InSegment* seg, const TVDEdge* edge, double u ): + _inSeg(seg), _edge(edge), _uLast(u), _prev(0), _branchID( theNoBrachID ) {} + + void setIndexToEdge( size_t id ) + { + SMESH_MAT2d::Branch::setBndSegment( id, _edge ); + } + + int branchID() const { return Abs( _branchID ); } + + size_t geomEdge() const { return _inSeg->_geomEdgeInd; } + + static BndSeg* getBndSegOfEdge( const TVDEdge* edge, + vector< vector< BndSeg > >& bndSegsPerEdge ) + { + BndSeg* seg = 0; + if ( edge ) + { + size_t oppSegIndex = SMESH_MAT2d::Branch::getBndSegment( edge ); + size_t oppEdgeIndex = SMESH_MAT2d::Branch::getGeomEdge ( edge ); + if ( oppEdgeIndex < bndSegsPerEdge.size() && + oppSegIndex < bndSegsPerEdge[ oppEdgeIndex ].size() ) + { + seg = & bndSegsPerEdge[ oppEdgeIndex ][ oppSegIndex ]; + } + } + return seg; + } + + void setBranch( int branchID, vector< vector< BndSeg > >& bndSegsPerEdge ) + { + _branchID = branchID; + + // pass branch to an opposite BndSeg + if ( _edge ) + if ( BndSeg* oppSeg = getBndSegOfEdge( _edge->twin(), bndSegsPerEdge )) + { + if ( oppSeg->_branchID == theNoBrachID ) + oppSeg->_branchID = -branchID; + } + } + bool hasOppositeEdge() + { + if ( !_edge ) return false; + return ( _inSeg->getGeomEdge( _edge->twin()->cell() ) != theNoEdgeID ); + } + + // check a next segment in CW order + bool isSameBranch( const BndSeg& seg2 ) + { + if ( !_edge || !seg2._edge ) + return true; + + if ( _edge->twin() == seg2._edge ) + return true; + + const TVDCell* cell1 = this->_edge->twin()->cell(); + const TVDCell* cell2 = seg2. _edge->twin()->cell(); + if ( cell1 == cell2 ) + return true; + + const TVDEdge* edgeMedium1 = this->_edge->twin()->next(); + const TVDEdge* edgeMedium2 = seg2. _edge->twin()->prev(); + + if ( edgeMedium1->is_secondary() && edgeMedium2->is_secondary() ) + { + if ( edgeMedium1->twin() == edgeMedium2 ) + return true; + // edgeMedium's are edges whose twin()->cell is built on an end point of inSegment + // and is located between cell1 and cell2 + if ( edgeMedium1->twin() == edgeMedium2->twin() ) // is this possible??? + return true; + if ( edgeMedium1->twin() == edgeMedium2->twin()->next() && + edgeMedium1->twin()->cell()->contains_point() ) + return true; + } + else if ( edgeMedium1->is_primary() && edgeMedium2->is_primary() ) + { + if ( edgeMedium1->twin() == edgeMedium2 && + SMESH_MAT2d::Branch::getGeomEdge( edgeMedium1 ) == + SMESH_MAT2d::Branch::getGeomEdge( edgeMedium2 )) + // this is an ignored MA edge between inSegment's on one EDGE forming a convex corner + return true; + } + + return false; + } + }; // struct BndSeg + + // ------------------------------------------------------------------------------------- + /*! + * \brief Iterator + */ + struct BranchIterator + { + int _i, _size; + const std::vector & _edges; + bool _closed; + + BranchIterator(const std::vector & edges, int i ) + :_i( i ), _size( edges.size() ), _edges( edges ) + { + _closed = ( edges[0]->vertex1() == edges.back()->vertex0() || // closed branch + edges[0]->vertex0() == edges.back()->vertex1() ); + } + const TVDEdge* operator++() { ++_i; return edge(); } + const TVDEdge* operator--() { --_i; return edge(); } + bool operator<( const BranchIterator& other ) { return _i < other._i; } + BranchIterator& operator=( const BranchIterator& other ) { _i = other._i; return *this; } + void set(int i) { _i = i; } + int index() const { return _i; } + int indexMod() const { return ( _i + _size ) % _size; } + const TVDEdge* edge() const { + return _closed ? _edges[ indexMod() ] : ( _i < 0 || _i >= _size ) ? 0 : _edges[ _i ]; + } + const TVDEdge* edgePrev() { --_i; const TVDEdge* e = edge(); ++_i; return e; } + const TVDEdge* edgeNext() { ++_i; const TVDEdge* e = edge(); --_i; return e; } + }; + + //================================================================================ + /*! + * \brief debug: to visually check found MA edges + */ + //================================================================================ + + void bndSegsToMesh( const vector< vector< BndSeg > >& bndSegsPerEdge ) + { +#ifdef _MYDEBUG_ + if ( !getenv("bndSegsToMesh")) return; + map< const TVDVertex *, int > v2Node; + map< const TVDVertex *, int >::iterator v2n; + set< const TVDEdge* > addedEdges; + + const char* fileName = "/misc/dn25/salome/eap/salome/misc/Code/C++/MAedges.py"; + SMESH_File file(fileName, false ); + file.remove(); + file.openForWriting(); + SMESH_Comment text; + text << "import salome, SMESH\n"; + text << "salome.salome_init()\n"; + text << "from salome.smesh import smeshBuilder\n"; + text << "smesh = smeshBuilder.New(salome.myStudy)\n"; + text << "m=smesh.Mesh()\n"; + for ( size_t iE = 0; iE < bndSegsPerEdge.size(); ++iE ) + { + const vector< BndSeg >& bndSegs = bndSegsPerEdge[ iE ]; + for ( size_t i = 0; i < bndSegs.size(); ++i ) + { + if ( !bndSegs[i]._edge ) + text << "# E=" << iE << " i=" << i << " NULL edge\n"; + else if ( !bndSegs[i]._edge->vertex0() || + !bndSegs[i]._edge->vertex1() ) + text << "# E=" << iE << " i=" << i << " INFINITE edge\n"; + else if ( addedEdges.insert( bndSegs[i]._edge ).second && + addedEdges.insert( bndSegs[i]._edge->twin() ).second ) + { + v2n = v2Node.insert( make_pair( bndSegs[i]._edge->vertex0(), v2Node.size() + 1 )).first; + int n0 = v2n->second; + if ( n0 == v2Node.size() ) + text << "n" << n0 << " = m.AddNode( " + << bndSegs[i]._edge->vertex0()->x() / theScale[0] << ", " + << bndSegs[i]._edge->vertex0()->y() / theScale[1] << ", 0 )\n"; + + v2n = v2Node.insert( make_pair( bndSegs[i]._edge->vertex1(), v2Node.size() + 1 )).first; + int n1 = v2n->second; + if ( n1 == v2Node.size() ) + text << "n" << n1 << " = m.AddNode( " + << bndSegs[i]._edge->vertex1()->x() / theScale[0] << ", " + << bndSegs[i]._edge->vertex1()->y() / theScale[1] << ", 0 )\n"; + + text << "e" << i << " = m.AddEdge([ n" << n0 << ", n" << n1 << " ])\n"; + } + } + } + text << "\n"; + file.write( text.c_str(), text.size() ); + cout << "execfile( '" << fileName << "')" << endl; +#endif + } + + //================================================================================ + /*! + * \brief Computes length of a TVDEdge + */ + //================================================================================ + + double length( const TVDEdge* edge ) + { + gp_XY d( edge->vertex0()->x() - edge->vertex1()->x(), + edge->vertex0()->y() - edge->vertex1()->y() ); + return d.Modulus(); + } + + //================================================================================ + /*! + * \brief Compute scale to have the same 2d proportions as in 3d + */ + //================================================================================ + + void computeProportionScale( const TopoDS_Face& face, + const Bnd_B2d& uvBox, + double scale[2]) + { + scale[0] = scale[1] = 1.; + if ( uvBox.IsVoid() ) return; + + TopLoc_Location loc; + Handle(Geom_Surface) surface = BRep_Tool::Surface( face, loc ); + + const int nbDiv = 30; + gp_XY uvMin = uvBox.CornerMin(), uvMax = uvBox.CornerMax(); + gp_XY uvMid = 0.5 * ( uvMin + uvMax ); + double du = ( uvMax.X() - uvMin.X() ) / nbDiv; + double dv = ( uvMax.Y() - uvMin.Y() ) / nbDiv; + + double uLen3d = 0, vLen3d = 0; + gp_Pnt uPrevP = surface->Value( uvMin.X(), uvMid.Y() ); + gp_Pnt vPrevP = surface->Value( uvMid.X(), uvMin.Y() ); + for (int i = 1; i <= nbDiv; i++) + { + double u = uvMin.X() + du * i; + double v = uvMin.Y() + dv * i; + gp_Pnt uP = surface->Value( u, uvMid.Y() ); + gp_Pnt vP = surface->Value( uvMid.X(), v ); + uLen3d += uP.Distance( uPrevP ); + vLen3d += vP.Distance( vPrevP ); + uPrevP = uP; + vPrevP = vP; + } + scale[0] = uLen3d / ( uvMax.X() - uvMin.X() ); + scale[1] = vLen3d / ( uvMax.Y() - uvMin.Y() ); + } + + //================================================================================ + /*! + * \brief Fill input data for construct_voronoi() + */ + //================================================================================ + + bool makeInputData(const TopoDS_Face& face, + const std::vector< TopoDS_Edge >& edges, + const double minSegLen, + vector< InPoint >& inPoints, + vector< InSegment>& inSegments, + double scale[2]) + { + const double theDiscrCoef = 0.5; // to decrease minSegLen for discretization + TopLoc_Location loc; + + // discretize the EDGEs to get 2d points and segments + + vector< vector< UVU > > uvuVec( edges.size() ); + Bnd_B2d uvBox; + for ( size_t iE = 0; iE < edges.size(); ++iE ) + { + vector< UVU > & points = uvuVec[ iE ]; + + double f,l; + Handle(Geom_Curve) c3d = BRep_Tool::Curve ( edges[ iE ], loc, f, l ); + Handle(Geom2d_Curve) c2d = BRep_Tool::CurveOnSurface( edges[ iE ], face, f, l ); + if ( c2d.IsNull() ) return false; + + points.push_back( UVU( c2d->Value( f ), f )); + uvBox.Add( points.back()._uv ); + + Geom2dAdaptor_Curve c2dAdaptor (c2d, f,l ); + double curDeflect = 0.3; //0.01; //Curvature deflection + double angDeflect = 0.2; // 0.09; //Angular deflection + + GCPnts_TangentialDeflection discret(c2dAdaptor, angDeflect, curDeflect); + // if ( discret.NbPoints() > 2 ) + // { + // cout << endl; + // do + // { + // discret.Initialize( c2dAdaptor, 100, curDeflect ); + // cout << "C " << curDeflect << " " << discret.NbPoints() << endl; + // curDeflect *= 1.5; + // } + // while ( discret.NbPoints() > 5 ); + // cout << endl; + // do + // { + // discret.Initialize( c2dAdaptor, angDeflect, 100 ); + // cout << "A " << angDeflect << " " << discret.NbPoints() << endl; + // angDeflect *= 1.5; + // } + // while ( discret.NbPoints() > 5 ); + // } + gp_Pnt p, pPrev; + if ( !c3d.IsNull() ) + pPrev = c3d->Value( f ); + if ( discret.NbPoints() > 2 ) + for ( int i = 2; i <= discret.NbPoints(); i++ ) // skip the 1st point + { + double u = discret.Parameter(i); + if ( !c3d.IsNull() ) + { + p = c3d->Value( u ); + int nbDiv = int( p.Distance( pPrev ) / minSegLen / theDiscrCoef ); + double dU = ( u - points.back()._u ) / nbDiv; + for ( int iD = 1; iD < nbDiv; ++iD ) + { + double uD = points.back()._u + dU; + points.push_back( UVU( c2d->Value( uD ), uD )); + } + pPrev = p; + } + points.push_back( UVU( c2d->Value( u ), u )); + uvBox.Add( points.back()._uv ); + } + // if ( !c3d.IsNull() ) + // { + // vector params; + // GeomAdaptor_Curve c3dAdaptor( c3d,f,l ); + // if ( useDefl ) + // { + // const double deflection = minSegLen * 0.1; + // GCPnts_UniformDeflection discret( c3dAdaptor, deflection, f, l, true ); + // if ( !discret.IsDone() ) + // return false; + // int nbP = discret.NbPoints(); + // for ( int i = 2; i < nbP; i++ ) // skip 1st and last points + // params.push_back( discret.Parameter(i) ); + // } + // else + // { + // double eLen = GCPnts_AbscissaPoint::Length( c3dAdaptor ); + // int nbSeg = Max( 1, int( eLen / minSegLen / theDiscrCoef )); + // double segLen = eLen / nbSeg; + // GCPnts_UniformAbscissa discret( c3dAdaptor, segLen, f, l ); + // int nbP = Min( discret.NbPoints(), nbSeg + 1 ); + // for ( int i = 2; i < nbP; i++ ) // skip 1st and last points + // params.push_back( discret.Parameter(i) ); + // } + // for ( size_t i = 0; i < params.size(); ++i ) + // { + // points.push_back( UVU( c2d->Value( params[i] ), params[i] )); + // uvBox.Add( points.back()._uv ); + // } + // } + if ( points.size() < 2 ) + { + points.push_back( UVU( c2d->Value( l ), l )); + uvBox.Add( points.back()._uv ); + } + if ( edges[ iE ].Orientation() == TopAbs_REVERSED ) + std::reverse( points.begin(), points.end() ); + } + + // make connected EDGEs have same UV at shared VERTEX + TopoDS_Vertex vShared; + for ( size_t iE = 0; iE < edges.size(); ++iE ) + { + size_t iE2 = (iE+1) % edges.size(); + if ( !TopExp::CommonVertex( edges[iE], edges[iE2], vShared )) + continue; + if ( !vShared.IsSame( TopExp::LastVertex( edges[iE], true ))) + return false; + vector< UVU > & points1 = uvuVec[ iE ]; + vector< UVU > & points2 = uvuVec[ iE2 ]; + gp_Pnt2d & uv1 = points1.back() ._uv; + gp_Pnt2d & uv2 = points2.front()._uv; + uv1 = uv2 = 0.5 * ( uv1.XY() + uv2.XY() ); + } + + // get scale to have the same 2d proportions as in 3d + computeProportionScale( face, uvBox, scale ); + + // make scale to have coordinates precise enough when converted to int + + gp_XY uvMin = uvBox.CornerMin(), uvMax = uvBox.CornerMax(); + uvMin.ChangeCoord(1) = uvMin.X() * scale[0]; + uvMin.ChangeCoord(2) = uvMin.Y() * scale[1]; + uvMax.ChangeCoord(1) = uvMax.X() * scale[0]; + uvMax.ChangeCoord(2) = uvMax.Y() * scale[1]; + double vMax[2] = { Max( Abs( uvMin.X() ), Abs( uvMax.X() )), + Max( Abs( uvMin.Y() ), Abs( uvMax.Y() )) }; + int iMax = ( vMax[0] > vMax[1] ) ? 0 : 1; + const double precision = 1e-5; + double preciScale = Min( vMax[iMax] / precision, + std::numeric_limits::max() / vMax[iMax] ); + preciScale /= scale[iMax]; + double roundedScale = 10; // to ease debug + while ( roundedScale * 10 < preciScale ) + roundedScale *= 10.; + scale[0] *= roundedScale; + scale[1] *= roundedScale; + + // create input points and segments + + inPoints.clear(); + inSegments.clear(); + size_t nbPnt = 0; + for ( size_t iE = 0; iE < uvuVec.size(); ++iE ) + nbPnt += uvuVec[ iE ].size(); + inPoints.resize( nbPnt ); + inSegments.reserve( nbPnt ); + + size_t iP = 0; + if ( face.Orientation() == TopAbs_REVERSED ) + { + for ( int iE = uvuVec.size()-1; iE >= 0; --iE ) + { + vector< UVU > & points = uvuVec[ iE ]; + inPoints[ iP++ ] = points.back().getInPoint( scale ); + for ( size_t i = points.size()-1; i >= 1; --i ) + { + inPoints[ iP++ ] = points[i-1].getInPoint( scale ); + inSegments.push_back( InSegment( & inPoints[ iP-2 ], & inPoints[ iP-1 ], iE )); + } + } + } + else + { + for ( size_t iE = 0; iE < uvuVec.size(); ++iE ) + { + vector< UVU > & points = uvuVec[ iE ]; + inPoints[ iP++ ] = points[0].getInPoint( scale ); + for ( size_t i = 1; i < points.size(); ++i ) + { + inPoints[ iP++ ] = points[i].getInPoint( scale ); + inSegments.push_back( InSegment( & inPoints[ iP-2 ], & inPoints[ iP-1 ], iE )); + } + } + } + // debug + theScale[0] = scale[0]; + theScale[1] = scale[1]; + + return true; + } + + //================================================================================ + /*! + * \brief Update a branch joined to another one + */ + //================================================================================ + + void updateJoinedBranch( vector< const TVDEdge* > & branchEdges, + const size_t newID, + vector< vector< BndSeg > > & bndSegs, + const bool reverse) + { + BndSeg *seg1, *seg2; + if ( reverse ) + { + for ( size_t i = 0; i < branchEdges.size(); ++i ) + { + if (( seg1 = BndSeg::getBndSegOfEdge( branchEdges[i], bndSegs )) && + ( seg2 = BndSeg::getBndSegOfEdge( branchEdges[i]->twin(), bndSegs ))) + { + seg1->_branchID /= seg1->branchID(); + seg2->_branchID /= seg2->branchID(); + seg1->_branchID *= -newID; + seg2->_branchID *= -newID; + branchEdges[i] = branchEdges[i]->twin(); + } + } + std::reverse( branchEdges.begin(), branchEdges.end() ); + } + else + { + for ( size_t i = 0; i < branchEdges.size(); ++i ) + { + if (( seg1 = BndSeg::getBndSegOfEdge( branchEdges[i], bndSegs )) && + ( seg2 = BndSeg::getBndSegOfEdge( branchEdges[i]->twin(), bndSegs ))) + { + seg1->_branchID /= seg1->branchID(); + seg2->_branchID /= seg2->branchID(); + seg1->_branchID *= newID; + seg2->_branchID *= newID; + } + } + } + } + + //================================================================================ + /*! + * \brief Create MA branches and FACE boundary data + * \param [in] vd - voronoi diagram of \a inSegments + * \param [in] inPoints - FACE boundary points + * \param [in,out] inSegments - FACE boundary segments + * \param [out] branch - MA branches to fill + * \param [out] branchEnd - ends of MA branches to fill + * \param [out] boundary - FACE boundary to fill + */ + //================================================================================ + + void makeMA( const TVD& vd, + const bool ignoreCorners, + vector< InPoint >& inPoints, + vector< InSegment > & inSegments, + vector< SMESH_MAT2d::Branch >& branch, + vector< const SMESH_MAT2d::BranchEnd* >& branchPnt, + SMESH_MAT2d::Boundary& boundary ) + { + // Associate MA cells with geom EDGEs + for (TVD::const_cell_iterator it = vd.cells().begin(); it != vd.cells().end(); ++it) + { + const TVDCell* cell = &(*it); + if ( cell->contains_segment() ) + { + InSegment& seg = inSegments[ cell->source_index() ]; + seg._cell = cell; + seg.setGeomEdgeToCell( cell, seg._geomEdgeInd ); + } + else + { + InSegment::setGeomEdgeToCell( cell, theNoEdgeID ); + } + } + + vector< bool > inPntChecked( inPoints.size(), false ); + + // Find MA edges of each inSegment + + for ( size_t i = 0; i < inSegments.size(); ++i ) + { + InSegment& inSeg = inSegments[i]; + + // get edges around the cell lying on MA + bool hasSecondary = false; + const TVDEdge* edge = inSeg._cell->incident_edge(); + do { + edge = edge->next(); // Returns the CCW next edge within the cell. + if ( edge->is_primary() && !inSeg.isExternal( edge ) ) + inSeg._edges.push_back( edge ); // edge equidistant from two InSegments + else + hasSecondary = true; + } while (edge != inSeg._cell->incident_edge()); + + // there can be several continuous MA edges but maEdges can begin in the middle of + // a chain of continuous MA edges. Make the chain continuous. + list< const TVDEdge* >& maEdges = inSeg._edges; + if ( maEdges.empty() ) + continue; + if ( hasSecondary ) + while ( maEdges.back()->next() == maEdges.front() ) + maEdges.splice( maEdges.end(), maEdges, maEdges.begin() ); + + // remove maEdges equidistant from two neighbor InSegments of the same geom EDGE + list< const TVDEdge* >::iterator e = maEdges.begin(); + while ( e != maEdges.end() ) + { + const TVDCell* cell2 = (*e)->twin()->cell(); // cell on the other side of a MA edge + size_t geoE2 = InSegment::getGeomEdge( cell2 ); + bool toRemove = ( inSeg._geomEdgeInd == geoE2 && inSeg.isConnected( *e )); + if ( toRemove ) + e = maEdges.erase( e ); + else + ++e; + } + if ( maEdges.empty() ) + continue; + + // add MA edges corresponding to concave InPoints + for ( int is2nd = 0; is2nd < 2; ++is2nd ) // loop on two ends of inSeg + { + InPoint& inPnt = *( is2nd ? inSeg._p1 : inSeg._p0 ); + size_t pInd = inPnt.index( inPoints ); + if ( inPntChecked[ pInd ] ) + continue; + if ( pInd > 0 && + inPntChecked[ pInd-1 ] && + inPoints[ pInd-1 ] == inPnt ) + continue; + inPntChecked[ pInd ] = true; + + const TVDEdge* maE = is2nd ? maEdges.front() : maEdges.back(); + if ( inPnt == ( is2nd ? maE->vertex0() : maE->vertex1() )) + continue; + const TVDEdge* edge = // a secondary TVDEdge connecting inPnt and maE + is2nd ? maE->prev() : maE->next(); + while ( inSeg.isConnected( edge )) + { + if ( edge->is_primary() ) break; // this should not happen + const TVDEdge* edge2 = edge->twin(); // we are in a neighbor cell, add MA edges to inPnt + if ( inSeg.getGeomEdge( edge2->cell() ) != theNoEdgeID ) + break; // cell of an InSegment + bool hasInfinite = false; + list< const TVDEdge* > pointEdges; + edge = edge2; + do + { + edge = edge->next(); // Returns the CCW next edge within the cell. + if ( edge->is_infinite() ) + hasInfinite = true; + else if ( edge->is_primary() && !inSeg.isExternal( edge )) + pointEdges.push_back( edge ); + } + while ( edge != edge2 && !hasInfinite ); + + if ( hasInfinite || pointEdges.empty() ) + break; + inPnt._edges.splice( inPnt._edges.end(), pointEdges ); + inSeg.setGeomEdgeToCell( edge->cell(), inSeg._geomEdgeInd ); + + edge = is2nd ? inPnt._edges.front()->prev() : inPnt._edges.back()->next(); + } + } // add MA edges corresponding to concave InPoints + + } // loop on inSegments to find corresponding MA edges + + + // ------------------------------------------- + // Create Branches and BndPoints for each EDGE + // ------------------------------------------- + + if ( inPoints.front() == inPoints.back() /*&& !inPoints[0]._edges.empty()*/ ) + { + inPntChecked[0] = false; // do not use the 1st point twice + //InSegment::setGeomEdgeToCell( inPoints[0]._edges.back()->cell(), theNoEdgeID ); + inPoints[0]._edges.clear(); + } + + // Divide InSegment's into BndSeg's (so that each BndSeg corresponds to one MA edge) + + vector< vector< BndSeg > > bndSegsPerEdge( boundary.nbEdges() ); // all BndSeg's + { + vector< BndSeg > bndSegs; // bndSeg's of a current EDGE + size_t prevGeomEdge = theNoEdgeID; + + list< const TVDEdge* >::reverse_iterator e; + for ( size_t i = 0; i < inSegments.size(); ++i ) + { + InSegment& inSeg = inSegments[i]; + + if ( inSeg._geomEdgeInd != prevGeomEdge ) + { + if ( !bndSegs.empty() ) + bndSegsPerEdge[ prevGeomEdge ].swap( bndSegs ); + prevGeomEdge = inSeg._geomEdgeInd; + } + + // segments around 1st concave point + size_t ip0 = inSeg._p0->index( inPoints ); + if ( inPntChecked[ ip0 ] ) + for ( e = inSeg._p0->_edges.rbegin(); e != inSeg._p0->_edges.rend(); ++e ) + bndSegs.push_back( BndSeg( &inSeg, *e, inSeg._p0->_param )); + inPntChecked[ ip0 ] = false; + + // segments of InSegment's + const size_t nbMaEdges = inSeg._edges.size(); + switch ( nbMaEdges ) { + case 0: // "around" circle center + bndSegs.push_back( BndSeg( &inSeg, 0, inSeg._p1->_param )); break; + case 1: + bndSegs.push_back( BndSeg( &inSeg, inSeg._edges.back(), inSeg._p1->_param )); break; + default: + gp_XY inSegDir( inSeg._p1->_a - inSeg._p0->_a, + inSeg._p1->_b - inSeg._p0->_b ); + const double inSegLen2 = inSegDir.SquareModulus(); + e = inSeg._edges.rbegin(); + for ( size_t iE = 1; iE < nbMaEdges; ++e, ++iE ) + { + gp_XY toMA( (*e)->vertex0()->x() - inSeg._p0->_a, + (*e)->vertex0()->y() - inSeg._p0->_b ); + double r = toMA * inSegDir / inSegLen2; + double u = r * inSeg._p1->_param + ( 1. - r ) * inSeg._p0->_param; + bndSegs.push_back( BndSeg( &inSeg, *e, u )); + } + bndSegs.push_back( BndSeg( &inSeg, *e, inSeg._p1->_param )); + } + // segments around 2nd concave point + size_t ip1 = inSeg._p1->index( inPoints ); + if ( inPntChecked[ ip1 ] ) + for ( e = inSeg._p1->_edges.rbegin(); e != inSeg._p1->_edges.rend(); ++e ) + bndSegs.push_back( BndSeg( &inSeg, *e, inSeg._p1->_param )); + inPntChecked[ ip1 ] = false; + } + if ( !bndSegs.empty() ) + bndSegsPerEdge[ prevGeomEdge ].swap( bndSegs ); + } + + // prepare to MA branch search + for ( size_t iE = 0; iE < bndSegsPerEdge.size(); ++iE ) + { + // 1) make TVDEdge's know it's BndSeg to enable passing branchID to + // an opposite BndSeg in BndSeg::setBranch(); geom EDGE ID is known from TVDCell + // 2) connect bndSegs via BndSeg::_prev + + vector< BndSeg >& bndSegs = bndSegsPerEdge[ iE ]; + if ( bndSegs.empty() ) continue; + + for ( size_t i = 1; i < bndSegs.size(); ++i ) + { + bndSegs[i]._prev = & bndSegs[i-1]; + bndSegs[i].setIndexToEdge( i ); + } + // look for the last bndSeg of previous EDGE to set bndSegs[0]._prev + const InPoint& p0 = bndSegs[0]._inSeg->point0(); + for ( size_t iE2 = 0; iE2 < bndSegsPerEdge.size(); ++iE2 ) + if ( p0 == bndSegsPerEdge[ iE2 ].back()._inSeg->point1() ) + { + bndSegs[0]._prev = & bndSegsPerEdge[ iE2 ].back(); + break; + } + bndSegs[0].setIndexToEdge( 0 ); + } + + bndSegsToMesh( bndSegsPerEdge ); // debug: visually check found MA edges + + + // Find TVDEdge's of Branches and associate them with bndSegs + + vector< vector > branchEdges; + branchEdges.reserve( boundary.nbEdges() * 4 ); + + map< const TVDVertex*, SMESH_MAT2d::BranchEndType > endType; + + int branchID = 1; // we code orientation as branchID sign + branchEdges.resize( branchID ); + + for ( size_t iE = 0; iE < bndSegsPerEdge.size(); ++iE ) + { + vector< BndSeg >& bndSegs = bndSegsPerEdge[ iE ]; + for ( size_t i = 0; i < bndSegs.size(); ++i ) + { + if ( bndSegs[i].branchID() ) + { + if ( bndSegs[i]._prev && + bndSegs[i]._branchID == -bndSegs[i]._prev->_branchID && + bndSegs[i]._edge ) + { + SMESH_MAT2d::BranchEndType type = + ( bndSegs[i]._inSeg->isConnected( bndSegs[i]._edge ) ? + SMESH_MAT2d::BE_ON_VERTEX : + SMESH_MAT2d::BE_END ); + endType.insert( make_pair( bndSegs[i]._edge->vertex1(), type )); + } + continue; + } + if ( !bndSegs[i]._prev && + !bndSegs[i].hasOppositeEdge() ) + continue; + + if ( !bndSegs[i]._prev || + !bndSegs[i]._prev->isSameBranch( bndSegs[i] )) + { + branchEdges.resize(( branchID = branchEdges.size()) + 1 ); + if ( bndSegs[i]._edge && bndSegs[i]._prev ) + endType.insert( make_pair( bndSegs[i]._edge->vertex1(), SMESH_MAT2d::BE_BRANCH_POINT )); + } + else if ( bndSegs[i]._prev->_branchID ) + { + branchID = bndSegs[i]._prev->_branchID; // with sign + } + else if ( bndSegs[i]._edge ) // 1st bndSeg of a WIRE + { + branchEdges.resize(( branchID = branchEdges.size()) + 1 ); + if ( bndSegs[i]._inSeg->isConnected( bndSegs[i]._edge )) + { + if ( bndSegs[i]._inSeg->point0() == bndSegs[i]._edge->vertex1() ) + endType.insert( make_pair( bndSegs[i]._edge->vertex1(), SMESH_MAT2d::BE_ON_VERTEX )); + else + endType.insert( make_pair( bndSegs[i]._edge->vertex0(), SMESH_MAT2d::BE_ON_VERTEX )); + } + } + + bndSegs[i].setBranch( branchID, bndSegsPerEdge ); // set to i-th and to the opposite bndSeg + if ( bndSegs[i].hasOppositeEdge() ) + branchEdges[ bndSegs[i].branchID() ].push_back( bndSegs[i]._edge ); + } + } + + // join the 1st and the last branch edges if it is the same branch + // if ( bndSegs.back().branchID() != bndSegs.front().branchID() && + // bndSegs.back().isSameBranch( bndSegs.front() )) + // { + // vector & br1 = branchEdges[ bndSegs.front().branchID() ]; + // vector & br2 = branchEdges[ bndSegs.back().branchID() ]; + // br1.insert( br1.begin(), br2.begin(), br2.end() ); + // br2.clear(); + // } + + // remove branches ending at BE_ON_VERTEX + + vector isBranchRemoved( branchEdges.size(), false ); + + if ( ignoreCorners && branchEdges.size() > 2 && !branchEdges[2].empty() ) + { + // find branches to remove + map< const TVDVertex*, SMESH_MAT2d::BranchEndType >::iterator v2et; + for ( size_t iB = 1; iB < branchEdges.size(); ++iB ) + { + if ( branchEdges[iB].empty() ) + continue; + const TVDVertex* v0 = branchEdges[iB][0]->vertex1(); + const TVDVertex* v1 = branchEdges[iB].back()->vertex0(); + v2et = endType.find( v0 ); + if ( v2et != endType.end() && v2et->second == SMESH_MAT2d::BE_ON_VERTEX ) + isBranchRemoved[ iB ] = true; + v2et = endType.find( v1 ); + if ( v2et != endType.end() && v2et->second == SMESH_MAT2d::BE_ON_VERTEX ) + isBranchRemoved[ iB ] = true; + } + // try to join not removed branches into one + for ( size_t iB = 1; iB < branchEdges.size(); ++iB ) + { + if ( branchEdges[iB].empty() || isBranchRemoved[iB] ) + continue; + const TVDVertex* v0 = branchEdges[iB][0]->vertex1(); + const TVDVertex* v1 = branchEdges[iB].back()->vertex0(); + v2et = endType.find( v0 ); + if ( v2et == endType.end() || v2et->second != SMESH_MAT2d::BE_BRANCH_POINT ) + v0 = 0; + v2et = endType.find( v1 ); + if ( v2et == endType.end() || v2et->second != SMESH_MAT2d::BE_BRANCH_POINT ) + v1 = 0; + if ( !v0 && !v1 ) + continue; + + for ( int isV0 = 0; isV0 < 2; ++isV0 ) + { + const TVDVertex* v = isV0 ? v0 : v1; + size_t iBrToJoin = 0; + for ( size_t iB2 = 1; iB2 < branchEdges.size(); ++iB2 ) + { + if ( branchEdges[iB2].empty() || isBranchRemoved[iB2] || iB == iB2 ) + continue; + const TVDVertex* v02 = branchEdges[iB2][0]->vertex1(); + const TVDVertex* v12 = branchEdges[iB2].back()->vertex0(); + if ( v == v02 || v == v12 ) + { + if ( iBrToJoin > 0 ) + { + iBrToJoin = 0; + break; // more than 2 not removed branches meat at a TVDVertex + } + iBrToJoin = iB2; + } + } + if ( iBrToJoin > 0 ) + { + vector& branch = branchEdges[ iBrToJoin ]; + const TVDVertex* v02 = branch[0]->vertex1(); + const TVDVertex* v12 = branch.back()->vertex0(); + updateJoinedBranch( branch, iB, bndSegsPerEdge, /*reverse=*/(v0 == v02 || v1 == v12 )); + if ( v0 == v02 || v0 == v12 ) + branchEdges[iB].insert( branchEdges[iB].begin(), branch.begin(), branch.end() ); + else + branchEdges[iB].insert( branchEdges[iB].end(), branch.begin(), branch.end() ); + branch.clear(); + } + } + } // loop on branchEdges + } // if ( ignoreCorners ) + + // associate branchIDs and the input branch vector (arg) + vector< SMESH_MAT2d::Branch* > branchByID( branchEdges.size(), 0 ); + int nbBranches = 0; + for ( size_t i = 0; i < branchEdges.size(); ++i ) + { + nbBranches += ( !branchEdges[i].empty() ); + } + branch.resize( nbBranches ); + size_t iBr = 0; + for ( size_t brID = 1; brID < branchEdges.size(); ++brID ) // 1st - not removed + { + if ( !branchEdges[ brID ].empty() && !isBranchRemoved[ brID ]) + branchByID[ brID ] = & branch[ iBr++ ]; + } + for ( size_t brID = 1; brID < branchEdges.size(); ++brID ) // then - removed + { + if ( !branchEdges[ brID ].empty() && isBranchRemoved[ brID ]) + branchByID[ brID ] = & branch[ iBr++ ]; + } + + // Fill in BndPoints of each EDGE of the boundary + + //size_t iSeg = 0; + int edgeInd = -1, dInd = 0; + for ( size_t iE = 0; iE < bndSegsPerEdge.size(); ++iE ) + { + vector< BndSeg >& bndSegs = bndSegsPerEdge[ iE ]; + SMESH_MAT2d::BndPoints & bndPoints = boundary.getPoints( iE ); + + // make TVDEdge know an index of bndSegs within BndPoints + for ( size_t i = 0; i < bndSegs.size(); ++i ) + if ( bndSegs[i]._edge ) + SMESH_MAT2d::Branch::setBndSegment( i, bndSegs[i]._edge ); + + // parameters on EDGE + + bndPoints._params.reserve( bndSegs.size() + 1 ); + bndPoints._params.push_back( bndSegs[ 0 ]._inSeg->_p0->_param ); + + for ( size_t i = 0; i < bndSegs.size(); ++i ) + bndPoints._params.push_back( bndSegs[ i ]._uLast ); + + // MA edges + + bndPoints._maEdges.reserve( bndSegs.size() ); + + for ( size_t i = 0; i < bndSegs.size(); ++i ) + { + const size_t brID = bndSegs[ i ].branchID(); + const SMESH_MAT2d::Branch* br = branchByID[ brID ]; + + if ( bndSegs[ i ]._edge && !branchEdges[ brID ].empty() ) + { + edgeInd += dInd; + + if (( edgeInd < 0 || + edgeInd >= (int) branchEdges[ brID ].size() ) || + ( branchEdges[ brID ][ edgeInd ] != bndSegs[ i ]._edge && + branchEdges[ brID ][ edgeInd ]->twin() != bndSegs[ i ]._edge )) + { + if ( bndSegs[ i ]._branchID < 0 ) + { + dInd = -1; + for ( edgeInd = branchEdges[ brID ].size() - 1; edgeInd > 0; --edgeInd ) + if ( branchEdges[ brID ][ edgeInd ]->twin() == bndSegs[ i ]._edge ) + break; + } + else // bndSegs[ i ]._branchID > 0 + { + dInd = +1; + for ( edgeInd = 0; edgeInd < branchEdges[ brID ].size(); ++edgeInd ) + if ( branchEdges[ brID ][ edgeInd ] == bndSegs[ i ]._edge ) + break; + } + } + } + else + { + // no MA edge, bndSeg corresponds to an end point of a branch + if ( bndPoints._maEdges.empty() ) + edgeInd = 0; + else + edgeInd = branchEdges[ brID ].size(); + dInd = bndSegs[ i ]._branchID > 0 ? +1 : -1; + } + + bndPoints._maEdges.push_back( make_pair( br, ( 1 + edgeInd ) * dInd )); + + } // loop on bndSegs of an EDGE + } // loop on all bndSegs to construct Boundary + + // Initialize branches + + // find a not removed branch + size_t iBrNorRemoved = 0; + for ( size_t brID = 1; brID < branchEdges.size(); ++brID ) + if ( !branchEdges[brID].empty() && !isBranchRemoved[brID] ) + { + iBrNorRemoved = brID; + break; + } + // fill the branches with MA edges + for ( size_t brID = 1; brID < branchEdges.size(); ++brID ) + if ( !branchEdges[brID].empty() ) + { + branchByID[ brID ]->init( branchEdges[brID], & boundary, endType ); + } + // mark removed branches + for ( size_t brID = 1; brID < branchEdges.size(); ++brID ) + if ( isBranchRemoved[brID] && iBrNorRemoved > 0 ) + { + SMESH_MAT2d::Branch* branch = branchByID[ brID ]; + SMESH_MAT2d::Branch* mainBranch = branchByID[ iBrNorRemoved ]; + bool is1stBrPnt = ( branch->getEnd(0)->_type == SMESH_MAT2d::BE_BRANCH_POINT ); + const TVDVertex* branchVextex = + is1stBrPnt ? branch->getEnd(0)->_vertex : branch->getEnd(1)->_vertex; + SMESH_MAT2d::BranchPoint bp = mainBranch->getPoint( branchVextex ); + branch->setRemoved( bp ); + } + // set branches to branch ends + for ( size_t i = 0; i < branch.size(); ++i ) + if ( !branch[i].isRemoved() ) + branch[i].setBranchesToEnds( branch ); + + // fill branchPnt arg + map< const TVDVertex*, const SMESH_MAT2d::BranchEnd* > v2end; + for ( size_t i = 0; i < branch.size(); ++i ) + { + if ( branch[i].getEnd(0)->_branches.size() > 2 ) + v2end.insert( make_pair( branch[i].getEnd(0)->_vertex, branch[i].getEnd(0) )); + if ( branch[i].getEnd(1)->_branches.size() > 2 ) + v2end.insert( make_pair( branch[i].getEnd(1)->_vertex, branch[i].getEnd(1) )); + } + branchPnt.resize( v2end.size() ); + map< const TVDVertex*, const SMESH_MAT2d::BranchEnd* >::iterator v2e = v2end.begin(); + for ( size_t i = 0; v2e != v2end.end(); ++v2e, ++i ) + branchPnt[ i ] = v2e->second; + + } // makeMA() + +} // namespace + +//================================================================================ +/*! + * \brief MedialAxis constructor + * \param [in] face - a face to create MA for + * \param [in] edges - edges of the face (possibly not all) on the order they + * encounter in the face boundary. + * \param [in] minSegLen - minimal length of a mesh segment used to discretize + * the edges. It is used to define precision of MA approximation + */ +//================================================================================ + +SMESH_MAT2d::MedialAxis::MedialAxis(const TopoDS_Face& face, + const std::vector< TopoDS_Edge >& edges, + const double minSegLen, + const bool ignoreCorners): + _face( face ), _boundary( edges.size() ) +{ + // input to construct_voronoi() + vector< InPoint > inPoints; + vector< InSegment> inSegments; + if ( !makeInputData( face, edges, minSegLen, inPoints, inSegments, _scale )) + return; + + inSegmentsToFile( inSegments ); + + // build voronoi diagram + construct_voronoi( inSegments.begin(), inSegments.end(), &_vd ); + + // make MA data + makeMA( _vd, ignoreCorners, inPoints, inSegments, _branch, _branchPnt, _boundary ); + + // count valid branches + _nbBranches = _branch.size(); + for ( size_t i = 0; i < _branch.size(); ++i ) + if ( _branch[i].isRemoved() ) + --_nbBranches; +} + +//================================================================================ +/*! + * \brief Returns the i-th branch + */ +//================================================================================ + +const SMESH_MAT2d::Branch* SMESH_MAT2d::MedialAxis::getBranch(size_t i) const +{ + return i < _nbBranches ? &_branch[i] : 0; +} + +//================================================================================ +/*! + * \brief Return UVs of ends of MA edges of a branch + */ +//================================================================================ + +void SMESH_MAT2d::MedialAxis::getPoints( const Branch* branch, + std::vector< gp_XY >& points) const +{ + branch->getPoints( points, _scale ); +} + +//================================================================================ +/*! + * \brief Returns a BranchPoint corresponding to a given point on a geom EDGE + * \param [in] iEdge - index of geom EDGE within a vector passed at MA construction + * \param [in] u - parameter of the point on EDGE curve + * \param [out] p - the found BranchPoint + * \return bool - is OK + */ +//================================================================================ + +bool SMESH_MAT2d::Boundary::getBranchPoint( const std::size_t iEdge, + double u, + BranchPoint& p ) const +{ + if ( iEdge >= _pointsPerEdge.size() || _pointsPerEdge[iEdge]._params.empty() ) + return false; + + const BndPoints& points = _pointsPerEdge[ iEdge ]; + const bool edgeReverse = ( points._params[0] > points._params.back() ); + + if ( u < ( edgeReverse ? points._params.back() : points._params[0] )) + u = edgeReverse ? points._params.back() : points._params[0]; + else if ( u > ( edgeReverse ? points._params[0] : points._params.back()) ) + u = edgeReverse ? points._params[0] : points._params.back(); + + double r = ( u - points._params[0] ) / ( points._params.back() - points._params[0] ); + int i = int( r * double( points._maEdges.size()-1 )); + if ( edgeReverse ) + { + while ( points._params[i ] < u ) --i; + while ( points._params[i+1] > u ) ++i; + } + else + { + while ( points._params[i ] > u ) --i; + while ( points._params[i+1] < u ) ++i; + } + + if ( points._params[i] == points._params[i+1] ) // coincident points at some end + { + int di = ( points._params[0] == points._params[i] ) ? +1 : -1; + while ( points._params[i] == points._params[i+1] ) + i += di; + if ( i < 0 || i+1 >= points._params.size() ) + i = 0; + } + + double edgeParam = ( u - points._params[i] ) / ( points._params[i+1] - points._params[i] ); + + if ( !points._maEdges[ i ].second ) // no branch at the EDGE end, look for a closest branch + { + if ( i < points._maEdges.size() / 2 ) // near 1st point + { + while ( i < points._maEdges.size()-1 && !points._maEdges[ i ].second ) + ++i; + edgeParam = edgeReverse; + } + else // near last point + { + while ( i > 0 && !points._maEdges[ i ].second ) + --i; + edgeParam = !edgeReverse; + } + } + const std::pair< const Branch*, int >& maE = points._maEdges[ i ]; + bool maReverse = ( maE.second < 0 ); + + p._branch = maE.first; + p._iEdge = ( maReverse ? -maE.second : maE.second ) - 1; // countered from 1 to store sign + p._edgeParam = ( maE.first && maReverse ) ? ( 1. - edgeParam ) : edgeParam; + + return true; +} + +//================================================================================ +/*! + * \brief Returns a BranchPoint corresponding to a given BoundaryPoint on a geom EDGE + * \param [in] bp - the BoundaryPoint + * \param [out] p - the found BranchPoint + * \return bool - is OK + */ +//================================================================================ + +bool SMESH_MAT2d::Boundary::getBranchPoint( const BoundaryPoint& bp, + BranchPoint& p ) const +{ + return getBranchPoint( bp._edgeIndex, bp._param, p ); +} + +//================================================================================ +/*! + * \brief Check if a given boundary segment is a null-length segment on a concave + * boundary corner. + * \param [in] iEdge - index of a geom EDGE + * \param [in] iSeg - index of a boundary segment + * \return bool - true if the segment is on concave corner + */ +//================================================================================ + +bool SMESH_MAT2d::Boundary::isConcaveSegment( std::size_t iEdge, std::size_t iSeg ) const +{ + if ( iEdge >= _pointsPerEdge.size() || _pointsPerEdge[iEdge]._params.empty() ) + return false; + + const BndPoints& points = _pointsPerEdge[ iEdge ]; + if ( points._params.size() <= iSeg+1 ) + return false; + + return Abs( points._params[ iSeg ] - points._params[ iSeg+1 ]) < 1e-20; +} + +//================================================================================ +/*! + * \brief Moves (changes _param) a given BoundaryPoint to a closest EDGE end + */ +//================================================================================ + +bool SMESH_MAT2d::Boundary::moveToClosestEdgeEnd( BoundaryPoint& bp ) const +{ + if ( bp._edgeIndex >= _pointsPerEdge.size() ) + return false; + + const BndPoints& points = _pointsPerEdge[ bp._edgeIndex ]; + if ( Abs( bp._param - points._params[0]) < Abs( points._params.back() - bp._param )) + bp._param = points._params[0]; + else + bp._param = points._params.back(); + + return true; +} + +//================================================================================ +/*! + * \brief Creates a 3d curve corresponding to a Branch + * \param [in] branch - the Branch + * \return Adaptor3d_Curve* - the new curve the caller is to delete + */ +//================================================================================ + +Adaptor3d_Curve* SMESH_MAT2d::MedialAxis::make3DCurve(const Branch& branch) const +{ + Handle(Geom_Surface) surface = BRep_Tool::Surface( _face ); + if ( surface.IsNull() ) + return 0; + + vector< gp_XY > uv; + branch.getPoints( uv, _scale ); + if ( uv.size() < 2 ) + return 0; + + vector< TopoDS_Vertex > vertex( uv.size() ); + for ( size_t i = 0; i < uv.size(); ++i ) + vertex[i] = BRepBuilderAPI_MakeVertex( surface->Value( uv[i].X(), uv[i].Y() )); + + TopoDS_Wire aWire; + BRep_Builder aBuilder; + aBuilder.MakeWire(aWire); + for ( size_t i = 1; i < vertex.size(); ++i ) + { + TopoDS_Edge edge = BRepBuilderAPI_MakeEdge( vertex[i-1], vertex[i] ); + aBuilder.Add( aWire, edge ); + } + + // if ( myEdge.size() == 2 && FirstVertex().IsSame( LastVertex() )) + // aWire.Closed(true); // issue 0021141 + + return new BRepAdaptor_CompCurve( aWire ); +} + +//================================================================================ +/*! + * \brief Copy points of an EDGE + */ +//================================================================================ + +void SMESH_MAT2d::Branch::init( vector& maEdges, + const Boundary* boundary, + map< const TVDVertex*, BranchEndType > endType ) +{ + if ( maEdges.empty() ) return; + + _boundary = boundary; + _maEdges.swap( maEdges ); + + + _params.reserve( _maEdges.size() + 1 ); + _params.push_back( 0. ); + for ( size_t i = 0; i < _maEdges.size(); ++i ) + _params.push_back( _params.back() + length( _maEdges[i] )); + + for ( size_t i = 1; i < _params.size(); ++i ) + _params[i] /= _params.back(); + + + _endPoint1._vertex = _maEdges.front()->vertex1(); + _endPoint2._vertex = _maEdges.back ()->vertex0(); + + if ( endType.count( _endPoint1._vertex )) + _endPoint1._type = endType[ _endPoint1._vertex ]; + if ( endType.count( _endPoint2._vertex )) + _endPoint2._type = endType[ _endPoint2._vertex ]; +} + +//================================================================================ +/*! + * \brief fills BranchEnd::_branches of its ends + */ +//================================================================================ + +void SMESH_MAT2d::Branch::setBranchesToEnds( const vector< Branch >& branches ) +{ + for ( size_t i = 0; i < branches.size(); ++i ) + { + if ( this->_endPoint1._vertex == branches[i]._endPoint1._vertex || + this->_endPoint1._vertex == branches[i]._endPoint2._vertex ) + this->_endPoint1._branches.push_back( &branches[i] ); + + if ( this->_endPoint2._vertex == branches[i]._endPoint1._vertex || + this->_endPoint2._vertex == branches[i]._endPoint2._vertex ) + this->_endPoint2._branches.push_back( &branches[i] ); + } +} + +//================================================================================ +/*! + * \brief returns a BranchPoint corresponding to a TVDVertex + */ +//================================================================================ + +SMESH_MAT2d::BranchPoint SMESH_MAT2d::Branch::getPoint( const TVDVertex* vertex ) const +{ + BranchPoint p; + p._branch = this; + p._iEdge = 0; + + if ( vertex == _maEdges[0]->vertex1() ) + { + p._edgeParam = 0; + } + else + { + for ( ; p._iEdge < _maEdges.size(); ++p._iEdge ) + if ( vertex == _maEdges[ p._iEdge ]->vertex0() ) + { + p._edgeParam = _params[ p._iEdge ]; + break; + } + } + return p; +} + +//================================================================================ +/*! + * \brief Sets a proxy point for a removed branch + * \param [in] proxyPoint - a point of another branch to which all points of this + * branch are mapped + */ +//================================================================================ + +void SMESH_MAT2d::Branch::setRemoved( const BranchPoint& proxyPoint ) +{ + _proxyPoint = proxyPoint; +} + +//================================================================================ +/*! + * \brief Returns points on two EDGEs, equidistant from a given point of this Branch + * \param [in] param - [0;1] normalized param on the Branch + * \param [out] bp1 - BoundaryPoint on EDGE with a lower index + * \param [out] bp2 - BoundaryPoint on EDGE with a higher index + * \return bool - true if the BoundaryPoint's found + */ +//================================================================================ + +bool SMESH_MAT2d::Branch::getBoundaryPoints(double param, + BoundaryPoint& bp1, + BoundaryPoint& bp2 ) const +{ + if ( param < _params[0] || param > _params.back() ) + return false; + + // look for an index of a MA edge by param + double ip = param * _params.size(); + size_t i = size_t( Min( int( _maEdges.size()-1), int( ip ))); + + while ( param < _params[i ] ) --i; + while ( param > _params[i+1] ) ++i; + + double r = ( param - _params[i] ) / ( _params[i+1] - _params[i] ); + + return getBoundaryPoints( i, r, bp1, bp2 ); +} + +//================================================================================ +/*! + * \brief Returns points on two EDGEs, equidistant from a given point of this Branch + * \param [in] iMAEdge - index of a MA edge within this Branch + * \param [in] maEdgeParam - [0;1] normalized param on the \a iMAEdge + * \param [out] bp1 - BoundaryPoint on EDGE with a lower index + * \param [out] bp2 - BoundaryPoint on EDGE with a higher index + * \return bool - true if the BoundaryPoint's found + */ +//================================================================================ + +bool SMESH_MAT2d::Branch::getBoundaryPoints(std::size_t iMAEdge, + double maEdgeParam, + BoundaryPoint& bp1, + BoundaryPoint& bp2 ) const +{ + if ( isRemoved() ) + return _proxyPoint._branch->getBoundaryPoints( _proxyPoint, bp1, bp2 ); + + if ( iMAEdge > _maEdges.size() ) + return false; + if ( iMAEdge == _maEdges.size() ) + iMAEdge = _maEdges.size() - 1; + + size_t iGeom1 = getGeomEdge( _maEdges[ iMAEdge ] ); + size_t iGeom2 = getGeomEdge( _maEdges[ iMAEdge ]->twin() ); + size_t iSeg1 = getBndSegment( _maEdges[ iMAEdge ] ); + size_t iSeg2 = getBndSegment( _maEdges[ iMAEdge ]->twin() ); + + return ( _boundary->getPoint( iGeom1, iSeg1, maEdgeParam, bp1 ) && + _boundary->getPoint( iGeom2, iSeg2, maEdgeParam, bp2 )); +} + +//================================================================================ +/*! + * \brief Returns points on two EDGEs, equidistant from a given point of this Branch + */ +//================================================================================ + +bool SMESH_MAT2d::Branch::getBoundaryPoints(const BranchPoint& p, + BoundaryPoint& bp1, + BoundaryPoint& bp2 ) const +{ + return ( p._branch ? p._branch : this )->getBoundaryPoints( p._iEdge, p._edgeParam, bp1, bp2 ); +} + +//================================================================================ +/*! + * \brief Return a parameter of a BranchPoint normalized within this Branch + */ +//================================================================================ + +bool SMESH_MAT2d::Branch::getParameter(const BranchPoint & p, double & u ) const +{ + if ( this != p._branch && p._branch ) + return p._branch->getParameter( p, u ); + + if ( isRemoved() ) + return _proxyPoint._branch->getParameter( _proxyPoint, u ); + + if ( p._iEdge > _params.size()-1 ) + return false; + if ( p._iEdge == _params.size()-1 ) + return u = 1.; + + u = ( _params[ p._iEdge ] * ( 1 - p._edgeParam ) + + _params[ p._iEdge+1 ] * p._edgeParam ); + + return true; +} + +//================================================================================ +/*! + * \brief Check type of both ends + */ +//================================================================================ + +bool SMESH_MAT2d::Branch::hasEndOfType(BranchEndType type) const +{ + return ( _endPoint1._type == type || _endPoint2._type == type ); +} + +//================================================================================ +/*! + * \brief Returns MA points + * \param [out] points - the 2d points + * \param [in] scale - the scale that was used to scale the 2d space of MA + */ +//================================================================================ + +void SMESH_MAT2d::Branch::getPoints( std::vector< gp_XY >& points, + const double scale[2]) const +{ + points.resize( _maEdges.size() + 1 ); + + points[0].SetCoord( _maEdges[0]->vertex1()->x() / scale[0], // CCW order! -> vertex1 not vertex0 + _maEdges[0]->vertex1()->y() / scale[1] ); + + for ( size_t i = 0; i < _maEdges.size(); ++i ) + points[i+1].SetCoord( _maEdges[i]->vertex0()->x() / scale[0], + _maEdges[i]->vertex0()->y() / scale[1] ); +} + +//================================================================================ +/*! + * \brief Return indices of EDGEs equidistant from this branch + */ +//================================================================================ + +void SMESH_MAT2d::Branch::getGeomEdges( std::vector< std::size_t >& edgeIDs1, + std::vector< std::size_t >& edgeIDs2 ) const +{ + edgeIDs1.push_back( getGeomEdge( _maEdges[0] )); + edgeIDs2.push_back( getGeomEdge( _maEdges[0]->twin() )); + + for ( size_t i = 1; i < _maEdges.size(); ++i ) + { + size_t ie1 = getGeomEdge( _maEdges[i] ); + size_t ie2 = getGeomEdge( _maEdges[i]->twin() ); + + if ( edgeIDs1.back() != ie1 ) edgeIDs1.push_back( ie1 ); + if ( edgeIDs2.back() != ie2 ) edgeIDs2.push_back( ie2 ); + } +} + +//================================================================================ +/*! + * \brief Looks for a BranchPoint position around a concave VERTEX + */ +//================================================================================ + +bool SMESH_MAT2d::Branch::addDivPntForConcaVertex( std::vector< std::size_t >& edgeIDs1, + std::vector< std::size_t >& edgeIDs2, + std::vector< BranchPoint >& divPoints, + const vector& maEdges, + const vector& maEdgesTwin, + int & i) const +{ + // if there is a concave vertex between EDGEs + // then position of a dividing BranchPoint is undefined, it is somewhere + // on an arc-shaped part of the Branch around the concave vertex. + // Chose this position by a VERTEX of the opposite EDGE, or put it in the middle + // of the arc if there is no opposite VERTEX. + // All null-length segments around a VERTEX belong to one of EDGEs. + + BranchPoint divisionPnt; + divisionPnt._branch = this; + + BranchIterator iCur( maEdges, i ); + + size_t ie1 = getGeomEdge( maEdges [i] ); + size_t ie2 = getGeomEdge( maEdgesTwin[i] ); + + size_t iSeg1 = getBndSegment( iCur.edgePrev() ); + size_t iSeg2 = getBndSegment( iCur.edge() ); + bool isConcaPrev = _boundary->isConcaveSegment( edgeIDs1.back(), iSeg1 ); + bool isConcaNext = _boundary->isConcaveSegment( ie1, iSeg2 ); + if ( !isConcaNext && !isConcaPrev ) + return false; + + bool isConcaveV = false; + + const TVDEdge* maE; + BranchIterator iPrev( maEdges, i ), iNext( maEdges, i ); + --iPrev; + if ( isConcaNext ) // all null-length segments follow + { + // look for a VERTEX of the opposite EDGE + // iNext - next after all null-length segments + while ( maE = ++iNext ) + { + iSeg2 = getBndSegment( maE ); + if ( !_boundary->isConcaveSegment( ie1, iSeg2 )) + break; + } + bool vertexFound = false; + for ( ++iCur; iCur < iNext; ++iCur ) + { + ie2 = getGeomEdge( maEdgesTwin[ iCur.indexMod() ] ); + if ( ie2 != edgeIDs2.back() ) + { + // opposite VERTEX found + divisionPnt._iEdge = iCur.indexMod(); + divisionPnt._edgeParam = 0; + divPoints.push_back( divisionPnt ); + edgeIDs1.push_back( ie1 ); + edgeIDs2.push_back( ie2 ); + vertexFound = true; + } + } + if ( vertexFound ) + { + --iNext; + iPrev = iNext; // not to add a BP in the moddle + i = iNext.indexMod(); + isConcaveV = true; + } + } + else if ( isConcaPrev ) + { + // all null-length segments passed, find their beginning + while ( maE = iPrev.edgePrev() ) + { + iSeg1 = getBndSegment( maE ); + if ( _boundary->isConcaveSegment( edgeIDs1.back(), iSeg1 )) + --iPrev; + else + break; + } + } + + if ( iPrev.index() < i-1 || iNext.index() > i ) + { + // no VERTEX on the opposite EDGE, put the Branch Point in the middle + divisionPnt._iEdge = iPrev.indexMod(); + ++iPrev; + double par1 = _params[ iPrev.indexMod() ], par2 = _params[ iNext.indexMod() ]; + double midPar = 0.5 * ( par1 + par2 ); + for ( ; _params[ iPrev.indexMod() ] < midPar; ++iPrev ) + divisionPnt._iEdge = iPrev.indexMod(); + divisionPnt._edgeParam = + ( _params[ iPrev.indexMod() ] - midPar ) / + ( _params[ iPrev.indexMod() ] - _params[ divisionPnt._iEdge ] ); + divPoints.push_back( divisionPnt ); + isConcaveV = true; + } + + return isConcaveV; +} + +//================================================================================ +/*! + * \brief Return indices of opposite parts of EDGEs equidistant from this branch + * \param [out] edgeIDs1 - EDGE index opposite to the edgeIDs2[i]-th EDGE + * \param [out] edgeIDs2 - EDGE index opposite to the edgeIDs1[i]-th EDGE + * \param [out] divPoints - BranchPoint's located between two successive unique + * pairs of EDGE indices. A \a divPoints[i] can separate e.g. two following pairs + * of EDGE indices < 0, 2 > and < 0, 1 >. Number of \a divPoints is one less + * than number of \a edgeIDs + */ +//================================================================================ + +void SMESH_MAT2d::Branch::getOppositeGeomEdges( std::vector< std::size_t >& edgeIDs1, + std::vector< std::size_t >& edgeIDs2, + std::vector< BranchPoint >& divPoints) const +{ + edgeIDs1.clear(); + edgeIDs2.clear(); + divPoints.clear(); + + std::vector twins( _maEdges.size() ); + for ( size_t i = 0; i < _maEdges.size(); ++i ) + twins[i] = _maEdges[i]->twin(); + + BranchIterator maIter ( _maEdges, 0 ); + BranchIterator twIter ( twins, 0 ); + // size_t lastConcaE1 = _boundary.nbEdges(); + // size_t lastConcaE2 = _boundary.nbEdges(); + + // if ( maIter._closed ) // closed branch + // { + // edgeIDs1.push_back( getGeomEdge( _maEdges.back() )); + // edgeIDs2.push_back( getGeomEdge( _maEdges.back()->twin() )); + // } + // else + { + edgeIDs1.push_back( getGeomEdge( maIter.edge() )); + edgeIDs2.push_back( getGeomEdge( twIter.edge() )); + } + + BranchPoint divisionPnt; + divisionPnt._branch = this; + + for ( ++maIter, ++twIter; maIter.index() < _maEdges.size(); ++maIter, ++twIter ) + { + size_t ie1 = getGeomEdge( maIter.edge() ); + size_t ie2 = getGeomEdge( twIter.edge() ); + + bool otherE1 = ( edgeIDs1.back() != ie1 ); + bool otherE2 = ( edgeIDs2.back() != ie2 ); + + if ( !otherE1 && !otherE2 && maIter._closed ) + { + int iSegPrev1 = getBndSegment( maIter.edgePrev() ); + int iSegCur1 = getBndSegment( maIter.edge() ); + otherE1 = Abs( iSegPrev1 - iSegCur1 ) != 1; + int iSegPrev2 = getBndSegment( twIter.edgePrev() ); + int iSegCur2 = getBndSegment( twIter.edge() ); + otherE2 = Abs( iSegPrev2 - iSegCur2 ) != 1; + } + + if ( otherE1 || otherE2 ) + { + bool isConcaveV = false; + if ( otherE1 && !otherE2 ) + { + isConcaveV = addDivPntForConcaVertex( edgeIDs1, edgeIDs2, divPoints, + _maEdges, twins, maIter._i ); + } + if ( !otherE1 && otherE2 ) + { + isConcaveV = addDivPntForConcaVertex( edgeIDs2, edgeIDs1, divPoints, + twins, _maEdges, maIter._i ); + } + + if ( isConcaveV ) + { + ie1 = getGeomEdge( maIter.edge() ); + ie2 = getGeomEdge( twIter.edge() ); + } + if ( !isConcaveV || otherE1 || otherE2 ) + { + edgeIDs1.push_back( ie1 ); + edgeIDs2.push_back( ie2 ); + } + if ( divPoints.size() < edgeIDs1.size() - 1 ) + { + divisionPnt._iEdge = maIter.index(); + divisionPnt._edgeParam = 0; + divPoints.push_back( divisionPnt ); + } + + } // if ( edgeIDs1.back() != ie1 || edgeIDs2.back() != ie2 ) + } // loop on _maEdges +} + +//================================================================================ +/*! + * \brief Store data of boundary segments in TVDEdge + */ +//================================================================================ + +void SMESH_MAT2d::Branch::setGeomEdge( std::size_t geomIndex, const TVDEdge* maEdge ) +{ + if ( maEdge ) maEdge->cell()->color( geomIndex ); +} +std::size_t SMESH_MAT2d::Branch::getGeomEdge( const TVDEdge* maEdge ) +{ + return maEdge ? maEdge->cell()->color() : std::string::npos; +} +void SMESH_MAT2d::Branch::setBndSegment( std::size_t segIndex, const TVDEdge* maEdge ) +{ + if ( maEdge ) maEdge->color( segIndex ); +} +std::size_t SMESH_MAT2d::Branch::getBndSegment( const TVDEdge* maEdge ) +{ + return maEdge ? maEdge->color() : std::string::npos; +} + +//================================================================================ +/*! + * \brief Returns a boundary point on a given EDGE + * \param [in] iEdge - index of the EDGE within MedialAxis + * \param [in] iSeg - index of a boundary segment within this Branch + * \param [in] u - [0;1] normalized param within \a iSeg-th segment + * \param [out] bp - the found BoundaryPoint + * \return bool - true if the BoundaryPoint is found + */ +//================================================================================ + +bool SMESH_MAT2d::Boundary::getPoint( std::size_t iEdge, + std::size_t iSeg, + double u, + BoundaryPoint& bp ) const +{ + if ( iEdge >= _pointsPerEdge.size() ) + return false; + if ( iSeg+1 >= _pointsPerEdge[ iEdge ]._params.size() ) + return false; + + // This method is called by Branch that can have an opposite orientation, + // hence u is inverted depending on orientation coded as a sign of _maEdge index + bool isReverse = ( _pointsPerEdge[ iEdge ]._maEdges[ iSeg ].second < 0 ); + if ( isReverse ) + u = 1. - u; + + double p0 = _pointsPerEdge[ iEdge ]._params[ iSeg ]; + double p1 = _pointsPerEdge[ iEdge ]._params[ iSeg+1 ]; + + bp._param = p0 * ( 1. - u ) + p1 * u; + bp._edgeIndex = iEdge; + + return true; +} + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/SMESH_Quadtree.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/SMESH_Quadtree.cpp new file mode 100644 index 000000000000..b43fd02cb666 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/SMESH_Quadtree.cpp @@ -0,0 +1,76 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH_Quadtree : Quartree implementation +// File : SMESH_Quadtree.cxx +// Module : SMESH +// +#include "SMESH_Quadtree.hxx" + +//=========================================================================== +/*! + * Constructor. limit must be provided at tree root construction. + * limit will be deleted by SMESH_Quadtree. + */ +//=========================================================================== + +SMESH_Quadtree::SMESH_Quadtree (SMESH_TreeLimit* limit): TBaseTree( limit ) +{ +} + +//================================================================= +/*! + * \brief Allocate a bndbox according to childIndex. childIndex is zero based + */ +//================================================================= + +Bnd_B2d* SMESH_Quadtree::newChildBox(int childIndex) const +{ + gp_XY min = getBox()->CornerMin(); + gp_XY max = getBox()->CornerMax(); + gp_XY HSize = (max - min)/2.; + gp_XY childHsize = HSize/2.; + + gp_XY minChild( min.X() + childIndex%2 * HSize.X(), + min.Y() + ( childIndex<2 ) * HSize.Y()); + + return new Bnd_B2d(minChild+childHsize,childHsize); +} + +//=========================================================================== +/*! + * \brief Compute the bigger dimension of my box + */ +//=========================================================================== + +double SMESH_Quadtree::maxSize() const +{ + if ( getBox() && !getBox()->IsVoid() ) + { + gp_XY min = getBox()->CornerMin(); + gp_XY max = getBox()->CornerMax(); + gp_XY Size = (max - min); + double returnVal = (Size.X()>Size.Y())?Size.X():Size.Y(); + return returnVal; + } + return 0.; +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Adaptive1D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Adaptive1D.cpp new file mode 100644 index 000000000000..45b538ef37c5 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Adaptive1D.cpp @@ -0,0 +1,1513 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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_Adaptive1D.cxx +// Module : SMESH +// +#include "StdMeshers_Adaptive1D.hxx" + +#include "SMESH_Gen.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_Octree.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_HypoFilter.hxx" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace std; + +namespace // internal utils +{ + //================================================================================ + /*! + * \brief Bnd_B3d with access to its center and half-size + */ + struct BBox : public Bnd_B3d + { + gp_XYZ Center() const { return gp_XYZ( myCenter[0], myCenter[1], myCenter[2] ); } + gp_XYZ HSize() const { return gp_XYZ( myHSize[0], myHSize[1], myHSize[2] ); } + double Size() const { return 2 * myHSize[0]; } + }; + //================================================================================ + /*! + * \brief Working data of an EDGE + */ + struct EdgeData + { + struct ProbePnt + { + gp_Pnt myP; + double myU; + double mySegSize; + ProbePnt( gp_Pnt p, double u, double sz=1e100 ): myP( p ), myU( u ), mySegSize( sz ) {} + }; + BRepAdaptor_Curve myC3d; + double myLength; + list< ProbePnt > myPoints; + BBox myBBox; + + typedef list< ProbePnt >::iterator TPntIter; + void AddPoint( TPntIter where, double u ) + { + TPntIter it = myPoints.insert( where, ProbePnt( myC3d.Value( u ), u )); + myBBox.Add( it->myP.XYZ() ); + } + const ProbePnt& First() const { return myPoints.front(); } + const ProbePnt& Last() const { return myPoints.back(); } + const TopoDS_Edge& Edge() const { return myC3d.Edge(); } + bool IsTooDistant( const BBox& faceBox, double maxSegSize ) const + { + gp_XYZ hsize = myBBox.HSize() + gp_XYZ( maxSegSize, maxSegSize, maxSegSize ); + return faceBox.IsOut ( Bnd_B3d( myBBox.Center(), hsize )); + } + }; + //================================================================================ + /*! + * \brief Octree of local segment size + */ + class SegSizeTree : public SMESH_Octree + { + double mySegSize; // segment size + + // structure holding some common parameters of SegSizeTree + struct _CommonData : public SMESH_TreeLimit + { + double myGrading, myMinSize, myMaxSize; + }; + _CommonData* getData() const { return (_CommonData*) myLimit; } + + SegSizeTree(double size): SMESH_Octree(), mySegSize(size) + { + allocateChildren(); + } + void allocateChildren() + { + myChildren = new SMESH_Octree::TBaseTree*[nbChildren()]; + for ( int i = 0; i < nbChildren(); ++i ) + myChildren[i] = NULL; + } + virtual box_type* buildRootBox() { return 0; } + virtual SegSizeTree* newChild() const { return 0; } + virtual void buildChildrenData() {} + + public: + + SegSizeTree( Bnd_B3d & bb, double grading, double mixSize, double maxSize); + void SetSize( const gp_Pnt& p, double size ); + double SetSize( const gp_Pnt& p1, const gp_Pnt& p2 ); + double GetSize( const gp_Pnt& p ) const; + const BBox* GetBox() const { return (BBox*) getBox(); } + double GetMinSize() { return getData()->myMinSize; } + }; + //================================================================================ + /*! + * \brief Adaptive wire discertizator. + */ + class AdaptiveAlgo : public StdMeshers_Regular_1D + { + public: + AdaptiveAlgo(int hypId, int studyId, SMESH_Gen* gen); + virtual bool Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape ); + virtual bool Evaluate(SMESH_Mesh & theMesh, + const TopoDS_Shape & theShape, + MapShapeNbElems& theResMap); + void SetHypothesis( const StdMeshers_Adaptive1D* hyp ); + private: + + bool makeSegments(); + + const StdMeshers_Adaptive1D* myHyp; + SMESH_Mesh* myMesh; + vector< EdgeData > myEdges; + SegSizeTree* mySizeTree; + }; + + //================================================================================ + /*! + * \brief Segment of Poly_PolygonOnTriangulation + */ + struct Segment + { + gp_XYZ myPos, myDir; + double myLength; + + void Init( const gp_Pnt& p1, const gp_Pnt& p2 ) + { + myPos = p1.XYZ(); + myDir = p2.XYZ() - p1.XYZ(); + myLength = myDir.Modulus(); + if ( myLength > std::numeric_limits::min() ) + myDir /= myLength; + } + bool Distance( const gp_Pnt& P, double& dist ) const // returns length of normal projection + { + gp_XYZ p = P.XYZ(); + p.Subtract( myPos ); + double proj = p.Dot( myDir ); + if ( 0 < proj && proj < myLength ) + { + p.Cross( myDir ); + dist = p.Modulus(); + return true; + } + return false; + } + }; + //================================================================================ + /*! + * \brief Data of triangle used to locate it in an octree and to find distance + * to a point + */ + struct Triangle + { + Bnd_B3d myBox; + bool myIsChecked; // to mark treated trias instead of using std::set + bool myHasNodeOnVertex; + Segment* mySegments[3]; + // data for DistToProjection() + gp_XYZ myN0, myEdge1, myEdge2, myNorm, myPVec; + double myInvDet, myMaxSize2; + + void Init( const gp_Pnt& n1, const gp_Pnt& n2, const gp_Pnt& n3 ); + bool DistToProjection( const gp_Pnt& p, double& dist ) const; + bool DistToSegment ( const gp_Pnt& p, double& dist ) const; + }; + //================================================================================ + /*! + * \brief Element data held by ElementBndBoxTree + algorithm computing a distance + * from a point to element + */ + class ElementBndBoxTree; + struct ElemTreeData : public SMESH_TreeLimit + { + vector< int > myWorkIDs[8];// to speed up filling ElementBndBoxTree::_elementIDs + virtual const Bnd_B3d* GetBox(int elemID) const = 0; + }; + struct TriaTreeData : public ElemTreeData + { + vector< Triangle > myTrias; + vector< Segment > mySegments; + double myFaceTol; + double myTriasDeflection; + BBox myBBox; + BRepAdaptor_Surface mySurface; + ElementBndBoxTree* myTree; + const Poly_Array1OfTriangle* myPolyTrias; + const TColgp_Array1OfPnt* myNodes; + bool myOwnNodes; + + typedef vector IntVec; + IntVec myFoundTriaIDs; + + TriaTreeData( const TopoDS_Face& face, ElementBndBoxTree* triaTree ); + ~TriaTreeData() { if ( myOwnNodes ) delete myNodes; myNodes = NULL; } + virtual const Bnd_B3d* GetBox(int elemID) const { return &myTrias[elemID].myBox; } + void PrepareToTriaSearch(); + void SetSizeByTrias( SegSizeTree& sizeTree, double deflection ) const; + double GetMinDistInSphere(const gp_Pnt& p, + const double radius, + const bool projectedOnly, + const gp_Pnt* avoidP=0) const; + }; + //================================================================================ + /*! + * \brief Octree of triangles or segments + */ + class ElementBndBoxTree : public SMESH_Octree + { + public: + ElementBndBoxTree(const TopoDS_Face& face); + void GetElementsInSphere( const gp_XYZ& center, + const double radius, vector & foundElemIDs) const; + void FillIn(); + ElemTreeData* GetElemData() const { return (ElemTreeData*) myLimit; } + TriaTreeData* GetTriaData() const { return (TriaTreeData*) myLimit; } + + protected: + ElementBndBoxTree() {} + SMESH_Octree* newChild() const { return new ElementBndBoxTree; } + void buildChildrenData(); + Bnd_B3d* buildRootBox(); + private: + vector< int > _elementIDs; + }; + //================================================================================ + /*! + * \brief Link of two nodes + */ + struct NLink : public std::pair< int, int > + { + NLink( int n1, int n2 ) + { + if ( n1 < n2 ) + { + first = n1; + second = n2; + } + else + { + first = n2; + second = n1; + } + } + int N1() const { return first; } + int N2() const { return second; } + }; + + //================================================================================ + /*! + * \brief Initialize TriaTreeData + */ + //================================================================================ + + TriaTreeData::TriaTreeData( const TopoDS_Face& face, ElementBndBoxTree* triaTree ) + : myTriasDeflection(0), mySurface( face ), + myTree(NULL), myPolyTrias(NULL), myNodes(NULL), myOwnNodes(false) + { + TopLoc_Location loc; + Handle(Poly_Triangulation) tr = BRep_Tool::Triangulation( face, loc ); + if ( !tr.IsNull() ) + { + myFaceTol = SMESH_MesherHelper::MaxTolerance( face ); + myTree = triaTree; + myNodes = & tr->Nodes(); + myPolyTrias = & tr->Triangles(); + myTriasDeflection = tr->Deflection(); + if ( !loc.IsIdentity() ) // transform nodes if necessary + { + TColgp_Array1OfPnt* trsfNodes = new TColgp_Array1OfPnt( myNodes->Lower(), myNodes->Upper() ); + trsfNodes->Assign( *myNodes ); + myNodes = trsfNodes; + myOwnNodes = true; + const gp_Trsf& trsf = loc; + for ( int i = trsfNodes->Lower(); i <= trsfNodes->Upper(); ++i ) + trsfNodes->ChangeValue(i).Transform( trsf ); + } + for ( int i = myNodes->Lower(); i <= myNodes->Upper(); ++i ) + myBBox.Add( myNodes->Value(i).XYZ() ); + } + } + //================================================================================ + /*! + * \brief Prepare data for search of trinagles in GetMinDistInSphere() + */ + //================================================================================ + + void TriaTreeData::PrepareToTriaSearch() + { + if ( !myTrias.empty() ) return; // already done + if ( !myPolyTrias ) return; + + // get all boundary links and nodes on VERTEXes + map< NLink, Segment* > linkToSegMap; + map< NLink, Segment* >::iterator l2s; + set< int > vertexNodes; + TopLoc_Location loc; + Handle(Poly_Triangulation) tr = BRep_Tool::Triangulation( mySurface.Face(), loc ); + if ( !tr.IsNull() ) + { + TopTools_IndexedMapOfShape edgeMap; + TopExp::MapShapes( mySurface.Face(), TopAbs_EDGE, edgeMap ); + for ( int iE = 1; iE <= edgeMap.Extent(); ++iE ) + { + const TopoDS_Edge& edge = TopoDS::Edge( edgeMap( iE )); + Handle(Poly_PolygonOnTriangulation) polygon = + BRep_Tool::PolygonOnTriangulation( edge, tr, loc ); + if ( polygon.IsNull() ) + continue; + const TColStd_Array1OfInteger& nodes = polygon->Nodes(); + for ( int i = nodes.Lower(); i < nodes.Upper(); ++i ) + linkToSegMap.insert( make_pair( NLink( nodes(i), nodes(i+1)), (Segment*)0 )); + vertexNodes.insert( nodes( nodes.Lower())); + vertexNodes.insert( nodes( nodes.Upper())); + } + // fill mySegments by boundary links + mySegments.resize( linkToSegMap.size() ); + int iS = 0; + for ( l2s = linkToSegMap.begin(); l2s != linkToSegMap.end(); ++l2s, ++iS ) + { + const NLink& link = (*l2s).first; + (*l2s).second = & mySegments[ iS ]; + mySegments[ iS ].Init( myNodes->Value( link.N1() ), + myNodes->Value( link.N2() )); + } + } + + // initialize myTrias + myTrias.resize( myPolyTrias->Length() ); + Standard_Integer n1,n2,n3; + for ( int i = 1; i <= myPolyTrias->Upper(); ++i ) + { + Triangle & t = myTrias[ i-1 ]; + myPolyTrias->Value( i ).Get( n1,n2,n3 ); + t.Init( myNodes->Value( n1 ), + myNodes->Value( n2 ), + myNodes->Value( n3 )); + int nbSeg = 0; + if (( l2s = linkToSegMap.find( NLink( n1, n2 ))) != linkToSegMap.end()) + t.mySegments[ nbSeg++ ] = l2s->second; + if (( l2s = linkToSegMap.find( NLink( n2, n3 ))) != linkToSegMap.end()) + t.mySegments[ nbSeg++ ] = l2s->second; + if (( l2s = linkToSegMap.find( NLink( n3, n1 ))) != linkToSegMap.end()) + t.mySegments[ nbSeg++ ] = l2s->second; + while ( nbSeg < 3 ) + t.mySegments[ nbSeg++ ] = NULL; + + t.myIsChecked = false; + t.myHasNodeOnVertex = ( vertexNodes.count( n1 ) || + vertexNodes.count( n2 ) || + vertexNodes.count( n3 )); + } + + // fill the tree of triangles + myTree->FillIn(); + } + + //================================================================================ + /*! + * \brief Set size of segments by size of triangles + */ + //================================================================================ + + void TriaTreeData::SetSizeByTrias( SegSizeTree& sizeTree, double hypDeflection ) const + { + if ( mySurface.GetType() == GeomAbs_Plane || + myTriasDeflection <= 1e-100 ) + return; + const double factor = hypDeflection / myTriasDeflection; + + bool isConstSize; + switch( mySurface.GetType() ) { + case GeomAbs_Cylinder: + case GeomAbs_Sphere: + case GeomAbs_Torus: + isConstSize = true; break; + default: + isConstSize = false; + } + + map< NLink, double > lenOfDoneLink; + map< NLink, double >::iterator link2len; + + Standard_Integer n[4]; + gp_Pnt p[4]; + double a[3]; + bool isDone[3]; + double size = -1., maxLinkLen; + int jLongest; + + //int nbLinks = 0; + for ( int i = 1; i <= myPolyTrias->Upper(); ++i ) + { + // get corners of a triangle + myPolyTrias->Value( i ).Get( n[0],n[1],n[2] ); + n[3] = n[0]; + p[0] = myNodes->Value( n[0] ); + p[1] = myNodes->Value( n[1] ); + p[2] = myNodes->Value( n[2] ); + p[3] = p[0]; + // get length of links and find the longest one + maxLinkLen = 0; + for ( int j = 0; j < 3; ++j ) + { + link2len = lenOfDoneLink.insert( make_pair( NLink( n[j], n[j+1] ), -1. )).first; + isDone[j] = !((*link2len).second < 0 ); + a[j] = isDone[j] ? (*link2len).second : (*link2len).second = p[j].Distance( p[j+1] ); + if ( isDone[j] ) + lenOfDoneLink.erase( link2len ); + if ( a[j] > maxLinkLen ) + { + maxLinkLen = a[j]; + jLongest = j; + } + } + // compute minimal altitude of a triangle + if ( !isConstSize || size < 0. ) + { + double s = 0.5 * ( a[0] + a[1] + a[2] ); + double area = sqrt( s * (s - a[0]) * (s - a[1]) * (s - a[2])); + size = 2 * area / maxLinkLen; // minimal altitude + } + // set size to the size tree + if ( !isDone[ jLongest ] || !isConstSize ) + { + //++nbLinks; + if ( size < numeric_limits::min() ) + continue; + int nb = Max( 1, int( maxLinkLen / size / 2 )); + for ( int k = 0; k <= nb; ++k ) + { + double r = double( k ) / nb; + sizeTree.SetSize( r * p[ jLongest ].XYZ() + ( 1-r ) * p[ jLongest+1 ].XYZ(), + size * factor ); + } + } + //cout << "SetSizeByTrias, i="<< i << " " << sz * factor << endl; + } + // cout << "SetSizeByTrias, nn tria="<< myPolyTrias->Upper() + // << " nb links" << nbLinks << " isConstSize="<( this ); + me->myFoundTriaIDs.clear(); + myTree->GetElementsInSphere( p.XYZ(), radius, me->myFoundTriaIDs ); + if ( myFoundTriaIDs.empty() ) + return minDist2; + + Standard_Integer n[ 3 ]; + for ( size_t i = 0; i < myFoundTriaIDs.size(); ++i ) + { + Triangle& t = me->myTrias[ myFoundTriaIDs[i] ]; + if ( t.myIsChecked ) + continue; + t.myIsChecked = true; + + double d, minD2 = minDist2; + myPolyTrias->Value( myFoundTriaIDs[i]+1 ).Get( n[0],n[1],n[2] ); + if ( avoidPnt && t.myHasNodeOnVertex ) + { + bool avoidTria = false; + for ( int i = 0; i < 3; ++i ) + { + const gp_Pnt& pn = myNodes->Value(n[i]); + if ( avoidTria = ( pn.SquareDistance( *avoidPnt ) <= tol2 )) + break; + if ( !projectedOnly ) + minD2 = Min( minD2, pn.SquareDistance( p )); + } + if ( avoidTria ) + continue; + if (( projectedOnly || minD2 < t.myMaxSize2 ) && + ( t.DistToProjection( p, d ) || t.DistToSegment( p, d ))) + minD2 = Min( minD2, d*d ); + minDist2 = Min( minDist2, minD2 ); + } + else if ( projectedOnly ) + { + if ( t.DistToProjection( p, d ) && d*d > dMin2 ) + minDist2 = Min( minDist2, d*d ); + } + else + { + for ( int i = 0; i < 3; ++i ) + minD2 = Min( minD2, p.SquareDistance( myNodes->Value(n[i]) )); + if ( minD2 < t.myMaxSize2 && ( t.DistToProjection( p, d ) || t.DistToSegment( p, d ))) + minD2 = Min( minD2, d*d ); + minDist2 = Min( minDist2, minD2 ); + } + } + + for ( size_t i = 0; i < myFoundTriaIDs.size(); ++i ) + me->myTrias[ myFoundTriaIDs[i] ].myIsChecked = false; + + return sqrt( minDist2 ); + } + //================================================================================ + /*! + * \brief Prepare Triangle data + */ + //================================================================================ + + void Triangle::Init( const gp_Pnt& p1, const gp_Pnt& p2, const gp_Pnt& p3 ) + { + myBox.Add( p1 ); + myBox.Add( p2 ); + myBox.Add( p3 ); + myN0 = p1.XYZ(); + myEdge1 = p2.XYZ() - myN0; + myEdge2 = p3.XYZ() - myN0; + myNorm = myEdge1 ^ myEdge2; + double normSize = myNorm.Modulus(); + if ( normSize > std::numeric_limits::min() ) + { + myNorm /= normSize; + myPVec = myNorm ^ myEdge2; + myInvDet = 1. / ( myEdge1 * myPVec ); + } + else + { + myInvDet = 0.; + } + myMaxSize2 = Max( p2.SquareDistance( p3 ), + Max( myEdge2.SquareModulus(), myEdge1.SquareModulus() )); + } + //================================================================================ + /*! + * \brief Compute distance from a point to the triangle. Return false if the point + * is not projected inside the triangle + */ + //================================================================================ + + bool Triangle::DistToProjection( const gp_Pnt& p, double& dist ) const + { + if ( myInvDet == 0 ) + return false; // degenerated triangle + + /* distance from n0 to the point */ + gp_XYZ tvec = p.XYZ() - myN0; + + /* calculate U parameter and test bounds */ + double u = ( tvec * myPVec ) * myInvDet; + if (u < 0.0 || u > 1.0) + return false; // projected outside the triangle + + /* calculate V parameter and test bounds */ + gp_XYZ qvec = tvec ^ myEdge1; + double v = ( myNorm * qvec) * myInvDet; + if ( v < 0.0 || u + v > 1.0 ) + return false; // projected outside the triangle + + dist = ( myEdge2 * qvec ) * myInvDet; + return true; + } + + //================================================================================ + /*! + * \brief Compute distance from a point to either of mySegments. Return false if the point + * is not projected on a segment + */ + //================================================================================ + + bool Triangle::DistToSegment( const gp_Pnt& p, double& dist ) const + { + dist = 1e100; + bool res = false; + double d; + for ( int i = 0; i < 3; ++i ) + { + if ( !mySegments[ i ]) + break; + if ( mySegments[ i ]->Distance( p, d )) + { + res = true; + dist = Min( dist, d ); + } + } + return res; + } + + //================================================================================ + /*! + * \brief Consturct ElementBndBoxTree of Poly_Triangulation of a FACE + */ + //================================================================================ + + ElementBndBoxTree::ElementBndBoxTree(const TopoDS_Face& face) + :SMESH_Octree() + { + TriaTreeData* data = new TriaTreeData( face, this ); + data->myMaxLevel = 5; + myLimit = data; + } + //================================================================================ + /*! + * \brief Fill all levels of octree of Poly_Triangulation of a FACE + */ + //================================================================================ + + void ElementBndBoxTree::FillIn() + { + if ( myChildren ) return; + TriaTreeData* data = GetTriaData(); + if ( !data->myTrias.empty() ) + { + for ( size_t i = 0; i < data->myTrias.size(); ++i ) + _elementIDs.push_back( i ); + + compute(); + } + } + //================================================================================ + /*! + * \brief Return the maximal box + */ + //================================================================================ + + Bnd_B3d* ElementBndBoxTree::buildRootBox() + { + TriaTreeData* data = GetTriaData(); + Bnd_B3d* box = new Bnd_B3d( data->myBBox ); + return box; + } + //================================================================================ + /*! + * \brief Redistrubute element boxes among children + */ + //================================================================================ + + void ElementBndBoxTree::buildChildrenData() + { + ElemTreeData* data = GetElemData(); + for ( int i = 0; i < _elementIDs.size(); ++i ) + { + const Bnd_B3d* elemBox = data->GetBox( _elementIDs[i] ); + for (int j = 0; j < 8; j++) + if ( !elemBox->IsOut( *myChildren[ j ]->getBox() )) + data->myWorkIDs[ j ].push_back( _elementIDs[i] ); + } + SMESHUtils::FreeVector( _elementIDs ); // = _elements.clear() + free memory + + const int theMaxNbElemsInLeaf = 7; + + for (int j = 0; j < 8; j++) + { + ElementBndBoxTree* child = static_cast( myChildren[j] ); + child->_elementIDs = data->myWorkIDs[ j ]; + if ( child->_elementIDs.size() <= theMaxNbElemsInLeaf ) + child->myIsLeaf = true; + data->myWorkIDs[ j ].clear(); + } + } + //================================================================================ + /*! + * \brief Return elements from leaves intersecting the sphere + */ + //================================================================================ + + void ElementBndBoxTree::GetElementsInSphere( const gp_XYZ& center, + const double radius, + vector & foundElemIDs) const + { + if ( const box_type* box = getBox() ) + { + if ( box->IsOut( center, radius )) + return; + + if ( isLeaf() ) + { + ElemTreeData* data = GetElemData(); + for ( int i = 0; i < _elementIDs.size(); ++i ) + if ( !data->GetBox( _elementIDs[i] )->IsOut( center, radius )) + foundElemIDs.push_back( _elementIDs[i] ); + } + else + { + for (int i = 0; i < 8; i++) + ((ElementBndBoxTree*) myChildren[i])->GetElementsInSphere( center, radius, foundElemIDs ); + } + } + } + + //================================================================================ + /*! + * \brief Constructor of SegSizeTree + * \param [in,out] bb - bounding box enclosing all EDGEs to discretize + * \param [in] grading - factor to get max size of the neighbour segment by + * size of a current one. + */ + //================================================================================ + + SegSizeTree::SegSizeTree( Bnd_B3d & bb, double grading, double minSize, double maxSize ) + : SMESH_Octree( new _CommonData() ) + { + // make cube myBox from the box bb + gp_XYZ pmin = bb.CornerMin(), pmax = bb.CornerMax(); + double maxBoxHSize = 0.5 * Max( pmax.X()-pmin.X(), Max( pmax.Y()-pmin.Y(), pmax.Z()-pmin.Z() )); + maxBoxHSize *= 1.01; + bb.SetHSize( gp_XYZ( maxBoxHSize, maxBoxHSize, maxBoxHSize )); + myBox = new box_type( bb ); + + mySegSize = Min( 2 * maxBoxHSize, maxSize ); + + getData()->myGrading = grading; + getData()->myMinSize = Max( minSize, 2*maxBoxHSize / 1.e6 ); + getData()->myMaxSize = maxSize; + allocateChildren(); + } + + //================================================================================ + /*! + * \brief Set segment size at a given point + */ + //================================================================================ + + void SegSizeTree::SetSize( const gp_Pnt& p, double size ) + { + // check if the point is out of the largest cube + SegSizeTree* root = this; + while ( root->myFather ) + root = (SegSizeTree*) root->myFather; + if ( root->getBox()->IsOut( p.XYZ() )) + return; + + // keep size whthin the valid range + size = Max( size, getData()->myMinSize ); + //size = Min( size, getData()->myMaxSize ); + + // find an existing leaf at the point + SegSizeTree* leaf = (SegSizeTree*) root; + int iChild; + while ( true ) + { + iChild = SMESH_Octree::getChildIndex( p.X(), p.Y(), p.Z(), leaf->GetBox()->Center() ); + if ( leaf->myChildren[ iChild ] ) + leaf = (SegSizeTree*) leaf->myChildren[ iChild ]; + else + break; + } + // don't increase the current size + if ( leaf->mySegSize <= 1.1 * size ) + return; + + // split the found leaf until its box size is less than the given size + const double rootSize = root->GetBox()->Size(); + while ( leaf->GetBox()->Size() > size ) + { + const BBox* bb = leaf->GetBox(); + iChild = SMESH_Octree::getChildIndex( p.X(), p.Y(), p.Z(), bb->Center() ); + SegSizeTree* newLeaf = new SegSizeTree( bb->Size() / 2 ); + leaf->myChildren[iChild] = newLeaf; + newLeaf->myFather = leaf; + newLeaf->myLimit = leaf->myLimit; + newLeaf->myLevel = leaf->myLevel + 1; + newLeaf->myBox = leaf->newChildBox( iChild ); + newLeaf->myBox->Enlarge( rootSize * 1e-10 ); + //newLeaf->myIsLeaf = ( newLeaf->mySegSize <= size ); + leaf = newLeaf; + } + leaf->mySegSize = size; + + // propagate increased size out from the leaf + double boxSize = leaf->GetBox()->Size(); + double sizeInc = size + boxSize * getData()->myGrading; + for ( int iDir = 1; iDir <= 3; ++iDir ) + { + gp_Pnt outPnt = p; + outPnt.SetCoord( iDir, p.Coord( iDir ) + boxSize ); + SetSize( outPnt, sizeInc ); + outPnt.SetCoord( iDir, p.Coord( iDir ) - boxSize ); + SetSize( outPnt, sizeInc ); + } + } + //================================================================================ + /*! + * \brief Set size of a segment given by two end points + */ + //================================================================================ + + double SegSizeTree::SetSize( const gp_Pnt& p1, const gp_Pnt& p2 ) + { + const double size = p1.Distance( p2 ); + gp_XYZ p = 0.5 * ( p1.XYZ() + p2.XYZ() ); + SetSize( p, size ); + SetSize( p1, size ); + SetSize( p2, size ); + //cout << "SetSize " << p1.Distance( p2 ) << " at " << p.X() <<", "<< p.Y()<<", "<GetBox()->Center() ); + if ( leaf->myChildren[ iChild ] ) + leaf = (SegSizeTree*) leaf->myChildren[ iChild ]; + else + return leaf->mySegSize; + } + return mySegSize; // just to return anything + } + + //================================================================================ + /*! + * \brief Evaluate curve deflection between two points + * \param theCurve - the curve + * \param theU1 - the parameter of the first point + * \param theU2 - the parameter of the second point + * \retval double - square deflection value + */ + //================================================================================ + + double deflection2(const BRepAdaptor_Curve & theCurve, + double theU1, + double theU2) + { + // line between theU1 and theU2 + gp_Pnt p1 = theCurve.Value( theU1 ), p2 = theCurve.Value( theU2 ); + gp_Lin segment( p1, gp_Vec( p1, p2 )); + + // evaluate square distance of theCurve from the segment + Standard_Real dist2 = 0; + const int nbPnt = 5; + const double step = ( theU2 - theU1 ) / nbPnt; + while (( theU1 += step ) < theU2 ) + dist2 = Max( dist2, segment.SquareDistance( theCurve.Value( theU1 ))); + + return dist2; + } + +} // namespace + +//======================================================================= +//function : StdMeshers_Adaptive1D +//purpose : Constructor +StdMeshers_Adaptive1D::StdMeshers_Adaptive1D(int hypId, + int studyId, + SMESH_Gen * gen) + :SMESH_Hypothesis(hypId, studyId, gen) +{ + myMinSize = 1e-10; + myMaxSize = 1e+10; + myDeflection = 1e-2; + myAlgo = NULL; + _name = "Adaptive1D"; + _param_algo_dim = 1; // is used by SMESH_Regular_1D +} +//======================================================================= +//function : ~StdMeshers_Adaptive1D +//purpose : Destructor +StdMeshers_Adaptive1D::~StdMeshers_Adaptive1D() +{ + delete myAlgo; myAlgo = NULL; +} +//======================================================================= +//function : SetDeflection +//purpose : +void StdMeshers_Adaptive1D::SetDeflection(double value) + throw(SALOME_Exception) +{ + if (value <= std::numeric_limits::min() ) + throw SALOME_Exception("Deflection must be greater that zero"); + if (myDeflection != value) + { + myDeflection = value; + NotifySubMeshesHypothesisModification(); + } +} +//======================================================================= +//function : SetMinSize +//purpose : Sets minimal allowed segment length +void StdMeshers_Adaptive1D::SetMinSize(double minSize) + throw(SALOME_Exception) +{ + if (minSize <= std::numeric_limits::min() ) + throw SALOME_Exception("Min size must be greater that zero"); + + if (myMinSize != minSize ) + { + myMinSize = minSize; + NotifySubMeshesHypothesisModification(); + } +} +//======================================================================= +//function : SetMaxSize +//purpose : Sets maximal allowed segment length +void StdMeshers_Adaptive1D::SetMaxSize(double maxSize) + throw(SALOME_Exception) +{ + if (maxSize <= std::numeric_limits::min() ) + throw SALOME_Exception("Max size must be greater that zero"); + + if (myMaxSize != maxSize ) + { + myMaxSize = maxSize; + NotifySubMeshesHypothesisModification(); + } +} +//======================================================================= +//function : SaveTo +//purpose : Persistence +ostream & StdMeshers_Adaptive1D::SaveTo(ostream & save) +{ + save << myMinSize << " " << myMaxSize << " " << myDeflection; + save << " " << -1 << " " << -1; // preview addition of parameters + return save; +} +//======================================================================= +//function : LoadFrom +//purpose : Persistence +istream & StdMeshers_Adaptive1D::LoadFrom(istream & load) +{ + int dummyParam; + bool isOK = (bool)(load >> myMinSize >> myMaxSize >> myDeflection >> dummyParam >> dummyParam); + if (!isOK) + load.clear(ios::badbit | load.rdstate()); + return load; +} +//======================================================================= +//function : SetParametersByMesh +//purpose : Initialize parameters 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 +bool StdMeshers_Adaptive1D::SetParametersByMesh(const SMESH_Mesh* theMesh, + const TopoDS_Shape& theShape) +{ + if ( !theMesh || theShape.IsNull() ) + return false; + + int nbEdges = 0; + TopTools_IndexedMapOfShape edgeMap; + TopExp::MapShapes( theShape, TopAbs_EDGE, edgeMap ); + + SMESH_MesherHelper helper( (SMESH_Mesh&) *theMesh ); + double minSz2 = 1e100, maxSz2 = 0, sz2, maxDefl2 = 0; + for ( int iE = 1; iE <= edgeMap.Extent(); ++iE ) + { + const TopoDS_Edge& edge = TopoDS::Edge( edgeMap( iE )); + SMESHDS_SubMesh* smDS = theMesh->GetMeshDS()->MeshElements( edge ); + if ( !smDS ) continue; + ++nbEdges; + + helper.SetSubShape( edge ); + BRepAdaptor_Curve curve( edge ); + + SMDS_ElemIteratorPtr segIt = smDS->GetElements(); + while ( segIt->more() ) + { + const SMDS_MeshElement* seg = segIt->next(); + const SMDS_MeshNode* n1 = seg->GetNode(0); + const SMDS_MeshNode* n2 = seg->GetNode(1); + sz2 = SMESH_TNodeXYZ( n1 ).SquareDistance( n2 ); + minSz2 = Min( minSz2, sz2 ); + maxSz2 = Max( maxSz2, sz2 ); + if ( curve.GetType() != GeomAbs_Line ) + { + double u1 = helper.GetNodeU( edge, n1, n2 ); + double u2 = helper.GetNodeU( edge, n2, n1 ); + maxDefl2 = Max( maxDefl2, deflection2( curve, u1, u2 )); + } + } + } + if ( nbEdges ) + { + myMinSize = sqrt( minSz2 ); + myMaxSize = sqrt( maxSz2 ); + if ( maxDefl2 > 0 ) + myDeflection = maxDefl2; + } + return nbEdges; +} + +//======================================================================= +//function : SetParametersByDefaults +//purpose : Initialize my parameter values by default parameters. +//retval : bool - true if parameter values have been successfully defined +bool StdMeshers_Adaptive1D::SetParametersByDefaults(const TDefaults& dflts, + const SMESH_Mesh* /*theMesh*/) +{ + myMinSize = dflts._elemLength / 10; + myMaxSize = dflts._elemLength * 2; + myDeflection = myMinSize / 7; + return true; +} + +//======================================================================= +//function : GetAlgo +//purpose : Returns an algorithm that works using this hypothesis +//======================================================================= + +SMESH_Algo* StdMeshers_Adaptive1D::GetAlgo() const +{ + if ( !myAlgo ) + { + AdaptiveAlgo* newAlgo = + new AdaptiveAlgo( _gen->GetANewId(), _studyId, _gen ); + newAlgo->SetHypothesis( this ); + + ((StdMeshers_Adaptive1D*) this)->myAlgo = newAlgo; + } + return myAlgo; +} + +//================================================================================ +/*! + * \brief Constructor + */ +//================================================================================ + +AdaptiveAlgo::AdaptiveAlgo(int hypId, + int studyId, + SMESH_Gen* gen) + : StdMeshers_Regular_1D( hypId, studyId, gen ), + myHyp(NULL) +{ + _name = "AdaptiveAlgo_1D"; +} + +//================================================================================ +/*! + * \brief Sets the hypothesis + */ +//================================================================================ + +void AdaptiveAlgo::SetHypothesis( const StdMeshers_Adaptive1D* hyp ) +{ + myHyp = hyp; +} + +//================================================================================ +/*! + * \brief Creates segments on all given EDGEs + */ +//================================================================================ + +bool AdaptiveAlgo::Compute(SMESH_Mesh & theMesh, + const TopoDS_Shape & theShape) +{ + // *theProgress = 0.01; + + if ( myHyp->GetMinSize() > myHyp->GetMaxSize() ) + return error( "Bad parameters: min size > max size" ); + + myMesh = &theMesh; + SMESH_MesherHelper helper( theMesh ); + const double grading = 0.7; + + TopTools_IndexedMapOfShape edgeMap, faceMap; + TopExp::MapShapes( theShape, TopAbs_EDGE, edgeMap ); + TopExp::MapShapes( theMesh.GetShapeToMesh(), TopAbs_FACE, faceMap ); + + // Triangulate the shape with the given deflection ????????? + { + BRepMesh_IncrementalMesh im( theMesh.GetShapeToMesh(), myHyp->GetDeflection(), /*isRelatif=*/0); + } + + // get a bnd box + Bnd_B3d box; + { + Bnd_Box aBox; + BRepBndLib::Add( theMesh.GetShapeToMesh(), aBox); + Standard_Real TXmin, TYmin, TZmin, TXmax, TYmax, TZmax; + aBox.Get(TXmin, TYmin, TZmin, TXmax, TYmax, TZmax); + box.Add( gp_XYZ( TXmin, TYmin, TZmin )); + box.Add( gp_XYZ( TXmax, TYmax, TZmax )); + } + // *theProgress = 0.3; + + // holder of segment size at each point + SegSizeTree sizeTree( box, grading, myHyp->GetMinSize(), myHyp->GetMaxSize() ); + mySizeTree = & sizeTree; + + // minimal segment size that sizeTree can store with reasonable tree height + const double minSize = Max( myHyp->GetMinSize(), 1.1 * sizeTree.GetMinSize() ); + + + // fill myEdges - working data of EDGEs + { + // sort EDGEs by length + multimap< double, TopoDS_Edge > edgeOfLength; + for ( int iE = 1; iE <= edgeMap.Extent(); ++iE ) + { + const TopoDS_Edge & edge = TopoDS::Edge( edgeMap( iE )); + if ( !SMESH_Algo::isDegenerated( edge) ) + edgeOfLength.insert( make_pair( EdgeLength( edge ), edge )); + } + myEdges.clear(); + myEdges.resize( edgeOfLength.size() ); + multimap< double, TopoDS_Edge >::const_iterator len2edge = edgeOfLength.begin(); + for ( int iE = 0; len2edge != edgeOfLength.end(); ++len2edge, ++iE ) + { + const TopoDS_Edge & edge = len2edge->second; + EdgeData& eData = myEdges[ iE ]; + eData.myC3d.Initialize( edge ); + eData.myLength = EdgeLength( edge ); + eData.AddPoint( eData.myPoints.end(), eData.myC3d.FirstParameter() ); + eData.AddPoint( eData.myPoints.end(), eData.myC3d.LastParameter() ); + } + } + if ( myEdges.empty() ) return true; + if ( _computeCanceled ) return false; + + // Take into account size of already existing segments + SMDS_EdgeIteratorPtr segIterator = theMesh.GetMeshDS()->edgesIterator(); + while ( segIterator->more() ) + { + const SMDS_MeshElement* seg = segIterator->next(); + sizeTree.SetSize( SMESH_TNodeXYZ( seg->GetNode( 0 )), SMESH_TNodeXYZ( seg->GetNode( 1 ))); + } + if ( _computeCanceled ) return false; + + // Set size of segments according to the deflection + + StdMeshers_Regular_1D::_hypType = DEFLECTION; + StdMeshers_Regular_1D::_value[ DEFLECTION_IND ] = myHyp->GetDeflection(); + + list< double > params; + for ( int iE = 0; iE < myEdges.size(); ++iE ) + { + EdgeData& eData = myEdges[ iE ]; + //cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() ) << endl; + + double f = eData.First().myU, l = eData.Last().myU; + if ( !computeInternalParameters( theMesh, eData.myC3d, eData.myLength, f,l, params, false, false )) + continue; + if ( params.size() <= 1 && helper.IsClosedEdge( eData.Edge() ) ) // 2 segments on a circle + { + params.clear(); + for ( int i = 1; i < 6; ++i ) + params.push_back(( l - f ) * i/6. ); + } + EdgeData::TPntIter where = --eData.myPoints.end(); + list< double >::const_iterator param = params.begin(); + for ( ; param != params.end(); ++param ) + eData.AddPoint( where, *param ); + + EdgeData::TPntIter pIt2 = eData.myPoints.begin(), pIt1 = pIt2++; + for ( ; pIt2 != eData.myPoints.end(); ++pIt1, ++pIt2 ) + { + double sz = sizeTree.SetSize( (*pIt1).myP, (*pIt2).myP ); + sz = Min( sz, myHyp->GetMaxSize() ); + pIt1->mySegSize = Min( sz, pIt1->mySegSize ); + pIt2->mySegSize = Min( sz, pIt2->mySegSize ); + } + + if ( _computeCanceled ) return false; + } + + // Limit size of segments according to distance to closest FACE + + for ( int iF = 1; iF <= faceMap.Extent(); ++iF ) + { + if ( _computeCanceled ) return false; + + const TopoDS_Face & face = TopoDS::Face( faceMap( iF )); + // cout << "FACE " << iF << "/" << faceMap.Extent() + // << " id-" << theMesh.GetMeshDS()->ShapeToIndex( face ) << endl; + + ElementBndBoxTree triaTree( face ); // tree of FACE triangulation + TriaTreeData* triaSearcher = triaTree.GetTriaData(); + + triaSearcher->SetSizeByTrias( sizeTree, myHyp->GetDeflection() ); + + for ( int iE = 0; iE < myEdges.size(); ++iE ) + { + EdgeData& eData = myEdges[ iE ]; + + // check if the face is in topological contact with the edge + bool isAdjFace = ( helper.IsSubShape( helper.IthVertex( 0, eData.Edge()), face ) || + helper.IsSubShape( helper.IthVertex( 1, eData.Edge()), face )); + + if ( isAdjFace && triaSearcher->mySurface.GetType() == GeomAbs_Plane ) + continue; + + bool sizeDecreased = true; + for (int iLoop = 0; sizeDecreased; ++iLoop ) //repeat until segment size along the edge becomes stable + { + double maxSegSize = 0; + + // get points to check distance to the face + EdgeData::TPntIter pIt2 = eData.myPoints.begin(), pIt1 = pIt2++, pItLast; + maxSegSize = pIt1->mySegSize = Min( pIt1->mySegSize, sizeTree.GetSize( pIt1->myP )); + for ( ; pIt2 != eData.myPoints.end(); ) + { + pIt2->mySegSize = Min( pIt2->mySegSize, sizeTree.GetSize( pIt2->myP )); + double curSize = Min( pIt1->mySegSize, pIt2->mySegSize ); + maxSegSize = Max( pIt2->mySegSize, maxSegSize ); + if ( pIt1->myP.Distance( pIt2->myP ) > curSize ) + { + double midU = 0.5*( pIt1->myU + pIt2->myU ); + gp_Pnt midP = eData.myC3d.Value( midU ); + double midSz = sizeTree.GetSize( midP ); + pIt2 = eData.myPoints.insert( pIt2, EdgeData::ProbePnt( midP, midU, midSz )); + eData.myBBox.Add( midP.XYZ() ); + } + else + { + ++pIt1, ++pIt2; + } + } + // check if the face is more distant than a half of the current segment size, + // if not, segment size is decreased + + if ( iLoop == 0 && eData.IsTooDistant( triaSearcher->myBBox, maxSegSize )) + break; + triaSearcher->PrepareToTriaSearch(); + + //cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() ) << endl; + sizeDecreased = false; + const gp_Pnt* avoidPnt = & eData.First().myP; + pItLast = --eData.myPoints.end(); + for ( pIt1 = eData.myPoints.begin(); pIt1 != eData.myPoints.end(); ) + { + double distToFace = + triaSearcher->GetMinDistInSphere( pIt1->myP, pIt1->mySegSize, isAdjFace, avoidPnt ); + double allowedSize = Max( minSize, distToFace*( 1. + grading )); + if ( allowedSize < pIt1->mySegSize ) + { + // cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() ) + // << "\t closure detected " << endl; + if ( 1.1 * allowedSize < pIt1->mySegSize ) + { + sizeDecreased = true; + sizeTree.SetSize( pIt1->myP, allowedSize ); + // cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() ) + // << "\t SetSize " << allowedSize << " at " + // << pIt1->myP.X() <<", "<< pIt1->myP.Y()<<", "<myP.Z() << endl; + pIt2 = pIt1; + if ( --pIt2 != eData.myPoints.end() && pIt2->mySegSize > allowedSize ) + sizeTree.SetSize( eData.myC3d.Value( 0.6*pIt2->myU + 0.4*pIt1->myU ), allowedSize ); + pIt2 = pIt1; + if ( ++pIt2 != eData.myPoints.end() && pIt2->mySegSize > allowedSize ) + sizeTree.SetSize( eData.myC3d.Value( 0.6*pIt2->myU + 0.4*pIt1->myU ), allowedSize ); + } + pIt1->mySegSize = allowedSize; + } + ++pIt1; + if ( pIt1 == pItLast ) + avoidPnt = & eData.Last().myP; + else + avoidPnt = NULL; + + if ( iLoop > 20 ) + { +#ifdef _DEBUG_ + cout << "Infinite loop in AdaptiveAlgo::Compute()" << endl; +#endif + sizeDecreased = false; + break; + } + } + } // while ( sizeDecreased ) + } // loop on myEdges + + // *theProgress = 0.3 + 0.3 * iF / double( faceMap.Extent() ); + + } // loop on faceMap + + return makeSegments(); +} + +//================================================================================ +/*! + * \brief Create segments + */ +//================================================================================ + +bool AdaptiveAlgo::makeSegments() +{ + SMESH_HypoFilter quadHyp( SMESH_HypoFilter::HasName( "QuadraticMesh" )); + _quadraticMesh = myMesh->GetHypothesis( myEdges[0].Edge(), quadHyp, /*andAncestors=*/true ); + + SMESH_MesherHelper helper( *myMesh ); + helper.SetIsQuadratic( _quadraticMesh ); + + vector< double > nbSegs, params; + + for ( int iE = 0; iE < myEdges.size(); ++iE ) + { + EdgeData& eData = myEdges[ iE ]; + + // estimate roughly min segment size on the EDGE + double edgeMinSize = myHyp->GetMaxSize(); + EdgeData::TPntIter pIt1 = eData.myPoints.begin(); + for ( ; pIt1 != eData.myPoints.end(); ++pIt1 ) + edgeMinSize = Min( edgeMinSize, + Min( pIt1->mySegSize, mySizeTree->GetSize( pIt1->myP ))); + + const double f = eData.myC3d.FirstParameter(), l = eData.myC3d.LastParameter(); + const double parLen = l - f; + const int nbDivSeg = 5; + int nbDiv = Max( 1, int ( eData.myLength / edgeMinSize * nbDivSeg )); + + // compute nb of segments + bool toRecompute = true; + double maxSegSize = 0; + size_t i = 1, segCount; + //cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() ) << endl; + while ( toRecompute ) // recompute if segment size at some point is less than edgeMinSize/nbDivSeg + { + nbSegs.resize( nbDiv + 1 ); + nbSegs[0] = 0; + toRecompute = false; + + // fill nbSegs with segment size stored in EdgeData::ProbePnt::mySegSize which can + // be less than size in mySizeTree + pIt1 = eData.myPoints.begin(); + EdgeData::ProbePnt* pp1 = &(*pIt1), *pp2; + for ( ++pIt1; pIt1 != eData.myPoints.end(); ++pIt1 ) + { + pp2 = &(*pIt1); + double size1 = Min( pp1->mySegSize, myHyp->GetMaxSize() ); + double size2 = Min( pp2->mySegSize, myHyp->GetMaxSize() ); + double r, u, du = pp2->myU - pp1->myU; + while(( u = f + parLen * i / nbDiv ) < pp2->myU ) + { + r = ( u - pp1->myU ) / du; + nbSegs[i] = (1-r) * size1 + r * size2; + ++i; + } + if ( i < nbSegs.size() ) + nbSegs[i] = size2; + pp1 = pp2; + } + // fill nbSegs with local nb of segments + gp_Pnt p1 = eData.First().myP, p2, pDiv = p1; + for ( i = 1, segCount = 1; i < nbSegs.size(); ++i ) + { + p2 = eData.myC3d.Value( f + parLen * i / nbDiv ); + double locSize = Min( mySizeTree->GetSize( p2 ), nbSegs[i] ); + double nb = p1.Distance( p2 ) / locSize; + // if ( nbSegs.size() < 30 ) + // cout << "locSize " << locSize << " nb " << nb << endl; + if ( nb > 1. ) + { + toRecompute = true; + edgeMinSize = locSize; + nbDiv = int ( eData.myLength / edgeMinSize * nbDivSeg ); + break; + } + nbSegs[i] = nbSegs[i-1] + nb; + p1 = p2; + if ( nbSegs[i] >= segCount ) + { + maxSegSize = Max( maxSegSize, pDiv.Distance( p2 )); + pDiv = p2; + ++segCount; + } + } + } + + // compute parameters of nodes + int nbSegFinal = Max( 1, int(floor( nbSegs.back() + 0.5 ))); + double fact = nbSegFinal / nbSegs.back(); + if ( maxSegSize / fact > myHyp->GetMaxSize() ) + fact = ++nbSegFinal / nbSegs.back(); + //cout << "nbSegs.back() " << nbSegs.back() << " nbSegFinal " << nbSegFinal << endl; + params.clear(); + for ( i = 0, segCount = 1; segCount < nbSegFinal; ++segCount ) + { + while ( nbSegs[i] * fact < segCount ) + ++i; + if ( i < nbDiv ) + { + double d = i - ( nbSegs[i] - segCount/fact ) / ( nbSegs[i] - nbSegs[i-1] ); + params.push_back( f + parLen * d / nbDiv ); + //params.push_back( f + parLen * i / nbDiv ); + } + else + break; + } + // get nodes on VERTEXes + TopoDS_Vertex vf = helper.IthVertex( 0, eData.Edge(), false ); + TopoDS_Vertex vl = helper.IthVertex( 1, eData.Edge(), false ); + myMesh->GetSubMesh( vf )->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + myMesh->GetSubMesh( vl )->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + const SMDS_MeshNode * nf = VertexNode( vf, myMesh->GetMeshDS() ); + const SMDS_MeshNode * nl = VertexNode( vl, myMesh->GetMeshDS() ); + if ( !nf || !nl ) + return error("No node on vertex"); + + // create segments + helper.SetSubShape( eData.Edge() ); + helper.SetElementsOnShape( true ); + const int ID = 0; + const SMDS_MeshNode *n1 = nf, *n2; + for ( i = 0; i < params.size(); ++i, n1 = n2 ) + { + gp_Pnt p2 = eData.myC3d.Value( params[i] ); + n2 = helper.AddNode( p2.X(), p2.Y(), p2.Z(), ID, params[i] ); + helper.AddEdge( n1, n2, ID, /*force3d=*/false ); + } + helper.AddEdge( n1, nl, ID, /*force3d=*/false ); + + eData.myPoints.clear(); + + //*theProgress = 0.6 + 0.4 * iE / double( myEdges.size() ); + if ( _computeCanceled ) + return false; + + } // loop on EDGEs + + SMESHUtils::FreeVector( myEdges ); + + return true; +} + +//================================================================================ +/*! + * \brief Predict number of segments on all given EDGEs + */ +//================================================================================ + +bool AdaptiveAlgo::Evaluate(SMESH_Mesh & theMesh, + const TopoDS_Shape & theShape, + MapShapeNbElems& theResMap) +{ + // initialize fields of inherited StdMeshers_Regular_1D + StdMeshers_Regular_1D::_hypType = DEFLECTION; + StdMeshers_Regular_1D::_value[ DEFLECTION_IND ] = myHyp->GetDeflection(); + + TopExp_Explorer edExp( theShape, TopAbs_EDGE ); + + for ( ; edExp.More(); edExp.Next() ) + { + const TopoDS_Edge & edge = TopoDS::Edge( edExp.Current() ); + StdMeshers_Regular_1D::Evaluate( theMesh, theShape, theResMap ); + } + return true; +} + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Arithmetic1D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Arithmetic1D.cpp index fc2d00c50213..eb01e611fee0 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Arithmetic1D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Arithmetic1D.cpp @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Arithmetic1D.cxx // Author : Damien COQUERET, OCC // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_Arithmetic1D.cxx,v 1.8.2.1 2008/11/27 13:03:49 abd Exp $ // #include "StdMeshers_Arithmetic1D.hxx" @@ -74,11 +74,11 @@ StdMeshers_Arithmetic1D::~StdMeshers_Arithmetic1D() //============================================================================= void StdMeshers_Arithmetic1D::SetLength(double length, bool isStartLength) - throw(SMESH_Exception) + throw(SALOME_Exception) { if ( (isStartLength ? _begLength : _endLength) != length ) { if (length <= 0) - throw SMESH_Exception(LOCALIZED("length must be positive")); + throw SALOME_Exception(LOCALIZED("length must be positive")); if ( isStartLength ) _begLength = length; else @@ -105,9 +105,32 @@ double StdMeshers_Arithmetic1D::GetLength(bool isStartLength) const */ //============================================================================= +void StdMeshers_Arithmetic1D::SetReversedEdges( std::vector& ids ) +{ + if ( ids != _edgeIDs ) { + _edgeIDs = ids; + + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= + ostream & StdMeshers_Arithmetic1D::SaveTo(ostream & save) { - save << _begLength << " " << _endLength; + int listSize = _edgeIDs.size(); + save << _begLength << " " << _endLength << " " << listSize; + + if ( listSize > 0 ) { + for ( int i = 0; i < listSize; i++) + save << " " << _edgeIDs[i]; + save << " " << _objEntry; + } + return save; } @@ -120,12 +143,25 @@ ostream & StdMeshers_Arithmetic1D::SaveTo(ostream & save) istream & StdMeshers_Arithmetic1D::LoadFrom(istream & load) { bool isOK = true; - isOK = !(load >> _begLength).bad(); + int intVal; + isOK = (bool)(load >> _begLength); if (!isOK) load.clear(ios::badbit | load.rdstate()); - isOK = !(load >> _endLength).bad(); + isOK = (bool)(load >> _endLength); + if (!isOK) load.clear(ios::badbit | load.rdstate()); + + isOK = (bool)(load >> intVal); + if (isOK && intVal > 0) { + _edgeIDs.reserve( intVal ); + for (int i = 0; i < _edgeIDs.capacity() && isOK; i++) { + isOK = (bool)(load >> intVal); + if ( isOK ) _edgeIDs.push_back( intVal ); + } + isOK = (bool)(load >> _objEntry); + } + return load; } @@ -178,7 +214,7 @@ bool StdMeshers_Arithmetic1D::SetParametersByMesh(const SMESH_Mesh* theMesh, { const TopoDS_Edge& edge = TopoDS::Edge( edgeMap( i )); Handle(Geom_Curve) C = BRep_Tool::Curve(edge, L, UMin, UMax); - GeomAdaptor_Curve AdaptCurve(C); + GeomAdaptor_Curve AdaptCurve(C, UMin, UMax); vector< double > params; SMESHDS_Mesh* aMeshDS = const_cast< SMESH_Mesh* >( theMesh )->GetMeshDS(); @@ -209,3 +245,4 @@ bool StdMeshers_Arithmetic1D::SetParametersByDefaults(const TDefaults& dflts, { return ( _begLength = _endLength = dflts._elemLength ); } + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_AutomaticLength.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_AutomaticLength.cpp index 75eaf24aa1d2..1bfa33215eca 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_AutomaticLength.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_AutomaticLength.cpp @@ -1,34 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_AutomaticLength.cxx // Author : Edward AGAPOV, OCC // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_AutomaticLength.cxx,v 1.7.2.1 2008/11/27 13:03:50 abd Exp $ -// -#ifdef _MSC_VER -#define _USE_MATH_DEFINES -#endif // _MSC_VER -#include #include "StdMeshers_AutomaticLength.hxx" @@ -44,10 +39,6 @@ #include #include -#ifndef PI -#define PI M_PI -#endif - using namespace std; //============================================================================= @@ -93,10 +84,10 @@ const double theCoarseConst = 0.5; const double theFineConst = 4.5; void StdMeshers_AutomaticLength::SetFineness(double theFineness) - throw(SMESH_Exception) + throw(SALOME_Exception) { if ( theFineness < 0.0 || theFineness > 1.0 ) - throw SMESH_Exception(LOCALIZED("theFineness is out of range [0.0-1.0]")); + throw SALOME_Exception(LOCALIZED("theFineness is out of range [0.0-1.0]")); if ( _fineness != theFineness ) { @@ -126,17 +117,44 @@ namespace { */ //================================================================================ - const double a14divPI = 14. / PI; + const double a14divPI = 14. / M_PI; + inline double segLength(double S0, double edgeLen, double minLen ) { // PAL10237 // S = S0 * f(L/Lmin) where f(x) = 1 + (2/Pi * 7 * atan(x/5) ) + // => // S = S0 * ( 1 + 14/PI * atan( L / ( 5 * Lmin ))) return S0 * ( 1. + a14divPI * atan( edgeLen / ( 5 * minLen ))); } +#if 0 + //const double a14divPI = 14. / M_PI; + const double a2div7divPI = 2. / 7. / M_PI; + inline double segLength(double S0, double edgeLen, double minLen ) + { + // PAL10237 + // S = S0 * f(L/Lmin) where + // f(x) = 1 + (7 * 2/Pi * atan(x/5)) + // => + // S = S0 * ( 1 + 14/PI * atan( L / ( 5 * Lmin ))) + // + // return S0 * ( 1. + a14divPI * atan( edgeLen / ( 5 * minLen ))); + + // The above formular gives too short segments when Lmax/Lmin is too high + // because by this formular the largest segment is only 8 times longer than the + // shortest one ( 2/Pi * atan(x/5) varies within [0,1] ). So a new formular is: + // + // f(x) = 1 + (x/7 * 2/Pi * atan(x/5)) + // => + // S = S0 * ( 1 + 2/7/PI * L/Lmin * atan( 5 * L/Lmin )) + // + const double Lratio = edgeLen / minLen; + return S0 * ( 1. + a2div7divPI * Lratio * atan( 5 * Lratio )); + } +#endif //================================================================================ /*! * \brief Compute segment length for all edges @@ -173,22 +191,22 @@ namespace { theTShapeToLengthMap.insert( make_pair( getTShape( edge ), L )); } - // Compute S0 - - // image attached to PAL10237 - - // NbSeg - // ^ - // | - // 10|\ - // | \ - // | \ - // | \ - // 5| -------- - // | - // +------------> - // 1 10 Lmax/Lmin - + // Compute S0 - minimal segement length, is computed by the shortest EDGE + + /* image attached to PAL10237 + + NbSeg (on the shortest EDGE) + ^ + | + 10|\ + | \ + | \ + | \ + 5| -------- + | + +------------> + 1 10 Lmax/Lmin + */ const int NbSegMin = 5, NbSegMax = 10; // on axis NbSeg const double Lrat1 = 1., Lrat2 = 10.; // on axis Lmax/Lmin @@ -201,6 +219,7 @@ namespace { MESSAGE( "S0 = " << S0 << ", Lmin = " << Lmin << ", Nbseg = " << (int) NbSeg); // Compute segments length for all edges + map::iterator tshape_length = theTShapeToLengthMap.begin(); for ( ; tshape_length != theTShapeToLengthMap.end(); ++tshape_length ) { @@ -220,9 +239,9 @@ namespace { double StdMeshers_AutomaticLength::GetLength(const SMESH_Mesh* theMesh, const double theEdgeLength) - throw(SMESH_Exception) + throw(SALOME_Exception) { - if ( !theMesh ) throw SMESH_Exception(LOCALIZED("NULL Mesh")); + if ( !theMesh ) throw SALOME_Exception(LOCALIZED("NULL Mesh")); SMESHDS_Mesh* aMeshDS = const_cast< SMESH_Mesh* > ( theMesh )->GetMeshDS(); if ( theMesh != _mesh ) @@ -242,12 +261,12 @@ double StdMeshers_AutomaticLength::GetLength(const SMESH_Mesh* theMesh, double StdMeshers_AutomaticLength::GetLength(const SMESH_Mesh* theMesh, const TopoDS_Shape& anEdge) - throw(SMESH_Exception) + throw(SALOME_Exception) { - if ( !theMesh ) throw SMESH_Exception(LOCALIZED("NULL Mesh")); + if ( !theMesh ) throw SALOME_Exception(LOCALIZED("NULL Mesh")); if ( anEdge.IsNull() || anEdge.ShapeType() != TopAbs_EDGE ) - throw SMESH_Exception(LOCALIZED("Bad edge shape")); + throw SALOME_Exception(LOCALIZED("Bad edge shape")); if ( theMesh != _mesh ) { diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_CartesianParameters3D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_CartesianParameters3D.cpp new file mode 100644 index 000000000000..ee41dc681756 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_CartesianParameters3D.cpp @@ -0,0 +1,879 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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_CartesianParameters3D.cxx +// Author : Edward AGAPOV +// Module : SMESH +// +#include "StdMeshers_CartesianParameters3D.hxx" + +#include "StdMeshers_NumberOfSegments.hxx" +#include "StdMeshers_Distribution.hxx" +#include "SMESH_Gen.hxx" + +#include "utilities.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +//======================================================================= +//function : StdMeshers_CartesianParameters3D +//purpose : Constructor +//======================================================================= + +StdMeshers_CartesianParameters3D::StdMeshers_CartesianParameters3D(int hypId, + int studyId, + SMESH_Gen * gen) + : SMESH_Hypothesis(hypId, studyId, gen), + _sizeThreshold( 4.0 ), // default according to the customer specification + _toAddEdges( false ) +{ + _name = "CartesianParameters3D"; // used by "Cartesian_3D" + _param_algo_dim = 3; // 3D + + _axisDirs[0] = 1.; + _axisDirs[1] = 0.; + _axisDirs[2] = 0.; + + _axisDirs[3] = 0.; + _axisDirs[4] = 1.; + _axisDirs[5] = 0.; + + _axisDirs[6] = 0.; + _axisDirs[7] = 0.; + _axisDirs[8] = 1.; + + _fixedPoint[0] = 0.; + _fixedPoint[1] = 0.; + _fixedPoint[2] = 0.; + SetFixedPoint( _fixedPoint, /*toUnset=*/true ); +} + + +namespace +{ + const char* axisName[3] = { "X", "Y", "Z" }; + + typedef std::pair< double, std::pair< double, double > > TCooTriple; + +#define gpXYZ( cTriple ) gp_XYZ( (cTriple).first, (cTriple).second.first, (cTriple).second.second ) + + //================================================================================ + /*! + * \brief Compare two normals + */ + //================================================================================ + + bool sameDir( const TCooTriple& n1, const TCooTriple& n2 ) + { + gp_XYZ xyz1 = gpXYZ( n1 ), xyz2 = gpXYZ( n2 ); + return ( xyz1 - xyz2 ).Modulus() < 0.01; + } + + //================================================================================ + /*! + * \brief Checks validity of an axis index, throws in case of invalidity + */ + //================================================================================ + + void checkAxis(const int axis) + { + if ( axis < 0 || axis > 2 ) + throw SALOME_Exception(SMESH_Comment("Invalid axis index ") << axis << + ". Valid axis indices are 0, 1 and 2"); + } + + //================================================================================ + /*! + * \brief Checks validity of spacing data, throws in case of invalidity + */ + //================================================================================ + + void checkGridSpacing(std::vector& spaceFunctions, + std::vector& internalPoints, + const std::string& axis) + throw ( SALOME_Exception ) + { + if ( spaceFunctions.empty() ) + throw SALOME_Exception(SMESH_Comment("Empty space function for ") << axis ); + + for ( size_t i = 1; i < internalPoints.size(); ++i ) + if ( internalPoints[i] - internalPoints[i-1] < 0 ) + throw SALOME_Exception(SMESH_Comment("Wrong order of internal points along ") << axis); + else if ( internalPoints[i] - internalPoints[i-1] < 1e-3 ) + throw SALOME_Exception(SMESH_Comment("Too close internal points along ") << axis ); + + const double tol = Precision::Confusion(); + if ( !internalPoints.empty() && + ( internalPoints.front() < -tol || internalPoints.back() > 1 + tol )) + throw SALOME_Exception(SMESH_Comment("Invalid internal points along ") << axis); + + if ( internalPoints.empty() || internalPoints.front() > tol ) + internalPoints.insert( internalPoints.begin(), 0. ); + if ( internalPoints.size() < 2 || internalPoints.back() < 1 - tol ) + internalPoints.push_back( 1. ); + + if ( internalPoints.size() != spaceFunctions.size() + 1 ) + throw SALOME_Exception + (SMESH_Comment("Numbre of internal points mismatch number of functions for ") << axis); + + for ( size_t i = 0; i < spaceFunctions.size(); ++i ) + spaceFunctions[i] = + StdMeshers_NumberOfSegments::CheckExpressionFunction( spaceFunctions[i], -1 ); + } +} + +//======================================================================= +//function : SetGrid +//purpose : Sets coordinates of node positions along an axes +//======================================================================= + +void StdMeshers_CartesianParameters3D::SetGrid(std::vector& coords, int axis) + throw ( SALOME_Exception ) +{ + checkAxis( axis ); + + if ( coords.size() < 2 ) + throw SALOME_Exception(LOCALIZED("Wrong number of grid coordinates")); + + std::sort( coords.begin(), coords.end() ); + + bool changed = ( _coords[axis] != coords ); + if ( changed ) + { + _coords[axis] = coords; + NotifySubMeshesHypothesisModification(); + } + + _spaceFunctions[axis].clear(); + _internalPoints[axis].clear(); +} + +//======================================================================= +//function : SetGridSpacing +//purpose : Set grid spacing along the three axes +//======================================================================= + +void StdMeshers_CartesianParameters3D::SetGridSpacing(std::vector& xSpaceFuns, + std::vector& xInternalPoints, + const int axis) + throw ( SALOME_Exception ) +{ + checkAxis( axis ); + + checkGridSpacing( xSpaceFuns, xInternalPoints, axisName[axis] ); + + bool changed = ( xSpaceFuns != _spaceFunctions[axis] || + xInternalPoints != _internalPoints[axis] ); + + _spaceFunctions[axis] = xSpaceFuns; + _internalPoints[axis] = xInternalPoints; + _coords[axis].clear(); + + if ( changed ) + NotifySubMeshesHypothesisModification(); +} + +//======================================================================= +//function : SetFixedPoint +//purpose : * Set/unset a fixed point, at which a node will be created provided that grid +// * is defined by spacing in all directions +//======================================================================= + +void StdMeshers_CartesianParameters3D::SetFixedPoint(const double p[3], bool toUnset) +{ + if ( toUnset != Precision::IsInfinite( _fixedPoint[0] )) + NotifySubMeshesHypothesisModification(); + + if ( toUnset ) + _fixedPoint[0] = Precision::Infinite(); + else + std::copy( &p[0], &p[0]+3, &_fixedPoint[0] ); +} + +//======================================================================= +//function : GetFixedPoint +//purpose : Returns either false or (true + point coordinates) +//======================================================================= + +bool StdMeshers_CartesianParameters3D::GetFixedPoint(double p[3]) const +{ + if ( Precision::IsInfinite( _fixedPoint[0] )) + return false; + std::copy( &_fixedPoint[0], &_fixedPoint[0]+3, &p[0] ); +} + + +//======================================================================= +//function : SetSizeThreshold +//purpose : Set size threshold +//======================================================================= + +void StdMeshers_CartesianParameters3D::SetSizeThreshold(const double threshold) + throw ( SALOME_Exception ) +{ + if ( threshold <= 1.0 ) + throw SALOME_Exception(LOCALIZED("threshold must be > 1.0")); + + bool changed = fabs( _sizeThreshold - threshold ) > 1e-6; + _sizeThreshold = threshold; + + if ( changed ) + NotifySubMeshesHypothesisModification(); +} + +//======================================================================= +//function : GetGridSpacing +//purpose : return spacing +//======================================================================= + +void StdMeshers_CartesianParameters3D::GetGridSpacing(std::vector& spaceFunctions, + std::vector& internalPoints, + const int axis) const + throw ( SALOME_Exception ) +{ + if ( !IsGridBySpacing(axis) ) + throw SALOME_Exception(LOCALIZED("The grid is defined by coordinates and not by spacing")); + + spaceFunctions = _spaceFunctions[axis]; + internalPoints = _internalPoints[axis]; +} + +//======================================================================= +//function : IsGridBySpacing +//======================================================================= + +bool StdMeshers_CartesianParameters3D::IsGridBySpacing(const int axis) const + throw ( SALOME_Exception ) +{ + checkAxis(axis); + return !_spaceFunctions[axis].empty(); +} + + +//======================================================================= +//function : ComputeCoordinates +//purpose : Computes node coordinates by spacing functions +//======================================================================= + +void StdMeshers_CartesianParameters3D::ComputeCoordinates(const double x0, + const double x1, + vector& theSpaceFuns, + vector& thePoints, + vector& coords, + const string& axis, + const double* xForced ) + throw ( SALOME_Exception ) +{ + checkGridSpacing( theSpaceFuns, thePoints, axis ); + + vector spaceFuns = theSpaceFuns; + vector points = thePoints; + + bool forced = false; + if (( forced = ( xForced && ( x0 < *xForced ) && ( *xForced < x1 )))) + { + // divide a range at xForced + + // find a range to insert xForced + double pos = ( *xForced - x0 ) / ( x1 - x0 ); + int iR = 1; + while ( pos > points[ iR ] ) ++iR; + + // insert xForced + vector::iterator pntIt = points.begin() + iR; + points.insert( pntIt, pos ); + vector::iterator funIt = spaceFuns.begin() + iR; + spaceFuns.insert( funIt, spaceFuns[ iR-1 ]); + } + + coords.clear(); + for ( size_t i = 0; i < spaceFuns.size(); ++i ) + { + StdMeshers::FunctionExpr fun( spaceFuns[i].c_str(), /*convMode=*/-1 ); + + const double p0 = x0 * ( 1. - points[i]) + x1 * points[i]; + const double p1 = x0 * ( 1. - points[i+1]) + x1 * points[i+1]; + const double length = p1 - p0; + + const size_t nbSections = 1000; + const double sectionLen = ( p1 - p0 ) / nbSections; + vector< double > nbSegments( nbSections + 1 ); + nbSegments[ 0 ] = 0.; + + double t, spacing = 0; + for ( size_t i = 1; i <= nbSections; ++i ) + { + t = double( i ) / nbSections; + if ( !fun.value( t, spacing ) || spacing < std::numeric_limits::min() ) + throw SALOME_Exception(LOCALIZED("Invalid spacing function")); + nbSegments[ i ] = nbSegments[ i-1 ] + std::min( 1., sectionLen / spacing ); + } + + const int nbCells = max (1, int(floor(nbSegments.back()+0.5))); + const double corr = nbCells / nbSegments.back(); + + if ( coords.empty() ) coords.push_back( p0 ); + + for ( size_t iCell = 1, i = 1; i <= nbSections; ++i ) + { + if ( nbSegments[i]*corr >= iCell ) + { + t = (i - ( nbSegments[i] - iCell/corr )/( nbSegments[i] - nbSegments[i-1] )) / nbSections; + coords.push_back( p0 + t * length ); + ++iCell; + } + } + const double lastCellLen = coords.back() - coords[ coords.size() - 2 ]; + if ( fabs( coords.back() - p1 ) > 0.5 * lastCellLen ) + coords.push_back ( p1 ); + } + + // correct coords if a forced point is too close to a neighbor node + if ( forced ) + { + int iF = 0; + double minLen = ( x1 - x0 ); + for ( size_t i = 1; i < coords.size(); ++i ) + { + if ( !iF && Abs( coords[i] - *xForced ) < 1e-20 ) + iF = i++; // xForced found + else + minLen = Min( minLen, coords[i] - coords[i-1] ); + } + const double tol = minLen * 1e-3; + int iRem = -1; + if (( iF > 1 ) && ( coords[iF] - coords[iF-1] < tol )) + iRem = iF-1; + else if (( iF < coords.size()-2 ) && ( coords[iF+1] - coords[iF] < tol )) + iRem = iF+1; + if ( iRem > 0 ) + coords.erase( coords.begin() + iRem ); + } +} + +//======================================================================= +//function : GetCoordinates +//purpose : Return coordinates of node positions along the three axes. +// If the grid is defined by spacing functions, the coordinates are computed +//======================================================================= + +void StdMeshers_CartesianParameters3D::GetCoordinates(std::vector& xNodes, + std::vector& yNodes, + std::vector& zNodes, + const Bnd_Box& bndBox) const + throw ( SALOME_Exception ) +{ + double x0,y0,z0, x1,y1,z1; + if ( IsGridBySpacing(0) || IsGridBySpacing(1) || IsGridBySpacing(2)) + { + if ( bndBox.IsVoid() || + bndBox.IsXThin( Precision::Confusion() ) || + bndBox.IsYThin( Precision::Confusion() ) || + bndBox.IsZThin( Precision::Confusion() ) ) + throw SALOME_Exception(LOCALIZED("Invalid bounding box")); + bndBox.Get(x0,y0,z0, x1,y1,z1); + } + + double fp[3], *pfp[3] = { NULL, NULL, NULL }; + if ( GetFixedPoint( fp )) + { + // convert fp into a basis defined by _axisDirs + gp_XYZ axis[3] = { gp_XYZ( _axisDirs[0], _axisDirs[1], _axisDirs[2] ), + gp_XYZ( _axisDirs[3], _axisDirs[4], _axisDirs[5] ), + gp_XYZ( _axisDirs[6], _axisDirs[7], _axisDirs[8] ) }; + axis[0].Normalize(); + axis[1].Normalize(); + axis[2].Normalize(); + + gp_Mat basis( axis[0], axis[1], axis[2] ); + gp_Mat bi = basis.Inverted(); + + gp_XYZ p( fp[0], fp[1], fp[2] ); + p *= bi; + p.Coord( fp[0], fp[1], fp[2] ); + + pfp[0] = & fp[0]; + pfp[1] = & fp[1]; + pfp[2] = & fp[2]; + } + + StdMeshers_CartesianParameters3D* me = const_cast(this); + if ( IsGridBySpacing(0) ) + ComputeCoordinates + ( x0, x1, me->_spaceFunctions[0], me->_internalPoints[0], xNodes, "X", pfp[0] ); + else + xNodes = _coords[0]; + + if ( IsGridBySpacing(1) ) + ComputeCoordinates + ( y0, y1, me->_spaceFunctions[1], me->_internalPoints[1], yNodes, "Y", pfp[1] ); + else + yNodes = _coords[1]; + + if ( IsGridBySpacing(2) ) + ComputeCoordinates + ( z0, z1, me->_spaceFunctions[2], me->_internalPoints[2], zNodes, "Z", pfp[2] ); + else + zNodes = _coords[2]; +} + +//======================================================================= +//function : ComputeOptimalAxesDirs +//purpose : Returns axes at which number of hexahedra is maximal +//======================================================================= + +void StdMeshers_CartesianParameters3D:: +ComputeOptimalAxesDirs(const TopoDS_Shape& shape, + const bool isOrthogonal, + double dirCoords[9]) +{ + for ( int i = 0; i < 9; ++i ) dirCoords[i] = 0.; + dirCoords[0] = dirCoords[4] = dirCoords[8] = 1.; + + if ( shape.IsNull() ) return; + + TopLoc_Location loc; + TopExp_Explorer exp; + + // get external FACEs of the shape + TopTools_MapOfShape faceMap; + for ( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() ) + if ( !faceMap.Add( exp.Current() )) + faceMap.Remove( exp.Current() ); + + // sort areas of planar faces by normal direction + + std::multimap< TCooTriple, double > areasByNormal; + + TopTools_MapIteratorOfMapOfShape fIt ( faceMap ); + for ( ; fIt.More(); fIt.Next() ) + { + const TopoDS_Face& face = TopoDS::Face( fIt.Key() ); + Handle(Geom_Surface) surf = BRep_Tool::Surface( face, loc ); + if ( surf.IsNull() ) continue; + + GeomLib_IsPlanarSurface check( surf, 1e-5 ); + if ( !check.IsPlanar() ) continue; + + GProp_GProps SProps; + BRepGProp::SurfaceProperties( face, SProps ); + double area = SProps.Mass(); + + gp_Pln pln = check.Plan(); + gp_Dir norm = pln.Axis().Direction().Transformed( loc ); + if ( norm.X() < -1e-3 ) { // negative X + norm.Reverse(); + } else if ( norm.X() < 1e-3 ) { // zero X + if ( norm.Y() < -1e-3 ) { // negative Y + norm.Reverse(); + } else if ( norm.Y() < 1e-3 ) { // zero X && zero Y + if ( norm.Y() < -1e-3 ) // negative Z + norm.Reverse(); + } + } + TCooTriple coo3( norm.X(), make_pair( norm.Y(), norm.Z() )); + areasByNormal.insert( make_pair( coo3, area )); + } + + // group coplanar normals and sort groups by sum area + + std::multimap< double, vector< const TCooTriple* > > normsByArea; + std::multimap< TCooTriple, double >::iterator norm2a = areasByNormal.begin(); + const TCooTriple* norm1 = 0; + double sumArea = 0; + vector< const TCooTriple* > norms; + for ( int iF = 1; norm2a != areasByNormal.end(); ++norm2a, ++iF ) + { + + if ( !norm1 || !sameDir( *norm1, norm2a->first )) + { + if ( !norms.empty() ) + { + normsByArea.insert( make_pair( sumArea, norms )); + norms.clear(); + } + norm1 = & norm2a->first; + sumArea = norm2a->second; + norms.push_back( norm1 ); + } + else + { + sumArea += norm2a->second; + norms.push_back( & norm2a->first ); + } + if ( iF == areasByNormal.size() ) + normsByArea.insert( make_pair( sumArea, norms )); + } + + // try to set dirs by planar faces + + gp_XYZ normDirs[3]; // normals to largest planes + + if ( !normsByArea.empty() ) + { + norm1 = normsByArea.rbegin()->second[0]; + normDirs[0] = gpXYZ( *norm1 ); + + if ( normsByArea.size() == 1 ) + { + normDirs[1] = normDirs[0]; + if ( Abs( normDirs[0].Y() ) < 1e-100 && + Abs( normDirs[0].Z() ) < 1e-100 ) // normDirs[0] || OX + normDirs[1].SetY( normDirs[0].Y() + 1. ); + else + normDirs[1].SetX( normDirs[0].X() + 1. ); + } + else + { + // look for 2 other directions + gp_XYZ testDir = normDirs[0], minDir, maxDir; + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + double maxMetric = 0, minMetric = 1e100; + std::multimap< double, vector< const TCooTriple* > >::iterator a2n; + for ( a2n = normsByArea.begin(); a2n != normsByArea.end(); ++a2n ) + { + gp_XYZ n = gpXYZ( *( a2n->second[0]) ); + double dot = Abs( n * testDir ); + double metric = ( 1. - dot ) * ( isOrthogonal ? 1 : a2n->first ); + if ( metric > maxMetric ) + { + maxDir = n; + maxMetric = metric; + } + if ( metric < minMetric ) + { + minDir = n; + minMetric = metric; + } + } + if ( is2nd ) + { + normDirs[2] = minDir; + } + else + { + normDirs[1] = maxDir; + normDirs[2] = normDirs[0] ^ normDirs[1]; + if ( isOrthogonal || normsByArea.size() < 3 ) + break; + testDir = normDirs[2]; + } + } + } + if ( isOrthogonal || normsByArea.size() == 1 ) + { + normDirs[2] = normDirs[0] ^ normDirs[1]; + normDirs[1] = normDirs[2] ^ normDirs[0]; + } + } + else + { + return; + } + + gp_XYZ dirs[3]; + dirs[0] = normDirs[0] ^ normDirs[1]; + dirs[1] = normDirs[1] ^ normDirs[2]; + dirs[2] = normDirs[2] ^ normDirs[0]; + + dirs[0].Normalize(); + dirs[1].Normalize(); + dirs[2].Normalize(); + + // Select dirs for X, Y and Z axes + int iX = ( Abs( dirs[0].X() ) > Abs( dirs[1].X() )) ? 0 : 1; + if ( Abs( dirs[iX].X() ) < Abs( dirs[2].X() )) + iX = 2; + int iY = ( iX == 0 ) ? 1 : (( Abs( dirs[0].Y() ) > Abs( dirs[1].Y() )) ? 0 : 1 ); + if ( Abs( dirs[iY].Y() ) < Abs( dirs[2].Y() ) && iX != 2 ) + iY = 2; + int iZ = 3 - iX - iY; + + if ( dirs[iX].X() < 0 ) dirs[iX].Reverse(); + if ( dirs[iY].Y() < 0 ) dirs[iY].Reverse(); + gp_XYZ zDir = dirs[iX] ^ dirs[iY]; + if ( dirs[iZ] * zDir < 0 ) + dirs[iZ].Reverse(); + + dirCoords[0] = dirs[iX].X(); + dirCoords[1] = dirs[iX].Y(); + dirCoords[2] = dirs[iX].Z(); + dirCoords[3] = dirs[iY].X(); + dirCoords[4] = dirs[iY].Y(); + dirCoords[5] = dirs[iY].Z(); + dirCoords[6] = dirs[iZ].X(); + dirCoords[7] = dirs[iZ].Y(); + dirCoords[8] = dirs[iZ].Z(); +} + +//======================================================================= +//function : SetAxisDirs +//purpose : Sets custom direction of axes +//======================================================================= + +void StdMeshers_CartesianParameters3D::SetAxisDirs(const double* the9DirComps) + throw ( SALOME_Exception ) +{ + gp_Vec x( the9DirComps[0], + the9DirComps[1], + the9DirComps[2] ); + gp_Vec y( the9DirComps[3], + the9DirComps[4], + the9DirComps[5] ); + gp_Vec z( the9DirComps[6], + the9DirComps[7], + the9DirComps[8] ); + if ( x.Magnitude() < RealSmall() || + y.Magnitude() < RealSmall() || + z.Magnitude() < RealSmall() ) + throw SALOME_Exception("Zero magnitude of axis direction"); + + if ( x.IsParallel( y, M_PI / 180. ) || + x.IsParallel( z, M_PI / 180. ) || + y.IsParallel( z, M_PI / 180. )) + throw SALOME_Exception("Parallel axis directions"); + + gp_Vec normXY = x ^ y, normYZ = y ^ z; + if ( normXY.IsParallel( normYZ, M_PI / 180. )) + throw SALOME_Exception("Axes lie in one plane"); + + bool isChanged = false; + for ( int i = 0; i < 9; ++i ) + { + if ( Abs( _axisDirs[i] - the9DirComps[i] ) > 1e-7 ) + isChanged = true; + _axisDirs[i] = the9DirComps[i]; + } + if ( isChanged ) + NotifySubMeshesHypothesisModification(); +} + +//======================================================================= +//function : GetGrid +//purpose : Return coordinates of node positions along the three axes +//======================================================================= + +void StdMeshers_CartesianParameters3D::GetGrid(std::vector& coords, int axis) const + throw ( SALOME_Exception ) +{ + if ( IsGridBySpacing(axis) ) + throw SALOME_Exception(LOCALIZED("The grid is defined by spacing and not by coordinates")); + + coords = _coords[axis]; +} + +//======================================================================= +//function : GetSizeThreshold +//purpose : Return size threshold +//======================================================================= + +double StdMeshers_CartesianParameters3D::GetSizeThreshold() const +{ + return _sizeThreshold; +} + +//======================================================================= +//function : SetToAddEdges +//purpose : Enables implementation of geometrical edges into the mesh. If this feature +// is disabled, sharp edges of the shape are lost ("smoothed") in the mesh if +// they don't coincide with the grid lines +//======================================================================= + +void StdMeshers_CartesianParameters3D::SetToAddEdges(bool toAdd) +{ + if ( _toAddEdges != toAdd ) + { + _toAddEdges = toAdd; + NotifySubMeshesHypothesisModification(); + } +} + +//======================================================================= +//function : GetToAddEdges +//purpose : Returns true if implementation of geometrical edges into the +// mesh is enabled +//======================================================================= + +bool StdMeshers_CartesianParameters3D::GetToAddEdges() const +{ + return _toAddEdges; +} + +//======================================================================= +//function : IsDefined +//purpose : Return true if parameters are well defined +//======================================================================= + +bool StdMeshers_CartesianParameters3D::IsDefined() const +{ + for ( int i = 0; i < 3; ++i ) + if (_coords[i].empty() && (_spaceFunctions[i].empty() || _internalPoints[i].empty())) + return false; + + return ( _sizeThreshold > 1.0 ); +} + +//======================================================================= +//function : SaveTo +//purpose : store my parameters into a stream +//======================================================================= + +std::ostream & StdMeshers_CartesianParameters3D::SaveTo(std::ostream & save) +{ + save << _sizeThreshold << " "; + + for ( int i = 0; i < 3; ++i ) + { + save << _coords[i].size() << " "; + for ( size_t j = 0; j < _coords[i].size(); ++j ) + save << _coords[i][j] << " "; + + save << _internalPoints[i].size() << " "; + for ( size_t j = 0; j < _internalPoints[i].size(); ++j ) + save << _internalPoints[i][j] << " "; + + save << _spaceFunctions[i].size() << " "; + for ( size_t j = 0; j < _spaceFunctions[i].size(); ++j ) + save << _spaceFunctions[i][j] << " "; + } + save << _toAddEdges << " "; + + save.setf( save.scientific ); + save.precision( 12 ); + for ( int i = 0; i < 9; ++i ) + save << _axisDirs[i] << " "; + + for ( int i = 0; i < 3; ++i ) + save << _fixedPoint[i] << " "; + + return save; +} + +//======================================================================= +//function : LoadFrom +//purpose : resore my parameters from a stream +//======================================================================= + +std::istream & StdMeshers_CartesianParameters3D::LoadFrom(std::istream & load) +{ + bool ok; + + ok = (bool)( load >> _sizeThreshold ); + for ( int ax = 0; ax < 3; ++ax ) + { + if (ok) + { + size_t i = 0; + ok = (bool)(load >> i ); + if ( i > 0 && ok ) + { + _coords[ax].resize( i ); + for ( i = 0; i < _coords[ax].size() && ok; ++i ) + ok = (bool)(load >> _coords[ax][i] ); + } + } + if (ok) + { + size_t i = 0; + ok = (bool)(load >> i ); + if ( i > 0 && ok ) + { + _internalPoints[ax].resize( i ); + for ( i = 0; i < _internalPoints[ax].size() && ok; ++i ) + ok = (bool)(load >> _internalPoints[ax][i] ); + } + } + if (ok) + { + size_t i = 0; + ok = (bool)(load >> i ); + if ( i > 0 && ok ) + { + _spaceFunctions[ax].resize( i ); + for ( i = 0; i < _spaceFunctions[ax].size() && ok; ++i ) + ok = (bool)(load >> _spaceFunctions[ax][i] ); + } + } + } + + ok = (bool)( load >> _toAddEdges ); + + for ( int i = 0; i < 9 && ok; ++i ) + ok = (bool)( load >> _axisDirs[i]); + + for ( int i = 0; i < 3 && ok ; ++i ) + ok = (bool)( load >> _fixedPoint[i]); + + return load; +} + +//======================================================================= +//function : SetParametersByMesh +//======================================================================= + +bool StdMeshers_CartesianParameters3D::SetParametersByMesh(const SMESH_Mesh* , + const TopoDS_Shape& ) +{ + return false; +} + +//======================================================================= +//function : SetParametersByDefaults +//======================================================================= + +bool StdMeshers_CartesianParameters3D::SetParametersByDefaults(const TDefaults& dflts, + const SMESH_Mesh* /*theMesh*/) +{ + if ( dflts._elemLength > 1e-100 ) + { + vector spacing( 1, SMESH_Comment(dflts._elemLength)); + vector intPnts; + SetGridSpacing( spacing, intPnts, 0 ); + SetGridSpacing( spacing, intPnts, 1 ); + SetGridSpacing( spacing, intPnts, 2 ); + return true; + } + return false; +} + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Cartesian_3D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Cartesian_3D.cpp new file mode 100644 index 000000000000..a787d959aaea --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Cartesian_3D.cpp @@ -0,0 +1,3788 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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_Cartesian_3D.cxx +// Module : SMESH +// +#include "StdMeshers_Cartesian_3D.hxx" + +#include "SMDS_MeshNode.hxx" +#include "SMESH_Block.hxx" +#include "SMESH_Comment.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_subMeshEventListener.hxx" +#include "StdMeshers_CartesianParameters3D.hxx" + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//#undef WITH_TBB +#ifdef WITH_TBB +#include +//#include +#endif + +using namespace std; + +#ifdef _DEBUG_ +//#define _MY_DEBUG_ +#endif + +//============================================================================= +/*! + * Constructor + */ +//============================================================================= + +StdMeshers_Cartesian_3D::StdMeshers_Cartesian_3D(int hypId, int studyId, SMESH_Gen * gen) + :SMESH_3D_Algo(hypId, studyId, gen) +{ + _name = "Cartesian_3D"; + _shapeType = (1 << TopAbs_SOLID); // 1 bit /shape type + _compatibleHypothesis.push_back("CartesianParameters3D"); + + _onlyUnaryInput = false; // to mesh all SOLIDs at once + _requireDiscreteBoundary = false; // 2D mesh not needed + _supportSubmeshes = false; // do not use any existing mesh +} + +//============================================================================= +/*! + * Check presence of a hypothesis + */ +//============================================================================= + +bool StdMeshers_Cartesian_3D::CheckHypothesis (SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + Hypothesis_Status& aStatus) +{ + aStatus = SMESH_Hypothesis::HYP_MISSING; + + const list& hyps = GetUsedHypothesis(aMesh, aShape); + list ::const_iterator h = hyps.begin(); + if ( h == hyps.end()) + { + return false; + } + + for ( ; h != hyps.end(); ++h ) + { + if (( _hyp = dynamic_cast( *h ))) + { + aStatus = _hyp->IsDefined() ? HYP_OK : HYP_BAD_PARAMETER; + break; + } + } + + return aStatus == HYP_OK; +} + +namespace +{ + typedef int TGeomID; + + //============================================================================= + // Definitions of internal utils + // -------------------------------------------------------------------------- + enum Transition { + Trans_TANGENT = IntCurveSurface_Tangent, + Trans_IN = IntCurveSurface_In, + Trans_OUT = IntCurveSurface_Out, + Trans_APEX + }; + // -------------------------------------------------------------------------- + /*! + * \brief Common data of any intersection between a Grid and a shape + */ + struct B_IntersectPoint + { + mutable const SMDS_MeshNode* _node; + mutable vector< TGeomID > _faceIDs; + + B_IntersectPoint(): _node(NULL) {} + void Add( const vector< TGeomID >& fIDs, const SMDS_MeshNode* n=0 ) const; + int HasCommonFace( const B_IntersectPoint * other, int avoidFace=-1 ) const; + bool IsOnFace( int faceID ) const; + virtual ~B_IntersectPoint() {} + }; + // -------------------------------------------------------------------------- + /*! + * \brief Data of intersection between a GridLine and a TopoDS_Face + */ + struct F_IntersectPoint : public B_IntersectPoint + { + double _paramOnLine; + mutable Transition _transition; + mutable size_t _indexOnLine; + + bool operator< ( const F_IntersectPoint& o ) const { return _paramOnLine < o._paramOnLine; } + }; + // -------------------------------------------------------------------------- + /*! + * \brief Data of intersection between GridPlanes and a TopoDS_EDGE + */ + struct E_IntersectPoint : public B_IntersectPoint + { + gp_Pnt _point; + double _uvw[3]; + TGeomID _shapeID; + }; + // -------------------------------------------------------------------------- + /*! + * \brief A line of the grid and its intersections with 2D geometry + */ + struct GridLine + { + gp_Lin _line; + double _length; // line length + multiset< F_IntersectPoint > _intPoints; + + void RemoveExcessIntPoints( const double tol ); + bool GetIsOutBefore( multiset< F_IntersectPoint >::iterator ip, bool prevIsOut ); + }; + // -------------------------------------------------------------------------- + /*! + * \brief Planes of the grid used to find intersections of an EDGE with a hexahedron + */ + struct GridPlanes + { + gp_XYZ _zNorm; + vector< gp_XYZ > _origins; // origin points of all planes in one direction + vector< double > _zProjs; // projections of origins to _zNorm + }; + // -------------------------------------------------------------------------- + /*! + * \brief Iterator on the parallel grid lines of one direction + */ + struct LineIndexer + { + size_t _size [3]; + size_t _curInd[3]; + size_t _iVar1, _iVar2, _iConst; + string _name1, _name2, _nameConst; + LineIndexer() {} + LineIndexer( size_t sz1, size_t sz2, size_t sz3, + size_t iv1, size_t iv2, size_t iConst, + const string& nv1, const string& nv2, const string& nConst ) + { + _size[0] = sz1; _size[1] = sz2; _size[2] = sz3; + _curInd[0] = _curInd[1] = _curInd[2] = 0; + _iVar1 = iv1; _iVar2 = iv2; _iConst = iConst; + _name1 = nv1; _name2 = nv2; _nameConst = nConst; + } + + size_t I() const { return _curInd[0]; } + size_t J() const { return _curInd[1]; } + size_t K() const { return _curInd[2]; } + void SetIJK( size_t i, size_t j, size_t k ) + { + _curInd[0] = i; _curInd[1] = j; _curInd[2] = k; + } + void operator++() + { + if ( ++_curInd[_iVar1] == _size[_iVar1] ) + _curInd[_iVar1] = 0, ++_curInd[_iVar2]; + } + bool More() const { return _curInd[_iVar2] < _size[_iVar2]; } + size_t LineIndex () const { return _curInd[_iVar1] + _curInd[_iVar2]* _size[_iVar1]; } + size_t LineIndex10 () const { return (_curInd[_iVar1] + 1 ) + _curInd[_iVar2]* _size[_iVar1]; } + size_t LineIndex01 () const { return _curInd[_iVar1] + (_curInd[_iVar2] + 1 )* _size[_iVar1]; } + size_t LineIndex11 () const { return (_curInd[_iVar1] + 1 ) + (_curInd[_iVar2] + 1 )* _size[_iVar1]; } + void SetIndexOnLine (size_t i) { _curInd[ _iConst ] = i; } + size_t NbLines() const { return _size[_iVar1] * _size[_iVar2]; } + }; + // -------------------------------------------------------------------------- + /*! + * \brief Container of GridLine's + */ + struct Grid + { + vector< double > _coords[3]; // coordinates of grid nodes + gp_XYZ _axes [3]; // axis directions + vector< GridLine > _lines [3]; // in 3 directions + double _tol, _minCellSize; + gp_XYZ _origin; + gp_Mat _invB; // inverted basis of _axes + + vector< const SMDS_MeshNode* > _nodes; // mesh nodes at grid nodes + vector< const F_IntersectPoint* > _gridIntP; // grid node intersection with geometry + + list< E_IntersectPoint > _edgeIntP; // intersections with EDGEs + TopTools_IndexedMapOfShape _shapes; + + SMESH_MesherHelper* _helper; + + size_t CellIndex( size_t i, size_t j, size_t k ) const + { + return i + j*(_coords[0].size()-1) + k*(_coords[0].size()-1)*(_coords[1].size()-1); + } + size_t NodeIndex( size_t i, size_t j, size_t k ) const + { + return i + j*_coords[0].size() + k*_coords[0].size()*_coords[1].size(); + } + size_t NodeIndexDX() const { return 1; } + size_t NodeIndexDY() const { return _coords[0].size(); } + size_t NodeIndexDZ() const { return _coords[0].size() * _coords[1].size(); } + + LineIndexer GetLineIndexer(size_t iDir) const; + + void SetCoordinates(const vector& xCoords, + const vector& yCoords, + const vector& zCoords, + const double* axesDirs, + const Bnd_Box& bndBox ); + void ComputeUVW(const gp_XYZ& p, double uvw[3]); + void ComputeNodes(SMESH_MesherHelper& helper); + }; + // -------------------------------------------------------------------------- + /*! + * \brief Intersector of TopoDS_Face with all GridLine's + */ + struct FaceGridIntersector + { + TopoDS_Face _face; + TGeomID _faceID; + Grid* _grid; + Bnd_Box _bndBox; + IntCurvesFace_Intersector* _surfaceInt; + vector< std::pair< GridLine*, F_IntersectPoint > > _intersections; + + FaceGridIntersector(): _grid(0), _surfaceInt(0) {} + void Intersect(); + + void StoreIntersections() + { + for ( size_t i = 0; i < _intersections.size(); ++i ) + { + multiset< F_IntersectPoint >::iterator ip = + _intersections[i].first->_intPoints.insert( _intersections[i].second ); + ip->_faceIDs.reserve( 1 ); + ip->_faceIDs.push_back( _faceID ); + } + } + const Bnd_Box& GetFaceBndBox() + { + GetCurveFaceIntersector(); + return _bndBox; + } + IntCurvesFace_Intersector* GetCurveFaceIntersector() + { + if ( !_surfaceInt ) + { + _surfaceInt = new IntCurvesFace_Intersector( _face, Precision::PConfusion() ); + _bndBox = _surfaceInt->Bounding(); + if ( _bndBox.IsVoid() ) + BRepBndLib::Add (_face, _bndBox); + } + return _surfaceInt; + } + bool IsThreadSafe(set< const Standard_Transient* >& noSafeTShapes) const; + }; + // -------------------------------------------------------------------------- + /*! + * \brief Intersector of a surface with a GridLine + */ + struct FaceLineIntersector + { + double _tol; + double _u, _v, _w; // params on the face and the line + Transition _transition; // transition of at intersection (see IntCurveSurface.cdl) + Transition _transIn, _transOut; // IN and OUT transitions depending of face orientation + + gp_Pln _plane; + gp_Cylinder _cylinder; + gp_Cone _cone; + gp_Sphere _sphere; + gp_Torus _torus; + IntCurvesFace_Intersector* _surfaceInt; + + vector< F_IntersectPoint > _intPoints; + + void IntersectWithPlane (const GridLine& gridLine); + void IntersectWithCylinder(const GridLine& gridLine); + void IntersectWithCone (const GridLine& gridLine); + void IntersectWithSphere (const GridLine& gridLine); + void IntersectWithTorus (const GridLine& gridLine); + void IntersectWithSurface (const GridLine& gridLine); + + bool UVIsOnFace() const; + void addIntPoint(const bool toClassify=true); + bool isParamOnLineOK( const double linLength ) + { + return -_tol < _w && _w < linLength + _tol; + } + FaceLineIntersector():_surfaceInt(0) {} + ~FaceLineIntersector() { if (_surfaceInt ) delete _surfaceInt; _surfaceInt = 0; } + }; + // -------------------------------------------------------------------------- + /*! + * \brief Class representing topology of the hexahedron and creating a mesh + * volume basing on analysis of hexahedron intersection with geometry + */ + class Hexahedron + { + // -------------------------------------------------------------------------------- + struct _Face; + struct _Link; + // -------------------------------------------------------------------------------- + struct _Node //!< node either at a hexahedron corner or at intersection + { + const SMDS_MeshNode* _node; // mesh node at hexahedron corner + const B_IntersectPoint* _intPoint; + const _Face* _usedInFace; + + _Node(const SMDS_MeshNode* n=0, const B_IntersectPoint* ip=0) + :_node(n), _intPoint(ip), _usedInFace(0) {} + const SMDS_MeshNode* Node() const + { return ( _intPoint && _intPoint->_node ) ? _intPoint->_node : _node; } + const E_IntersectPoint* EdgeIntPnt() const + { return static_cast< const E_IntersectPoint* >( _intPoint ); } + bool IsUsedInFace( const _Face* polygon = 0 ) + { + return polygon ? ( _usedInFace == polygon ) : bool( _usedInFace ); + } + void Add( const E_IntersectPoint* ip ) + { + if ( !_intPoint ) { + _intPoint = ip; + } + else if ( !_intPoint->_node ) { + ip->Add( _intPoint->_faceIDs ); + _intPoint = ip; + } + else { + _intPoint->Add( ip->_faceIDs ); + } + } + TGeomID IsLinked( const B_IntersectPoint* other, + TGeomID avoidFace=-1 ) const // returns id of a common face + { + return _intPoint ? _intPoint->HasCommonFace( other, avoidFace ) : 0; + } + bool IsOnFace( TGeomID faceID ) const // returns true if faceID is found + { + return _intPoint ? _intPoint->IsOnFace( faceID ) : false; + } + gp_Pnt Point() const + { + if ( const SMDS_MeshNode* n = Node() ) + return SMESH_TNodeXYZ( n ); + if ( const E_IntersectPoint* eip = + dynamic_cast< const E_IntersectPoint* >( _intPoint )) + return eip->_point; + return gp_Pnt( 1e100, 0, 0 ); + } + TGeomID ShapeID() const + { + if ( const E_IntersectPoint* eip = dynamic_cast< const E_IntersectPoint* >( _intPoint )) + return eip->_shapeID; + return 0; + } + }; + // -------------------------------------------------------------------------------- + struct _Link // link connecting two _Node's + { + _Node* _nodes[2]; + _Face* _faces[2]; // polygons sharing a link + vector< const F_IntersectPoint* > _fIntPoints; // GridLine intersections with FACEs + vector< _Node* > _fIntNodes; // _Node's at _fIntPoints + vector< _Link > _splits; + _Link() { _faces[0] = 0; } + }; + // -------------------------------------------------------------------------------- + struct _OrientedLink + { + _Link* _link; + bool _reverse; + _OrientedLink( _Link* link=0, bool reverse=false ): _link(link), _reverse(reverse) {} + void Reverse() { _reverse = !_reverse; } + int NbResultLinks() const { return _link->_splits.size(); } + _OrientedLink ResultLink(int i) const + { + return _OrientedLink(&_link->_splits[_reverse ? NbResultLinks()-i-1 : i],_reverse); + } + _Node* FirstNode() const { return _link->_nodes[ _reverse ]; } + _Node* LastNode() const { return _link->_nodes[ !_reverse ]; } + operator bool() const { return _link; } + vector< TGeomID > GetNotUsedFace(const set& usedIDs ) const // returns supporting FACEs + { + vector< TGeomID > faces; + const B_IntersectPoint *ip0, *ip1; + if (( ip0 = _link->_nodes[0]->_intPoint ) && + ( ip1 = _link->_nodes[1]->_intPoint )) + { + for ( size_t i = 0; i < ip0->_faceIDs.size(); ++i ) + if ( ip1->IsOnFace ( ip0->_faceIDs[i] ) && + !usedIDs.count( ip0->_faceIDs[i] ) ) + faces.push_back( ip0->_faceIDs[i] ); + } + return faces; + } + bool HasEdgeNodes() const + { + return ( dynamic_cast< const E_IntersectPoint* >( _link->_nodes[0]->_intPoint ) || + dynamic_cast< const E_IntersectPoint* >( _link->_nodes[1]->_intPoint )); + } + int NbFaces() const + { + return !_link->_faces[0] ? 0 : 1 + bool( _link->_faces[1] ); + } + void AddFace( _Face* f ) + { + if ( _link->_faces[0] ) + { + _link->_faces[1] = f; + } + else + { + _link->_faces[0] = f; + _link->_faces[1] = 0; + } + } + void RemoveFace( _Face* f ) + { + if ( !_link->_faces[0] ) return; + + if ( _link->_faces[1] == f ) + { + _link->_faces[1] = 0; + } + else if ( _link->_faces[0] == f ) + { + _link->_faces[0] = 0; + if ( _link->_faces[1] ) + { + _link->_faces[0] = _link->_faces[1]; + _link->_faces[1] = 0; + } + } + } + }; + // -------------------------------------------------------------------------------- + struct _Face + { + vector< _OrientedLink > _links; // links on GridLine's + vector< _Link > _polyLinks; // links added to close a polygonal face + vector< _Node* > _eIntNodes; // nodes at intersection with EDGEs + bool IsPolyLink( const _OrientedLink& ol ) + { + return _polyLinks.empty() ? false : + ( &_polyLinks[0] <= ol._link && ol._link <= &_polyLinks.back() ); + } + void AddPolyLink(_Node* n0, _Node* n1, _Face* faceToFindEqual=0) + { + if ( faceToFindEqual && faceToFindEqual != this ) { + for ( size_t iL = 0; iL < faceToFindEqual->_polyLinks.size(); ++iL ) + if ( faceToFindEqual->_polyLinks[iL]._nodes[0] == n1 && + faceToFindEqual->_polyLinks[iL]._nodes[1] == n0 ) + { + _links.push_back + ( _OrientedLink( & faceToFindEqual->_polyLinks[iL], /*reverse=*/true )); + return; + } + } + _Link l; + l._nodes[0] = n0; + l._nodes[1] = n1; + _polyLinks.push_back( l ); + _links.push_back( _OrientedLink( &_polyLinks.back() )); + } + }; + // -------------------------------------------------------------------------------- + struct _volumeDef // holder of nodes of a volume mesh element + { + vector< _Node* > _nodes; + vector< int > _quantities; + typedef boost::shared_ptr<_volumeDef> Ptr; + void set( const vector< _Node* >& nodes, + const vector< int >& quant = vector< int >() ) + { _nodes = nodes; _quantities = quant; } + void set( _Node** nodes, int nb ) + { _nodes.assign( nodes, nodes + nb ); } + }; + + // topology of a hexahedron + int _nodeShift[8]; + _Node _hexNodes [8]; + _Link _hexLinks [12]; + _Face _hexQuads [6]; + + // faces resulted from hexahedron intersection + vector< _Face > _polygons; + + // intresections with EDGEs + vector< const E_IntersectPoint* > _eIntPoints; + + // additional nodes created at intersection points + vector< _Node > _intNodes; + + // nodes inside the hexahedron (at VERTEXes) + vector< _Node* > _vIntNodes; + + // computed volume elements + //vector< _volumeDef::Ptr > _volumeDefs; + _volumeDef _volumeDefs; + + Grid* _grid; + double _sizeThreshold, _sideLength[3]; + int _nbCornerNodes, _nbFaceIntNodes, _nbBndNodes; + int _origNodeInd; // index of _hexNodes[0] node within the _grid + size_t _i,_j,_k; + + public: + Hexahedron(const double sizeThreshold, Grid* grid); + int MakeElements(SMESH_MesherHelper& helper, + const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap); + void ComputeElements(); + void Init() { init( _i, _j, _k ); } + + private: + Hexahedron(const Hexahedron& other ); + void init( size_t i, size_t j, size_t k ); + void init( size_t i ); + void addEdges(SMESH_MesherHelper& helper, + vector< Hexahedron* >& intersectedHex, + const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap); + gp_Pnt findIntPoint( double u1, double proj1, double u2, double proj2, + double proj, BRepAdaptor_Curve& curve, + const gp_XYZ& axis, const gp_XYZ& origin ); + int getEntity( const E_IntersectPoint* ip, int* facets, int& sub ); + bool addIntersection( const E_IntersectPoint& ip, + vector< Hexahedron* >& hexes, + int ijk[], int dIJK[] ); + bool findChain( _Node* n1, _Node* n2, _Face& quad, vector<_Node*>& chainNodes ); + bool closePolygon( _Face* polygon, vector<_Node*>& chainNodes ) const; + bool findChainOnEdge( const vector< _OrientedLink >& splits, + const _OrientedLink& prevSplit, + const _OrientedLink& avoidSplit, + size_t & iS, + _Face& quad, + vector<_Node*>& chn); + int addElements(SMESH_MesherHelper& helper); + bool isOutPoint( _Link& link, int iP, SMESH_MesherHelper& helper ) const; + void sortVertexNodes(vector<_Node*>& nodes, _Node* curNode, TGeomID face); + bool isInHole() const; + bool checkPolyhedronSize() const; + bool addHexa (); + bool addTetra(); + bool addPenta(); + bool addPyra (); + bool debugDumpLink( _Link* link ); + _Node* findEqualNode( vector< _Node* >& nodes, + const E_IntersectPoint* ip, + const double tol2 ) + { + for ( size_t i = 0; i < nodes.size(); ++i ) + if ( nodes[i]->EdgeIntPnt() == ip || + nodes[i]->Point().SquareDistance( ip->_point ) <= tol2 ) + return nodes[i]; + return 0; + } + bool isImplementEdges() const { return !_grid->_edgeIntP.empty(); } + bool isOutParam(const double uvw[3]) const; + }; + +#ifdef WITH_TBB + // -------------------------------------------------------------------------- + /*! + * \brief Hexahedron computing volumes in one thread + */ + struct ParallelHexahedron + { + vector< Hexahedron* >& _hexVec; + ParallelHexahedron( vector< Hexahedron* >& hv ): _hexVec(hv) {} + void operator() ( const tbb::blocked_range& r ) const + { + for ( size_t i = r.begin(); i != r.end(); ++i ) + if ( Hexahedron* hex = _hexVec[ i ] ) + hex->ComputeElements(); + } + }; + // -------------------------------------------------------------------------- + /*! + * \brief Structure intersecting certain nb of faces with GridLine's in one thread + */ + struct ParallelIntersector + { + vector< FaceGridIntersector >& _faceVec; + ParallelIntersector( vector< FaceGridIntersector >& faceVec): _faceVec(faceVec){} + void operator() ( const tbb::blocked_range& r ) const + { + for ( size_t i = r.begin(); i != r.end(); ++i ) + _faceVec[i].Intersect(); + } + }; +#endif + + //============================================================================= + // Implementation of internal utils + //============================================================================= + /*! + * \brief adjust \a i to have \a val between values[i] and values[i+1] + */ + inline void locateValue( int & i, double val, const vector& values, + int& di, double tol ) + { + //val += values[0]; // input \a val is measured from 0. + if ( i > values.size()-2 ) + i = values.size()-2; + else + while ( i+2 < values.size() && val > values[ i+1 ]) + ++i; + while ( i > 0 && val < values[ i ]) + --i; + + if ( i > 0 && val - values[ i ] < tol ) + di = -1; + else if ( i+2 < values.size() && values[ i+1 ] - val < tol ) + di = 1; + else + di = 0; + } + //============================================================================= + /* + * Remove coincident intersection points + */ + void GridLine::RemoveExcessIntPoints( const double tol ) + { + if ( _intPoints.size() < 2 ) return; + + set< Transition > tranSet; + multiset< F_IntersectPoint >::iterator ip1, ip2 = _intPoints.begin(); + while ( ip2 != _intPoints.end() ) + { + tranSet.clear(); + ip1 = ip2++; + while ( ip2 != _intPoints.end() && ip2->_paramOnLine - ip1->_paramOnLine <= tol ) + { + tranSet.insert( ip1->_transition ); + tranSet.insert( ip2->_transition ); + ip2->Add( ip1->_faceIDs ); + _intPoints.erase( ip1 ); + ip1 = ip2++; + } + if ( tranSet.size() > 1 ) // points with different transition coincide + { + bool isIN = tranSet.count( Trans_IN ); + bool isOUT = tranSet.count( Trans_OUT ); + if ( isIN && isOUT ) + (*ip1)._transition = Trans_TANGENT; + else + (*ip1)._transition = isIN ? Trans_IN : Trans_OUT; + } + } + } + //================================================================================ + /* + * Return "is OUT" state for nodes before the given intersection point + */ + bool GridLine::GetIsOutBefore( multiset< F_IntersectPoint >::iterator ip, bool prevIsOut ) + { + if ( ip->_transition == Trans_IN ) + return true; + if ( ip->_transition == Trans_OUT ) + return false; + if ( ip->_transition == Trans_APEX ) + { + // singularity point (apex of a cone) + if ( _intPoints.size() == 1 || ip == _intPoints.begin() ) + return true; + multiset< F_IntersectPoint >::iterator ipBef = ip, ipAft = ++ip; + if ( ipAft == _intPoints.end() ) + return false; + --ipBef; + if ( ipBef->_transition != ipAft->_transition ) + return ( ipBef->_transition == Trans_OUT ); + return ( ipBef->_transition != Trans_OUT ); + } + // _transition == Trans_TANGENT + return !prevIsOut; + } + //================================================================================ + /* + * Adds face IDs + */ + void B_IntersectPoint::Add( const vector< TGeomID >& fIDs, + const SMDS_MeshNode* n) const + { + if ( _faceIDs.empty() ) + _faceIDs = fIDs; + else + for ( size_t i = 0; i < fIDs.size(); ++i ) + { + vector< TGeomID >::iterator it = + std::find( _faceIDs.begin(), _faceIDs.end(), fIDs[i] ); + if ( it == _faceIDs.end() ) + _faceIDs.push_back( fIDs[i] ); + } + if ( !_node ) + _node = n; + } + //================================================================================ + /* + * Returns index of a common face if any, else zero + */ + int B_IntersectPoint::HasCommonFace( const B_IntersectPoint * other, int avoidFace ) const + { + if ( other ) + for ( size_t i = 0; i < other->_faceIDs.size(); ++i ) + if ( avoidFace != other->_faceIDs[i] && + IsOnFace ( other->_faceIDs[i] )) + return other->_faceIDs[i]; + return 0; + } + //================================================================================ + /* + * Returns \c true if \a faceID in in this->_faceIDs + */ + bool B_IntersectPoint::IsOnFace( int faceID ) const // returns true if faceID is found + { + vector< TGeomID >::const_iterator it = + std::find( _faceIDs.begin(), _faceIDs.end(), faceID ); + return ( it != _faceIDs.end() ); + } + //================================================================================ + /* + * Return an iterator on GridLine's in a given direction + */ + LineIndexer Grid::GetLineIndexer(size_t iDir) const + { + const size_t indices[] = { 1,2,0, 0,2,1, 0,1,2 }; + const string s [] = { "X", "Y", "Z" }; + LineIndexer li( _coords[0].size(), _coords[1].size(), _coords[2].size(), + indices[iDir*3], indices[iDir*3+1], indices[iDir*3+2], + s[indices[iDir*3]], s[indices[iDir*3+1]], s[indices[iDir*3+2]]); + return li; + } + //============================================================================= + /* + * Creates GridLine's of the grid + */ + void Grid::SetCoordinates(const vector& xCoords, + const vector& yCoords, + const vector& zCoords, + const double* axesDirs, + const Bnd_Box& shapeBox) + { + _coords[0] = xCoords; + _coords[1] = yCoords; + _coords[2] = zCoords; + + _axes[0].SetCoord( axesDirs[0], + axesDirs[1], + axesDirs[2]); + _axes[1].SetCoord( axesDirs[3], + axesDirs[4], + axesDirs[5]); + _axes[2].SetCoord( axesDirs[6], + axesDirs[7], + axesDirs[8]); + _axes[0].Normalize(); + _axes[1].Normalize(); + _axes[2].Normalize(); + + _invB.SetCols( _axes[0], _axes[1], _axes[2] ); + _invB.Invert(); + + // compute tolerance + _minCellSize = Precision::Infinite(); + for ( int iDir = 0; iDir < 3; ++iDir ) // loop on 3 line directions + { + for ( size_t i = 1; i < _coords[ iDir ].size(); ++i ) + { + double cellLen = _coords[ iDir ][ i ] - _coords[ iDir ][ i-1 ]; + if ( cellLen < _minCellSize ) + _minCellSize = cellLen; + } + } + if ( _minCellSize < Precision::Confusion() ) + throw SMESH_ComputeError (COMPERR_ALGO_FAILED, + SMESH_Comment("Too small cell size: ") << _minCellSize ); + _tol = _minCellSize / 1000.; + + // attune grid extremities to shape bounding box + + double sP[6]; // aXmin, aYmin, aZmin, aXmax, aYmax, aZmax + shapeBox.Get(sP[0],sP[1],sP[2],sP[3],sP[4],sP[5]); + double* cP[6] = { &_coords[0].front(), &_coords[1].front(), &_coords[2].front(), + &_coords[0].back(), &_coords[1].back(), &_coords[2].back() }; + for ( int i = 0; i < 6; ++i ) + if ( fabs( sP[i] - *cP[i] ) < _tol ) + *cP[i] = sP[i];// + _tol/1000. * ( i < 3 ? +1 : -1 ); + + for ( int iDir = 0; iDir < 3; ++iDir ) + { + if ( _coords[iDir][0] - sP[iDir] > _tol ) + { + _minCellSize = Min( _minCellSize, _coords[iDir][0] - sP[iDir] ); + _coords[iDir].insert( _coords[iDir].begin(), sP[iDir] + _tol/1000.); + } + if ( sP[iDir+3] - _coords[iDir].back() > _tol ) + { + _minCellSize = Min( _minCellSize, sP[iDir+3] - _coords[iDir].back() ); + _coords[iDir].push_back( sP[iDir+3] - _tol/1000.); + } + } + _tol = _minCellSize / 1000.; + + _origin = ( _coords[0][0] * _axes[0] + + _coords[1][0] * _axes[1] + + _coords[2][0] * _axes[2] ); + + // create lines + for ( int iDir = 0; iDir < 3; ++iDir ) // loop on 3 line directions + { + LineIndexer li = GetLineIndexer( iDir ); + _lines[iDir].resize( li.NbLines() ); + double len = _coords[ iDir ].back() - _coords[iDir].front(); + for ( ; li.More(); ++li ) + { + GridLine& gl = _lines[iDir][ li.LineIndex() ]; + gl._line.SetLocation( _coords[0][li.I()] * _axes[0] + + _coords[1][li.J()] * _axes[1] + + _coords[2][li.K()] * _axes[2] ); + gl._line.SetDirection( _axes[ iDir ]); + gl._length = len; + } + } + } + //================================================================================ + /* + * Computes coordinates of a point in the grid CS + */ + void Grid::ComputeUVW(const gp_XYZ& P, double UVW[3]) + { + gp_XYZ p = P * _invB; + p.Coord( UVW[0], UVW[1], UVW[2] ); + } + //================================================================================ + /* + * Creates all nodes + */ + void Grid::ComputeNodes(SMESH_MesherHelper& helper) + { + // state of each node of the grid relative to the geometry + const size_t nbGridNodes = _coords[0].size() * _coords[1].size() * _coords[2].size(); + vector< bool > isNodeOut( nbGridNodes, false ); + _nodes.resize( nbGridNodes, 0 ); + _gridIntP.resize( nbGridNodes, NULL ); + + for ( int iDir = 0; iDir < 3; ++iDir ) // loop on 3 line directions + { + LineIndexer li = GetLineIndexer( iDir ); + + // find out a shift of node index while walking along a GridLine in this direction + li.SetIndexOnLine( 0 ); + size_t nIndex0 = NodeIndex( li.I(), li.J(), li.K() ); + li.SetIndexOnLine( 1 ); + const size_t nShift = NodeIndex( li.I(), li.J(), li.K() ) - nIndex0; + + const vector & coords = _coords[ iDir ]; + for ( ; li.More(); ++li ) // loop on lines in iDir + { + li.SetIndexOnLine( 0 ); + nIndex0 = NodeIndex( li.I(), li.J(), li.K() ); + + GridLine& line = _lines[ iDir ][ li.LineIndex() ]; + const gp_XYZ lineLoc = line._line.Location().XYZ(); + const gp_XYZ lineDir = line._line.Direction().XYZ(); + line.RemoveExcessIntPoints( _tol ); + multiset< F_IntersectPoint >& intPnts = line._intPoints; + multiset< F_IntersectPoint >::iterator ip = intPnts.begin(); + + bool isOut = true; + const double* nodeCoord = & coords[0]; + const double* coord0 = nodeCoord; + const double* coordEnd = coord0 + coords.size(); + double nodeParam = 0; + for ( ; ip != intPnts.end(); ++ip ) + { + // set OUT state or just skip IN nodes before ip + if ( nodeParam < ip->_paramOnLine - _tol ) + { + isOut = line.GetIsOutBefore( ip, isOut ); + + while ( nodeParam < ip->_paramOnLine - _tol ) + { + if ( isOut ) + isNodeOut[ nIndex0 + nShift * ( nodeCoord-coord0 ) ] = isOut; + if ( ++nodeCoord < coordEnd ) + nodeParam = *nodeCoord - *coord0; + else + break; + } + if ( nodeCoord == coordEnd ) break; + } + // create a mesh node on a GridLine at ip if it does not coincide with a grid node + if ( nodeParam > ip->_paramOnLine + _tol ) + { + // li.SetIndexOnLine( 0 ); + // double xyz[3] = { _coords[0][ li.I() ], _coords[1][ li.J() ], _coords[2][ li.K() ]}; + // xyz[ li._iConst ] += ip->_paramOnLine; + gp_XYZ xyz = lineLoc + ip->_paramOnLine * lineDir; + ip->_node = helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() ); + ip->_indexOnLine = nodeCoord-coord0-1; + } + // create a mesh node at ip concident with a grid node + else + { + int nodeIndex = nIndex0 + nShift * ( nodeCoord-coord0 ); + if ( !_nodes[ nodeIndex ] ) + { + //li.SetIndexOnLine( nodeCoord-coord0 ); + //double xyz[3] = { _coords[0][ li.I() ], _coords[1][ li.J() ], _coords[2][ li.K() ]}; + gp_XYZ xyz = lineLoc + nodeParam * lineDir; + _nodes [ nodeIndex ] = helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() ); + _gridIntP[ nodeIndex ] = & * ip; + } + if ( _gridIntP[ nodeIndex ] ) + _gridIntP[ nodeIndex ]->Add( ip->_faceIDs ); + else + _gridIntP[ nodeIndex ] = & * ip; + // ip->_node = _nodes[ nodeIndex ]; -- to differ from ip on links + ip->_indexOnLine = nodeCoord-coord0; + if ( ++nodeCoord < coordEnd ) + nodeParam = *nodeCoord - *coord0; + } + } + // set OUT state to nodes after the last ip + for ( ; nodeCoord < coordEnd; ++nodeCoord ) + isNodeOut[ nIndex0 + nShift * ( nodeCoord-coord0 ) ] = true; + } + } + + // Create mesh nodes at !OUT nodes of the grid + + for ( size_t z = 0; z < _coords[2].size(); ++z ) + for ( size_t y = 0; y < _coords[1].size(); ++y ) + for ( size_t x = 0; x < _coords[0].size(); ++x ) + { + size_t nodeIndex = NodeIndex( x, y, z ); + if ( !isNodeOut[ nodeIndex ] && !_nodes[ nodeIndex] ) + { + //_nodes[ nodeIndex ] = helper.AddNode( _coords[0][x], _coords[1][y], _coords[2][z] ); + gp_XYZ xyz = ( _coords[0][x] * _axes[0] + + _coords[1][y] * _axes[1] + + _coords[2][z] * _axes[2] ); + _nodes[ nodeIndex ] = helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() ); + } + } + +#ifdef _MY_DEBUG_ + // check validity of transitions + const char* trName[] = { "TANGENT", "IN", "OUT", "APEX" }; + for ( int iDir = 0; iDir < 3; ++iDir ) // loop on 3 line directions + { + LineIndexer li = GetLineIndexer( iDir ); + for ( ; li.More(); ++li ) + { + multiset< F_IntersectPoint >& intPnts = _lines[ iDir ][ li.LineIndex() ]._intPoints; + if ( intPnts.empty() ) continue; + if ( intPnts.size() == 1 ) + { + if ( intPnts.begin()->_transition != Trans_TANGENT && + intPnts.begin()->_transition != Trans_APEX ) + throw SMESH_ComputeError (COMPERR_ALGO_FAILED, + SMESH_Comment("Wrong SOLE transition of GridLine (") + << li._curInd[li._iVar1] << ", " << li._curInd[li._iVar2] + << ") along " << li._nameConst + << ": " << trName[ intPnts.begin()->_transition] ); + } + else + { + if ( intPnts.begin()->_transition == Trans_OUT ) + throw SMESH_ComputeError (COMPERR_ALGO_FAILED, + SMESH_Comment("Wrong START transition of GridLine (") + << li._curInd[li._iVar1] << ", " << li._curInd[li._iVar2] + << ") along " << li._nameConst + << ": " << trName[ intPnts.begin()->_transition ]); + if ( intPnts.rbegin()->_transition == Trans_IN ) + throw SMESH_ComputeError (COMPERR_ALGO_FAILED, + SMESH_Comment("Wrong END transition of GridLine (") + << li._curInd[li._iVar1] << ", " << li._curInd[li._iVar2] + << ") along " << li._nameConst + << ": " << trName[ intPnts.rbegin()->_transition ]); + } + } + } +#endif + } + + //============================================================================= + /* + * Intersects TopoDS_Face with all GridLine's + */ + void FaceGridIntersector::Intersect() + { + FaceLineIntersector intersector; + intersector._surfaceInt = GetCurveFaceIntersector(); + intersector._tol = _grid->_tol; + intersector._transOut = _face.Orientation() == TopAbs_REVERSED ? Trans_IN : Trans_OUT; + intersector._transIn = _face.Orientation() == TopAbs_REVERSED ? Trans_OUT : Trans_IN; + + typedef void (FaceLineIntersector::* PIntFun )(const GridLine& gridLine); + PIntFun interFunction; + + bool isDirect = true; + BRepAdaptor_Surface surf( _face ); + switch ( surf.GetType() ) { + case GeomAbs_Plane: + intersector._plane = surf.Plane(); + interFunction = &FaceLineIntersector::IntersectWithPlane; + isDirect = intersector._plane.Direct(); + break; + case GeomAbs_Cylinder: + intersector._cylinder = surf.Cylinder(); + interFunction = &FaceLineIntersector::IntersectWithCylinder; + isDirect = intersector._cylinder.Direct(); + break; + case GeomAbs_Cone: + intersector._cone = surf.Cone(); + interFunction = &FaceLineIntersector::IntersectWithCone; + //isDirect = intersector._cone.Direct(); + break; + case GeomAbs_Sphere: + intersector._sphere = surf.Sphere(); + interFunction = &FaceLineIntersector::IntersectWithSphere; + isDirect = intersector._sphere.Direct(); + break; + case GeomAbs_Torus: + intersector._torus = surf.Torus(); + interFunction = &FaceLineIntersector::IntersectWithTorus; + //isDirect = intersector._torus.Direct(); + break; + default: + interFunction = &FaceLineIntersector::IntersectWithSurface; + } + if ( !isDirect ) + std::swap( intersector._transOut, intersector._transIn ); + + _intersections.clear(); + for ( int iDir = 0; iDir < 3; ++iDir ) // loop on 3 line directions + { + if ( surf.GetType() == GeomAbs_Plane ) + { + // check if all lines in this direction are parallel to a plane + if ( intersector._plane.Axis().IsNormal( _grid->_lines[iDir][0]._line.Position(), + Precision::Angular())) + continue; + // find out a transition, that is the same for all lines of a direction + gp_Dir plnNorm = intersector._plane.Axis().Direction(); + gp_Dir lineDir = _grid->_lines[iDir][0]._line.Direction(); + intersector._transition = + ( plnNorm * lineDir < 0 ) ? intersector._transIn : intersector._transOut; + } + if ( surf.GetType() == GeomAbs_Cylinder ) + { + // check if all lines in this direction are parallel to a cylinder + if ( intersector._cylinder.Axis().IsParallel( _grid->_lines[iDir][0]._line.Position(), + Precision::Angular())) + continue; + } + + // intersect the grid lines with the face + for ( size_t iL = 0; iL < _grid->_lines[iDir].size(); ++iL ) + { + GridLine& gridLine = _grid->_lines[iDir][iL]; + if ( _bndBox.IsOut( gridLine._line )) continue; + + intersector._intPoints.clear(); + (intersector.*interFunction)( gridLine ); // <- intersection with gridLine + for ( size_t i = 0; i < intersector._intPoints.size(); ++i ) + _intersections.push_back( make_pair( &gridLine, intersector._intPoints[i] )); + } + } + } + //================================================================================ + /* + * Return true if (_u,_v) is on the face + */ + bool FaceLineIntersector::UVIsOnFace() const + { + TopAbs_State state = _surfaceInt->ClassifyUVPoint(gp_Pnt2d( _u,_v )); + return ( state == TopAbs_IN || state == TopAbs_ON ); + } + //================================================================================ + /* + * Store an intersection if it is IN or ON the face + */ + void FaceLineIntersector::addIntPoint(const bool toClassify) + { + if ( !toClassify || UVIsOnFace() ) + { + F_IntersectPoint p; + p._paramOnLine = _w; + p._transition = _transition; + _intPoints.push_back( p ); + } + } + //================================================================================ + /* + * Intersect a line with a plane + */ + void FaceLineIntersector::IntersectWithPlane(const GridLine& gridLine) + { + IntAna_IntConicQuad linPlane( gridLine._line, _plane, Precision::Angular()); + _w = linPlane.ParamOnConic(1); + if ( isParamOnLineOK( gridLine._length )) + { + ElSLib::Parameters(_plane, linPlane.Point(1) ,_u,_v); + addIntPoint(); + } + } + //================================================================================ + /* + * Intersect a line with a cylinder + */ + void FaceLineIntersector::IntersectWithCylinder(const GridLine& gridLine) + { + IntAna_IntConicQuad linCylinder( gridLine._line, _cylinder ); + if ( linCylinder.IsDone() && linCylinder.NbPoints() > 0 ) + { + _w = linCylinder.ParamOnConic(1); + if ( linCylinder.NbPoints() == 1 ) + _transition = Trans_TANGENT; + else + _transition = _w < linCylinder.ParamOnConic(2) ? _transIn : _transOut; + if ( isParamOnLineOK( gridLine._length )) + { + ElSLib::Parameters(_cylinder, linCylinder.Point(1) ,_u,_v); + addIntPoint(); + } + if ( linCylinder.NbPoints() > 1 ) + { + _w = linCylinder.ParamOnConic(2); + if ( isParamOnLineOK( gridLine._length )) + { + ElSLib::Parameters(_cylinder, linCylinder.Point(2) ,_u,_v); + _transition = ( _transition == Trans_OUT ) ? Trans_IN : Trans_OUT; + addIntPoint(); + } + } + } + } + //================================================================================ + /* + * Intersect a line with a cone + */ + void FaceLineIntersector::IntersectWithCone (const GridLine& gridLine) + { + IntAna_IntConicQuad linCone(gridLine._line,_cone); + if ( !linCone.IsDone() ) return; + gp_Pnt P; + gp_Vec du, dv, norm; + for ( int i = 1; i <= linCone.NbPoints(); ++i ) + { + _w = linCone.ParamOnConic( i ); + if ( !isParamOnLineOK( gridLine._length )) continue; + ElSLib::Parameters(_cone, linCone.Point(i) ,_u,_v); + if ( UVIsOnFace() ) + { + ElSLib::D1( _u, _v, _cone, P, du, dv ); + norm = du ^ dv; + double normSize2 = norm.SquareMagnitude(); + if ( normSize2 > Precision::Angular() * Precision::Angular() ) + { + double cos = norm.XYZ() * gridLine._line.Direction().XYZ(); + cos /= sqrt( normSize2 ); + if ( cos < -Precision::Angular() ) + _transition = _transIn; + else if ( cos > Precision::Angular() ) + _transition = _transOut; + else + _transition = Trans_TANGENT; + } + else + { + _transition = Trans_APEX; + } + addIntPoint( /*toClassify=*/false); + } + } + } + //================================================================================ + /* + * Intersect a line with a sphere + */ + void FaceLineIntersector::IntersectWithSphere (const GridLine& gridLine) + { + IntAna_IntConicQuad linSphere(gridLine._line,_sphere); + if ( linSphere.IsDone() && linSphere.NbPoints() > 0 ) + { + _w = linSphere.ParamOnConic(1); + if ( linSphere.NbPoints() == 1 ) + _transition = Trans_TANGENT; + else + _transition = _w < linSphere.ParamOnConic(2) ? _transIn : _transOut; + if ( isParamOnLineOK( gridLine._length )) + { + ElSLib::Parameters(_sphere, linSphere.Point(1) ,_u,_v); + addIntPoint(); + } + if ( linSphere.NbPoints() > 1 ) + { + _w = linSphere.ParamOnConic(2); + if ( isParamOnLineOK( gridLine._length )) + { + ElSLib::Parameters(_sphere, linSphere.Point(2) ,_u,_v); + _transition = ( _transition == Trans_OUT ) ? Trans_IN : Trans_OUT; + addIntPoint(); + } + } + } + } + //================================================================================ + /* + * Intersect a line with a torus + */ + void FaceLineIntersector::IntersectWithTorus (const GridLine& gridLine) + { + IntAna_IntLinTorus linTorus(gridLine._line,_torus); + if ( !linTorus.IsDone()) return; + gp_Pnt P; + gp_Vec du, dv, norm; + for ( int i = 1; i <= linTorus.NbPoints(); ++i ) + { + _w = linTorus.ParamOnLine( i ); + if ( !isParamOnLineOK( gridLine._length )) continue; + linTorus.ParamOnTorus( i, _u,_v ); + if ( UVIsOnFace() ) + { + ElSLib::D1( _u, _v, _torus, P, du, dv ); + norm = du ^ dv; + double normSize = norm.Magnitude(); + double cos = norm.XYZ() * gridLine._line.Direction().XYZ(); + cos /= normSize; + if ( cos < -Precision::Angular() ) + _transition = _transIn; + else if ( cos > Precision::Angular() ) + _transition = _transOut; + else + _transition = Trans_TANGENT; + addIntPoint( /*toClassify=*/false); + } + } + } + //================================================================================ + /* + * Intersect a line with a non-analytical surface + */ + void FaceLineIntersector::IntersectWithSurface (const GridLine& gridLine) + { + _surfaceInt->Perform( gridLine._line, 0.0, gridLine._length ); + if ( !_surfaceInt->IsDone() ) return; + for ( int i = 1; i <= _surfaceInt->NbPnt(); ++i ) + { + _transition = Transition( _surfaceInt->Transition( i ) ); + _w = _surfaceInt->WParameter( i ); + addIntPoint(/*toClassify=*/false); + } + } + //================================================================================ + /* + * check if its face can be safely intersected in a thread + */ + bool FaceGridIntersector::IsThreadSafe(set< const Standard_Transient* >& noSafeTShapes) const + { + bool isSafe = true; + + // check surface + TopLoc_Location loc; + Handle(Geom_Surface) surf = BRep_Tool::Surface( _face, loc ); + Handle(Geom_RectangularTrimmedSurface) ts = + Handle(Geom_RectangularTrimmedSurface)::DownCast( surf ); + while( !ts.IsNull() ) { + surf = ts->BasisSurface(); + ts = Handle(Geom_RectangularTrimmedSurface)::DownCast(surf); + } + if ( surf->IsKind( STANDARD_TYPE(Geom_BSplineSurface )) || + surf->IsKind( STANDARD_TYPE(Geom_BezierSurface ))) + // if ( !noSafeTShapes.insert((const Standard_Transient*) _face.TShape() ).second ) + isSafe = false; + + double f, l; + TopExp_Explorer exp( _face, TopAbs_EDGE ); + for ( ; exp.More(); exp.Next() ) + { + bool edgeIsSafe = true; + const TopoDS_Edge& e = TopoDS::Edge( exp.Current() ); + // check 3d curve + { + Handle(Geom_Curve) c = BRep_Tool::Curve( e, loc, f, l); + if ( !c.IsNull() ) + { + Handle(Geom_TrimmedCurve) tc = Handle(Geom_TrimmedCurve)::DownCast(c); + while( !tc.IsNull() ) { + c = tc->BasisCurve(); + tc = Handle(Geom_TrimmedCurve)::DownCast(c); + } + if ( c->IsKind( STANDARD_TYPE(Geom_BSplineCurve )) || + c->IsKind( STANDARD_TYPE(Geom_BezierCurve ))) + edgeIsSafe = false; + } + } + // check 2d curve + if ( edgeIsSafe ) + { + Handle(Geom2d_Curve) c2 = BRep_Tool::CurveOnSurface( e, surf, loc, f, l); + if ( !c2.IsNull() ) + { + Handle(Geom2d_TrimmedCurve) tc = Handle(Geom2d_TrimmedCurve)::DownCast(c2); + while( !tc.IsNull() ) { + c2 = tc->BasisCurve(); + tc = Handle(Geom2d_TrimmedCurve)::DownCast(c2); + } + if ( c2->IsKind( STANDARD_TYPE(Geom2d_BSplineCurve )) || + c2->IsKind( STANDARD_TYPE(Geom2d_BezierCurve ))) + edgeIsSafe = false; + } + } + if ( !edgeIsSafe ) // && !noSafeTShapes.insert((const Standard_Transient*) e.TShape() ).second ) + isSafe = false; + } + return isSafe; + } + //================================================================================ + /*! + * \brief Creates topology of the hexahedron + */ + Hexahedron::Hexahedron(const double sizeThreshold, Grid* grid) + : _grid( grid ), _sizeThreshold( sizeThreshold ), _nbFaceIntNodes(0) + { + _polygons.reserve(100); // to avoid reallocation; + + //set nodes shift within grid->_nodes from the node 000 + size_t dx = _grid->NodeIndexDX(); + size_t dy = _grid->NodeIndexDY(); + size_t dz = _grid->NodeIndexDZ(); + size_t i000 = 0; + size_t i100 = i000 + dx; + size_t i010 = i000 + dy; + size_t i110 = i010 + dx; + size_t i001 = i000 + dz; + size_t i101 = i100 + dz; + size_t i011 = i010 + dz; + size_t i111 = i110 + dz; + _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V000 )] = i000; + _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V100 )] = i100; + _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V010 )] = i010; + _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V110 )] = i110; + _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V001 )] = i001; + _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V101 )] = i101; + _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V011 )] = i011; + _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V111 )] = i111; + + vector< int > idVec; + // set nodes to links + for ( int linkID = SMESH_Block::ID_Ex00; linkID <= SMESH_Block::ID_E11z; ++linkID ) + { + SMESH_Block::GetEdgeVertexIDs( linkID, idVec ); + _Link& link = _hexLinks[ SMESH_Block::ShapeIndex( linkID )]; + link._nodes[0] = &_hexNodes[ SMESH_Block::ShapeIndex( idVec[0] )]; + link._nodes[1] = &_hexNodes[ SMESH_Block::ShapeIndex( idVec[1] )]; + } + + // set links to faces + int interlace[4] = { 0, 3, 1, 2 }; // to walk by links around a face: { u0, 1v, u1, 0v } + for ( int faceID = SMESH_Block::ID_Fxy0; faceID <= SMESH_Block::ID_F1yz; ++faceID ) + { + SMESH_Block::GetFaceEdgesIDs( faceID, idVec ); + _Face& quad = _hexQuads[ SMESH_Block::ShapeIndex( faceID )]; + bool revFace = ( faceID == SMESH_Block::ID_Fxy0 || + faceID == SMESH_Block::ID_Fx1z || + faceID == SMESH_Block::ID_F0yz ); + quad._links.resize(4); + vector<_OrientedLink>::iterator frwLinkIt = quad._links.begin(); + vector<_OrientedLink>::reverse_iterator revLinkIt = quad._links.rbegin(); + for ( int i = 0; i < 4; ++i ) + { + bool revLink = revFace; + if ( i > 1 ) // reverse links u1 and v0 + revLink = !revLink; + _OrientedLink& link = revFace ? *revLinkIt++ : *frwLinkIt++; + link = _OrientedLink( & _hexLinks[ SMESH_Block::ShapeIndex( idVec[interlace[i]] )], + revLink ); + } + } + } + //================================================================================ + /*! + * \brief Copy constructor + */ + Hexahedron::Hexahedron( const Hexahedron& other ) + :_grid( other._grid ), _sizeThreshold( other._sizeThreshold ), _nbFaceIntNodes(0) + { + _polygons.reserve(100); // to avoid reallocation; + + for ( int i = 0; i < 8; ++i ) + _nodeShift[i] = other._nodeShift[i]; + + for ( int i = 0; i < 12; ++i ) + { + const _Link& srcLink = other._hexLinks[ i ]; + _Link& tgtLink = this->_hexLinks[ i ]; + tgtLink._nodes[0] = _hexNodes + ( srcLink._nodes[0] - other._hexNodes ); + tgtLink._nodes[1] = _hexNodes + ( srcLink._nodes[1] - other._hexNodes ); + } + + for ( int i = 0; i < 6; ++i ) + { + const _Face& srcQuad = other._hexQuads[ i ]; + _Face& tgtQuad = this->_hexQuads[ i ]; + tgtQuad._links.resize(4); + for ( int j = 0; j < 4; ++j ) + { + const _OrientedLink& srcLink = srcQuad._links[ j ]; + _OrientedLink& tgtLink = tgtQuad._links[ j ]; + tgtLink._reverse = srcLink._reverse; + tgtLink._link = _hexLinks + ( srcLink._link - other._hexLinks ); + } + } + } + + //================================================================================ + /*! + * \brief Initializes its data by given grid cell + */ + void Hexahedron::init( size_t i, size_t j, size_t k ) + { + _i = i; _j = j; _k = k; + // set nodes of grid to nodes of the hexahedron and + // count nodes at hexahedron corners located IN and ON geometry + _nbCornerNodes = _nbBndNodes = 0; + _origNodeInd = _grid->NodeIndex( i,j,k ); + for ( int iN = 0; iN < 8; ++iN ) + { + _hexNodes[iN]._node = _grid->_nodes [ _origNodeInd + _nodeShift[iN] ]; + _hexNodes[iN]._intPoint = _grid->_gridIntP[ _origNodeInd + _nodeShift[iN] ]; + _nbCornerNodes += bool( _hexNodes[iN]._node ); + _nbBndNodes += bool( _hexNodes[iN]._intPoint ); + } + _sideLength[0] = _grid->_coords[0][i+1] - _grid->_coords[0][i]; + _sideLength[1] = _grid->_coords[1][j+1] - _grid->_coords[1][j]; + _sideLength[2] = _grid->_coords[2][k+1] - _grid->_coords[2][k]; + + _intNodes.clear(); + _vIntNodes.clear(); + + if ( _nbFaceIntNodes + _eIntPoints.size() > 0 && + _nbFaceIntNodes + _nbCornerNodes + _eIntPoints.size() > 3) + { + _intNodes.reserve( 3 * _nbBndNodes + _nbFaceIntNodes + _eIntPoints.size() ); + + // this method can be called in parallel, so use own helper + SMESH_MesherHelper helper( *_grid->_helper->GetMesh() ); + + // create sub-links (_splits) by splitting links with _fIntPoints + _Link split; + for ( int iLink = 0; iLink < 12; ++iLink ) + { + _Link& link = _hexLinks[ iLink ]; + link._fIntNodes.resize( link._fIntPoints.size() ); + for ( size_t i = 0; i < link._fIntPoints.size(); ++i ) + { + _intNodes.push_back( _Node( 0, link._fIntPoints[i] )); + link._fIntNodes[ i ] = & _intNodes.back(); + } + + link._splits.clear(); + split._nodes[ 0 ] = link._nodes[0]; + bool isOut = ( ! link._nodes[0]->Node() ); + bool checkTransition; + for ( size_t i = 0; i < link._fIntNodes.size(); ++i ) + { + const bool isGridNode = ( ! link._fIntNodes[i]->Node() ); + if ( !isGridNode ) // intersection non-coincident with a grid node + { + if ( split._nodes[ 0 ]->Node() && !isOut ) + { + split._nodes[ 1 ] = link._fIntNodes[i]; + link._splits.push_back( split ); + } + split._nodes[ 0 ] = link._fIntNodes[i]; + checkTransition = true; + } + else // FACE intersection coincident with a grid node (at link ends) + { + checkTransition = ( i == 0 && link._nodes[0]->Node() ); + } + if ( checkTransition ) + { + if ( link._fIntPoints[i]->_faceIDs.size() > 1 || _eIntPoints.size() > 0 ) + isOut = isOutPoint( link, i, helper ); + else + switch ( link._fIntPoints[i]->_transition ) { + case Trans_OUT: isOut = true; break; + case Trans_IN : isOut = false; break; + default: + isOut = isOutPoint( link, i, helper ); + } + } + } + if ( link._nodes[ 1 ]->Node() && split._nodes[ 0 ]->Node() && !isOut ) + { + split._nodes[ 1 ] = link._nodes[1]; + link._splits.push_back( split ); + } + } + + // Create _Node's at intersections with EDGEs. + + const double tol2 = _grid->_tol * _grid->_tol; + int facets[3], nbFacets, subEntity; + + for ( size_t iP = 0; iP < _eIntPoints.size(); ++iP ) + { + nbFacets = getEntity( _eIntPoints[iP], facets, subEntity ); + _Node* equalNode = 0; + switch( nbFacets ) { + case 1: // in a _Face + { + _Face& quad = _hexQuads[ facets[0] - SMESH_Block::ID_FirstF ]; + equalNode = findEqualNode( quad._eIntNodes, _eIntPoints[ iP ], tol2 ); + if ( equalNode ) { + equalNode->Add( _eIntPoints[ iP ] ); + } + else { + _intNodes.push_back( _Node( 0, _eIntPoints[ iP ])); + quad._eIntNodes.push_back( & _intNodes.back() ); + } + break; + } + case 2: // on a _Link + { + _Link& link = _hexLinks[ subEntity - SMESH_Block::ID_FirstE ]; + if ( link._splits.size() > 0 ) + { + equalNode = findEqualNode( link._fIntNodes, _eIntPoints[ iP ], tol2 ); + if ( equalNode ) + equalNode->Add( _eIntPoints[ iP ] ); + } + else + { + _intNodes.push_back( _Node( 0, _eIntPoints[ iP ])); + for ( int iF = 0; iF < 2; ++iF ) + { + _Face& quad = _hexQuads[ facets[iF] - SMESH_Block::ID_FirstF ]; + equalNode = findEqualNode( quad._eIntNodes, _eIntPoints[ iP ], tol2 ); + if ( equalNode ) { + equalNode->Add( _eIntPoints[ iP ] ); + } + else { + quad._eIntNodes.push_back( & _intNodes.back() ); + } + } + } + break; + } + case 3: // at a corner + { + _Node& node = _hexNodes[ subEntity - SMESH_Block::ID_FirstV ]; + if ( node.Node() > 0 ) + { + if ( node._intPoint ) + node._intPoint->Add( _eIntPoints[ iP ]->_faceIDs, _eIntPoints[ iP ]->_node ); + } + else + { + _intNodes.push_back( _Node( 0, _eIntPoints[ iP ])); + for ( int iF = 0; iF < 3; ++iF ) + { + _Face& quad = _hexQuads[ facets[iF] - SMESH_Block::ID_FirstF ]; + equalNode = findEqualNode( quad._eIntNodes, _eIntPoints[ iP ], tol2 ); + if ( equalNode ) { + equalNode->Add( _eIntPoints[ iP ] ); + } + else { + quad._eIntNodes.push_back( & _intNodes.back() ); + } + } + } + break; + } + } // switch( nbFacets ) + + if ( nbFacets == 0 || + _grid->_shapes( _eIntPoints[ iP ]->_shapeID ).ShapeType() == TopAbs_VERTEX ) + { + equalNode = findEqualNode( _vIntNodes, _eIntPoints[ iP ], tol2 ); + if ( equalNode ) { + equalNode->Add( _eIntPoints[ iP ] ); + } + else if ( nbFacets == 0 ) { + if ( _intNodes.empty() || _intNodes.back().EdgeIntPnt() != _eIntPoints[ iP ]) + _intNodes.push_back( _Node( 0, _eIntPoints[ iP ])); + _vIntNodes.push_back( & _intNodes.back() ); + } + } + } // loop on _eIntPoints + } + else if ( 3 < _nbCornerNodes && _nbCornerNodes < 8 ) // _nbFaceIntNodes == 0 + { + _Link split; + // create sub-links (_splits) of whole links + for ( int iLink = 0; iLink < 12; ++iLink ) + { + _Link& link = _hexLinks[ iLink ]; + link._splits.clear(); + if ( link._nodes[ 0 ]->Node() && link._nodes[ 1 ]->Node() ) + { + split._nodes[ 0 ] = link._nodes[0]; + split._nodes[ 1 ] = link._nodes[1]; + link._splits.push_back( split ); + } + } + } + + } + //================================================================================ + /*! + * \brief Initializes its data by given grid cell (countered from zero) + */ + void Hexahedron::init( size_t iCell ) + { + size_t iNbCell = _grid->_coords[0].size() - 1; + size_t jNbCell = _grid->_coords[1].size() - 1; + _i = iCell % iNbCell; + _j = ( iCell % ( iNbCell * jNbCell )) / iNbCell; + _k = iCell / iNbCell / jNbCell; + init( _i, _j, _k ); + } + + //================================================================================ + /*! + * \brief Compute mesh volumes resulted from intersection of the Hexahedron + */ + void Hexahedron::ComputeElements() + { + Init(); + + int nbIntersections = _nbFaceIntNodes + _eIntPoints.size(); + if ( _nbCornerNodes + nbIntersections < 4 ) + return; + + if ( _nbBndNodes == _nbCornerNodes && nbIntersections == 0 && isInHole() ) + return; + + _polygons.clear(); + _polygons.reserve( 20 ); + + // Create polygons from quadrangles + // -------------------------------- + + vector< _OrientedLink > splits; + vector<_Node*> chainNodes; + _Face* coplanarPolyg; + + bool hasEdgeIntersections = !_eIntPoints.empty(); + + for ( int iF = 0; iF < 6; ++iF ) // loop on 6 sides of a hexahedron + { + _Face& quad = _hexQuads[ iF ] ; + + _polygons.resize( _polygons.size() + 1 ); + _Face* polygon = &_polygons.back(); + polygon->_polyLinks.reserve( 20 ); + + splits.clear(); + for ( int iE = 0; iE < 4; ++iE ) // loop on 4 sides of a quadrangle + for ( int iS = 0; iS < quad._links[ iE ].NbResultLinks(); ++iS ) + splits.push_back( quad._links[ iE ].ResultLink( iS )); + + // add splits of links to a polygon and add _polyLinks to make + // polygon's boundary closed + + int nbSplits = splits.size(); + if (( nbSplits == 1 ) && + ( quad._eIntNodes.empty() || + splits[0].FirstNode()->IsLinked( splits[0].LastNode()->_intPoint ))) + //( quad._eIntNodes.empty() || _nbCornerNodes + nbIntersections > 6 )) + nbSplits = 0; + +#ifdef _DEBUG_ + for ( size_t iP = 0; iP < quad._eIntNodes.size(); ++iP ) + if ( quad._eIntNodes[ iP ]->IsUsedInFace( polygon )) + quad._eIntNodes[ iP ]->_usedInFace = 0; +#endif + int nbUsedEdgeNodes = 0; + _Face* prevPolyg = 0; // polygon previously created from this quad + + while ( nbSplits > 0 ) + { + size_t iS = 0; + while ( !splits[ iS ] ) + ++iS; + + if ( !polygon->_links.empty() ) + { + _polygons.resize( _polygons.size() + 1 ); + polygon = &_polygons.back(); + polygon->_polyLinks.reserve( 20 ); + } + polygon->_links.push_back( splits[ iS ] ); + splits[ iS++ ]._link = 0; + --nbSplits; + + _Node* nFirst = polygon->_links.back().FirstNode(); + _Node *n1,*n2 = polygon->_links.back().LastNode(); + for ( ; nFirst != n2 && iS < splits.size(); ++iS ) + { + _OrientedLink& split = splits[ iS ]; + if ( !split ) continue; + + n1 = split.FirstNode(); + if ( n1 == n2 && + n1->_intPoint && + n1->_intPoint->_faceIDs.size() > 1 ) + { + // n1 is at intersection with EDGE + if ( findChainOnEdge( splits, polygon->_links.back(), split, iS, quad, chainNodes )) + { + for ( size_t i = 1; i < chainNodes.size(); ++i ) + polygon->AddPolyLink( chainNodes[i-1], chainNodes[i], prevPolyg ); + prevPolyg = polygon; + n2 = chainNodes.back(); + continue; + } + } + else if ( n1 != n2 ) + { + // try to connect to intersections with EDGEs + if ( quad._eIntNodes.size() > nbUsedEdgeNodes && + findChain( n2, n1, quad, chainNodes )) + { + for ( size_t i = 1; i < chainNodes.size(); ++i ) + { + polygon->AddPolyLink( chainNodes[i-1], chainNodes[i] ); + nbUsedEdgeNodes += ( chainNodes[i]->IsUsedInFace( polygon )); + } + if ( chainNodes.back() != n1 ) + { + n2 = chainNodes.back(); + --iS; + continue; + } + } + // try to connect to a split ending on the same FACE + else + { + _OrientedLink foundSplit; + for ( int i = iS; i < splits.size() && !foundSplit; ++i ) + if (( foundSplit = splits[ i ]) && + ( n2->IsLinked( foundSplit.FirstNode()->_intPoint ))) + { + iS = i - 1; + } + else + { + foundSplit._link = 0; + } + if ( foundSplit ) + { + if ( n2 != foundSplit.FirstNode() ) + { + polygon->AddPolyLink( n2, foundSplit.FirstNode() ); + n2 = foundSplit.FirstNode(); + } + continue; + } + else + { + if ( n2->IsLinked( nFirst->_intPoint )) + break; + polygon->AddPolyLink( n2, n1, prevPolyg ); + } + } + } // if ( n1 != n2 ) + + polygon->_links.push_back( split ); + split._link = 0; + --nbSplits; + n2 = polygon->_links.back().LastNode(); + + } // loop on splits + + if ( nFirst != n2 ) // close a polygon + { + if ( !findChain( n2, nFirst, quad, chainNodes )) + { + if ( !closePolygon( polygon, chainNodes )) + if ( !isImplementEdges() ) + chainNodes.push_back( nFirst ); + } + for ( size_t i = 1; i < chainNodes.size(); ++i ) + { + polygon->AddPolyLink( chainNodes[i-1], chainNodes[i], prevPolyg ); + nbUsedEdgeNodes += bool( chainNodes[i]->IsUsedInFace( polygon )); + } + } + + if ( polygon->_links.size() < 3 && nbSplits > 0 ) + { + polygon->_polyLinks.clear(); + polygon->_links.clear(); + } + } // while ( nbSplits > 0 ) + + if ( polygon->_links.size() < 3 ) + { + _polygons.pop_back(); + } + } // loop on 6 hexahedron sides + + // Create polygons closing holes in a polyhedron + // ---------------------------------------------- + + // clear _usedInFace + for ( size_t iN = 0; iN < _intNodes.size(); ++iN ) + _intNodes[ iN ]._usedInFace = 0; + + // add polygons to their links and mark used nodes + for ( size_t iP = 0; iP < _polygons.size(); ++iP ) + { + _Face& polygon = _polygons[ iP ]; + for ( size_t iL = 0; iL < polygon._links.size(); ++iL ) + { + polygon._links[ iL ].AddFace( &polygon ); + polygon._links[ iL ].FirstNode()->_usedInFace = &polygon; + } + } + // find free links + vector< _OrientedLink* > freeLinks; + freeLinks.reserve(20); + for ( size_t iP = 0; iP < _polygons.size(); ++iP ) + { + _Face& polygon = _polygons[ iP ]; + for ( size_t iL = 0; iL < polygon._links.size(); ++iL ) + if ( polygon._links[ iL ].NbFaces() < 2 ) + freeLinks.push_back( & polygon._links[ iL ]); + } + int nbFreeLinks = freeLinks.size(); + if ( nbFreeLinks == 1 ) return; + + // put not used intersection nodes to _vIntNodes + int nbVertexNodes = 0; // nb not used vertex nodes + { + for ( size_t iN = 0; iN < _vIntNodes.size(); ++iN ) + nbVertexNodes += ( !_vIntNodes[ iN ]->IsUsedInFace() ); + + const double tol = 1e-3 * Min( Min( _sideLength[0], _sideLength[1] ), _sideLength[0] ); + for ( size_t iN = _nbFaceIntNodes; iN < _intNodes.size(); ++iN ) + { + if ( _intNodes[ iN ].IsUsedInFace() ) continue; + if ( dynamic_cast< const F_IntersectPoint* >( _intNodes[ iN ]._intPoint )) continue; + _Node* equalNode = + findEqualNode( _vIntNodes, _intNodes[ iN ].EdgeIntPnt(), tol*tol ); + if ( !equalNode ) + { + _vIntNodes.push_back( &_intNodes[ iN ]); + ++nbVertexNodes; + } + } + } + + set usedFaceIDs; + vector< TGeomID > faces; + TGeomID curFace = 0; + const size_t nbQuadPolygons = _polygons.size(); + E_IntersectPoint ipTmp; + + // create polygons by making closed chains of free links + size_t iPolygon = _polygons.size(); + while ( nbFreeLinks > 0 ) + { + if ( iPolygon == _polygons.size() ) + { + _polygons.resize( _polygons.size() + 1 ); + _polygons[ iPolygon ]._polyLinks.reserve( 20 ); + _polygons[ iPolygon ]._links.reserve( 20 ); + } + _Face& polygon = _polygons[ iPolygon ]; + + _OrientedLink* curLink = 0; + _Node* curNode; + if (( !hasEdgeIntersections ) || + ( nbFreeLinks < 4 && nbVertexNodes == 0 )) + { + // get a remaining link to start from + for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL ) + if (( curLink = freeLinks[ iL ] )) + freeLinks[ iL ] = 0; + polygon._links.push_back( *curLink ); + --nbFreeLinks; + do + { + // find all links connected to curLink + curNode = curLink->FirstNode(); + curLink = 0; + for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL ) + if ( freeLinks[ iL ] && freeLinks[ iL ]->LastNode() == curNode ) + { + curLink = freeLinks[ iL ]; + freeLinks[ iL ] = 0; + --nbFreeLinks; + polygon._links.push_back( *curLink ); + } + } while ( curLink ); + } + else // there are intersections with EDGEs + { + // get a remaining link to start from, one lying on minimal nb of FACEs + { + typedef pair< TGeomID, int > TFaceOfLink; + TFaceOfLink faceOfLink( -1, -1 ); + TFaceOfLink facesOfLink[3] = { faceOfLink, faceOfLink, faceOfLink }; + for ( size_t iL = 0; iL < freeLinks.size(); ++iL ) + if ( freeLinks[ iL ] ) + { + faces = freeLinks[ iL ]->GetNotUsedFace( usedFaceIDs ); + if ( faces.size() == 1 ) + { + faceOfLink = TFaceOfLink( faces[0], iL ); + if ( !freeLinks[ iL ]->HasEdgeNodes() ) + break; + facesOfLink[0] = faceOfLink; + } + else if ( facesOfLink[0].first < 0 ) + { + faceOfLink = TFaceOfLink(( faces.empty() ? -1 : faces[0]), iL ); + facesOfLink[ 1 + faces.empty() ] = faceOfLink; + } + } + for ( int i = 0; faceOfLink.first < 0 && i < 3; ++i ) + faceOfLink = facesOfLink[i]; + + if ( faceOfLink.first < 0 ) // all faces used + { + for ( size_t iL = 0; iL < freeLinks.size() && faceOfLink.first < 1; ++iL ) + if (( curLink = freeLinks[ iL ])) + { + faceOfLink.first = + curLink->FirstNode()->IsLinked( curLink->LastNode()->_intPoint ); + faceOfLink.second = iL; + } + usedFaceIDs.clear(); + } + curFace = faceOfLink.first; + curLink = freeLinks[ faceOfLink.second ]; + freeLinks[ faceOfLink.second ] = 0; + } + usedFaceIDs.insert( curFace ); + polygon._links.push_back( *curLink ); + --nbFreeLinks; + + // find all links lying on a curFace + do + { + // go forward from curLink + curNode = curLink->LastNode(); + curLink = 0; + for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL ) + if ( freeLinks[ iL ] && + freeLinks[ iL ]->FirstNode() == curNode && + freeLinks[ iL ]->LastNode()->IsOnFace( curFace )) + { + curLink = freeLinks[ iL ]; + freeLinks[ iL ] = 0; + polygon._links.push_back( *curLink ); + --nbFreeLinks; + } + } while ( curLink ); + + std::reverse( polygon._links.begin(), polygon._links.end() ); + + curLink = & polygon._links.back(); + do + { + // go backward from curLink + curNode = curLink->FirstNode(); + curLink = 0; + for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL ) + if ( freeLinks[ iL ] && + freeLinks[ iL ]->LastNode() == curNode && + freeLinks[ iL ]->FirstNode()->IsOnFace( curFace )) + { + curLink = freeLinks[ iL ]; + freeLinks[ iL ] = 0; + polygon._links.push_back( *curLink ); + --nbFreeLinks; + } + } while ( curLink ); + + curNode = polygon._links.back().FirstNode(); + + if ( polygon._links[0].LastNode() != curNode ) + { + if ( nbVertexNodes > 0 ) + { + // add links with _vIntNodes if not already used + chainNodes.clear(); + for ( size_t iN = 0; iN < _vIntNodes.size(); ++iN ) + if ( !_vIntNodes[ iN ]->IsUsedInFace() && + _vIntNodes[ iN ]->IsOnFace( curFace )) + { + _vIntNodes[ iN ]->_usedInFace = &polygon; + chainNodes.push_back( _vIntNodes[ iN ] ); + } + if ( chainNodes.size() > 1 ) + { + sortVertexNodes( chainNodes, curNode, curFace ); + } + for ( int i = 0; i < chainNodes.size(); ++i ) + { + polygon.AddPolyLink( chainNodes[ i ], curNode ); + curNode = chainNodes[ i ]; + freeLinks.push_back( &polygon._links.back() ); + ++nbFreeLinks; + } + nbVertexNodes -= chainNodes.size(); + } + // if ( polygon._links.size() > 1 ) + { + polygon.AddPolyLink( polygon._links[0].LastNode(), curNode ); + freeLinks.push_back( &polygon._links.back() ); + ++nbFreeLinks; + } + } + } // if there are intersections with EDGEs + + if ( polygon._links.size() < 2 || + polygon._links[0].LastNode() != polygon._links.back().FirstNode() ) + return; // closed polygon not found -> invalid polyhedron + + if ( polygon._links.size() == 2 ) + { + if ( freeLinks.back() == &polygon._links.back() ) + { + freeLinks.pop_back(); + --nbFreeLinks; + } + if ( polygon._links.front().NbFaces() > 0 ) + polygon._links.back().AddFace( polygon._links.front()._link->_faces[0] ); + if ( polygon._links.back().NbFaces() > 0 ) + polygon._links.front().AddFace( polygon._links.back()._link->_faces[0] ); + + if ( iPolygon == _polygons.size()-1 ) + _polygons.pop_back(); + } + else // polygon._links.size() >= 2 + { + // add polygon to its links + for ( size_t iL = 0; iL < polygon._links.size(); ++iL ) + { + polygon._links[ iL ].AddFace( &polygon ); + polygon._links[ iL ].Reverse(); + } + if ( /*hasEdgeIntersections &&*/ iPolygon == _polygons.size() - 1 ) + { + // check that a polygon does not lie on a hexa side + coplanarPolyg = 0; + for ( size_t iL = 0; iL < polygon._links.size() && !coplanarPolyg; ++iL ) + { + if ( polygon._links[ iL ].NbFaces() < 2 ) + continue; // it's a just added free link + // look for a polygon made on a hexa side and sharing + // two or more haxa links + size_t iL2; + coplanarPolyg = polygon._links[ iL ]._link->_faces[0]; + for ( iL2 = iL + 1; iL2 < polygon._links.size(); ++iL2 ) + if ( polygon._links[ iL2 ]._link->_faces[0] == coplanarPolyg && + !coplanarPolyg->IsPolyLink( polygon._links[ iL ]) && + !coplanarPolyg->IsPolyLink( polygon._links[ iL2 ]) && + coplanarPolyg < & _polygons[ nbQuadPolygons ]) + break; + if ( iL2 == polygon._links.size() ) + coplanarPolyg = 0; + } + if ( coplanarPolyg ) // coplanar polygon found + { + freeLinks.resize( freeLinks.size() - polygon._polyLinks.size() ); + nbFreeLinks -= polygon._polyLinks.size(); + + // an E_IntersectPoint used to mark nodes of coplanarPolyg + // as lying on curFace while they are not at intersection with geometry + ipTmp._faceIDs.resize(1); + ipTmp._faceIDs[0] = curFace; + + // fill freeLinks with links not shared by coplanarPolyg and polygon + for ( size_t iL = 0; iL < polygon._links.size(); ++iL ) + if ( polygon._links[ iL ]._link->_faces[1] && + polygon._links[ iL ]._link->_faces[0] != coplanarPolyg ) + { + _Face* p = polygon._links[ iL ]._link->_faces[0]; + for ( size_t iL2 = 0; iL2 < p->_links.size(); ++iL2 ) + if ( p->_links[ iL2 ]._link == polygon._links[ iL ]._link ) + { + freeLinks.push_back( & p->_links[ iL2 ] ); + ++nbFreeLinks; + freeLinks.back()->RemoveFace( &polygon ); + break; + } + } + for ( size_t iL = 0; iL < coplanarPolyg->_links.size(); ++iL ) + if ( coplanarPolyg->_links[ iL ]._link->_faces[1] && + coplanarPolyg->_links[ iL ]._link->_faces[1] != &polygon ) + { + _Face* p = coplanarPolyg->_links[ iL ]._link->_faces[0]; + if ( p == coplanarPolyg ) + p = coplanarPolyg->_links[ iL ]._link->_faces[1]; + for ( size_t iL2 = 0; iL2 < p->_links.size(); ++iL2 ) + if ( p->_links[ iL2 ]._link == coplanarPolyg->_links[ iL ]._link ) + { + // set links of coplanarPolyg in place of used freeLinks + // to re-create coplanarPolyg next + size_t iL3 = 0; + for ( ; iL3 < freeLinks.size() && freeLinks[ iL3 ]; ++iL3 ); + if ( iL3 < freeLinks.size() ) + freeLinks[ iL3 ] = ( & p->_links[ iL2 ] ); + else + freeLinks.push_back( & p->_links[ iL2 ] ); + ++nbFreeLinks; + freeLinks[ iL3 ]->RemoveFace( coplanarPolyg ); + // mark nodes of coplanarPolyg as lying on curFace + for ( int iN = 0; iN < 2; ++iN ) + { + _Node* n = freeLinks[ iL3 ]->_link->_nodes[ iN ]; + if ( n->_intPoint ) n->_intPoint->Add( ipTmp._faceIDs ); + else n->_intPoint = &ipTmp; + } + break; + } + } + // set coplanarPolyg to be re-created next + for ( size_t iP = 0; iP < _polygons.size(); ++iP ) + if ( coplanarPolyg == & _polygons[ iP ] ) + { + iPolygon = iP; + _polygons[ iPolygon ]._links.clear(); + _polygons[ iPolygon ]._polyLinks.clear(); + break; + } + _polygons.pop_back(); + usedFaceIDs.erase( curFace ); + continue; + } // if ( coplanarPolyg ) + } // if ( hasEdgeIntersections ) - search for coplanarPolyg + + iPolygon = _polygons.size(); + + } // end of case ( polygon._links.size() > 2 ) + } // while ( nbFreeLinks > 0 ) + + if ( ! checkPolyhedronSize() ) + { + return; + } + + for ( size_t i = 0; i < 8; ++i ) + if ( _hexNodes[ i ]._intPoint == &ipTmp ) + _hexNodes[ i ]._intPoint = 0; + + // create a classic cell if possible + + int nbPolygons = 0; + for ( size_t iF = 0; iF < _polygons.size(); ++iF ) + nbPolygons += (_polygons[ iF ]._links.size() > 0 ); + + //const int nbNodes = _nbCornerNodes + nbIntersections; + int nbNodes = 0; + for ( size_t i = 0; i < 8; ++i ) + nbNodes += _hexNodes[ i ].IsUsedInFace(); + for ( size_t i = 0; i < _intNodes.size(); ++i ) + nbNodes += _intNodes[ i ].IsUsedInFace(); + + bool isClassicElem = false; + if ( nbNodes == 8 && nbPolygons == 6 ) isClassicElem = addHexa(); + else if ( nbNodes == 4 && nbPolygons == 4 ) isClassicElem = addTetra(); + else if ( nbNodes == 6 && nbPolygons == 5 ) isClassicElem = addPenta(); + else if ( nbNodes == 5 && nbPolygons == 5 ) isClassicElem = addPyra (); + if ( !isClassicElem ) + { + _volumeDefs._nodes.clear(); + _volumeDefs._quantities.clear(); + + for ( size_t iF = 0; iF < _polygons.size(); ++iF ) + { + const size_t nbLinks = _polygons[ iF ]._links.size(); + if ( nbLinks == 0 ) continue; + _volumeDefs._quantities.push_back( nbLinks ); + for ( size_t iL = 0; iL < nbLinks; ++iL ) + _volumeDefs._nodes.push_back( _polygons[ iF ]._links[ iL ].FirstNode() ); + } + } + } + //================================================================================ + /*! + * \brief Create elements in the mesh + */ + int Hexahedron::MakeElements(SMESH_MesherHelper& helper, + const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap) + { + SMESHDS_Mesh* mesh = helper.GetMeshDS(); + + size_t nbCells[3] = { _grid->_coords[0].size() - 1, + _grid->_coords[1].size() - 1, + _grid->_coords[2].size() - 1 }; + const size_t nbGridCells = nbCells[0] * nbCells[1] * nbCells[2]; + vector< Hexahedron* > allHexa( nbGridCells, 0 ); + int nbIntHex = 0; + + // set intersection nodes from GridLine's to links of allHexa + int i,j,k, iDirOther[3][2] = {{ 1,2 },{ 0,2 },{ 0,1 }}; + for ( int iDir = 0; iDir < 3; ++iDir ) + { + int dInd[4][3] = { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} }; + dInd[1][ iDirOther[iDir][0] ] = -1; + dInd[2][ iDirOther[iDir][1] ] = -1; + dInd[3][ iDirOther[iDir][0] ] = -1; dInd[3][ iDirOther[iDir][1] ] = -1; + // loop on GridLine's parallel to iDir + LineIndexer lineInd = _grid->GetLineIndexer( iDir ); + for ( ; lineInd.More(); ++lineInd ) + { + GridLine& line = _grid->_lines[ iDir ][ lineInd.LineIndex() ]; + multiset< F_IntersectPoint >::const_iterator ip = line._intPoints.begin(); + for ( ; ip != line._intPoints.end(); ++ip ) + { + // if ( !ip->_node ) continue; // intersection at a grid node + lineInd.SetIndexOnLine( ip->_indexOnLine ); + for ( int iL = 0; iL < 4; ++iL ) // loop on 4 cells sharing a link + { + i = int(lineInd.I()) + dInd[iL][0]; + j = int(lineInd.J()) + dInd[iL][1]; + k = int(lineInd.K()) + dInd[iL][2]; + if ( i < 0 || i >= nbCells[0] || + j < 0 || j >= nbCells[1] || + k < 0 || k >= nbCells[2] ) continue; + + const size_t hexIndex = _grid->CellIndex( i,j,k ); + Hexahedron *& hex = allHexa[ hexIndex ]; + if ( !hex) + { + hex = new Hexahedron( *this ); + hex->_i = i; + hex->_j = j; + hex->_k = k; + ++nbIntHex; + } + const int iLink = iL + iDir * 4; + hex->_hexLinks[iLink]._fIntPoints.push_back( &(*ip) ); + hex->_nbFaceIntNodes += bool( ip->_node ); + } + } + } + } + + // implement geom edges into the mesh + addEdges( helper, allHexa, edge2faceIDsMap ); + + // add not split hexadrons to the mesh + int nbAdded = 0; + vector< Hexahedron* > intHexa( nbIntHex, (Hexahedron*) NULL ); + for ( size_t i = 0; i < allHexa.size(); ++i ) + { + Hexahedron * & hex = allHexa[ i ]; + if ( hex ) + { + intHexa.push_back( hex ); + if ( hex->_nbFaceIntNodes > 0 || hex->_eIntPoints.size() > 0 ) + continue; // treat intersected hex later + this->init( hex->_i, hex->_j, hex->_k ); + } + else + { + this->init( i ); + } + if (( _nbCornerNodes == 8 ) && + ( _nbBndNodes < _nbCornerNodes || !isInHole() )) + { + // order of _hexNodes is defined by enum SMESH_Block::TShapeID + SMDS_MeshElement* el = + mesh->AddVolume( _hexNodes[0].Node(), _hexNodes[2].Node(), + _hexNodes[3].Node(), _hexNodes[1].Node(), + _hexNodes[4].Node(), _hexNodes[6].Node(), + _hexNodes[7].Node(), _hexNodes[5].Node() ); + mesh->SetMeshElementOnShape( el, helper.GetSubShapeID() ); + ++nbAdded; + if ( hex ) + intHexa.pop_back(); + } + else if ( _nbCornerNodes > 3 && !hex ) + { + // all intersection of hex with geometry are at grid nodes + hex = new Hexahedron( *this ); + hex->_i = _i; + hex->_j = _j; + hex->_k = _k; + intHexa.push_back( hex ); + } + } + + // add elements resulted from hexadron intersection +#ifdef WITH_TBB + tbb::parallel_for ( tbb::blocked_range( 0, intHexa.size() ), + ParallelHexahedron( intHexa ), + tbb::simple_partitioner()); // ComputeElements() is called here + for ( size_t i = 0; i < intHexa.size(); ++i ) + if ( Hexahedron * hex = intHexa[ i ] ) + nbAdded += hex->addElements( helper ); +#else + for ( size_t i = 0; i < intHexa.size(); ++i ) + if ( Hexahedron * hex = intHexa[ i ] ) + { + hex->ComputeElements(); + nbAdded += hex->addElements( helper ); + } +#endif + + for ( size_t i = 0; i < allHexa.size(); ++i ) + if ( allHexa[ i ] ) + delete allHexa[ i ]; + + return nbAdded; + } + + //================================================================================ + /*! + * \brief Implements geom edges into the mesh + */ + void Hexahedron::addEdges(SMESH_MesherHelper& helper, + vector< Hexahedron* >& hexes, + const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap) + { + if ( edge2faceIDsMap.empty() ) return; + + // Prepare planes for intersecting with EDGEs + GridPlanes pln[3]; + { + for ( int iDirZ = 0; iDirZ < 3; ++iDirZ ) // iDirZ gives normal direction to planes + { + GridPlanes& planes = pln[ iDirZ ]; + int iDirX = ( iDirZ + 1 ) % 3; + int iDirY = ( iDirZ + 2 ) % 3; + planes._zNorm = ( _grid->_axes[ iDirX ] ^ _grid->_axes[ iDirY ] ).Normalized(); + planes._zProjs.resize ( _grid->_coords[ iDirZ ].size() ); + planes._zProjs [0] = 0; + const double zFactor = _grid->_axes[ iDirZ ] * planes._zNorm; + const vector< double > & u = _grid->_coords[ iDirZ ]; + for ( int i = 1; i < planes._zProjs.size(); ++i ) + { + planes._zProjs [i] = zFactor * ( u[i] - u[0] ); + } + } + } + const double deflection = _grid->_minCellSize / 20.; + const double tol = _grid->_tol; + E_IntersectPoint ip; + + // Intersect EDGEs with the planes + map< TGeomID, vector< TGeomID > >::const_iterator e2fIt = edge2faceIDsMap.begin(); + for ( ; e2fIt != edge2faceIDsMap.end(); ++e2fIt ) + { + const TGeomID edgeID = e2fIt->first; + const TopoDS_Edge & E = TopoDS::Edge( _grid->_shapes( edgeID )); + BRepAdaptor_Curve curve( E ); + TopoDS_Vertex v1 = helper.IthVertex( 0, E, false ); + TopoDS_Vertex v2 = helper.IthVertex( 1, E, false ); + + ip._faceIDs = e2fIt->second; + ip._shapeID = edgeID; + + // discretize the EGDE + GCPnts_UniformDeflection discret( curve, deflection, true ); + if ( !discret.IsDone() || discret.NbPoints() < 2 ) + continue; + + // perform intersection + for ( int iDirZ = 0; iDirZ < 3; ++iDirZ ) + { + GridPlanes& planes = pln[ iDirZ ]; + int iDirX = ( iDirZ + 1 ) % 3; + int iDirY = ( iDirZ + 2 ) % 3; + double xLen = _grid->_coords[ iDirX ].back() - _grid->_coords[ iDirX ][0]; + double yLen = _grid->_coords[ iDirY ].back() - _grid->_coords[ iDirY ][0]; + double zLen = _grid->_coords[ iDirZ ].back() - _grid->_coords[ iDirZ ][0]; + int dIJK[3], d000[3] = { 0,0,0 }; + double o[3] = { _grid->_coords[0][0], + _grid->_coords[1][0], + _grid->_coords[2][0] }; + + // locate the 1st point of a segment within the grid + gp_XYZ p1 = discret.Value( 1 ).XYZ(); + double u1 = discret.Parameter( 1 ); + double zProj1 = planes._zNorm * ( p1 - _grid->_origin ); + + _grid->ComputeUVW( p1, ip._uvw ); + int iX1 = int(( ip._uvw[iDirX] - o[iDirX]) / xLen * (_grid->_coords[ iDirX ].size() - 1)); + int iY1 = int(( ip._uvw[iDirY] - o[iDirY]) / yLen * (_grid->_coords[ iDirY ].size() - 1)); + int iZ1 = int(( ip._uvw[iDirZ] - o[iDirZ]) / zLen * (_grid->_coords[ iDirZ ].size() - 1)); + locateValue( iX1, ip._uvw[iDirX], _grid->_coords[ iDirX ], dIJK[ iDirX ], tol ); + locateValue( iY1, ip._uvw[iDirY], _grid->_coords[ iDirY ], dIJK[ iDirY ], tol ); + locateValue( iZ1, ip._uvw[iDirZ], _grid->_coords[ iDirZ ], dIJK[ iDirZ ], tol ); + + int ijk[3]; // grid index where a segment intersect a plane + ijk[ iDirX ] = iX1; + ijk[ iDirY ] = iY1; + ijk[ iDirZ ] = iZ1; + + // add the 1st vertex point to a hexahedron + if ( iDirZ == 0 ) + { + ip._point = p1; + ip._shapeID = _grid->_shapes.Add( v1 ); + _grid->_edgeIntP.push_back( ip ); + if ( !addIntersection( _grid->_edgeIntP.back(), hexes, ijk, d000 )) + _grid->_edgeIntP.pop_back(); + ip._shapeID = edgeID; + } + for ( int iP = 2; iP <= discret.NbPoints(); ++iP ) + { + // locate the 2nd point of a segment within the grid + gp_XYZ p2 = discret.Value( iP ).XYZ(); + double u2 = discret.Parameter( iP ); + double zProj2 = planes._zNorm * ( p2 - _grid->_origin ); + int iZ2 = iZ1; + if ( Abs( zProj2 - zProj1 ) > std::numeric_limits::min() ) + { + locateValue( iZ2, zProj2, planes._zProjs, dIJK[ iDirZ ], tol ); + + // treat intersections with planes between 2 end points of a segment + int dZ = ( iZ1 <= iZ2 ) ? +1 : -1; + int iZ = iZ1 + ( iZ1 < iZ2 ); + for ( int i = 0, nb = Abs( iZ1 - iZ2 ); i < nb; ++i, iZ += dZ ) + { + ip._point = findIntPoint( u1, zProj1, u2, zProj2, + planes._zProjs[ iZ ], + curve, planes._zNorm, _grid->_origin ); + _grid->ComputeUVW( ip._point.XYZ(), ip._uvw ); + locateValue( ijk[iDirX], ip._uvw[iDirX], _grid->_coords[iDirX], dIJK[iDirX], tol ); + locateValue( ijk[iDirY], ip._uvw[iDirY], _grid->_coords[iDirY], dIJK[iDirY], tol ); + ijk[ iDirZ ] = iZ; + + // add ip to hex "above" the plane + _grid->_edgeIntP.push_back( ip ); + dIJK[ iDirZ ] = 0; + bool added = addIntersection(_grid->_edgeIntP.back(), hexes, ijk, dIJK); + + // add ip to hex "below" the plane + ijk[ iDirZ ] = iZ-1; + if ( !addIntersection( _grid->_edgeIntP.back(), hexes, ijk, dIJK ) && + !added) + _grid->_edgeIntP.pop_back(); + } + } + iZ1 = iZ2; + p1 = p2; + u1 = u2; + zProj1 = zProj2; + } + // add the 2nd vertex point to a hexahedron + if ( iDirZ == 0 ) + { + ip._shapeID = _grid->_shapes.Add( v2 ); + ip._point = p1; + _grid->ComputeUVW( p1, ip._uvw ); + locateValue( ijk[iDirX], ip._uvw[iDirX], _grid->_coords[iDirX], dIJK[iDirX], tol ); + locateValue( ijk[iDirY], ip._uvw[iDirY], _grid->_coords[iDirY], dIJK[iDirY], tol ); + ijk[ iDirZ ] = iZ1; + _grid->_edgeIntP.push_back( ip ); + if ( !addIntersection( _grid->_edgeIntP.back(), hexes, ijk, d000 )) + _grid->_edgeIntP.pop_back(); + ip._shapeID = edgeID; + } + } // loop on 3 grid directions + } // loop on EDGEs + + } + + //================================================================================ + /*! + * \brief Finds intersection of a curve with a plane + * \param [in] u1 - parameter of one curve point + * \param [in] proj1 - projection of the curve point to the plane normal + * \param [in] u2 - parameter of another curve point + * \param [in] proj2 - projection of the other curve point to the plane normal + * \param [in] proj - projection of a point where the curve intersects the plane + * \param [in] curve - the curve + * \param [in] axis - the plane normal + * \param [in] origin - the plane origin + * \return gp_Pnt - the found intersection point + */ + gp_Pnt Hexahedron::findIntPoint( double u1, double proj1, + double u2, double proj2, + double proj, + BRepAdaptor_Curve& curve, + const gp_XYZ& axis, + const gp_XYZ& origin) + { + double r = (( proj - proj1 ) / ( proj2 - proj1 )); + double u = u1 * ( 1 - r ) + u2 * r; + gp_Pnt p = curve.Value( u ); + double newProj = axis * ( p.XYZ() - origin ); + if ( Abs( proj - newProj ) > _grid->_tol / 10. ) + { + if ( r > 0.5 ) + return findIntPoint( u2, proj2, u, newProj, proj, curve, axis, origin ); + else + return findIntPoint( u1, proj2, u, newProj, proj, curve, axis, origin ); + } + return p; + } + + //================================================================================ + /*! + * \brief Returns indices of a hexahedron sub-entities holding a point + * \param [in] ip - intersection point + * \param [out] facets - 0-3 facets holding a point + * \param [out] sub - index of a vertex or an edge holding a point + * \return int - number of facets holding a point + */ + int Hexahedron::getEntity( const E_IntersectPoint* ip, int* facets, int& sub ) + { + enum { X = 1, Y = 2, Z = 4 }; // == 001, 010, 100 + int nbFacets = 0; + int vertex = 0, egdeMask = 0; + + if ( Abs( _grid->_coords[0][ _i ] - ip->_uvw[0] ) < _grid->_tol ) { + facets[ nbFacets++ ] = SMESH_Block::ID_F0yz; + egdeMask |= X; + } + else if ( Abs( _grid->_coords[0][ _i+1 ] - ip->_uvw[0] ) < _grid->_tol ) { + facets[ nbFacets++ ] = SMESH_Block::ID_F1yz; + vertex |= X; + egdeMask |= X; + } + if ( Abs( _grid->_coords[1][ _j ] - ip->_uvw[1] ) < _grid->_tol ) { + facets[ nbFacets++ ] = SMESH_Block::ID_Fx0z; + egdeMask |= Y; + } + else if ( Abs( _grid->_coords[1][ _j+1 ] - ip->_uvw[1] ) < _grid->_tol ) { + facets[ nbFacets++ ] = SMESH_Block::ID_Fx1z; + vertex |= Y; + egdeMask |= Y; + } + if ( Abs( _grid->_coords[2][ _k ] - ip->_uvw[2] ) < _grid->_tol ) { + facets[ nbFacets++ ] = SMESH_Block::ID_Fxy0; + egdeMask |= Z; + } + else if ( Abs( _grid->_coords[2][ _k+1 ] - ip->_uvw[2] ) < _grid->_tol ) { + facets[ nbFacets++ ] = SMESH_Block::ID_Fxy1; + vertex |= Z; + egdeMask |= Z; + } + + switch ( nbFacets ) + { + case 0: sub = 0; break; + case 1: sub = facets[0]; break; + case 2: { + const int edge [3][8] = { + { SMESH_Block::ID_E00z, SMESH_Block::ID_E10z, + SMESH_Block::ID_E01z, SMESH_Block::ID_E11z }, + { SMESH_Block::ID_E0y0, SMESH_Block::ID_E1y0, 0, 0, + SMESH_Block::ID_E0y1, SMESH_Block::ID_E1y1 }, + { SMESH_Block::ID_Ex00, 0, SMESH_Block::ID_Ex10, 0, + SMESH_Block::ID_Ex01, 0, SMESH_Block::ID_Ex11 } + }; + switch ( egdeMask ) { + case X | Y: sub = edge[ 0 ][ vertex ]; break; + case X | Z: sub = edge[ 1 ][ vertex ]; break; + default: sub = edge[ 2 ][ vertex ]; + } + break; + } + //case 3: + default: + sub = vertex + SMESH_Block::ID_FirstV; + } + + return nbFacets; + } + //================================================================================ + /*! + * \brief Adds intersection with an EDGE + */ + bool Hexahedron::addIntersection( const E_IntersectPoint& ip, + vector< Hexahedron* >& hexes, + int ijk[], int dIJK[] ) + { + bool added = false; + + size_t hexIndex[4] = { + _grid->CellIndex( ijk[0], ijk[1], ijk[2] ), + dIJK[0] ? _grid->CellIndex( ijk[0]+dIJK[0], ijk[1], ijk[2] ) : -1, + dIJK[1] ? _grid->CellIndex( ijk[0], ijk[1]+dIJK[1], ijk[2] ) : -1, + dIJK[2] ? _grid->CellIndex( ijk[0], ijk[1], ijk[2]+dIJK[2] ) : -1 + }; + for ( int i = 0; i < 4; ++i ) + { + if ( /*0 <= hexIndex[i] &&*/ hexIndex[i] < hexes.size() && hexes[ hexIndex[i] ] ) + { + Hexahedron* h = hexes[ hexIndex[i] ]; + // check if ip is really inside the hex +#ifdef _DEBUG_ + if ( h->isOutParam( ip._uvw )) + throw SALOME_Exception("ip outside a hex"); +#endif + h->_eIntPoints.push_back( & ip ); + added = true; + } + } + return added; + } + //================================================================================ + /*! + * \brief Finds nodes at a path from one node to another via intersections with EDGEs + */ + bool Hexahedron::findChain( _Node* n1, + _Node* n2, + _Face& quad, + vector<_Node*>& chn ) + { + chn.clear(); + chn.push_back( n1 ); + for ( size_t iP = 0; iP < quad._eIntNodes.size(); ++iP ) + if ( !quad._eIntNodes[ iP ]->IsUsedInFace( &quad ) && + n1->IsLinked( quad._eIntNodes[ iP ]->_intPoint ) && + n2->IsLinked( quad._eIntNodes[ iP ]->_intPoint )) + { + chn.push_back( quad._eIntNodes[ iP ]); + chn.push_back( n2 ); + quad._eIntNodes[ iP ]->_usedInFace = &quad; + return true; + } + bool found; + do + { + found = false; + for ( size_t iP = 0; iP < quad._eIntNodes.size(); ++iP ) + if ( !quad._eIntNodes[ iP ]->IsUsedInFace( &quad ) && + chn.back()->IsLinked( quad._eIntNodes[ iP ]->_intPoint )) + { + chn.push_back( quad._eIntNodes[ iP ]); + found = quad._eIntNodes[ iP ]->_usedInFace = &quad; + break; + } + } while ( found && ! chn.back()->IsLinked( n2->_intPoint ) ); + + if ( chn.back() != n2 && chn.back()->IsLinked( n2->_intPoint )) + chn.push_back( n2 ); + + return chn.size() > 1; + } + //================================================================================ + /*! + * \brief Try to heal a polygon whose ends are not connected + */ + bool Hexahedron::closePolygon( _Face* polygon, vector<_Node*>& chainNodes ) const + { + int i = -1, nbLinks = polygon->_links.size(); + if ( nbLinks < 3 ) + return false; + vector< _OrientedLink > newLinks; + // find a node lying on the same FACE as the last one + _Node* node = polygon->_links.back().LastNode(); + int avoidFace = node->IsLinked( polygon->_links.back().FirstNode()->_intPoint ); + for ( i = nbLinks - 2; i >= 0; --i ) + if ( node->IsLinked( polygon->_links[i].FirstNode()->_intPoint, avoidFace )) + break; + if ( i >= 0 ) + { + for ( ; i < nbLinks; ++i ) + newLinks.push_back( polygon->_links[i] ); + } + else + { + // find a node lying on the same FACE as the first one + node = polygon->_links[0].FirstNode(); + avoidFace = node->IsLinked( polygon->_links[0].LastNode()->_intPoint ); + for ( i = 1; i < nbLinks; ++i ) + if ( node->IsLinked( polygon->_links[i].LastNode()->_intPoint, avoidFace )) + break; + if ( i < nbLinks ) + for ( nbLinks = i + 1, i = 0; i < nbLinks; ++i ) + newLinks.push_back( polygon->_links[i] ); + } + if ( newLinks.size() > 1 ) + { + polygon->_links.swap( newLinks ); + chainNodes.clear(); + chainNodes.push_back( polygon->_links.back().LastNode() ); + chainNodes.push_back( polygon->_links[0].FirstNode() ); + return true; + } + return false; + } + //================================================================================ + /*! + * \brief Finds nodes on the same EDGE as the first node of avoidSplit. + * + * This function is for a case where an EDGE lies on a quad which lies on a FACE + * so that a part of quad in ON and another part in IN + */ + bool Hexahedron::findChainOnEdge( const vector< _OrientedLink >& splits, + const _OrientedLink& prevSplit, + const _OrientedLink& avoidSplit, + size_t & iS, + _Face& quad, + vector<_Node*>& chn ) + { + if ( !isImplementEdges() ) + return false; + + _Node* pn1 = prevSplit.FirstNode(); + _Node* pn2 = prevSplit.LastNode(); + int avoidFace = pn1->IsLinked( pn2->_intPoint ); // FACE under the quad + if ( avoidFace < 1 && pn1->_intPoint ) + return false; + + _Node* n, *stopNode = avoidSplit.LastNode(); + + chn.clear(); + if ( !quad._eIntNodes.empty() ) + { + chn.push_back( pn2 ); + bool found; + do + { + found = false; + for ( size_t iP = 0; iP < quad._eIntNodes.size(); ++iP ) + if (( !quad._eIntNodes[ iP ]->IsUsedInFace( &quad )) && + ( chn.back()->IsLinked( quad._eIntNodes[ iP ]->_intPoint, avoidFace )) && + ( !avoidFace || quad._eIntNodes[ iP ]->IsOnFace( avoidFace ))) + { + chn.push_back( quad._eIntNodes[ iP ]); + found = quad._eIntNodes[ iP ]->_usedInFace = &quad; + break; + } + } while ( found ); + pn2 = chn.back(); + } + + int i; + for ( i = splits.size()-1; i >= 0; --i ) + { + if ( !splits[i] ) + continue; + + n = splits[i].LastNode(); + if ( n == stopNode ) + break; + if (( n != pn1 ) && + ( n->IsLinked( pn2->_intPoint, avoidFace )) && + ( !avoidFace || n->IsOnFace( avoidFace ))) + break; + + n = splits[i].FirstNode(); + if ( n == stopNode ) + break; + if (( n->IsLinked( pn2->_intPoint, avoidFace )) && + ( !avoidFace || n->IsOnFace( avoidFace ))) + break; + n = 0; + } + if ( n && n != stopNode) + { + if ( chn.empty() ) + chn.push_back( pn2 ); + chn.push_back( n ); + iS = i-1; + return true; + } + return false; + } + //================================================================================ + /*! + * \brief Checks transition at the ginen intersection node of a link + */ + bool Hexahedron::isOutPoint( _Link& link, int iP, SMESH_MesherHelper& helper ) const + { + bool isOut = false; + + const bool moreIntPoints = ( iP+1 < link._fIntPoints.size() ); + + // get 2 _Node's + _Node* n1 = link._fIntNodes[ iP ]; + if ( !n1->Node() ) + n1 = link._nodes[0]; + _Node* n2 = moreIntPoints ? link._fIntNodes[ iP+1 ] : 0; + if ( !n2 || !n2->Node() ) + n2 = link._nodes[1]; + if ( !n2->Node() ) + return true; + + // get all FACEs under n1 and n2 + set< TGeomID > faceIDs; + if ( moreIntPoints ) faceIDs.insert( link._fIntPoints[iP+1]->_faceIDs.begin(), + link._fIntPoints[iP+1]->_faceIDs.end() ); + if ( n2->_intPoint ) faceIDs.insert( n2->_intPoint->_faceIDs.begin(), + n2->_intPoint->_faceIDs.end() ); + if ( faceIDs.empty() ) + return false; // n2 is inside + if ( n1->_intPoint ) faceIDs.insert( n1->_intPoint->_faceIDs.begin(), + n1->_intPoint->_faceIDs.end() ); + faceIDs.insert( link._fIntPoints[iP]->_faceIDs.begin(), + link._fIntPoints[iP]->_faceIDs.end() ); + + // get a point between 2 nodes + gp_Pnt p1 = n1->Point(); + gp_Pnt p2 = n2->Point(); + gp_Pnt pOnLink = 0.8 * p1.XYZ() + 0.2 * p2.XYZ(); + + TopLoc_Location loc; + + set< TGeomID >::iterator faceID = faceIDs.begin(); + for ( ; faceID != faceIDs.end(); ++faceID ) + { + // project pOnLink on a FACE + if ( *faceID < 1 ) continue; + const TopoDS_Face& face = TopoDS::Face( _grid->_shapes( *faceID )); + GeomAPI_ProjectPointOnSurf& proj = + helper.GetProjector( face, loc, 0.1*_grid->_tol ); + gp_Pnt testPnt = pOnLink.Transformed( loc.Transformation().Inverted() ); + proj.Perform( testPnt ); + if ( proj.IsDone() && proj.NbPoints() > 0 ) + { + Quantity_Parameter u,v; + proj.LowerDistanceParameters( u,v ); + + if ( proj.LowerDistance() <= 0.1 * _grid->_tol ) + { + isOut = false; + } + else + { + // find isOut by normals + gp_Dir normal; + if ( GeomLib::NormEstim( BRep_Tool::Surface( face, loc ), + gp_Pnt2d( u,v ), + 0.1*_grid->_tol, + normal ) < 3 ) + { + if ( face.Orientation() == TopAbs_REVERSED ) + normal.Reverse(); + gp_Vec v( proj.NearestPoint(), testPnt ); + isOut = ( v * normal > 0 ); + } + } + if ( !isOut ) + { + // classify a projection + if ( !n1->IsOnFace( *faceID ) || !n2->IsOnFace( *faceID )) + { + BRepTopAdaptor_FClass2d cls( face, Precision::Confusion() ); + TopAbs_State state = cls.Perform( gp_Pnt2d( u,v )); + if ( state == TopAbs_OUT ) + { + isOut = true; + continue; + } + } + return false; + } + } + } + return isOut; + } + //================================================================================ + /*! + * \brief Sort nodes on a FACE + */ + void Hexahedron::sortVertexNodes(vector<_Node*>& nodes, _Node* curNode, TGeomID faceID) + { + if ( nodes.size() > 20 ) return; + + // get shapes under nodes + TGeomID nShapeIds[20], *nShapeIdsEnd = &nShapeIds[0] + nodes.size(); + for ( size_t i = 0; i < nodes.size(); ++i ) + if ( !( nShapeIds[i] = nodes[i]->ShapeID() )) + return; + + // get shapes of the FACE + const TopoDS_Face& face = TopoDS::Face( _grid->_shapes( faceID )); + list< TopoDS_Edge > edges; + list< int > nbEdges; + int nbW = SMESH_Block::GetOrderedEdges (face, edges, nbEdges); + if ( nbW > 1 ) { + // select a WIRE - remove EDGEs of irrelevant WIREs from edges + list< TopoDS_Edge >::iterator e = edges.begin(), eEnd = e; + list< int >::iterator nE = nbEdges.begin(); + for ( ; nbW > 0; ++nE, --nbW ) + { + std::advance( eEnd, *nE ); + for ( ; e != eEnd; ++e ) + for ( int i = 0; i < 2; ++i ) + { + TGeomID id = i==0 ? + _grid->_shapes.FindIndex( *e ) : + _grid->_shapes.FindIndex( SMESH_MesherHelper::IthVertex( 0, *e )); + if (( id > 0 ) && + ( std::find( &nShapeIds[0], nShapeIdsEnd, id ) != nShapeIdsEnd )) + { + edges.erase( eEnd, edges.end() ); // remove rest wires + e = eEnd = edges.end(); + --e; + nbW = 0; + break; + } + } + if ( nbW > 0 ) + edges.erase( edges.begin(), eEnd ); // remove a current irrelevant wire + } + } + // rotate edges to have the first one at least partially out of the hexa + list< TopoDS_Edge >::iterator e = edges.begin(), eMidOut = edges.end(); + for ( ; e != edges.end(); ++e ) + { + if ( !_grid->_shapes.FindIndex( *e )) + continue; + bool isOut = false; + gp_Pnt p; + double uvw[3], f,l; + for ( int i = 0; i < 2 && !isOut; ++i ) + { + if ( i == 0 ) + { + TopoDS_Vertex v = SMESH_MesherHelper::IthVertex( 0, *e ); + p = BRep_Tool::Pnt( v ); + } + else if ( eMidOut == edges.end() ) + { + TopLoc_Location loc; + Handle(Geom_Curve) c = BRep_Tool::Curve( *e, loc, f, l); + if ( c.IsNull() ) break; + p = c->Value( 0.5 * ( f + l )).Transformed( loc ); + } + else + { + continue; + } + + _grid->ComputeUVW( p.XYZ(), uvw ); + if ( isOutParam( uvw )) + { + if ( i == 0 ) + isOut = true; + else + eMidOut = e; + } + } + if ( isOut ) + break; + } + if ( e != edges.end() ) + edges.splice( edges.end(), edges, edges.begin(), e ); + else if ( eMidOut != edges.end() ) + edges.splice( edges.end(), edges, edges.begin(), eMidOut ); + + // sort nodes accoring to the order of edges + _Node* orderNodes [20]; + TGeomID orderShapeIDs[20]; + int nbN = 0; + TGeomID id, *pID; + for ( e = edges.begin(); e != edges.end(); ++e ) + { + if (( id = _grid->_shapes.FindIndex( SMESH_MesherHelper::IthVertex( 0, *e ))) && + (( pID = std::find( &nShapeIds[0], nShapeIdsEnd, id )) != nShapeIdsEnd )) + { + orderShapeIDs[ nbN ] = id; + orderNodes [ nbN++ ] = nodes[ pID - &nShapeIds[0] ]; + *pID = -1; + } + if (( id = _grid->_shapes.FindIndex( *e )) && + (( pID = std::find( &nShapeIds[0], nShapeIdsEnd, id )) != nShapeIdsEnd )) + { + orderShapeIDs[ nbN ] = id; + orderNodes [ nbN++ ] = nodes[ pID - &nShapeIds[0] ]; + *pID = -1; + } + } + if ( nbN != nodes.size() ) + return; + + bool reverse = ( orderNodes[0 ]->Point().SquareDistance( curNode->Point() ) > + orderNodes[nbN-1]->Point().SquareDistance( curNode->Point() )); + + for ( size_t i = 0; i < nodes.size(); ++i ) + nodes[ i ] = orderNodes[ reverse ? nbN-1-i : i ]; + } + + //================================================================================ + /*! + * \brief Adds computed elements to the mesh + */ + int Hexahedron::addElements(SMESH_MesherHelper& helper) + { + int nbAdded = 0; + // add elements resulted from hexahedron intersection + //for ( size_t i = 0; i < _volumeDefs.size(); ++i ) + { + vector< const SMDS_MeshNode* > nodes( _volumeDefs._nodes.size() ); + for ( size_t iN = 0; iN < nodes.size(); ++iN ) + if ( !( nodes[iN] = _volumeDefs._nodes[iN]->Node() )) + { + if ( const E_IntersectPoint* eip = _volumeDefs._nodes[iN]->EdgeIntPnt() ) + nodes[iN] = _volumeDefs._nodes[iN]->_intPoint->_node = + helper.AddNode( eip->_point.X(), + eip->_point.Y(), + eip->_point.Z() ); + else + throw SALOME_Exception("Bug: no node at intersection point"); + } + + if ( !_volumeDefs._quantities.empty() ) + { + helper.AddPolyhedralVolume( nodes, _volumeDefs._quantities ); + } + else + { + switch ( nodes.size() ) + { + case 8: helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3], + nodes[4],nodes[5],nodes[6],nodes[7] ); + break; + case 4: helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3] ); + break; + case 6: helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3], nodes[4],nodes[5] ); + break; + case 5: + helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3],nodes[4] ); + break; + } + } + nbAdded += int ( _volumeDefs._nodes.size() > 0 ); + } + + return nbAdded; + } + //================================================================================ + /*! + * \brief Return true if the element is in a hole + */ + bool Hexahedron::isInHole() const + { + if ( !_vIntNodes.empty() ) + return false; + + const int ijk[3] = { (int)_i, (int)_j, (int)_k }; + F_IntersectPoint curIntPnt; + + // consider a cell to be in a hole if all links in any direction + // comes OUT of geometry + for ( int iDir = 0; iDir < 3; ++iDir ) + { + const vector& coords = _grid->_coords[ iDir ]; + LineIndexer li = _grid->GetLineIndexer( iDir ); + li.SetIJK( _i,_j,_k ); + size_t lineIndex[4] = { li.LineIndex (), + li.LineIndex10(), + li.LineIndex01(), + li.LineIndex11() }; + bool allLinksOut = true, hasLinks = false; + for ( int iL = 0; iL < 4 && allLinksOut; ++iL ) // loop on 4 links parallel to iDir + { + const _Link& link = _hexLinks[ iL + 4*iDir ]; + // check transition of the first node of a link + const F_IntersectPoint* firstIntPnt = 0; + if ( link._nodes[0]->Node() ) // 1st node is a hexa corner + { + curIntPnt._paramOnLine = coords[ ijk[ iDir ]] - coords[0]; + const GridLine& line = _grid->_lines[ iDir ][ lineIndex[ iL ]]; + multiset< F_IntersectPoint >::const_iterator ip = + line._intPoints.upper_bound( curIntPnt ); + --ip; + firstIntPnt = &(*ip); + } + else if ( !link._fIntPoints.empty() ) + { + firstIntPnt = link._fIntPoints[0]; + } + + if ( firstIntPnt ) + { + hasLinks = true; + allLinksOut = ( firstIntPnt->_transition == Trans_OUT ); + } + } + if ( hasLinks && allLinksOut ) + return true; + } + return false; + } + + //================================================================================ + /*! + * \brief Return true if a polyhedron passes _sizeThreshold criterion + */ + bool Hexahedron::checkPolyhedronSize() const + { + double volume = 0; + for ( size_t iP = 0; iP < _polygons.size(); ++iP ) + { + const _Face& polygon = _polygons[iP]; + if ( polygon._links.empty() ) + continue; + gp_XYZ area (0,0,0); + gp_XYZ p1 = polygon._links[ 0 ].FirstNode()->Point().XYZ(); + for ( size_t iL = 0; iL < polygon._links.size(); ++iL ) + { + gp_XYZ p2 = polygon._links[ iL ].LastNode()->Point().XYZ(); + area += p1 ^ p2; + p1 = p2; + } + volume += p1 * area; + } + volume /= 6; + + double initVolume = _sideLength[0] * _sideLength[1] * _sideLength[2]; + + return volume > initVolume / _sizeThreshold; + } + //================================================================================ + /*! + * \brief Tries to create a hexahedron + */ + bool Hexahedron::addHexa() + { + int nbQuad = 0, iQuad = -1; + for ( size_t i = 0; i < _polygons.size(); ++i ) + { + if ( _polygons[i]._links.empty() ) + continue; + if ( _polygons[i]._links.size() != 4 ) + return false; + ++nbQuad; + if ( iQuad < 0 ) + iQuad = i; + } + if ( nbQuad != 6 ) + return false; + + _Node* nodes[8]; + int nbN = 0; + for ( int iL = 0; iL < 4; ++iL ) + { + // a base node + nodes[iL] = _polygons[iQuad]._links[iL].FirstNode(); + ++nbN; + + // find a top node above the base node + _Link* link = _polygons[iQuad]._links[iL]._link; + if ( !link->_faces[0] || !link->_faces[1] ) + return debugDumpLink( link ); + // a quadrangle sharing with _polygons[iQuad] + _Face* quad = link->_faces[ bool( link->_faces[0] == & _polygons[iQuad] )]; + for ( int i = 0; i < 4; ++i ) + if ( quad->_links[i]._link == link ) + { + // 1st node of a link opposite to in + nodes[iL+4] = quad->_links[(i+2)%4].FirstNode(); + ++nbN; + break; + } + } + if ( nbN == 8 ) + _volumeDefs.set( &nodes[0], 8 ); + + return nbN == 8; + } + //================================================================================ + /*! + * \brief Tries to create a tetrahedron + */ + bool Hexahedron::addTetra() + { + int iTria = -1; + for ( size_t i = 0; i < _polygons.size() && iTria < 0; ++i ) + if ( _polygons[i]._links.size() == 3 ) + iTria = i; + if ( iTria < 0 ) + return false; + + _Node* nodes[4]; + nodes[0] = _polygons[iTria]._links[0].FirstNode(); + nodes[1] = _polygons[iTria]._links[1].FirstNode(); + nodes[2] = _polygons[iTria]._links[2].FirstNode(); + + _Link* link = _polygons[iTria]._links[0]._link; + if ( !link->_faces[0] || !link->_faces[1] ) + return debugDumpLink( link ); + + // a triangle sharing with _polygons[0] + _Face* tria = link->_faces[ bool( link->_faces[0] == & _polygons[iTria] )]; + for ( int i = 0; i < 3; ++i ) + if ( tria->_links[i]._link == link ) + { + nodes[3] = tria->_links[(i+1)%3].LastNode(); + _volumeDefs.set( &nodes[0], 4 ); + return true; + } + + return false; + } + //================================================================================ + /*! + * \brief Tries to create a pentahedron + */ + bool Hexahedron::addPenta() + { + // find a base triangular face + int iTri = -1; + for ( int iF = 0; iF < 5 && iTri < 0; ++iF ) + if ( _polygons[ iF ]._links.size() == 3 ) + iTri = iF; + if ( iTri < 0 ) return false; + + // find nodes + _Node* nodes[6]; + int nbN = 0; + for ( int iL = 0; iL < 3; ++iL ) + { + // a base node + nodes[iL] = _polygons[ iTri ]._links[iL].FirstNode(); + ++nbN; + + // find a top node above the base node + _Link* link = _polygons[ iTri ]._links[iL]._link; + if ( !link->_faces[0] || !link->_faces[1] ) + return debugDumpLink( link ); + // a quadrangle sharing with a base triangle + _Face* quad = link->_faces[ bool( link->_faces[0] == & _polygons[ iTri ] )]; + if ( quad->_links.size() != 4 ) return false; + for ( int i = 0; i < 4; ++i ) + if ( quad->_links[i]._link == link ) + { + // 1st node of a link opposite to in + nodes[iL+3] = quad->_links[(i+2)%4].FirstNode(); + ++nbN; + break; + } + } + if ( nbN == 6 ) + _volumeDefs.set( &nodes[0], 6 ); + + return ( nbN == 6 ); + } + //================================================================================ + /*! + * \brief Tries to create a pyramid + */ + bool Hexahedron::addPyra() + { + // find a base quadrangle + int iQuad = -1; + for ( int iF = 0; iF < 5 && iQuad < 0; ++iF ) + if ( _polygons[ iF ]._links.size() == 4 ) + iQuad = iF; + if ( iQuad < 0 ) return false; + + // find nodes + _Node* nodes[5]; + nodes[0] = _polygons[iQuad]._links[0].FirstNode(); + nodes[1] = _polygons[iQuad]._links[1].FirstNode(); + nodes[2] = _polygons[iQuad]._links[2].FirstNode(); + nodes[3] = _polygons[iQuad]._links[3].FirstNode(); + + _Link* link = _polygons[iQuad]._links[0]._link; + if ( !link->_faces[0] || !link->_faces[1] ) + return debugDumpLink( link ); + + // a triangle sharing with a base quadrangle + _Face* tria = link->_faces[ bool( link->_faces[0] == & _polygons[ iQuad ] )]; + if ( tria->_links.size() != 3 ) return false; + for ( int i = 0; i < 3; ++i ) + if ( tria->_links[i]._link == link ) + { + nodes[4] = tria->_links[(i+1)%3].LastNode(); + _volumeDefs.set( &nodes[0], 5 ); + return true; + } + + return false; + } + //================================================================================ + /*! + * \brief Dump a link and return \c false + */ + bool Hexahedron::debugDumpLink( Hexahedron::_Link* link ) + { +#ifdef _DEBUG_ + gp_Pnt p1 = link->_nodes[0]->Point(), p2 = link->_nodes[1]->Point(); + cout << "BUG: not shared link. IKJ = ( "<< _i << " " << _j << " " << _k << " )" << endl + << "n1 (" << p1.X() << ", "<< p1.Y() << ", "<< p1.Z() << " )" << endl + << "n2 (" << p2.X() << ", "<< p2.Y() << ", "<< p2.Z() << " )" << endl; +#endif + return false; + } + //================================================================================ + /*! + * \brief Classify a point by grid paremeters + */ + bool Hexahedron::isOutParam(const double uvw[3]) const + { + return (( _grid->_coords[0][ _i ] - _grid->_tol > uvw[0] ) || + ( _grid->_coords[0][ _i+1 ] + _grid->_tol < uvw[0] ) || + ( _grid->_coords[1][ _j ] - _grid->_tol > uvw[1] ) || + ( _grid->_coords[1][ _j+1 ] + _grid->_tol < uvw[1] ) || + ( _grid->_coords[2][ _k ] - _grid->_tol > uvw[2] ) || + ( _grid->_coords[2][ _k+1 ] + _grid->_tol < uvw[2] )); + } + + //================================================================================ + /*! + * \brief computes exact bounding box with axes parallel to given ones + */ + //================================================================================ + + void getExactBndBox( const vector< TopoDS_Shape >& faceVec, + const double* axesDirs, + Bnd_Box& shapeBox ) + { + BRep_Builder b; + TopoDS_Compound allFacesComp; + b.MakeCompound( allFacesComp ); + for ( size_t iF = 0; iF < faceVec.size(); ++iF ) + b.Add( allFacesComp, faceVec[ iF ] ); + + double sP[6]; // aXmin, aYmin, aZmin, aXmax, aYmax, aZmax + shapeBox.Get(sP[0],sP[1],sP[2],sP[3],sP[4],sP[5]); + double farDist = 0; + for ( int i = 0; i < 6; ++i ) + farDist = Max( farDist, 10 * sP[i] ); + + gp_XYZ axis[3] = { gp_XYZ( axesDirs[0], axesDirs[1], axesDirs[2] ), + gp_XYZ( axesDirs[3], axesDirs[4], axesDirs[5] ), + gp_XYZ( axesDirs[6], axesDirs[7], axesDirs[8] ) }; + axis[0].Normalize(); + axis[1].Normalize(); + axis[2].Normalize(); + + gp_Mat basis( axis[0], axis[1], axis[2] ); + gp_Mat bi = basis.Inverted(); + + gp_Pnt pMin, pMax; + for ( int iDir = 0; iDir < 3; ++iDir ) + { + gp_XYZ axis0 = axis[ iDir ]; + gp_XYZ axis1 = axis[ ( iDir + 1 ) % 3 ]; + gp_XYZ axis2 = axis[ ( iDir + 2 ) % 3 ]; + for ( int isMax = 0; isMax < 2; ++isMax ) + { + double shift = isMax ? farDist : -farDist; + gp_XYZ orig = shift * axis0; + gp_XYZ norm = axis1 ^ axis2; + gp_Pln pln( orig, norm ); + norm = pln.Axis().Direction().XYZ(); + BRepBuilderAPI_MakeFace plane( pln, -farDist, farDist, -farDist, farDist ); + + gp_Pnt& pAxis = isMax ? pMax : pMin; + gp_Pnt pPlane, pFaces; + double dist = GEOMUtils::GetMinDistance( plane, allFacesComp, pPlane, pFaces ); + if ( dist < 0 ) + { + Bnd_B3d bb; + gp_XYZ corner; + for ( int i = 0; i < 2; ++i ) { + corner.SetCoord( 1, sP[ i*3 ]); + for ( int j = 0; j < 2; ++j ) { + corner.SetCoord( 2, sP[ i*3 + 1 ]); + for ( int k = 0; k < 2; ++k ) + { + corner.SetCoord( 3, sP[ i*3 + 2 ]); + corner *= bi; + bb.Add( corner ); + } + } + } + corner = isMax ? bb.CornerMax() : bb.CornerMin(); + pAxis.SetCoord( iDir+1, corner.Coord( iDir+1 )); + } + else + { + gp_XYZ pf = pFaces.XYZ() * bi; + pAxis.SetCoord( iDir+1, pf.Coord( iDir+1 ) ); + } + } + } // loop on 3 axes + + shapeBox.SetVoid(); + shapeBox.Add( pMin ); + shapeBox.Add( pMax ); + + return; + } + +} // namespace + +//============================================================================= +/*! + * \brief Generates 3D structured Cartesian mesh in the internal part of + * solid shapes and polyhedral volumes near the shape boundary. + * \param theMesh - mesh to fill in + * \param theShape - a compound of all SOLIDs to mesh + * \retval bool - true in case of success + */ +//============================================================================= + +bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh, + const TopoDS_Shape & theShape) +{ + // The algorithm generates the mesh in following steps: + + // 1) Intersection of grid lines with the geometry boundary. + // This step allows to find out if a given node of the initial grid is + // inside or outside the geometry. + + // 2) For each cell of the grid, check how many of it's nodes are outside + // of the geometry boundary. Depending on a result of this check + // - skip a cell, if all it's nodes are outside + // - skip a cell, if it is too small according to the size threshold + // - add a hexahedron in the mesh, if all nodes are inside + // - add a polyhedron in the mesh, if some nodes are inside and some outside + + _computeCanceled = false; + + SMESH_MesherHelper helper( theMesh ); + + try + { + Grid grid; + grid._helper = &helper; + + vector< TopoDS_Shape > faceVec; + { + TopTools_MapOfShape faceMap; + TopExp_Explorer fExp; + for ( fExp.Init( theShape, TopAbs_FACE ); fExp.More(); fExp.Next() ) + if ( !faceMap.Add( fExp.Current() )) + faceMap.Remove( fExp.Current() ); // remove a face shared by two solids + + for ( fExp.ReInit(); fExp.More(); fExp.Next() ) + if ( faceMap.Contains( fExp.Current() )) + faceVec.push_back( fExp.Current() ); + } + vector facesItersectors( faceVec.size() ); + map< TGeomID, vector< TGeomID > > edge2faceIDsMap; + TopExp_Explorer eExp; + Bnd_Box shapeBox; + for ( int i = 0; i < faceVec.size(); ++i ) + { + facesItersectors[i]._face = TopoDS::Face ( faceVec[i] ); + facesItersectors[i]._faceID = grid._shapes.Add( faceVec[i] ); + facesItersectors[i]._grid = &grid; + shapeBox.Add( facesItersectors[i].GetFaceBndBox() ); + + if ( _hyp->GetToAddEdges() ) + { + helper.SetSubShape( faceVec[i] ); + for ( eExp.Init( faceVec[i], TopAbs_EDGE ); eExp.More(); eExp.Next() ) + { + const TopoDS_Edge& edge = TopoDS::Edge( eExp.Current() ); + if ( !SMESH_Algo::isDegenerated( edge ) && + !helper.IsRealSeam( edge )) + edge2faceIDsMap[ grid._shapes.Add( edge )].push_back( facesItersectors[i]._faceID ); + } + } + } + + getExactBndBox( faceVec, _hyp->GetAxisDirs(), shapeBox ); + + vector xCoords, yCoords, zCoords; + _hyp->GetCoordinates( xCoords, yCoords, zCoords, shapeBox ); + + grid.SetCoordinates( xCoords, yCoords, zCoords, _hyp->GetAxisDirs(), shapeBox ); + + if ( _computeCanceled ) return false; + +#ifdef WITH_TBB + { // copy partner faces and curves of not thread-safe types + set< const Standard_Transient* > tshapes; + BRepBuilderAPI_Copy copier; + for ( size_t i = 0; i < facesItersectors.size(); ++i ) + { + if ( !facesItersectors[i].IsThreadSafe(tshapes) ) + { + copier.Perform( facesItersectors[i]._face ); + facesItersectors[i]._face = TopoDS::Face( copier ); + } + } + } + // Intersection of grid lines with the geometry boundary. + tbb::parallel_for ( tbb::blocked_range( 0, facesItersectors.size() ), + ParallelIntersector( facesItersectors ), + tbb::simple_partitioner()); +#else + for ( size_t i = 0; i < facesItersectors.size(); ++i ) + facesItersectors[i].Intersect(); +#endif + + // put interesection points onto the GridLine's; this is done after intersection + // to avoid contention of facesItersectors for writing into the same GridLine + // in case of parallel work of facesItersectors + for ( size_t i = 0; i < facesItersectors.size(); ++i ) + facesItersectors[i].StoreIntersections(); + + TopExp_Explorer solidExp (theShape, TopAbs_SOLID); + helper.SetSubShape( solidExp.Current() ); + helper.SetElementsOnShape( true ); + + if ( _computeCanceled ) return false; + + // create nodes on the geometry + grid.ComputeNodes(helper); + + if ( _computeCanceled ) return false; + + // create volume elements + Hexahedron hex( _hyp->GetSizeThreshold(), &grid ); + int nbAdded = hex.MakeElements( helper, edge2faceIDsMap ); + + SMESHDS_Mesh* meshDS = theMesh.GetMeshDS(); + if ( nbAdded > 0 ) + { + // make all SOLIDs computed + if ( SMESHDS_SubMesh* sm1 = meshDS->MeshElements( solidExp.Current()) ) + { + SMDS_ElemIteratorPtr volIt = sm1->GetElements(); + for ( ; solidExp.More() && volIt->more(); solidExp.Next() ) + { + const SMDS_MeshElement* vol = volIt->next(); + sm1->RemoveElement( vol, /*isElemDeleted=*/false ); + meshDS->SetMeshElementOnShape( vol, solidExp.Current() ); + } + } + // make other sub-shapes computed + setSubmeshesComputed( theMesh, theShape ); + } + + // remove free nodes + if ( SMESHDS_SubMesh * smDS = meshDS->MeshElements( helper.GetSubShapeID() )) + { + TIDSortedNodeSet nodesToRemove; + // get intersection nodes + for ( int iDir = 0; iDir < 3; ++iDir ) + { + vector< GridLine >& lines = grid._lines[ iDir ]; + for ( size_t i = 0; i < lines.size(); ++i ) + { + multiset< F_IntersectPoint >::iterator ip = lines[i]._intPoints.begin(); + for ( ; ip != lines[i]._intPoints.end(); ++ip ) + if ( ip->_node && ip->_node->NbInverseElements() == 0 ) + nodesToRemove.insert( nodesToRemove.end(), ip->_node ); + } + } + // get grid nodes + for ( size_t i = 0; i < grid._nodes.size(); ++i ) + if ( grid._nodes[i] && grid._nodes[i]->NbInverseElements() == 0 ) + nodesToRemove.insert( nodesToRemove.end(), grid._nodes[i] ); + + // do remove + TIDSortedNodeSet::iterator n = nodesToRemove.begin(); + for ( ; n != nodesToRemove.end(); ++n ) + meshDS->RemoveFreeNode( *n, smDS, /*fromGroups=*/false ); + } + + return nbAdded; + + } + // SMESH_ComputeError is not caught at SMESH_submesh level for an unknown reason + catch ( SMESH_ComputeError& e) + { + return error( SMESH_ComputeErrorPtr( new SMESH_ComputeError( e ))); + } + return false; +} + +//============================================================================= +/*! + * Evaluate + */ +//============================================================================= + +bool StdMeshers_Cartesian_3D::Evaluate(SMESH_Mesh & theMesh, + const TopoDS_Shape & theShape, + MapShapeNbElems& theResMap) +{ + // TODO +// std::vector aResVec(SMDSEntity_Last); +// for(int i=SMDSEntity_Node; igetDependsOnIterator(/*includeSelf=*/false, /*complexShapeFirst=*/false); + while ( smIt->more() ) + { + SMESH_subMesh* sm = smIt->next(); + sm->SetIsAlwaysComputed( isComputed ); + } + subMeshOfSolid->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + + // -------------------------------------------------------------------------------- + // unsetting _alwaysComputed flag if "Cartesian_3D" was removed + // + virtual void ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* subMeshOfSolid, + SMESH_subMeshEventListenerData* data, + const SMESH_Hypothesis* hyp = 0) + { + if ( eventType == SMESH_subMesh::COMPUTE_EVENT ) + { + setAlwaysComputed( subMeshOfSolid->GetComputeState() == SMESH_subMesh::COMPUTE_OK, + subMeshOfSolid ); + } + else + { + SMESH_Algo* algo3D = subMeshOfSolid->GetAlgo(); + if ( !algo3D || _algoName != algo3D->GetName() ) + setAlwaysComputed( false, subMeshOfSolid ); + } + } + + // -------------------------------------------------------------------------------- + // set the event listener + // + static void SetOn( SMESH_subMesh* subMeshOfSolid, const string& algoName ) + { + subMeshOfSolid->SetEventListener( new _EventListener( algoName ), + /*data=*/0, + subMeshOfSolid ); + } + + }; // struct _EventListener + +} // namespace + +//================================================================================ +/*! + * \brief Sets event listener to submeshes if necessary + * \param subMesh - submesh where algo is set + * This method is called when a submesh gets HYP_OK algo_state. + * After being set, event listener is notified on each event of a submesh. + */ +//================================================================================ + +void StdMeshers_Cartesian_3D::SetEventListener(SMESH_subMesh* subMesh) +{ + _EventListener::SetOn( subMesh, GetName() ); +} + +//================================================================================ +/*! + * \brief Set _alwaysComputed flag to submeshes of inferior levels to avoid their computing + */ +//================================================================================ + +void StdMeshers_Cartesian_3D::setSubmeshesComputed(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape) +{ + for ( TopExp_Explorer soExp( theShape, TopAbs_SOLID ); soExp.More(); soExp.Next() ) + _EventListener::setAlwaysComputed( true, theMesh.GetSubMesh( soExp.Current() )); +} + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_CompositeHexa_3D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_CompositeHexa_3D.cpp index 04ac9e7becb5..7c9dca548a82 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_CompositeHexa_3D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_CompositeHexa_3D.cpp @@ -1,32 +1,27 @@ -// SMESH SMESH : implementaion of SMESH idl descriptions +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 // -// 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 // + +// SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_CompositeHexa_3D.cxx // Module : SMESH // Created : Tue Nov 25 11:04:59 2008 // Author : Edward AGAPOV (eap) -#ifdef _MSC_VER -#define _USE_MATH_DEFINES -#endif // _MSC_VER -#include #include "StdMeshers_CompositeHexa_3D.hxx" @@ -37,6 +32,7 @@ #include "SMESH_Comment.hxx" #include "SMESH_ComputeError.hxx" #include "SMESH_Mesh.hxx" +#include "SMESH_MeshAlgos.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_subMesh.hxx" @@ -45,8 +41,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -60,23 +58,17 @@ #include #include -#ifndef PI -#define PI M_PI -#endif - #ifdef _DEBUG_ - // #define DEB_FACES // #define DEB_GRID -#define DUMP_VERT(msg,V) \ -// { TopoDS_Vertex v = V; gp_Pnt p = BRep_Tool::Pnt(v);\ -// cout << msg << "( "<< p.X()<<", "<& edges); _FaceSide* GetSide(const int i); const _FaceSide* GetSide(const int i) const; - int size() { return myChildren.size(); } + int size() const { return myChildren.size(); } int NbVertices() const; + int NbCommonVertices( const TopTools_MapOfShape& VV ) const; TopoDS_Vertex FirstVertex() const; TopoDS_Vertex LastVertex() const; TopoDS_Vertex Vertex(int i) const; + TopoDS_Edge Edge(int i) const; bool Contain( const _FaceSide& side, int* which=0 ) const; bool Contain( const TopoDS_Vertex& vertex ) const; void AppendSide( const _FaceSide& side ); @@ -132,16 +126,9 @@ class _FaceSide TopoDS_Edge myEdge; - - #ifdef __BORLANDC__ - vector< _FaceSide > myChildren; - #else list< _FaceSide > myChildren; - #endif - int myNbChildren; - //set myVertices; TopTools_MapOfShape myVertices; EQuadSides myID; // debug @@ -153,34 +140,36 @@ class _FaceSide */ class _QuadFaceGrid { - #ifdef __BORLANDC__ - typedef vector< _QuadFaceGrid > TChildren; - #else typedef list< _QuadFaceGrid > TChildren; - #endif public: _QuadFaceGrid(); public: //** Methods to find and orient faces of 6 sides of the box **// //!< initialization - bool Init(const TopoDS_Face& f); + bool Init(const TopoDS_Face& f, SMESH_Mesh& mesh ); //!< try to unite self with other face - bool AddContinuousFace( const _QuadFaceGrid& f ); + bool AddContinuousFace( const _QuadFaceGrid& f, const TopTools_MapOfShape& internalEdges ); //!< Try to set the side as bottom hirizontal side bool SetBottomSide(const _FaceSide& side, int* sideIndex=0); - //!< Return face adjacent to i-th side of this face - _QuadFaceGrid* FindAdjacentForSide(int i, vector<_QuadFaceGrid>& faces) const; // (0& faces, EBoxSides id) const; //!< Reverse edges in order to have the bottom edge going along axes of the unit box void ReverseEdges(/*int e1, int e2*/); bool IsComplex() const { return !myChildren.empty(); } - typedef SMDS_SetIterator< const _QuadFaceGrid&, TChildren::const_iterator > TChildIterator; + int NbChildren() const { return myChildren.size(); } + + typedef SMDS_SetIterator< const _QuadFaceGrid&, + TChildren::const_iterator, + SMDS::SimpleAccessor, + SMDS::PassAllValueFilter<_QuadFaceGrid> > + TChildIterator; TChildIterator GetChildren() const { return TChildIterator( myChildren.begin(), myChildren.end()); } @@ -196,6 +185,9 @@ class _QuadFaceGrid //!< Return number of segments on the vertical sides int GetNbVertSegments(SMESH_Mesh& mesh, bool withBrothers=false) const; + //!< Return edge on the hirizontal bottom sides + int GetHoriEdges(vector & edges) const; + //!< Return a node by its position const SMDS_MeshNode* GetNode(int iHori, int iVert) const; @@ -223,7 +215,7 @@ class _QuadFaceGrid private: - bool error(std::string& text, int code = COMPERR_ALGO_FAILED) + bool error(const std::string& text, int code = COMPERR_ALGO_FAILED) { myError = SMESH_ComputeError::New( code, text ); return false; } bool error(const SMESH_ComputeErrorPtr& err) @@ -269,7 +261,7 @@ StdMeshers_CompositeHexa_3D::StdMeshers_CompositeHexa_3D(int hypId, int studyId, :SMESH_3D_Algo(hypId, studyId, gen) { _name = "CompositeHexa_3D"; - _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID); // 1 bit /shape type + _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID); // 1 bit /shape type } //================================================================================ @@ -286,37 +278,222 @@ bool StdMeshers_CompositeHexa_3D::CheckHypothesis(SMESH_Mesh& aMesh, return true; } +namespace +{ + + //================================================================================ + /*! + * \brief Checks structure of a quadrangular mesh at the common VERTEX of two EDGEs. + * Returns true if there are two quadrangles near the VERTEX. + */ + //================================================================================ + + bool isContinuousMesh(TopoDS_Edge E1, + TopoDS_Edge E2, + const TopoDS_Face& F, + const SMESH_Mesh& mesh) + { + if (E1.Orientation() > TopAbs_REVERSED) // INTERNAL + E1.Orientation( TopAbs_FORWARD ); + if (E2.Orientation() > TopAbs_REVERSED) // INTERNAL + E2.Orientation( TopAbs_FORWARD ); + + TopoDS_Vertex V; + if ( !TopExp::CommonVertex( E1, E2, V )) return false; + + const SMDS_MeshNode* n = SMESH_Algo::VertexNode( V, mesh.GetMeshDS() ); + if ( !n ) return false; + + SMESHDS_SubMesh* sm = mesh.GetSubMeshContaining( F )->GetSubMeshDS(); + if ( !sm ) return false; + + int nbQuads = 0; + SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + if ( !sm->Contains( f )) continue; + + if ( f->NbCornerNodes() == 4 ) + ++nbQuads; + else + return false; + } + return nbQuads == 2; + } + + //================================================================================ + /*! + * \brief Finds VERTEXes located at block corners + */ + //================================================================================ + + void getBlockCorners( SMESH_Mesh& mesh, + const TopoDS_Shape& shape, + TopTools_MapOfShape& cornerVV) + { + set faceIDs; // ids of FACEs in the shape + TopExp_Explorer exp; + for ( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() ) + faceIDs.insert( mesh.GetMeshDS()->ShapeToIndex( exp.Current() )); + + TopTools_MapOfShape checkedVV; + for ( exp.Init( shape, TopAbs_VERTEX ); exp.More(); exp.Next() ) + { + TopoDS_Vertex V = TopoDS::Vertex( exp.Current() ); + if ( !checkedVV.Add( V )) continue; + + const SMDS_MeshNode* n = SMESH_Algo::VertexNode( V, mesh.GetMeshDS() ); + if ( !n ) continue; + + int nbQuads = 0; + SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + if ( !faceIDs.count( f->getshapeId() )) continue; + + if ( f->NbCornerNodes() == 4 ) + ++nbQuads; + else + nbQuads = 100; + } + if ( nbQuads == 3 ) + cornerVV.Add( V ); + } + } + + //================================================================================ + /*! + * \brief Return EDGEs dividing one box side + */ + //================================================================================ + + bool getInternalEdges( SMESH_Mesh& mesh, + const TopoDS_Shape& shape, + const TopTools_MapOfShape& cornerVV, + TopTools_MapOfShape& internEE) + { + TopTools_IndexedMapOfShape subEE, subFF; + TopExp::MapShapes( shape, TopAbs_EDGE, subEE ); + TopExp::MapShapes( shape, TopAbs_FACE, subFF ); + + TopoDS_Vertex VV[2]; + TopTools_MapOfShape subChecked/*, ridgeEE*/; + TopTools_MapIteratorOfMapOfShape vIt( cornerVV ); + for ( ; vIt.More(); vIt.Next() ) + { + TopoDS_Shape V0 = vIt.Key(); + // walk from one corner VERTEX to another along ridge EDGEs + PShapeIteratorPtr riIt = SMESH_MesherHelper::GetAncestors( V0, mesh, TopAbs_EDGE ); + while ( const TopoDS_Shape* riE = riIt->next() ) + { + if ( !subEE.Contains( *riE ) || !subChecked.Add( *riE )) + continue; + TopoDS_Edge ridgeE = TopoDS::Edge( *riE ); + while ( !ridgeE.IsNull() ) + { + TopExp::Vertices( ridgeE, VV[0], VV[1] ); + TopoDS_Shape V1 = VV[ V0.IsSame( VV[0] )]; + if ( cornerVV.Contains( V1 ) ) + break; // ridgeE reached a corner VERTEX + + // detect internal EDGEs among those sharing V1. There can be 2, 3 or 4 EDGEs and + // number of internal EDGEs is N-2 + TopoDS_Shape nextRidgeE; + PShapeIteratorPtr eIt = SMESH_MesherHelper::GetAncestors( V1, mesh, TopAbs_EDGE ); + while ( const TopoDS_Shape* E = eIt->next() ) + { + if ( E->IsSame( ridgeE ) || !subEE.Contains( *E ) || !subChecked.Add( *E )) + continue; + // look for FACEs sharing both E and ridgeE + PShapeIteratorPtr fIt = SMESH_MesherHelper::GetAncestors( *E, mesh, TopAbs_FACE ); + while ( const TopoDS_Shape* F = fIt->next() ) + { + if ( !SMESH_MesherHelper::IsSubShape( ridgeE, *F )) + continue; + if ( isContinuousMesh( ridgeE, TopoDS::Edge( *E ), TopoDS::Face( *F ), mesh )) + { + nextRidgeE = *E; + } + else + { + internEE.Add( *E ); + } + break; + } + } + // look for the next ridge EDGE ending at V1 + if ( nextRidgeE.IsNull() ) + { + eIt = SMESH_MesherHelper::GetAncestors( V1, mesh, TopAbs_EDGE ); + while ( const TopoDS_Shape* E = eIt->next() ) + if ( !ridgeE.IsSame( *E ) && !internEE.Contains( *E ) && subEE.Contains( *E )) + { + nextRidgeE = *E; + break; + } + } + ridgeE = TopoDS::Edge( nextRidgeE ); + V0 = V1; + + if ( ridgeE.IsNull() ) + return false; + } // check EDGEs around the last VERTEX of ridgeE + } // loop on ridge EDGEs around a corner VERTEX + } // loop on on corner VERTEXes + + return true; + } // getInternalEdges() +} // namespace + //================================================================================ /*! - * \brief Computes hexahedral mesh on a box with composite sides - * \param aMesh - mesh to compute - * \param aShape - shape to mesh - * \retval bool - succes sign + * \brief Tries to find 6 sides of a box */ //================================================================================ -bool StdMeshers_CompositeHexa_3D::Compute(SMESH_Mesh& theMesh, - const TopoDS_Shape& theShape) +bool StdMeshers_CompositeHexa_3D::findBoxFaces( const TopoDS_Shape& shape, + list< _QuadFaceGrid >& boxFaces, + SMESH_Mesh& mesh, + _QuadFaceGrid * & fBottom, + _QuadFaceGrid * & fTop, + _QuadFaceGrid * & fFront, + _QuadFaceGrid * & fBack, + _QuadFaceGrid * & fLeft, + _QuadFaceGrid * & fRight) { - SMESH_MesherHelper helper( theMesh ); - _quadraticMesh = helper.IsQuadraticSubMesh( theShape ); - helper.SetElementsOnShape( true ); - - // ------------------------- - // Try to find 6 side faces - // ------------------------- - vector< _QuadFaceGrid > boxFaces; boxFaces.reserve( 6 ); + TopTools_MapOfShape cornerVertices; + getBlockCorners( mesh, shape, cornerVertices ); + if ( cornerVertices.Extent() != 8 ) + return error( COMPERR_BAD_INPUT_MESH, "Can't find 8 corners of a block by 2D mesh" ); + TopTools_MapOfShape internalEdges; + if ( !getInternalEdges( mesh, shape, cornerVertices, internalEdges )) + return error( COMPERR_BAD_INPUT_MESH, "2D mesh is not suitable for i,j,k hexa meshing" ); + + list< _QuadFaceGrid >::iterator boxFace; TopExp_Explorer exp; - int iFace, nbFaces = 0; - for ( exp.Init(theShape, TopAbs_FACE); exp.More(); exp.Next(), ++nbFaces ) + int nbFaces = 0; + for ( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next(), ++nbFaces ) { _QuadFaceGrid f; - if ( !f.Init( TopoDS::Face( exp.Current() ))) + if ( !f.Init( TopoDS::Face( exp.Current() ), mesh )) return error (COMPERR_BAD_SHAPE); - bool isContinuous = false; - for ( int i=0; i < boxFaces.size() && !isContinuous; ++i ) - isContinuous = boxFaces[ i ].AddContinuousFace( f ); - if ( !isContinuous ) + + _QuadFaceGrid* prevContinuous = 0; + for ( boxFace = boxFaces.begin(); boxFace != boxFaces.end(); ++boxFace ) + { + if ( prevContinuous ) + { + if ( prevContinuous->AddContinuousFace( *boxFace, internalEdges )) + boxFace = --boxFaces.erase( boxFace ); + } + else if ( boxFace->AddContinuousFace( f, internalEdges )) + { + prevContinuous = & (*boxFace); + } + } + if ( !prevContinuous ) boxFaces.push_back( f ); } // Check what we have @@ -327,29 +504,30 @@ bool StdMeshers_CompositeHexa_3D::Compute(SMESH_Mesh& theMesh, if ( boxFaces.size() != 6 && nbFaces == 6 ) { // strange ordinary box with continuous faces boxFaces.resize( 6 ); - iFace = 0; - for ( exp.Init(theShape, TopAbs_FACE); exp.More(); exp.Next(), ++iFace ) - boxFaces[ iFace ].Init( TopoDS::Face( exp.Current() ) ); + boxFace = boxFaces.begin(); + for ( exp.Init( shape, TopAbs_FACE); exp.More(); exp.Next(), ++boxFace ) + boxFace->Init( TopoDS::Face( exp.Current() ), mesh ); } // ---------------------------------------- // Find out position of faces within a box // ---------------------------------------- - - _QuadFaceGrid *fBottom, *fTop, *fFront, *fBack, *fLeft, *fRight; // start from a bottom face - fBottom = &boxFaces[0]; + fBottom = &boxFaces.front(); + fBottom->SetID( B_BOTTOM ); // find vertical faces - fFront = fBottom->FindAdjacentForSide( Q_BOTTOM, boxFaces ); - fLeft = fBottom->FindAdjacentForSide( Q_RIGHT, boxFaces ); - fBack = fBottom->FindAdjacentForSide( Q_TOP, boxFaces ); - fRight = fBottom->FindAdjacentForSide( Q_LEFT, boxFaces ); + fFront = fBottom->FindAdjacentForSide( Q_BOTTOM, boxFaces, B_FRONT ); + fLeft = fBottom->FindAdjacentForSide( Q_RIGHT, boxFaces, B_LEFT ); + fBack = fBottom->FindAdjacentForSide( Q_TOP, boxFaces, B_BACK ); + fRight = fBottom->FindAdjacentForSide( Q_LEFT, boxFaces, B_RIGHT ); // check the found if ( !fFront || !fBack || !fLeft || !fRight ) return error(COMPERR_BAD_SHAPE); - // top face + // find a top face fTop = 0; - for ( int i=1; i < boxFaces.size() && !fTop; ++i ) { - fTop = & boxFaces[ i ]; + for ( boxFace = ++boxFaces.begin(); boxFace != boxFaces.end() && !fTop; ++boxFace ) + { + fTop = & (*boxFace); + fTop->SetID( B_TOP ); if ( fTop==fFront || fTop==fLeft || fTop==fBack || fTop==fRight ) fTop = 0; } @@ -369,18 +547,39 @@ bool StdMeshers_CompositeHexa_3D::Compute(SMESH_Mesh& theMesh, if ( !fTop ) return error(COMPERR_BAD_SHAPE); - fBottom->SetID( B_BOTTOM ); - fBack ->SetID( B_BACK ); - fLeft ->SetID( B_LEFT ); - fFront ->SetID( B_FRONT ); - fRight ->SetID( B_RIGHT ); - fTop ->SetID( B_TOP ); - // orient bottom egde of faces along axes of the unit box fBottom->ReverseEdges(); fBack ->ReverseEdges(); fLeft ->ReverseEdges(); + return true; +} + +//================================================================================ +/*! + * \brief Computes hexahedral mesh on a box with composite sides + * \param aMesh - mesh to compute + * \param aShape - shape to mesh + * \retval bool - succes sign + */ +//================================================================================ + +bool StdMeshers_CompositeHexa_3D::Compute(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape) +{ + SMESH_MesherHelper helper( theMesh ); + _quadraticMesh = helper.IsQuadraticSubMesh( theShape ); + helper.SetElementsOnShape( true ); + + // ------------------------- + // Try to find 6 side faces + // ------------------------- + list< _QuadFaceGrid > boxFaceContainer; + _QuadFaceGrid *fBottom, *fTop, *fFront, *fBack, *fLeft, *fRight; + if ( ! findBoxFaces( theShape, boxFaceContainer, theMesh, + fBottom, fTop, fFront, fBack, fLeft, fRight)) + return false; + // ------------------------------------------ // Fill columns of nodes with existing nodes // ------------------------------------------ @@ -434,7 +633,7 @@ bool StdMeshers_CompositeHexa_3D::Compute(SMESH_Mesh& theMesh, // ---------------------------- // Add internal nodes of a box // ---------------------------- - // projection points of internal nodes on box subshapes by which + // projection points of internal nodes on box sub-shapes by which // coordinates of internal nodes are computed vector pointsOnShapes( SMESH_Block::ID_Shell ); @@ -503,7 +702,7 @@ bool StdMeshers_CompositeHexa_3D::Compute(SMESH_Mesh& theMesh, } } // faces no more needed, free memory - boxFaces.clear(); + boxFaceContainer.clear(); // ---------------- // Add hexahedrons @@ -525,6 +724,90 @@ bool StdMeshers_CompositeHexa_3D::Compute(SMESH_Mesh& theMesh, return true; } +//================================================================================ +/*! + * Evaluate + */ +//================================================================================ + +bool StdMeshers_CompositeHexa_3D::Evaluate(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + MapShapeNbElems& aResMap) +{ + // ------------------------- + // Try to find 6 side faces + // ------------------------- + list< _QuadFaceGrid > boxFaceContainer; + _QuadFaceGrid *fBottom, *fTop, *fFront, *fBack, *fLeft, *fRight; + if ( ! findBoxFaces( theShape, boxFaceContainer, theMesh, + fBottom, fTop, fFront, fBack, fLeft, fRight)) + return false; + + // Find a less complex side + _QuadFaceGrid * lessComplexSide = & boxFaceContainer.front(); + list< _QuadFaceGrid >::iterator face = boxFaceContainer.begin(); + for ( ++face; face != boxFaceContainer.end() && lessComplexSide->IsComplex(); ++face ) + if ( face->NbChildren() < lessComplexSide->NbChildren() ) + lessComplexSide = & *face; + + // Get an 1D size of lessComplexSide + int nbSeg1 = 0; + vector edges; + if ( !lessComplexSide->GetHoriEdges(edges) ) + return false; + for ( size_t i = 0; i < edges.size(); ++i ) + { + const vector& nbElems = aResMap[ theMesh.GetSubMesh( edges[i] )]; + if ( !nbElems.empty() ) + nbSeg1 += Max( nbElems[ SMDSEntity_Edge ], nbElems[ SMDSEntity_Quad_Edge ]); + } + + // Get an 1D size of a box side ortogonal to lessComplexSide + int nbSeg2 = 0; + _QuadFaceGrid* ortoSide = + lessComplexSide->FindAdjacentForSide( Q_LEFT, boxFaceContainer, B_UNDEFINED ); + edges.clear(); + if ( !ortoSide || !ortoSide->GetHoriEdges(edges) ) return false; + for ( size_t i = 0; i < edges.size(); ++i ) + { + const vector& nbElems = aResMap[ theMesh.GetSubMesh( edges[i] )]; + if ( !nbElems.empty() ) + nbSeg2 += Max( nbElems[ SMDSEntity_Edge ], nbElems[ SMDSEntity_Quad_Edge ]); + } + + // Get an 2D size of a box side ortogonal to lessComplexSide + int nbFaces = 0, nbQuadFace = 0; + list< TopoDS_Face > sideFaces; + if ( ortoSide->IsComplex() ) + for ( _QuadFaceGrid::TChildIterator child = ortoSide->GetChildren(); child.more(); ) + sideFaces.push_back( child.next().GetFace() ); + else + sideFaces.push_back( ortoSide->GetFace() ); + // + list< TopoDS_Face >::iterator f = sideFaces.begin(); + for ( ; f != sideFaces.end(); ++f ) + { + const vector& nbElems = aResMap[ theMesh.GetSubMesh( *f )]; + if ( !nbElems.empty() ) + { + nbFaces = nbElems[ SMDSEntity_Quadrangle ]; + nbQuadFace = nbElems[ SMDSEntity_Quad_Quadrangle ]; + } + } + + // Fill nb of elements + vector aResVec(SMDSEntity_Last,0); + int nbSeg3 = ( nbFaces + nbQuadFace ) / nbSeg2; + aResVec[SMDSEntity_Node] = (nbSeg1-1) * (nbSeg2-1) * (nbSeg3-1); + aResVec[SMDSEntity_Hexa] = nbSeg1 * nbFaces; + aResVec[SMDSEntity_Quad_Hexa] = nbSeg1 * nbQuadFace; + + aResMap.insert( make_pair( theMesh.GetSubMesh(theShape), aResVec )); + + return true; +} + + //================================================================================ /*! * \brief constructor of non-initialized _QuadFaceGrid @@ -542,7 +825,7 @@ _QuadFaceGrid::_QuadFaceGrid(): */ //================================================================================ -bool _QuadFaceGrid::Init(const TopoDS_Face& f) +bool _QuadFaceGrid::Init(const TopoDS_Face& f, SMESH_Mesh& mesh) { myFace = f; mySides = _FaceSide(); @@ -553,10 +836,9 @@ bool _QuadFaceGrid::Init(const TopoDS_Face& f) //if ( myFace.Orientation() != TopAbs_FORWARD ) //myFace.Reverse(); - TopoDS_Vertex V; list< TopoDS_Edge > edges; list< int > nbEdgesInWire; - int nbWire = SMESH_Block::GetOrderedEdges (myFace, V, edges, nbEdgesInWire); + int nbWire = SMESH_Block::GetOrderedEdges (myFace, edges, nbEdgesInWire); if ( nbWire != 1 ) return false; @@ -578,6 +860,12 @@ bool _QuadFaceGrid::Init(const TopoDS_Face& f) else if ( SMESH_Algo::IsContinuous( sideEdges.front(), edges.back() )) { sideEdges.splice( sideEdges.begin(), edges, --edges.end()); } + else if ( isContinuousMesh( sideEdges.back(), edges.front(), f, mesh )) { + sideEdges.splice( sideEdges.end(), edges, edges.begin()); + } + else if ( isContinuousMesh( sideEdges.front(), edges.back(), f, mesh )) { + sideEdges.splice( sideEdges.begin(), edges, --edges.end()); + } else { break; } @@ -604,29 +892,17 @@ bool _QuadFaceGrid::Init(const TopoDS_Face& f) */ //================================================================================ -bool _QuadFaceGrid::AddContinuousFace( const _QuadFaceGrid& other ) +bool _QuadFaceGrid::AddContinuousFace( const _QuadFaceGrid& other, + const TopTools_MapOfShape& internalEdges) { - for ( int i = 0; i < 4; ++i ) { + for ( int i = 0; i < 4; ++i ) + { const _FaceSide& otherSide = other.GetSide( i ); int iMyCommon; - if ( mySides.Contain( otherSide, &iMyCommon ) ) { - // check if normals of two faces are collinear at all vertices of a otherSide - const double angleTol = PI / 180 / 2; - int iV, nbV = otherSide.NbVertices(), nbCollinear = 0; - for ( iV = 0; iV < nbV; ++iV ) + if ( mySides.Contain( otherSide, &iMyCommon ) ) + { + if ( internalEdges.Contains( otherSide.Edge( 0 ))) { - TopoDS_Vertex v = otherSide.Vertex( iV ); - gp_Vec n1, n2; - if ( !GetNormal( v, n1 ) || !other.GetNormal( v, n2 )) - continue; - if ( n1 * n2 < 0 ) - n1.Reverse(); - if ( n1.Angle(n2) < angleTol ) - nbCollinear++; - else - break; - } - if ( nbCollinear > 1 ) { // this face becomes composite if not yet is DUMP_VERT("Cont 1", mySides.GetSide(iMyCommon)->FirstVertex()); DUMP_VERT("Cont 2", mySides.GetSide(iMyCommon)->LastVertex()); DUMP_VERT("Cont 3", otherSide.FirstVertex()); @@ -635,14 +911,33 @@ bool _QuadFaceGrid::AddContinuousFace( const _QuadFaceGrid& other ) myChildren.push_back( *this ); myFace.Nullify(); } - myChildren.push_back( other ); + + // orient new children equally int otherBottomIndex = ( 4 + i - iMyCommon + 2 ) % 4; - myChildren.back().SetBottomSide( other.GetSide( otherBottomIndex )); + if ( other.IsComplex() ) + for ( TChildIterator children = other.GetChildren(); children.more(); ) { + myChildren.push_back( children.next() ); + myChildren.back().SetBottomSide( myChildren.back().GetSide( otherBottomIndex )); + } + else { + myChildren.push_back( other ); + myChildren.back().SetBottomSide( myChildren.back().GetSide( otherBottomIndex )); + } + + myLeftBottomChild = 0; + // collect vertices in mySides - mySides.AppendSide( other.GetSide(0) ); - mySides.AppendSide( other.GetSide(1) ); - mySides.AppendSide( other.GetSide(2) ); - mySides.AppendSide( other.GetSide(3) ); + if ( other.IsComplex() ) + for ( TChildIterator children = other.GetChildren(); children.more(); ) + { + const _QuadFaceGrid& child = children.next(); + for ( int i = 0; i < 4; ++i ) + mySides.AppendSide( child.GetSide(i) ); + } + else + for ( int i = 0; i < 4; ++i ) + mySides.AppendSide( other.GetSide(i) ); + return true; } } @@ -697,12 +992,17 @@ bool _QuadFaceGrid::SetBottomSide(const _FaceSide& bottom, int* sideIndex) */ //================================================================================ -_QuadFaceGrid* _QuadFaceGrid::FindAdjacentForSide(int i, vector<_QuadFaceGrid>& faces) const +_QuadFaceGrid* _QuadFaceGrid::FindAdjacentForSide(int i, + list<_QuadFaceGrid>& faces, + EBoxSides id) const { - for ( int iF = 0; iF < faces.size(); ++iF ) { - _QuadFaceGrid* f = &faces[ iF ]; - if ( f != this && f->SetBottomSide( GetSide( i ))) - return f; + const _FaceSide & iSide = GetSide( i ); + list< _QuadFaceGrid >::iterator boxFace = faces.begin(); + for ( ; boxFace != faces.end(); ++boxFace ) + { + _QuadFaceGrid* f = & (*boxFace); + if ( f != this && f->SetBottomSide( iSide )) + return f->SetID( id ), f; } return (_QuadFaceGrid*) 0; } @@ -798,6 +1098,13 @@ bool _QuadFaceGrid::LoadGrid( SMESH_Mesh& mesh ) if ( !myGrid.empty() ) return true; + SMESHDS_SubMesh* faceSubMesh = mesh.GetSubMesh( myFace )->GetSubMeshDS(); + // check that all faces are quadrangular + SMDS_ElemIteratorPtr fIt = faceSubMesh->GetElements(); + while ( fIt->more() ) + if ( fIt->next()->NbNodes() % 4 > 0 ) + return error("Non-quadrangular mesh faces are not allowed on sides of a composite block"); + myIndexer._xSize = 1 + mySides.GetSide( Q_BOTTOM )->GetNbSegments( mesh ); myIndexer._ySize = 1 + mySides.GetSide( Q_LEFT )->GetNbSegments( mesh ); @@ -808,11 +1115,9 @@ bool _QuadFaceGrid::LoadGrid( SMESH_Mesh& mesh ) // store the rest nodes row by row - SMESHDS_SubMesh* faceSubMesh = mesh.GetSubMesh( myFace )->GetSubMeshDS(); + TIDSortedElemSet emptySet, avoidSet; + const SMDS_MeshElement* firstQuad = 0; // most left face above the last row of found nodes - SMDS_MeshNode dummy(0,0,0); - const SMDS_MeshElement* firstQuad = &dummy;// most left face above the last row of found nodes - int nbFoundNodes = myIndexer._xSize; while ( nbFoundNodes != myGrid.size() ) { @@ -829,12 +1134,10 @@ bool _QuadFaceGrid::LoadGrid( SMESH_Mesh& mesh ) // o---o o o o o //n1down n2down // - TIDSortedElemSet emptySet, avoidSet; - avoidSet.insert( firstQuad ); - firstQuad = SMESH_MeshEditor::FindFaceInSet( n1down, n2down, emptySet, avoidSet); + firstQuad = SMESH_MeshAlgos::FindFaceInSet( n1down, n2down, emptySet, avoidSet); while ( firstQuad && !faceSubMesh->Contains( firstQuad )) { avoidSet.insert( firstQuad ); - firstQuad = SMESH_MeshEditor::FindFaceInSet( n1down, n2down, emptySet, avoidSet); + firstQuad = SMESH_MeshAlgos::FindFaceInSet( n1down, n2down, emptySet, avoidSet); } if ( !firstQuad || !faceSubMesh->Contains( firstQuad )) return error(ERR_LI("Error in _QuadFaceGrid::LoadGrid()")); @@ -864,7 +1167,7 @@ bool _QuadFaceGrid::LoadGrid( SMESH_Mesh& mesh ) { // next face avoidSet.clear(); avoidSet.insert( quad ); - quad = SMESH_MeshEditor::FindFaceInSet( n1down, n1up, emptySet, avoidSet ); + quad = SMESH_MeshAlgos::FindFaceInSet( n1down, n1up, emptySet, avoidSet ); if ( !quad || quad->NbNodes() % 4 > 0) return error(ERR_LI("Error in _QuadFaceGrid::LoadGrid()")); @@ -877,8 +1180,8 @@ bool _QuadFaceGrid::LoadGrid( SMESH_Mesh& mesh ) n1down = myGrid[ nbFoundNodes - myIndexer._xSize - 1 ]; n1up = n2up; } + avoidSet.clear(); avoidSet.insert( firstQuad ); } - DumpGrid(); // debug return true; @@ -971,21 +1274,22 @@ void _QuadFaceGrid::setBrothers( set< _QuadFaceGrid* >& notLocatedBrothers ) TopoDS_Vertex rightVertex = GetSide( Q_BOTTOM ).LastVertex(); DUMP_VERT("1 right bottom Vertex: ",rightVertex ); set< _QuadFaceGrid* >::iterator brIt, brEnd = notLocatedBrothers.end(); - for ( brIt = notLocatedBrothers.begin(); !myRightBrother && brIt != brEnd; ++brIt ) + for ( brIt = notLocatedBrothers.begin(); brIt != brEnd; ++brIt ) { _QuadFaceGrid* brother = *brIt; TopoDS_Vertex brotherLeftVertex = brother->GetSide( Q_BOTTOM ).FirstVertex(); DUMP_VERT( "brother left bottom: ", brotherLeftVertex ); if ( rightVertex.IsSame( brotherLeftVertex )) { myRightBrother = brother; - notLocatedBrothers.erase( myRightBrother ); + notLocatedBrothers.erase( brIt ); + break; } } // find upper brother TopoDS_Vertex upVertex = GetSide( Q_LEFT ).FirstVertex(); DUMP_VERT("1 left up Vertex: ",upVertex); brIt = notLocatedBrothers.begin(), brEnd = notLocatedBrothers.end(); - for ( ; !myUpBrother && brIt != brEnd; ++brIt ) + for ( ; brIt != brEnd; ++brIt ) { _QuadFaceGrid* brother = *brIt; TopoDS_Vertex brotherLeftVertex = brother->GetSide( Q_BOTTOM ).FirstVertex(); @@ -993,6 +1297,7 @@ void _QuadFaceGrid::setBrothers( set< _QuadFaceGrid* >& notLocatedBrothers ) if ( upVertex.IsSame( brotherLeftVertex )) { myUpBrother = brother; notLocatedBrothers.erase( myUpBrother ); + break; } } // recursive call @@ -1090,6 +1395,35 @@ int _QuadFaceGrid::GetNbVertSegments(SMESH_Mesh& mesh, bool withBrothers) const return nbSegs; } +//================================================================================ +/*! + * \brief Return edge on the hirizontal bottom sides + */ +//================================================================================ + +int _QuadFaceGrid::GetHoriEdges(vector & edges) const +{ + if ( myLeftBottomChild ) + { + return myLeftBottomChild->GetHoriEdges( edges ); + } + else + { + const _FaceSide* bottom = mySides.GetSide( Q_BOTTOM ); + int i = 0; + while ( true ) { + TopoDS_Edge e = bottom->Edge( i++ ); + if ( e.IsNull() ) + break; + else + edges.push_back( e ); + } + if ( myRightBrother ) + myRightBrother->GetHoriEdges( edges ); + } + return edges.size(); +} + //================================================================================ /*! * \brief Return a node by its position @@ -1279,12 +1613,7 @@ _FaceSide* _FaceSide::GetSide(const int i) if ( i >= myNbChildren ) return 0; - #ifdef __BORLANDC__ - vector< _FaceSide >::iterator side = myChildren.begin(); - #else list< _FaceSide >::iterator side = myChildren.begin(); - #endif - if ( i ) std::advance( side, i ); return & (*side); @@ -1309,14 +1638,28 @@ int _FaceSide::NbVertices() const { if ( myChildren.empty() ) return myVertices.Extent(); -// return myVertices.size(); return myNbChildren + 1; } +//======================================================================= +//function : NbCommonVertices +//purpose : Returns number of my vertices common with the given ones +//======================================================================= + +int _FaceSide::NbCommonVertices( const TopTools_MapOfShape& VV ) const +{ + int nbCommon = 0; + TopTools_MapIteratorOfMapOfShape vIt ( myVertices ); + for ( ; vIt.More(); vIt.Next() ) + nbCommon += ( VV.Contains( vIt.Key() )); + + return nbCommon; +} + //======================================================================= //function : FirstVertex -//purpose : +//purpose : //======================================================================= TopoDS_Vertex _FaceSide::FirstVertex() const @@ -1356,6 +1699,23 @@ TopoDS_Vertex _FaceSide::Vertex(int i) const return GetSide(i)->FirstVertex(); } +//================================================================================ +/*! + * \brief Return i-the zero-based edge of the side + */ +//================================================================================ + +TopoDS_Edge _FaceSide::Edge(int i) const +{ + if ( i == 0 && !myEdge.IsNull() ) + return myEdge; + + if ( const _FaceSide* iSide = GetSide( i )) + return iSide->myEdge; + + return TopoDS_Edge(); +} + //======================================================================= //function : Contain //purpose : @@ -1368,21 +1728,12 @@ bool _FaceSide::Contain( const _FaceSide& side, int* which ) const if ( which ) *which = 0; int nbCommon = 0; -// set::iterator v, vEnd = side.myVertices.end(); -// for ( v = side.myVertices.begin(); v != vEnd; ++v ) -// nbCommon += ( myVertices.find( *v ) != myVertices.end() ); TopTools_MapIteratorOfMapOfShape vIt ( side.myVertices ); for ( ; vIt.More(); vIt.Next() ) nbCommon += ( myVertices.Contains( vIt.Key() )); return (nbCommon > 1); } - - #ifdef __BORLANDC__ - vector< _FaceSide >::const_iterator mySide = myChildren.begin(), sideEnd = myChildren.end(); - #else list< _FaceSide >::const_iterator mySide = myChildren.begin(), sideEnd = myChildren.end(); - #endif - for ( int i = 0; mySide != sideEnd; ++mySide, ++i ) { if ( mySide->Contain( side )) { *which = i; @@ -1400,7 +1751,6 @@ bool _FaceSide::Contain( const _FaceSide& side, int* which ) const bool _FaceSide::Contain( const TopoDS_Vertex& vertex ) const { return myVertices.Contains( vertex ); -// return myVertices.find( ptr( vertex )) != myVertices.end(); } //======================================================================= @@ -1418,7 +1768,6 @@ void _FaceSide::AppendSide( const _FaceSide& side ) } myChildren.push_back( side ); myNbChildren++; - //myVertices.insert( side.myVertices.begin(), side.myVertices.end() ); TopTools_MapIteratorOfMapOfShape vIt ( side.myVertices ); for ( ; vIt.More(); vIt.Next() ) myVertices.Add( vIt.Key() ); @@ -1435,38 +1784,15 @@ void _FaceSide::AppendSide( const _FaceSide& side ) void _FaceSide::SetBottomSide( int i ) { if ( i > 0 && myID == Q_PARENT ) { - - #ifdef __BORLANDC__ - list< _FaceSide > aList; - aList.clear(); - - aList.assign(myChildren.begin(), myChildren.end()); - myChildren.clear(); - - list< _FaceSide >::iterator sideEnd, side = aList.begin(); - std::advance( side, i ); - aList.splice( aList.begin(), aList, side, aList.end() ); - side = aList.begin(), sideEnd = aList.end(); - for ( int i = 0; side != sideEnd; ++side, ++i ) { - side->SetID( EQuadSides(i) ); - side->SetBottomSide(i); - } - - myChildren.assign(aList.begin(), aList.end()); - aList.clear(); - - #else - list< _FaceSide >::iterator sideEnd, side = myChildren.begin(); std::advance( side, i ); myChildren.splice( myChildren.begin(), myChildren, side, myChildren.end() ); + side = myChildren.begin(), sideEnd = myChildren.end(); for ( int i = 0; side != sideEnd; ++side, ++i ) { side->SetID( EQuadSides(i) ); side->SetBottomSide(i); } - - #endif } } @@ -1484,12 +1810,7 @@ int _FaceSide::GetNbSegments(SMESH_Mesh& mesh) const } else { - #ifdef __BORLANDC__ - vector< _FaceSide >::const_iterator side = myChildren.begin(), sideEnd = myChildren.end(); - #else list< _FaceSide >::const_iterator side = myChildren.begin(), sideEnd = myChildren.end(); - #endif - for ( ; side != sideEnd; ++side ) nb += side->GetNbSegments(mesh); } @@ -1512,12 +1833,7 @@ bool _FaceSide::StoreNodes(SMESH_Mesh& mesh, } else { - #ifdef __BORLANDC__ - vector< _FaceSide >::const_iterator side = myChildren.begin(), sideEnd = myChildren.end(); - #else list< _FaceSide >::const_iterator side = myChildren.begin(), sideEnd = myChildren.end(); - #endif - for ( ; side != sideEnd; ++side ) if ( reverse ) edges.push_front( side->myEdge ); @@ -1578,12 +1894,7 @@ void _FaceSide::Dump() const } else { - #ifdef __BORLANDC__ - vector< _FaceSide >::const_iterator side = myChildren.begin(), sideEnd = myChildren.end(); - #else list< _FaceSide >::const_iterator side = myChildren.begin(), sideEnd = myChildren.end(); - #endif - for ( ; side != sideEnd; ++side ) { side->Dump(); cout << "\t"; diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_CompositeSegment_1D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_CompositeSegment_1D.cpp index 4c3d5e16738b..53e6d1c3ff9d 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_CompositeSegment_1D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_CompositeSegment_1D.cpp @@ -1,30 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions -// File : StdMeshers_Regular_1D.cxx -// Moved here from SMESH_Regular_1D.cxx -// Author : Paul RASCLE, EDF +// File : StdMeshers_CompositeSegment_1D.cxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_CompositeSegment_1D.cxx,v 1.2.2.1 2008/11/27 13:03:50 abd Exp $ // #include "StdMeshers_CompositeSegment_1D.hxx" #include "StdMeshers_FaceSide.hxx" @@ -65,6 +63,8 @@ using namespace std; namespace { + void careOfSubMeshes( StdMeshers_FaceSide& side ); + //================================================================================ /*! * \brief Search for an edge conjunct to the given one by the vertex @@ -73,15 +73,16 @@ namespace { */ //================================================================================ - TopoDS_Edge nextC1Edge(const TopoDS_Edge& edge, - SMESH_Mesh & aMesh, - const bool forward) + TopoDS_Edge nextC1Edge(TopoDS_Edge edge, + SMESH_Mesh & aMesh, + const bool forward) { + if (edge.Orientation() > TopAbs_REVERSED) // INTERNAL + edge.Orientation( TopAbs_FORWARD ); TopoDS_Edge eNext; TopTools_MapOfShape edgeCounter; edgeCounter.Add( edge ); - TopoDS_Vertex v; - v = forward ? TopExp::LastVertex( edge,1 ) : TopExp::FirstVertex( edge,1 ); + TopoDS_Vertex v = forward ? TopExp::LastVertex(edge,true) : TopExp::FirstVertex(edge,true); TopTools_ListIteratorOfListOfShape ancestIt = aMesh.GetAncestors( v ); for ( ; ancestIt.More(); ancestIt.Next() ) { @@ -92,11 +93,11 @@ namespace { if ( edgeCounter.Extent() < 3 && !eNext.IsNull() ) { if ( SMESH_Algo::IsContinuous( edge, eNext )) { // care of orientation - bool reverse; - if ( forward ) - reverse = ( !v.IsSame( TopExp::FirstVertex( eNext, true ))); - else - reverse = ( !v.IsSame( TopExp::LastVertex( eNext, true ))); + if (eNext.Orientation() > TopAbs_REVERSED) // INTERNAL + eNext.Orientation( TopAbs_FORWARD ); + TopoDS_Vertex vn = + forward ? TopExp::FirstVertex(eNext,true) : TopExp::LastVertex(eNext,true); + bool reverse = (!v.IsSame(vn)); if ( reverse ) eNext.Reverse(); return eNext; @@ -105,43 +106,6 @@ namespace { return TopoDS_Edge(); } - //================================================================================ - /*! - * \brief Update submeshes state for all edges and internal vertices, - * make them look computed even if none edge or node is set on them - */ - //================================================================================ - - void careOfSubMeshes( StdMeshers_FaceSide& side, EventListener* eListener) - { - if ( side.NbEdges() < 2) - return; - for ( int iE = 0; iE < side.NbEdges(); ++iE ) - { - // set listener and its data - EventListenerData * listenerData = new EventListenerData(true); - const TopoDS_Edge& edge = side.Edge( iE ); - SMESH_subMesh * sm = side.GetMesh()->GetSubMesh( edge ); - sm->SetEventListener( eListener, listenerData, sm ); - // add edge submesh to the data - sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); - if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK ) { - sm->SetIsAlwaysComputed( true ); - listenerData->mySubMeshes.push_back( sm ); - } - // add internal vertex submesh to the data - if ( iE ) - { - TopoDS_Vertex V = side.FirstVertex( iE ); - sm = side.GetMesh()->GetSubMesh( V ); - sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); - if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK ) - sm->SetIsAlwaysComputed( true ); - listenerData->mySubMeshes.push_back( sm ); - } - } - } - //================================================================================ /*! * \brief Class used to restore nodes on internal vertices of a complex side @@ -151,33 +115,43 @@ namespace { struct VertexNodesRestoringListener : public SMESH_subMeshEventListener { - VertexNodesRestoringListener():SMESH_subMeshEventListener(0) // won't be deleted by submesh + VertexNodesRestoringListener(): + SMESH_subMeshEventListener(1, // will be deleted by sub-mesh + "StdMeshers_CompositeSegment_1D::VertexNodesRestoringListener") {} - /*! - * \brief Restore nodes on internal vertices of a complex side - * \param event - algo_event or compute_event itself (of SMESH_subMesh) - * \param eventType - ALGO_EVENT or COMPUTE_EVENT (of SMESH_subMesh) - * \param subMesh - the submesh where the event occures - * \param data - listener data stored in the subMesh - * \param hyp - hypothesis, if eventType is algo_event - */ + static VertexNodesRestoringListener* New() { return new VertexNodesRestoringListener(); } + + /*! + * \brief Restore nodes on internal vertices of a complex side + * \param event - algo_event or compute_event itself (of SMESH_subMesh) + * \param eventType - ALGO_EVENT or COMPUTE_EVENT (of SMESH_subMesh) + * \param subMesh - the submesh where the event occures + * \param data - listener data stored in the subMesh + * \param hyp - hypothesis, if eventType is algo_event + */ void ProcessEvent(const int event, const int eventType, SMESH_subMesh* subMesh, EventListenerData* data, const SMESH_Hypothesis* /*hyp*/) { - bool hypRemoved = ( eventType == SMESH_subMesh::ALGO_EVENT && - subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK ); - if ( hypRemoved && data ) + if ( data && eventType == SMESH_subMesh::ALGO_EVENT ) { - list::iterator smIt = data->mySubMeshes.begin(); - for ( ; smIt != data->mySubMeshes.end(); ++smIt ) + bool hypRemoved; + if ( subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK ) + hypRemoved = true; + else { + SMESH_Algo* algo = subMesh->GetAlgo(); + hypRemoved = ( string( algo->GetName() ) != StdMeshers_CompositeSegment_1D::AlgoName()); + } + if ( hypRemoved ) { - if ( SMESH_subMesh* sm = *smIt ) { - sm->SetIsAlwaysComputed( false ); - sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); - } + list::iterator smIt = data->mySubMeshes.begin(); + for ( ; smIt != data->mySubMeshes.end(); ++smIt ) + if ( SMESH_subMesh* sm = *smIt ) { + sm->SetIsAlwaysComputed( false ); + sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } } } // at study restoration: @@ -203,13 +177,62 @@ namespace { ( StdMeshers_CompositeSegment_1D::GetFaceSide(*subMesh->GetFather(), edge, face, false )); if ( side->NbEdges() > 1 && side->NbSegments() ) - careOfSubMeshes( *side, this ); + careOfSubMeshes( *side ); } } } } + // clean all EDGEs of a complex side if one EDGE is cleaned + else if ( event == SMESH_subMesh::CLEAN && + eventType == SMESH_subMesh::COMPUTE_EVENT ) + { + SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(/*includeSelf=*/false); + while ( smIt->more() ) // loop on VERTEX sub-meshes + { + SMESH_subMesh* sm = smIt->next(); + if ( sm->IsAlwaysComputed() ) // it's an internal node sub-mesh + sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); + } + } } }; // struct VertexNodesRestoringListener + + //================================================================================ + /*! + * \brief Update submeshes state for all edges and internal vertices, + * make them look computed even if none edge or node is set on them + */ + //================================================================================ + + void careOfSubMeshes( StdMeshers_FaceSide& side ) + { + if ( side.NbEdges() < 2) + return; + for ( int iE = 0; iE < side.NbEdges(); ++iE ) + { + // set listener and its data + EventListenerData * listenerData = new EventListenerData(true); + const TopoDS_Edge& edge = side.Edge( iE ); + SMESH_subMesh * sm = side.GetMesh()->GetSubMesh( edge ); + sm->SetEventListener( new VertexNodesRestoringListener(), listenerData, sm ); + // add edge submesh to the data + sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK ) { + sm->SetIsAlwaysComputed( true ); + listenerData->mySubMeshes.push_back( sm ); + } + // add internal vertex submesh to the data + if ( iE ) + { + TopoDS_Vertex V = side.FirstVertex( iE ); + sm = side.GetMesh()->GetSubMesh( V ); + sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK ) + sm->SetIsAlwaysComputed( true ); + listenerData->mySubMeshes.push_back( sm ); + } + } + } } //============================================================================= @@ -224,19 +247,17 @@ StdMeshers_CompositeSegment_1D::StdMeshers_CompositeSegment_1D(int hypId :StdMeshers_Regular_1D(hypId, studyId, gen) { MESSAGE("StdMeshers_CompositeSegment_1D::StdMeshers_CompositeSegment_1D"); - _name = "CompositeSegment_1D"; - _EventListener = new VertexNodesRestoringListener(); + _name = AlgoName(); } -//============================================================================= -/*! - * - */ -//============================================================================= +//======================================================================= +//function : AlgoName +//purpose : Returns algo type name +//======================================================================= -StdMeshers_CompositeSegment_1D::~StdMeshers_CompositeSegment_1D() +std::string StdMeshers_CompositeSegment_1D::AlgoName() { - delete _EventListener; + return "CompositeSegment_1D"; } //============================================================================= @@ -280,7 +301,7 @@ void StdMeshers_CompositeSegment_1D::SetEventListener(SMESH_subMesh* subMesh) } } // set listener that will remove _alwaysComputed from submeshes at algorithm change - subMesh->SetEventListener( _EventListener, 0, subMesh); + subMesh->SetEventListener( new VertexNodesRestoringListener(), 0, subMesh); StdMeshers_Regular_1D::SetEventListener( subMesh ); } @@ -297,14 +318,17 @@ StdMeshers_CompositeSegment_1D::GetFaceSide(SMESH_Mesh& aMesh, const bool ignoreMeshed) { list< TopoDS_Edge > edges; - edges.push_back( anEdge ); + if ( anEdge.Orientation() <= TopAbs_REVERSED ) + edges.push_back( anEdge ); + else + edges.push_back( TopoDS::Edge( anEdge.Oriented( TopAbs_FORWARD ))); // PAL21718 list hypList; SMESH_Algo* theAlgo = aMesh.GetGen()->GetAlgo( aMesh, anEdge ); if ( theAlgo ) hypList = theAlgo->GetUsedHypothesis(aMesh, anEdge, false); for ( int forward = 0; forward < 2; ++forward ) { - TopoDS_Edge eNext = nextC1Edge( anEdge, aMesh, forward ); + TopoDS_Edge eNext = nextC1Edge( edges.back(), aMesh, forward ); while ( !eNext.IsNull() ) { if ( ignoreMeshed ) { // eNext must not have computed mesh @@ -318,6 +342,8 @@ StdMeshers_CompositeSegment_1D::GetFaceSide(SMESH_Mesh& aMesh, string(theAlgo->GetName()) != algo->GetName() || hypList != algo->GetUsedHypothesis(aMesh, eNext, false)) break; + if ( std::find( edges.begin(), edges.end(), eNext ) != edges.end() ) + break; if ( forward ) edges.push_back( eNext ); else @@ -375,6 +401,15 @@ bool StdMeshers_CompositeSegment_1D::Compute(SMESH_Mesh & aMesh, // Create mesh + // compute and get nodes on extremity VERTEX'es + SMESH_subMesh* smVFirst = aMesh.GetSubMesh( VFirst ); + smVFirst->SetIsAlwaysComputed( false ); + smVFirst->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + // + SMESH_subMesh* smVLast = aMesh.GetSubMesh( VLast ); + smVLast->SetIsAlwaysComputed( false ); + smVLast->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + // const SMDS_MeshNode * nFirst = SMESH_Algo::VertexNode( VFirst, meshDS ); const SMDS_MeshNode * nLast = SMESH_Algo::VertexNode( VLast, meshDS ); if (!nFirst) @@ -438,7 +473,7 @@ bool StdMeshers_CompositeSegment_1D::Compute(SMESH_Mesh & aMesh, // Update submeshes state for all edges and internal vertices, // make them look computed even if none edge or node is set on them - careOfSubMeshes( *side, _EventListener ); + careOfSubMeshes( *side ); return true; } diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Deflection1D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Deflection1D.cpp index 5033aa8127dc..3ef2d81ccd3a 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Deflection1D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Deflection1D.cpp @@ -1,28 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH StdMeshers_Deflection1D : implementaion of SMESH idl descriptions // File : StdMeshers_Deflection1D.cxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_Deflection1D.cxx,v 1.7.2.1 2008/11/27 13:03:49 abd Exp $ // #include "StdMeshers_Deflection1D.hxx" #include "utilities.h" @@ -76,11 +76,11 @@ StdMeshers_Deflection1D::~StdMeshers_Deflection1D() //============================================================================= void StdMeshers_Deflection1D::SetDeflection(double value) - throw(SMESH_Exception) + throw(SALOME_Exception) { if (_value != value) { if (value <= 0.) - throw SMESH_Exception(LOCALIZED("Value must be positive")); + throw SALOME_Exception(LOCALIZED("Value must be positive")); NotifySubMeshesHypothesisModification(); @@ -119,7 +119,7 @@ ostream & StdMeshers_Deflection1D::SaveTo(ostream & save) istream & StdMeshers_Deflection1D::LoadFrom(istream & load) { - bool isOK = !(load >> _value).bad(); + bool isOK = (bool)(load >> _value); if (!isOK) load.clear(ios::badbit | load.rdstate()); return load; @@ -204,7 +204,7 @@ bool StdMeshers_Deflection1D::SetParametersByMesh(const SMESH_Mesh* theMesh, { const TopoDS_Edge& edge = TopoDS::Edge( edgeMap( iE )); Handle(Geom_Curve) C = BRep_Tool::Curve( edge, L, UMin, UMax ); - GeomAdaptor_Curve AdaptCurve(C); + GeomAdaptor_Curve AdaptCurve(C, UMin, UMax); if ( AdaptCurve.GetType() != GeomAbs_Line ) { vector< double > params; @@ -234,4 +234,3 @@ bool StdMeshers_Deflection1D::SetParametersByDefaults(const TDefaults& /*dflts* { return false; } - diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Distribution.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Distribution.cpp index 6ab97173c072..d10b6faa71fd 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Distribution.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Distribution.cpp @@ -1,29 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH StdMeshers : implementaion of point distribution algorithm // File : StdMeshers_Distribution.cxx // Author : Alexandre SOLOVYOV // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_Distribution.cxx,v 1.6.2.2 2008/11/27 13:03:50 abd Exp $ +// $Header$ // #include "StdMeshers_Distribution.hxx" @@ -40,9 +41,11 @@ #ifdef NO_CAS_CATCH #include #endif - +#include using namespace std; +namespace StdMeshers { + Function::Function( const int conv ) : myConv( conv ) { @@ -304,21 +307,21 @@ double dihotomySolve( Function& f, const double val, const double _start, const } bool buildDistribution( const TCollection_AsciiString& f, const int conv, const double start, const double end, - const int nbSeg, vector& data, const double eps ) + const int nbSeg, vector& data, const double eps ) { FunctionExpr F( f.ToCString(), conv ); return buildDistribution( F, start, end, nbSeg, data, eps ); } bool buildDistribution( const std::vector& f, const int conv, const double start, const double end, - const int nbSeg, vector& data, const double eps ) + const int nbSeg, vector& data, const double eps ) { FunctionTable F( f, conv ); return buildDistribution( F, start, end, nbSeg, data, eps ); } bool buildDistribution( const Function& func, const double start, const double end, const int nbSeg, - vector& data, const double eps ) + vector& data, const double eps ) { if( nbSeg<=0 ) return false; @@ -345,3 +348,4 @@ bool buildDistribution( const Function& func, const double start, const double e data[nbSeg] = end; return true; } +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_FaceSide.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_FaceSide.cpp index 13cc6b7897d2..2625b9fb1322 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_FaceSide.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_FaceSide.cpp @@ -1,25 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMESH : implementaion of SMESH idl descriptions + // File : StdMeshers_FaceSide.hxx // Created : Wed Jan 31 18:41:25 2007 // Author : Edward AGAPOV (eap) @@ -31,7 +31,7 @@ #include "SMDS_MeshNode.hxx" #include "SMESHDS_Mesh.hxx" #include "SMESHDS_SubMesh.hxx" -//#include "SMESH_Algo.hxx" +#include "SMESH_Algo.hxx" #include "SMESH_Mesh.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_ComputeError.hxx" @@ -39,21 +39,23 @@ #include #include -#include #include #include +#include +#include +#include #include #include +#include #include #include #include #include +#include #include "utilities.h" -using namespace std; - //================================================================================ /*! * \brief Constructor of a side of one edge @@ -62,55 +64,63 @@ using namespace std; */ //================================================================================ -StdMeshers_FaceSide::StdMeshers_FaceSide(const TopoDS_Face& theFace, - const TopoDS_Edge& theEdge, - SMESH_Mesh* theMesh, - const bool theIsForward, - const bool theIgnoreMediumNodes) +StdMeshers_FaceSide::StdMeshers_FaceSide(const TopoDS_Face& theFace, + const TopoDS_Edge& theEdge, + SMESH_Mesh* theMesh, + const bool theIsForward, + const bool theIgnoreMediumNodes, + SMESH_ProxyMesh::Ptr theProxyMesh) { list edges(1,theEdge); - *this = StdMeshers_FaceSide( theFace, edges, theMesh, theIsForward, theIgnoreMediumNodes ); + *this = StdMeshers_FaceSide( theFace, edges, theMesh, theIsForward, + theIgnoreMediumNodes, theProxyMesh ); } //================================================================================ /*! * \brief Constructor of a side of several edges - * \param theFace - the face - * \param theEdge - the edge */ //================================================================================ -StdMeshers_FaceSide::StdMeshers_FaceSide(const TopoDS_Face& theFace, - list& theEdges, - SMESH_Mesh* theMesh, - const bool theIsForward, - const bool theIgnoreMediumNodes) +StdMeshers_FaceSide::StdMeshers_FaceSide(const TopoDS_Face& theFace, + list& theEdges, + SMESH_Mesh* theMesh, + const bool theIsForward, + const bool theIgnoreMediumNodes, + SMESH_ProxyMesh::Ptr theProxyMesh) { int nbEdges = theEdges.size(); - myEdge.resize( nbEdges ); - myC2d.resize( nbEdges ); - myFirst.resize( nbEdges ); - myLast.resize( nbEdges ); - myNormPar.resize( nbEdges ); - myLength = 0; - myNbPonits = myNbSegments = 0; - myMesh = theMesh; + myEdge.resize ( nbEdges ); + myEdgeID.resize ( nbEdges ); + myC2d.resize ( nbEdges ); + myC3dAdaptor.resize( nbEdges ); + myFirst.resize ( nbEdges ); + myLast.resize ( nbEdges ); + myNormPar.resize ( nbEdges ); + myEdgeLength.resize( nbEdges ); + myIsUniform.resize ( nbEdges, true ); + myFace = theFace; + myLength = 0; + myNbPonits = myNbSegments = 0; + myProxyMesh = theProxyMesh; myMissingVertexNodes = false; - myIgnoreMediumNodes = theIgnoreMediumNodes; + myIgnoreMediumNodes = theIgnoreMediumNodes; + myDefaultPnt2d = gp_Pnt2d( 1e+100, 1e+100 ); + if ( !myProxyMesh ) myProxyMesh.reset( new SMESH_ProxyMesh( *theMesh )); if ( nbEdges == 0 ) return; - SMESHDS_Mesh* meshDS = theMesh->GetMeshDS(); - vector len( nbEdges ); + SMESHDS_Mesh* meshDS = myProxyMesh->GetMeshDS(); int nbDegen = 0; list::iterator edge = theEdges.begin(); for ( int index = 0; edge != theEdges.end(); ++index, ++edge ) { - int i = theIsForward ? index : nbEdges - index - 1; - len[i] = SMESH_Algo::EdgeLength( *edge ); - if ( len[i] < DBL_MIN ) nbDegen++; - myLength += len[i]; - myEdge[i] = *edge; + int i = theIsForward ? index : nbEdges-index-1; + myEdgeLength[i] = SMESH_Algo::EdgeLength( *edge ); + if ( myEdgeLength[i] < DBL_MIN ) nbDegen++; + myLength += myEdgeLength[i]; + myEdge [i] = *edge; + myEdgeID[i] = meshDS->ShapeToIndex( *edge ); if ( !theIsForward ) myEdge[i].Reverse(); if ( theFace.IsNull() ) @@ -120,25 +130,38 @@ StdMeshers_FaceSide::StdMeshers_FaceSide(const TopoDS_Face& theFace, if ( myEdge[i].Orientation() == TopAbs_REVERSED ) std::swap( myFirst[i], myLast[i] ); - if ( SMESHDS_SubMesh* sm = meshDS->MeshElements( *edge )) { - int nbN = sm->NbNodes(); - if ( theIgnoreMediumNodes ) { - SMDS_ElemIteratorPtr elemIt = sm->GetElements(); - if ( elemIt->more() && elemIt->next()->IsQuadratic() ) - nbN -= sm->NbElements(); + // check if the edge has a non-uniform parametrization (issue 0020705) + if ( !myC2d[i].IsNull() ) + { + if ( myEdgeLength[i] > DBL_MIN ) + { + Geom2dAdaptor_Curve A2dC( myC2d[i], + std::min( myFirst[i], myLast[i] ), + std::max( myFirst[i], myLast[i] )); + double p2 = myFirst[i]+(myLast[i]-myFirst[i])/2.; + double p4 = myFirst[i]+(myLast[i]-myFirst[i])/4.; + double d2 = GCPnts_AbscissaPoint::Length( A2dC, myFirst[i], p2 ); + double d4 = GCPnts_AbscissaPoint::Length( A2dC, myFirst[i], p4 ); + //cout<<"len = "<GetProxySubMesh( myEdge[iE] ); + if ( proxySubMesh[iE] ) + { + if ( proxySubMesh[iE]->GetUVPtStructVec().empty() ) { + proxySubMesh[iE] = 0; + } + else { + nbProxyNodes += proxySubMesh[iE]->GetUVPtStructVec().size() - 1; + if ( iE+1 == myEdge.size() ) + ++nbProxyNodes; + continue; + } + } + + // Add 1st vertex node of a current edge + const SMDS_MeshNode* node = VertexNode( iE ); + const double prevNormPar = ( iE == 0 ? 0 : myNormPar[ iE-1 ]); // normalized param + if ( node ) // nodes on internal vertices may be missing + { + if ( vertexNodes.insert( node ).second || + fHelper.IsRealSeam ( node->getshapeId() ) || + fHelper.IsDegenShape( node->getshapeId() )) + u2node.insert( u2node.end(), make_pair( prevNormPar, node )); } + else if ( iE == 0 ) + { + for ( ++iE; iE < myEdge.size(); ++iE ) + if (( node = VertexNode( iE ))) { + u2node.insert( make_pair( prevNormPar, node )); + break; + } + --iE; - // put 2nd vertex node for a last edge - if ( i+1 == myEdge.size() ) { - node = SMESH_Algo::VertexNode( VLast, meshDS ); - if ( !node ) { - MESSAGE(" NO NODE on VERTEX" ); + if ( !node ) return myPoints; - } - u2node.insert( make_pair( 1., node )); + vertexNodes.insert( node ); } - // put internal nodes - SMESHDS_SubMesh* sm = meshDS->MeshElements( myEdge[i] ); - if ( !sm ) continue; - SMDS_NodeIteratorPtr nItr = sm->GetNodes(); - double paramSize = myLast[i] - myFirst[i], r = myNormPar[i] - prevNormPar; - while ( nItr->more() ) { - const SMDS_MeshNode* node = nItr->next(); - if ( myIgnoreMediumNodes && SMESH_MeshEditor::IsMedium( node, SMDSAbs_Edge )) - continue; - const SMDS_EdgePosition* epos = - static_cast(node->GetPosition().get()); - double u = epos->GetUParameter(); - // paramSize is signed so orientation is taken into account - double normPar = prevNormPar + r * ( u - myFirst[i] ) / paramSize; -#ifdef _DEBUG_ - if ( normPar > 1 || normPar < 0) { - dump("DEBUG"); - MESSAGE ( "WRONG normPar: "<second; + else + { + node = VertexNode( iE ); + while ( !node && iE > 0 ) + node = VertexNode( --iE ); + if ( !node ) + return myPoints; + } + if ( u2node.rbegin()->second == node && + !fHelper.IsRealSeam ( node->getshapeId() ) && + !fHelper.IsDegenShape( node->getshapeId() )) + u2node.erase( --u2node.end() ); + + u2node.insert( u2node.end(), make_pair( 1., node )); } - if ( u2node.size() != myNbPonits ) { + + if ( u2node.size() + nbProxyNodes != myNbPonits && + u2node.size() + nbProxyNodes != NbPoints( /*update=*/true )) + { MESSAGE("Wrong node parameters on edges, u2node.size():" <& StdMeshers_FaceSide::GetUVPtStruct(bool isXConst, // fill array of UVPtStruct - vector* points = const_cast*>( &myPoints ); - points->resize( myNbPonits ); + UVPtStructVec& points = me->myPoints; + points.resize( myNbPonits ); - int EdgeIndex = 0; - double prevNormPar = 0, paramSize = myNormPar[ EdgeIndex ]; + int iPt = 0; + double prevNormPar = 0, paramSize = myNormPar[ 0 ]; map< double, const SMDS_MeshNode*>::iterator u_node = u2node.begin(); - for (int i = 0 ; u_node != u2node.end(); ++u_node, ++i ) { - UVPtStruct & uvPt = (*points)[i]; - uvPt.node = u_node->second; - uvPt.x = uvPt.y = uvPt.normParam = u_node->first; - if ( isXConst ) uvPt.x = constValue; - else uvPt.y = constValue; - if ( myNormPar[ EdgeIndex ] < uvPt.normParam ) { - prevNormPar = myNormPar[ EdgeIndex ]; - ++EdgeIndex; -#ifdef _DEBUG_ - if ( EdgeIndex >= myEdge.size() ) { - dump("DEBUG"); - MESSAGE ( "WRONg EdgeIndex " << 1+EdgeIndex - << " myNormPar.size()="<IsSame( wireEdges.front() )) { + theError = TError + ( new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH,"No nodes on vertices")); + return TSideVector(0); + } + } } - // find out side orientation, which is important if there are several wires (PAL19080) - bool isForward = true; - if ( nbWires > 1 ) { - TopExp_Explorer e( theFace, TopAbs_EDGE ); - while ( ! e.Current().IsSame( wireEdges.back() )) - e.Next(); - isForward = ( e.Current().Orientation() == wireEdges.back().Orientation() ); + else if ( *nbE > 1 ) // Issue 0020676 (Face_pb_netgen.brep) - several internal edges in a wire + { + internalEdges.splice( internalEdges.end(), wireEdges, ++wireEdges.begin(), wireEdges.end()); } StdMeshers_FaceSide* wire = new StdMeshers_FaceSide( theFace, wireEdges, &theMesh, - isForward, theIgnoreMediumNodes); + /*isForward=*/true, theIgnoreMediumNodes, + theProxyMesh ); wires[ iW ] = StdMeshers_FaceSidePtr( wire ); from = to; } + while ( !internalEdges.empty() ) + { + StdMeshers_FaceSide* wire = new StdMeshers_FaceSide( theFace, internalEdges.back(), &theMesh, + /*isForward=*/true, theIgnoreMediumNodes, + theProxyMesh ); + wires.push_back( StdMeshers_FaceSidePtr( wire )); + internalEdges.pop_back(); + } return wires; } +//================================================================================ +/*! + * \brief Return 1st vertex of the i-the edge + */ +//================================================================================ + +TopoDS_Vertex StdMeshers_FaceSide::FirstVertex(int i) const +{ + TopoDS_Vertex v; + if ( i < NbEdges() ) + { + v = myEdge[i].Orientation() <= TopAbs_REVERSED ? // FORWARD || REVERSED + TopExp::FirstVertex( myEdge[i], 1 ) : + TopoDS::Vertex( TopoDS_Iterator( myEdge[i] ).Value() ); + } + return v; +} + +//================================================================================ +/*! + * \brief Return last vertex of the i-the edge + */ +//================================================================================ + +TopoDS_Vertex StdMeshers_FaceSide::LastVertex(int i) const +{ + TopoDS_Vertex v; + if ( i < NbEdges() ) + { + const TopoDS_Edge& edge = i<0 ? myEdge[ NbEdges() + i ] : myEdge[i]; + if ( edge.Orientation() <= TopAbs_REVERSED ) // FORWARD || REVERSED + v = TopExp::LastVertex( edge, 1 ); + else + for ( TopoDS_Iterator vIt( edge ); vIt.More(); vIt.Next() ) + v = TopoDS::Vertex( vIt.Value() ); + } + return v; +} + +//================================================================================ +/*! + * \brief Return \c true if the chain of EDGEs is closed + */ +//================================================================================ + +bool StdMeshers_FaceSide::IsClosed() const +{ + return myEdge.empty() ? false : FirstVertex().IsSame( LastVertex() ); +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_FixedPoints1D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_FixedPoints1D.cpp new file mode 100644 index 000000000000..89aa9cfc63c7 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_FixedPoints1D.cpp @@ -0,0 +1,244 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// File : StdMeshers_FixedPoints1D.cxx +// Author : Damien COQUERET, OCC +// Module : SMESH +// +#include "StdMeshers_FixedPoints1D.hxx" + +#include "SMESH_Algo.hxx" +#include "SMESH_Mesh.hxx" + +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include + +using namespace std; + +//============================================================================= +/*! + * + */ +//============================================================================= + +StdMeshers_FixedPoints1D::StdMeshers_FixedPoints1D(int hypId, int studyId, + SMESH_Gen * gen) + :SMESH_Hypothesis(hypId, studyId, gen) +{ + _name = "FixedPoints1D"; + _param_algo_dim = 1; + _nbsegs.reserve( 1 ); + _nbsegs.push_back( 1 ); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +StdMeshers_FixedPoints1D::~StdMeshers_FixedPoints1D() +{ +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +void StdMeshers_FixedPoints1D::SetPoints(std::vector& listParams) + throw(SALOME_Exception) +{ + _params = listParams; + NotifySubMeshesHypothesisModification(); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +void StdMeshers_FixedPoints1D::SetNbSegments(std::vector& listNbSeg) + throw(SALOME_Exception) +{ + _nbsegs = listNbSeg; + NotifySubMeshesHypothesisModification(); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +void StdMeshers_FixedPoints1D::SetReversedEdges( std::vector& ids ) +{ + if ( ids != _edgeIDs ) { + _edgeIDs = ids; + + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +ostream & StdMeshers_FixedPoints1D::SaveTo(ostream & save) +{ + int listSize = _params.size(); + save << listSize; + if ( listSize > 0 ) { + for ( int i = 0; i < listSize; i++) save << " " << _params[i]; + } + + listSize = _nbsegs.size(); + save << " " << listSize; + if ( listSize > 0 ) { + for ( int i = 0; i < listSize; i++) save << " " << _nbsegs[i]; + } + + listSize = _edgeIDs.size(); + save << " " << listSize; + if ( listSize > 0 ) { + for ( int i = 0; i < listSize; i++) + save << " " << _edgeIDs[i]; + } + + save << " " << _objEntry; + + return save; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +istream & StdMeshers_FixedPoints1D::LoadFrom(istream & load) +{ + bool isOK = true; + int intVal; + double dblVal; + + isOK = (bool)(load >> intVal); + if (isOK && intVal > 0) { + _params.clear(); + _params.reserve( intVal ); + for (int i = 0; i < _params.capacity() && isOK; i++) { + isOK = (bool)(load >> dblVal); + if ( isOK ) _params.push_back( dblVal ); + } + } + + isOK = (bool)(load >> intVal); + if (isOK && intVal > 0) { + _nbsegs.clear(); + _nbsegs.reserve( intVal ); + for (int i = 0; i < _nbsegs.capacity() && isOK; i++) { + isOK = (bool)(load >> intVal); + if ( isOK ) _nbsegs.push_back( intVal ); + } + } + + isOK = (bool)(load >> intVal); + if (isOK && intVal > 0) { + _edgeIDs.clear(); + _edgeIDs.reserve( intVal ); + for (int i = 0; i < _edgeIDs.capacity() && isOK; i++) { + isOK = (bool)(load >> intVal); + if ( isOK ) _edgeIDs.push_back( intVal ); + } + } + + isOK = (bool)(load >> _objEntry); + + return load; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +ostream & operator <<(ostream & save, StdMeshers_FixedPoints1D & hyp) +{ + return hyp.SaveTo( save ); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +istream & operator >>(istream & load, StdMeshers_FixedPoints1D & hyp) +{ + return hyp.LoadFrom( load ); +} + +//================================================================================ +/*! + * \brief Initialize start and end length 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 + */ +//================================================================================ + +bool StdMeshers_FixedPoints1D::SetParametersByMesh(const SMESH_Mesh* theMesh, + const TopoDS_Shape& theShape) +{ + if ( !theMesh || theShape.IsNull() ) + return false; + + _nbsegs.reserve( 1 ); + _nbsegs.push_back( 1 ); + return true; +} + +//================================================================================ +/*! + * \brief Initialize my parameter values by default parameters. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_FixedPoints1D::SetParametersByDefaults(const TDefaults& dflts, + const SMESH_Mesh* /*mesh*/) +{ + _nbsegs.reserve( 1 ); + _nbsegs.push_back( 1 ); + return true; +} + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Geometric1D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Geometric1D.cpp new file mode 100644 index 000000000000..06dd8745fa50 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Geometric1D.cpp @@ -0,0 +1,204 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// File : StdMeshers_Geometric1D.cxx +// Module : SMESH +// +#include "StdMeshers_Geometric1D.hxx" + +#include "SMESH_Mesh.hxx" + +#include +#include +#include +#include +#include +#include +#include + +//============================================================================= +/*! + * Constructor + */ +//============================================================================= + +StdMeshers_Geometric1D::StdMeshers_Geometric1D(int hypId, int studyId, SMESH_Gen * gen) + :StdMeshers_Reversible1D(hypId, studyId, gen) +{ + _begLength = 1.; + _ratio = 1.; + _name = "GeometricProgression"; +} + +//============================================================================= +/*! + * Sets length of the first segment + */ +//============================================================================= + +void StdMeshers_Geometric1D::SetStartLength(double length) + throw(SALOME_Exception) +{ + if ( _begLength != length ) + { + if (length <= 0) + throw SALOME_Exception(LOCALIZED("length must be positive")); + _begLength = length; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * Sets value of Common Ratio + */ +//============================================================================= + +void StdMeshers_Geometric1D::SetCommonRatio(double factor) + throw(SALOME_Exception) +{ + if ( _ratio != factor ) + { + if (factor == 0) + throw SALOME_Exception(LOCALIZED("Zero factor is not allowed")); + _ratio = factor; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * Returns length of the first segment + */ +//============================================================================= + +double StdMeshers_Geometric1D::GetStartLength() const +{ + return _begLength; +} + +//============================================================================= +/*! + * Returns value of Common Ratio + */ +//============================================================================= + +double StdMeshers_Geometric1D::GetCommonRatio() const +{ + return _ratio; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +ostream & StdMeshers_Geometric1D::SaveTo(ostream & save) +{ + save << _begLength << " " << _ratio << " "; + + StdMeshers_Reversible1D::SaveTo( save ); + + return save; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +istream & StdMeshers_Geometric1D::LoadFrom(istream & load) +{ + bool isOK = true; + isOK = (bool)(load >> _begLength); + isOK = (bool)(load >> _ratio); + + if (isOK) + StdMeshers_Reversible1D::LoadFrom( load ); + + return load; +} + +//================================================================================ +/*! + * \brief Initialize start and end length 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 + */ +//================================================================================ + +bool StdMeshers_Geometric1D::SetParametersByMesh(const SMESH_Mesh* theMesh, + const TopoDS_Shape& theShape) +{ + if ( !theMesh || theShape.IsNull() ) + return false; + + _begLength = _ratio = 0.; + + int nbEdges = 0; + TopTools_IndexedMapOfShape edgeMap; + TopExp::MapShapes( theShape, TopAbs_EDGE, edgeMap ); + for ( int i = 1; i <= edgeMap.Extent(); ++i ) + { + const TopoDS_Edge& edge = TopoDS::Edge( edgeMap( i )); + BRepAdaptor_Curve C( edge ); + + vector< double > params; + if ( SMESH_Algo::GetNodeParamOnEdge( theMesh->GetMeshDS(), edge, params )) + { + nbEdges++; + double l1 = GCPnts_AbscissaPoint::Length( C, params[0], params[1] ); + _begLength += l1; + if ( params.size() > 2 && l1 > 1e-100 ) + _ratio += GCPnts_AbscissaPoint::Length( C, params[1], params[2]) / l1; + else + _ratio += 1; + } + } + if ( nbEdges ) { + _begLength /= nbEdges; + _ratio /= nbEdges; + } + else { + _begLength = 1; + _ratio = 1; + } + return nbEdges; +} + +//================================================================================ +/*! + * \brief Initialize my parameter values by default parameters. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_Geometric1D::SetParametersByDefaults(const TDefaults& dflts, + const SMESH_Mesh* /*mesh*/) +{ + return ( _begLength = dflts._elemLength ); +} + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_HexaFromSkin_3D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_HexaFromSkin_3D.cpp new file mode 100644 index 000000000000..ba3e6beb01fb --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_HexaFromSkin_3D.cpp @@ -0,0 +1,1303 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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_HexaFromSkin_3D.cxx +// Created : Wed Jan 27 12:28:07 2010 +// Author : Edward AGAPOV (eap) + +#include "StdMeshers_HexaFromSkin_3D.hxx" + +#include "SMDS_VolumeOfNodes.hxx" +#include "SMDS_VolumeTool.hxx" +#include "SMESH_Block.hxx" +#include "SMESH_MeshAlgos.hxx" +#include "SMESH_MesherHelper.hxx" + +#include + +#include + +// Define error message and _MYDEBUG_ if needed +#ifdef _DEBUG_ +#define BAD_MESH_ERR \ + error(SMESH_Comment("Can't detect block-wise structure of the input 2D mesh.\n" \ + __FILE__ ":" )<<__LINE__) +//#define _MYDEBUG_ +#else +#define BAD_MESH_ERR \ + error(SMESH_Comment("Can't detect block-wise structure of the input 2D mesh")) +#endif + + +// Debug output +#ifdef _MYDEBUG_ +#define _DUMP_(msg) cout << msg << endl +#else +#define _DUMP_(msg) +#endif + + +namespace +{ + enum EBoxSides //!< sides of the block + { + B_BOTTOM=0, B_RIGHT, B_TOP, B_LEFT, B_FRONT, B_BACK, NB_BLOCK_SIDES + }; +#ifdef _MYDEBUG_ + const char* SBoxSides[] = //!< names of block sides -- needed for DEBUG only + { + "BOTTOM", "RIGHT", "TOP", "LEFT", "FRONT", "BACK", "UNDEFINED" + }; +#endif + enum EQuadEdge //!< edges of quadrangle side + { + Q_BOTTOM = 0, Q_RIGHT, Q_TOP, Q_LEFT, NB_QUAD_SIDES + }; + + + //================================================================================ + /*! + * \brief return logical coordinates (i.e. min or max) of ends of edge + */ + //================================================================================ + + bool getEdgeEnds(EQuadEdge edge, bool& xMax1, bool& yMax1, bool& xMax2, bool& yMax2 ) + { + xMax1=0, yMax1=0, xMax2=1, yMax2=1; + switch( edge ) + { + case Q_BOTTOM: yMax2 = 0; break; + case Q_RIGHT: xMax1 = 1; break; + case Q_TOP: yMax1 = 1; break; + case Q_LEFT: xMax2 = 0; break; + default: + return false; + } + return true; + } + + //================================================================================ + /*! + * \brief return true if a node is at block corner + * + * This check is valid for simple cases only + */ + //================================================================================ + + bool isCornerNode( const SMDS_MeshNode* n ) + { + int nbF = n ? n->NbInverseElements( SMDSAbs_Face ) : 1; + if ( nbF % 2 ) + return true; + + set nodesInInverseFaces; + SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face ); + while ( fIt->more() ) + { + const SMDS_MeshElement* face = fIt->next(); + nodesInInverseFaces.insert( face->begin_nodes(), face->end_nodes() ); + } + + return nodesInInverseFaces.size() != ( 6 + (nbF/2-1)*3 ); + } + + //================================================================================ + /*! + * \brief check element type + */ + //================================================================================ + + bool isQuadrangle(const SMDS_MeshElement* e) + { + return ( e && e->NbCornerNodes() == 4 ); + } + + //================================================================================ + /*! + * \brief return opposite node of a quadrangle face + */ + //================================================================================ + + const SMDS_MeshNode* oppositeNode(const SMDS_MeshElement* quad, int iNode) + { + return quad->GetNode( (iNode+2) % 4 ); + } + + //================================================================================ + /*! + * \brief Convertor of a pair of integers to a sole index + */ + struct _Indexer + { + int _xSize, _ySize; + _Indexer( int xSize=0, int ySize=0 ): _xSize(xSize), _ySize(ySize) {} + int size() const { return _xSize * _ySize; } + int operator()(int x, int y) const { return y * _xSize + x; } + }; + //================================================================================ + /*! + * \brief Oriented convertor of a pair of integers to a sole index + */ + class _OrientedIndexer : public _Indexer + { + public: + enum OriFlags //!< types of block side orientation + { + REV_X = 1, REV_Y = 2, SWAP_XY = 4, MAX_ORI = REV_X|REV_Y|SWAP_XY + }; + _OrientedIndexer( const _Indexer& indexer, const int oriFlags ): + _Indexer( indexer._xSize, indexer._ySize ), + _xSize (indexer._xSize), _ySize(indexer._ySize), + _xRevFun((oriFlags & REV_X) ? & reverse : & lazy), + _yRevFun((oriFlags & REV_Y) ? & reverse : & lazy), + _swapFun((oriFlags & SWAP_XY ) ? & swap : & lazy) + { + (*_swapFun)( _xSize, _ySize ); + } + //!< Return index by XY + int operator()(int x, int y) const + { + (*_xRevFun)( x, const_cast( _xSize )); + (*_yRevFun)( y, const_cast( _ySize )); + (*_swapFun)( x, y ); + return _Indexer::operator()(x,y); + } + //!< Return index for a corner + int corner(bool xMax, bool yMax) const + { + int x = xMax, y = yMax, size = 2; + (*_xRevFun)( x, size ); + (*_yRevFun)( y, size ); + (*_swapFun)( x, y ); + return _Indexer::operator()(x ? _Indexer::_xSize-1 : 0 , y ? _Indexer::_ySize-1 : 0); + } + int xSize() const { return _xSize; } + int ySize() const { return _ySize; } + private: + _Indexer _indexer; + int _xSize, _ySize; + + typedef void (*TFun)(int& x, int& y); + TFun _xRevFun, _yRevFun, _swapFun; + + static void lazy (int&, int&) {} + static void reverse(int& x, int& size) { x = size - x - 1; } + static void swap (int& x, int& y) { std::swap(x,y); } + }; + //================================================================================ + /*! + * \brief Structure corresponding to the meshed side of block + */ + struct _BlockSide + { + vector _grid; + _Indexer _index; + int _nbBlocksExpected; + int _nbBlocksFound; + +#ifdef _DEBUG_ // want to get SIGSEGV in case of invalid index +#define _grid_access_(pobj, i) pobj->_grid[ ((i) < pobj->_grid.size()) ? i : int(1e100)] +#else +#define _grid_access_(pobj, i) pobj->_grid[ i ] +#endif + //!< Return node at XY + const SMDS_MeshNode* getNode(int x, int y) const { return _grid_access_(this, _index( x,y ));} + //!< Set node at XY + void setNode(int x, int y, const SMDS_MeshNode* n) { _grid_access_(this, _index( x,y )) = n; } + //!< Return an edge + SMESH_OrientedLink getEdge(EQuadEdge edge) const + { + bool x1, y1, x2, y2; getEdgeEnds( edge, x1, y1, x2, y2 ); + return SMESH_OrientedLink( getCornerNode ( x1, y1 ), getCornerNode( x2, y2 )); + } + //!< Return a corner node + const SMDS_MeshNode* getCornerNode(bool isXMax, bool isYMax) const + { + return getNode( isXMax ? _index._xSize-1 : 0 , isYMax ? _index._ySize-1 : 0 ); + } + const SMDS_MeshElement* getCornerFace(const SMDS_MeshNode* cornerNode) const; + //!< True if all blocks this side belongs to have been found + bool isBound() const { return _nbBlocksExpected <= _nbBlocksFound; } + //!< Return coordinates of node at XY + gp_XYZ getXYZ(int x, int y) const { return SMESH_TNodeXYZ( getNode( x, y )); } + //!< Return gravity center of the four corners and the middle node + gp_XYZ getGC() const + { + gp_XYZ xyz = + getXYZ( 0, 0 ) + + getXYZ( _index._xSize-1, 0 ) + + getXYZ( 0, _index._ySize-1 ) + + getXYZ( _index._xSize-1, _index._ySize-1 ) + + getXYZ( _index._xSize/2, _index._ySize/2 ); + return xyz / 5; + } + //!< Return number of mesh faces + int getNbFaces() const { return (_index._xSize-1) * (_index._ySize-1); } + }; + //================================================================================ + /*! + * \brief _BlockSide with changed orientation + */ + struct _OrientedBlockSide + { + _BlockSide* _side; + _OrientedIndexer _index; + + _OrientedBlockSide( _BlockSide* side=0, const int oriFlags=0 ): + _side(side), _index(side ? side->_index : _Indexer(), oriFlags ) {} + //!< return coordinates by XY + gp_XYZ xyz(int x, int y) const + { + return SMESH_TNodeXYZ( _grid_access_(_side, _index( x, y )) ); + } + //!< safely return a node by XY + const SMDS_MeshNode* node(int x, int y) const + { + int i = _index( x, y ); + return ( i < 0 || i >= _side->_grid.size()) ? 0 : _side->_grid[i]; + } + //!< Return an edge + SMESH_OrientedLink edge(EQuadEdge edge) const + { + bool x1, y1, x2, y2; getEdgeEnds( edge, x1, y1, x2, y2 ); + return SMESH_OrientedLink( cornerNode ( x1, y1 ), cornerNode( x2, y2 )); + } + //!< Return a corner node + const SMDS_MeshNode* cornerNode(bool isXMax, bool isYMax) const + { + return _grid_access_(_side, _index.corner( isXMax, isYMax )); + } + //!< return its size in nodes + int getHoriSize() const { return _index.xSize(); } + int getVertSize() const { return _index.ySize(); } + //!< True if _side has been initialized + operator bool() const { return _side; } + //! Direct access to _side + const _BlockSide* operator->() const { return _side; } + _BlockSide* operator->() { return _side; } + }; + //================================================================================ + /*! + * \brief Meshed skin of block + */ + struct _Block + { + _OrientedBlockSide _side[6]; // 6 sides of a sub-block + set _corners; + + const _OrientedBlockSide& getSide(int i) const { return _side[i]; } + bool setSide( int i, const _OrientedBlockSide& s) + { + if (( _side[i] = s )) + { + _corners.insert( s.cornerNode(0,0)); + _corners.insert( s.cornerNode(1,0)); + _corners.insert( s.cornerNode(0,1)); + _corners.insert( s.cornerNode(1,1)); + } + return s; + } + void clear() { for (int i=0;i<6;++i) _side[i]=0; _corners.clear(); } + bool hasSide( const _OrientedBlockSide& s) const + { + if ( s ) for (int i=0;i<6;++i) if ( _side[i] && _side[i]._side == s._side ) return true; + return false; + } + int nbSides() const { int n=0; for (int i=0;i<6;++i) if ( _side[i] ) ++n; return n; } + bool isValid() const; + }; + //================================================================================ + /*! + * \brief Skin mesh possibly containing several meshed blocks + */ + class _Skin + { + public: + + int findBlocks(SMESH_Mesh& mesh); + //!< return i-th block + const _Block& getBlock(int i) const { return _blocks[i]; } + //!< return error description + const SMESH_Comment& error() const { return _error; } + + private: + bool fillSide( _BlockSide& side, + const SMDS_MeshElement* cornerQuad, + const SMDS_MeshNode* cornerNode); + bool fillRowsUntilCorner(const SMDS_MeshElement* quad, + const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + vector& verRow1, + vector& verRow2, + bool alongN1N2 ); + _OrientedBlockSide findBlockSide( EBoxSides startBlockSide, + EQuadEdge sharedSideEdge1, + EQuadEdge sharedSideEdge2, + bool withGeometricAnalysis, + set< _BlockSide* >& sidesAround); + //!< update own data and data of the side bound to block + void setSideBoundToBlock( _BlockSide& side ) + { + if ( side._nbBlocksFound++, side.isBound() ) + for ( int e = 0; e < int(NB_QUAD_SIDES); ++e ) + _edge2sides[ side.getEdge( (EQuadEdge) e ) ].erase( &side ); + } + //!< store reason of error + SMESH_Comment _error; + int error(const SMESH_Comment& reason) { _error = reason; return 0; } + + + list< _BlockSide > _allSides; + vector< _Block > _blocks; + + //map< const SMDS_MeshNode*, set< _BlockSide* > > _corner2sides; + map< SMESH_OrientedLink, set< _BlockSide* > > _edge2sides; + }; + + //================================================================================ + /*! + * \brief Find and return number of submeshes corresponding to blocks + */ + //================================================================================ + + int _Skin::findBlocks(SMESH_Mesh& mesh) + { + SMESHDS_Mesh* meshDS = mesh.GetMeshDS(); + + // Find a node at any block corner + + SMDS_NodeIteratorPtr nIt = meshDS->nodesIterator(/*idInceasingOrder=*/true); + if ( !nIt->more() ) return error("Empty mesh"); + + const SMDS_MeshNode* nCorner = 0; + while ( nIt->more() ) + { + nCorner = nIt->next(); + if ( isCornerNode( nCorner )) + break; + else + nCorner = 0; + } + if ( !nCorner ) + return BAD_MESH_ERR; + + // -------------------------------------------------------------------- + // Find all block sides starting from mesh faces sharing the corner node + // -------------------------------------------------------------------- + + int nbFacesOnSides = 0; + TIDSortedElemSet cornerFaces; // corner faces of found _BlockSide's + list< const SMDS_MeshNode* > corners( 1, nCorner ); + list< const SMDS_MeshNode* >::iterator corner = corners.begin(); + while ( corner != corners.end() ) + { + SMDS_ElemIteratorPtr faceIt = (*corner)->GetInverseElementIterator( SMDSAbs_Face ); + while ( faceIt->more() ) + { + const SMDS_MeshElement* face = faceIt->next(); + if ( !cornerFaces.insert( face ).second ) + continue; // already loaded block side + + if ( !isQuadrangle( face )) + return error("Non-quadrangle elements in the input mesh"); + + if ( _allSides.empty() || !_allSides.back()._grid.empty() ) + _allSides.push_back( _BlockSide() ); + + _BlockSide& side = _allSides.back(); + if ( !fillSide( side, face, *corner ) ) + { + if ( !_error.empty() ) + return false; + } + else + { + for ( int isXMax = 0; isXMax < 2; ++isXMax ) + for ( int isYMax = 0; isYMax < 2; ++isYMax ) + { + const SMDS_MeshNode* nCorner = side.getCornerNode(isXMax,isYMax ); + corners.push_back( nCorner ); + cornerFaces.insert( side.getCornerFace( nCorner )); + } + for ( int e = 0; e < int(NB_QUAD_SIDES); ++e ) + _edge2sides[ side.getEdge( (EQuadEdge) e ) ].insert( &side ); + + nbFacesOnSides += side.getNbFaces(); + } + } + ++corner; + + // find block sides of other domains if any + if ( corner == corners.end() && nbFacesOnSides < mesh.NbQuadrangles() ) + { + while ( nIt->more() ) + { + nCorner = nIt->next(); + if ( isCornerNode( nCorner )) + corner = corners.insert( corner, nCorner ); + } + nbFacesOnSides = mesh.NbQuadrangles(); + } + } + + if ( _allSides.empty() ) + return BAD_MESH_ERR; + if ( _allSides.back()._grid.empty() ) + _allSides.pop_back(); + _DUMP_("Nb detected sides "<< _allSides.size()); + + // --------------------------- + // Organize sides into blocks + // --------------------------- + + // analyse sharing of sides by blocks and sort sides by nb of adjacent sides + int nbBlockSides = 0; // total nb of block sides taking into account their sharing + multimap sortedSides; + { + list < _BlockSide >::iterator sideIt = _allSides.begin(); + for ( ; sideIt != _allSides.end(); ++sideIt ) + { + _BlockSide& side = *sideIt; + bool isSharedSide = true; + int nbAdjacent = 0; + for ( int e = 0; e < int(NB_QUAD_SIDES) && isSharedSide; ++e ) + { + int nbAdj = _edge2sides[ side.getEdge( (EQuadEdge) e ) ].size(); + nbAdjacent += nbAdj; + isSharedSide = ( nbAdj > 2 ); + } + side._nbBlocksFound = 0; + side._nbBlocksExpected = isSharedSide ? 2 : 1; + nbBlockSides += side._nbBlocksExpected; + sortedSides.insert( make_pair( nbAdjacent, & side )); + } + } + + // find sides of each block + int nbBlocks = 0; + while ( nbBlockSides >= 6 ) + { + // get any side not bound to all blocks it belongs to + multimap::iterator i_side = sortedSides.begin(); + while ( i_side != sortedSides.end() && i_side->second->isBound()) + ++i_side; + + // start searching for block sides from the got side + bool ok = true; + if ( _blocks.empty() || _blocks.back()._side[B_FRONT] ) + _blocks.resize( _blocks.size() + 1 ); + + _Block& block = _blocks.back(); + block.setSide( B_FRONT, i_side->second ); + setSideBoundToBlock( *i_side->second ); + nbBlockSides--; + + // edges of adjacent sides of B_FRONT corresponding to front's edges + EQuadEdge edgeOfFront[4] = { Q_BOTTOM, Q_RIGHT, Q_TOP, Q_LEFT }; + EQuadEdge edgeOfAdj [4] = { Q_BOTTOM, Q_LEFT, Q_BOTTOM, Q_LEFT }; + // first find all sides detectable w/o advanced analysis, + // then repeat the search, which then may pass without advanced analysis + set< _BlockSide* > sidesAround; + for ( int advAnalys = 0; advAnalys < 2; ++advAnalys ) + { + // try to find 4 sides adjacent to a FRONT side + for ( int i = 0; (ok || !advAnalys) && i < NB_QUAD_SIDES; ++i ) + if ( !block._side[i] ) + ok = block.setSide( i, findBlockSide( B_FRONT, edgeOfFront[i], edgeOfAdj[i], + advAnalys, sidesAround)); + // try to find a BACK side by a TOP one + if ( ok || !advAnalys) + if ( !block._side[B_BACK] && block._side[B_TOP] ) + ok = block.setSide( B_BACK, findBlockSide( B_TOP, Q_TOP, Q_TOP, + advAnalys, sidesAround )); + if ( !advAnalys ) ok = true; + } + ok = block.isValid(); + if ( ok ) + { + // check if just found block is same as one of previously found blocks + bool isSame = false; + for ( int i = 1; i < _blocks.size() && !isSame; ++i ) + isSame = ( block._corners == _blocks[i-1]._corners ); + ok = !isSame; + } + + // count the found sides + _DUMP_(endl << "** Block " << _blocks.size() << " valid: " << block.isValid()); + for (int i = 0; i < NB_BLOCK_SIDES; ++i ) + { + _DUMP_("\tSide "<< SBoxSides[i] <<" "<< block._side[ i ]._side); + if ( block._side[ i ] ) + { + if ( ok && i != B_FRONT) + { + setSideBoundToBlock( *block._side[ i ]._side ); + nbBlockSides--; + } + _DUMP_("\t corners "<< + block._side[ i ].cornerNode(0,0)->GetID() << ", " << + block._side[ i ].cornerNode(1,0)->GetID() << ", " << + block._side[ i ].cornerNode(1,1)->GetID() << ", " << + block._side[ i ].cornerNode(0,1)->GetID() << ", "<GetNodeIndex( nCorner ); + const SMDS_MeshNode* nOnEdge = firstQuad->GetNode( (iCorner+1) % 4); + + // find out size of block side + vector horRow1, horRow2, verRow1, verRow2; + if ( !fillRowsUntilCorner( firstQuad, nCorner, nOnEdge, horRow1, horRow2, true ) || + !fillRowsUntilCorner( firstQuad, nCorner, nOnEdge, verRow1, verRow2, false )) + return false; + nbX = horRow1.size(), nbY = verRow1.size(); + + // store found nodes + side._index._xSize = horRow1.size(); + side._index._ySize = verRow1.size(); + side._grid.resize( side._index.size(), NULL ); + + for ( x = 0; x < horRow1.size(); ++x ) + { + side.setNode( x, 0, horRow1[x] ); + side.setNode( x, 1, horRow2[x] ); + } + for ( y = 0; y < verRow1.size(); ++y ) + { + side.setNode( 0, y, verRow1[y] ); + side.setNode( 1, y, verRow2[y] ); + } + } + // Find the rest nodes + + y = 1; // y of the row to fill + TIDSortedElemSet emptySet, avoidSet; + while ( ++y < nbY ) + { + // get next firstQuad in the next row of quadrangles + // + // n2up + // o---o <- y row + // | | + // o---o o o o o <- found nodes + //n1down n2down + // + int i1down, i2down, i2up; + const SMDS_MeshNode* n1down = side.getNode( 0, y-1 ); + const SMDS_MeshNode* n2down = side.getNode( 1, y-1 ); + avoidSet.clear(); avoidSet.insert( firstQuad ); + firstQuad = SMESH_MeshAlgos::FindFaceInSet( n1down, n2down, emptySet, avoidSet, + &i1down, &i2down); + if ( !isQuadrangle( firstQuad )) + return BAD_MESH_ERR; + + const SMDS_MeshNode* n2up = oppositeNode( firstQuad, i1down ); + avoidSet.clear(); avoidSet.insert( firstQuad ); + + // find the rest nodes in the y-th row by faces in the row + + x = 1; + while ( ++x < nbX ) + { + const SMDS_MeshElement* quad = SMESH_MeshAlgos::FindFaceInSet( n2up, n2down, emptySet, + avoidSet, &i2up, &i2down); + if ( !isQuadrangle( quad )) + return BAD_MESH_ERR; + + n2up = oppositeNode( quad, i2down ); + n2down = oppositeNode( quad, i2up ); + avoidSet.clear(); avoidSet.insert( quad ); + + side.setNode( x, y, n2up ); + } + } + + // check side validity + bool ok = + side.getCornerFace( side.getCornerNode( 0, 0 )) && + side.getCornerFace( side.getCornerNode( 1, 0 )) && + side.getCornerFace( side.getCornerNode( 0, 1 )) && + side.getCornerFace( side.getCornerNode( 1, 1 )); + + return ok; + } + + //================================================================================ + /*! + * \brief Return true if it's possible to make a loop over corner2Sides starting + * from the startSide + */ + //================================================================================ + + bool isClosedChainOfSides( _BlockSide* startSide, + map< const SMDS_MeshNode*, list< _BlockSide* > > & corner2Sides ) + { + // get start and end nodes + const SMDS_MeshNode *n1 = 0, *n2 = 0, *n; + for ( int y = 0; y < 2; ++y ) + for ( int x = 0; x < 2; ++x ) + { + n = startSide->getCornerNode(x,y); + if ( !corner2Sides.count( n )) continue; + if ( n1 ) + n2 = n; + else + n1 = n; + } + if ( !n2 ) return false; + + map< const SMDS_MeshNode*, list< _BlockSide* > >::iterator + c2sides = corner2Sides.find( n1 ); + if ( c2sides == corner2Sides.end() ) return false; + + int nbChainLinks = 1; + n = n1; + _BlockSide* prevSide = startSide; + while ( n != n2 ) + { + // get the next side sharing n + list< _BlockSide* > & sides = c2sides->second; + _BlockSide* nextSide = ( sides.back() == prevSide ? sides.front() : sides.back() ); + if ( nextSide == prevSide ) return false; + + // find the next corner of the nextSide being in corner2Sides + n1 = n; + n = 0; + for ( int y = 0; y < 2 && !n; ++y ) + for ( int x = 0; x < 2; ++x ) + { + n = nextSide->getCornerNode(x,y); + c2sides = corner2Sides.find( n ); + if ( n == n1 || c2sides == corner2Sides.end() ) + n = 0; + else + break; + } + if ( !n ) return false; + + prevSide = nextSide; + nbChainLinks++; + } + + return ( n == n2 && nbChainLinks == NB_QUAD_SIDES ); + } + + //================================================================================ + /*! + * \brief Try to find a block side adjacent to the given side by given edge + */ + //================================================================================ + + _OrientedBlockSide _Skin::findBlockSide( EBoxSides startBlockSide, + EQuadEdge sharedSideEdge1, + EQuadEdge sharedSideEdge2, + bool withGeometricAnalysis, + set< _BlockSide* >& sidesAround) + { + _Block& block = _blocks.back(); + _OrientedBlockSide& side1 = block._side[ startBlockSide ]; + + // get corner nodes of the given block edge + SMESH_OrientedLink edge = side1.edge( sharedSideEdge1 ); + const SMDS_MeshNode* n1 = edge.node1(); + const SMDS_MeshNode* n2 = edge.node2(); + if ( edge._reversed ) swap( n1, n2 ); + + // find all sides sharing both nodes n1 and n2 + set< _BlockSide* > sidesOnEdge = _edge2sides[ edge ]; // copy a set + + // exclude loaded sides of block from sidesOnEdge + for (int i = 0; i < NB_BLOCK_SIDES; ++i ) + if ( block._side[ i ] ) + sidesOnEdge.erase( block._side[ i ]._side ); + + int nbSidesOnEdge = sidesOnEdge.size(); + _DUMP_("nbSidesOnEdge "<< nbSidesOnEdge << " " << n1->GetID() << "-" << n2->GetID() ); + if ( nbSidesOnEdge == 0 ) + return 0; + + _BlockSide* foundSide = 0; + if ( nbSidesOnEdge == 1 ) + { + foundSide = *sidesOnEdge.begin(); + } + else + { + set< _BlockSide* >::iterator sideIt = sidesOnEdge.begin(); + int nbLoadedSides = block.nbSides(); + if ( nbLoadedSides > 1 ) + { + // Find the side having more than 2 corners common with already loaded sides + for (; !foundSide && sideIt != sidesOnEdge.end(); ++sideIt ) + { + _BlockSide* sideI = *sideIt; + int nbCommonCorners = + block._corners.count( sideI->getCornerNode(0,0)) + + block._corners.count( sideI->getCornerNode(1,0)) + + block._corners.count( sideI->getCornerNode(0,1)) + + block._corners.count( sideI->getCornerNode(1,1)); + if ( nbCommonCorners > 2 ) + foundSide = sideI; + } + } + + if ( !foundSide ) + { + if ( !withGeometricAnalysis ) + { + sidesAround.insert( sidesOnEdge.begin(), sidesOnEdge.end() ); + return 0; + } + if ( nbLoadedSides == 1 ) + { + // Issue 0021529. There are at least 2 sides by each edge and + // position of block gravity center is undefined. + // Find a side starting from which we can walk around the startBlockSide + + // fill in corner2Sides + map< const SMDS_MeshNode*, list< _BlockSide* > > corner2Sides; + for ( sideIt = sidesAround.begin(); sideIt != sidesAround.end(); ++sideIt ) + { + _BlockSide* sideI = *sideIt; + corner2Sides[ sideI->getCornerNode(0,0) ].push_back( sideI ); + corner2Sides[ sideI->getCornerNode(1,0) ].push_back( sideI ); + corner2Sides[ sideI->getCornerNode(0,1) ].push_back( sideI ); + corner2Sides[ sideI->getCornerNode(1,1) ].push_back( sideI ); + } + // remove corners of startBlockSide from corner2Sides + set::iterator nIt = block._corners.begin(); + for ( ; nIt != block._corners.end(); ++nIt ) + corner2Sides.erase( *nIt ); + + // select a side + for ( sideIt = sidesOnEdge.begin(); sideIt != sidesOnEdge.end(); ++sideIt ) + { + if ( isClosedChainOfSides( *sideIt, corner2Sides )) + { + foundSide = *sideIt; + break; + } + } + if ( !foundSide ) + return 0; + } + else + { + // Select one of found sides most close to startBlockSide + + gp_XYZ p1 ( n1->X(),n1->Y(),n1->Z()), p2 (n2->X(),n2->Y(),n2->Z()); + gp_Vec p1p2( p1, p2 ); + + const SMDS_MeshElement* face1 = side1->getCornerFace( n1 ); + gp_XYZ p1Op = SMESH_TNodeXYZ( oppositeNode( face1, face1->GetNodeIndex(n1))); + gp_Vec side1Dir( p1, p1Op ); + gp_Ax2 pln( p1, p1p2, side1Dir ); // plane with normal p1p2 and X dir side1Dir + _DUMP_(" Select adjacent for "<< side1._side << " - side dir (" + << side1Dir.X() << ", " << side1Dir.Y() << ", " << side1Dir.Z() << ")" ); + + map < double , _BlockSide* > angleOfSide; + for (sideIt = sidesOnEdge.begin(); sideIt != sidesOnEdge.end(); ++sideIt ) + { + _BlockSide* sideI = *sideIt; + const SMDS_MeshElement* faceI = sideI->getCornerFace( n1 ); + gp_XYZ p1Op = SMESH_TNodeXYZ( oppositeNode( faceI, faceI->GetNodeIndex(n1))); + gp_Vec sideIDir( p1, p1Op ); + // compute angle of (sideIDir projection to pln) and (X dir of pln) + gp_Vec2d sideIDirProj( sideIDir * pln.XDirection(), sideIDir * pln.YDirection()); + double angle = sideIDirProj.Angle( gp::DX2d() ); + if ( angle < 0 ) angle += 2. * M_PI; // angle [0-2*PI] + angleOfSide.insert( make_pair( angle, sideI )); + _DUMP_(" "<< sideI << " - side dir (" + << sideIDir.X() << ", " << sideIDir.Y() << ", " << sideIDir.Z() << ")" + << " angle " << angle); + } + + gp_XYZ gc(0,0,0); // gravity center of already loaded block sides + for (int i = 0; i < NB_BLOCK_SIDES; ++i ) + if ( block._side[ i ] ) + gc += block._side[ i ]._side->getGC(); + gc /= nbLoadedSides; + + gp_Vec gcDir( p1, gc ); + gp_Vec2d gcDirProj( gcDir * pln.XDirection(), gcDir * pln.YDirection()); + double gcAngle = gcDirProj.Angle( gp::DX2d() ); + foundSide = gcAngle < 0 ? angleOfSide.rbegin()->second : angleOfSide.begin()->second; + } + } + _DUMP_(" selected "<< foundSide ); + } + + // Orient the found side correctly + + // corners of found side corresponding to nodes n1 and n2 + bool xMax1, yMax1, xMax2, yMax2; + if ( !getEdgeEnds( sharedSideEdge2, xMax1, yMax1, xMax2, yMax2 )) + return error(SMESH_Comment("Internal error at ")<<__FILE__<<":"<<__LINE__), + _OrientedBlockSide(0); + + for ( int ori = 0; ori < _OrientedIndexer::MAX_ORI+1; ++ori ) + { + _OrientedBlockSide orientedSide( foundSide, ori ); + const SMDS_MeshNode* n12 = orientedSide.cornerNode( xMax1, yMax1); + const SMDS_MeshNode* n22 = orientedSide.cornerNode( xMax2, yMax2); + if ( n1 == n12 && n2 == n22 ) + return orientedSide; + } + error(SMESH_Comment("Failed to orient a block side found by edge ")<& row1, + vector& row2, + const bool alongN1N2 ) + { + const SMDS_MeshNode* corner1 = n1; + + // Store nodes of quad in the rows and find new n1 and n2 to get + // the next face so that new n2 is on block edge + int i1 = quad->GetNodeIndex( n1 ); + int i2 = quad->GetNodeIndex( n2 ); + row1.clear(); row2.clear(); + row1.push_back( n1 ); + if ( alongN1N2 ) + { + row1.push_back( n2 ); + row2.push_back( oppositeNode( quad, i2 )); + row2.push_back( n1 = oppositeNode( quad, i1 )); + } + else + { + row2.push_back( n2 ); + row1.push_back( n2 = oppositeNode( quad, i2 )); + row2.push_back( n1 = oppositeNode( quad, i1 )); + } + + if ( isCornerNode( row1[1] )) + return true; + + // Find the rest nodes + TIDSortedElemSet emptySet, avoidSet; + while ( !isCornerNode( n2 ) ) + { + avoidSet.clear(); avoidSet.insert( quad ); + quad = SMESH_MeshAlgos::FindFaceInSet( n1, n2, emptySet, avoidSet, &i1, &i2 ); + if ( !isQuadrangle( quad )) + return BAD_MESH_ERR; + + row1.push_back( n2 = oppositeNode( quad, i1 )); + row2.push_back( n1 = oppositeNode( quad, i2 )); + } + return n1 != corner1; + } + + //================================================================================ + /*! + * \brief Return a corner face by a corner node + */ + //================================================================================ + + const SMDS_MeshElement* _BlockSide::getCornerFace(const SMDS_MeshNode* cornerNode) const + { + int x, y, isXMax, isYMax, found = 0; + for ( isXMax = 0; isXMax < 2; ++isXMax ) + { + for ( isYMax = 0; isYMax < 2; ++isYMax ) + { + x = isXMax ? _index._xSize-1 : 0; + y = isYMax ? _index._ySize-1 : 0; + found = ( getNode(x,y) == cornerNode ); + if ( found ) break; + } + if ( found ) break; + } + if ( !found ) return 0; + int dx = isXMax ? -1 : +1; + int dy = isYMax ? -1 : +1; + const SMDS_MeshNode* n1 = getNode(x,y); + const SMDS_MeshNode* n2 = getNode(x+dx,y); + const SMDS_MeshNode* n3 = getNode(x,y+dy); + const SMDS_MeshNode* n4 = getNode(x+dx,y+dy); + return SMDS_Mesh::FindFace(n1, n2, n3, n4 ); + } + + //================================================================================ + /*! + * \brief Checks own validity + */ + //================================================================================ + + bool _Block::isValid() const + { + bool ok = ( nbSides() == 6 ); + + // check only corners depending on side selection + EBoxSides adjacent[4] = { B_BOTTOM, B_RIGHT, B_TOP, B_LEFT }; + EQuadEdge edgeAdj [4] = { Q_TOP, Q_RIGHT, Q_TOP, Q_RIGHT }; + EQuadEdge edgeBack[4] = { Q_BOTTOM, Q_RIGHT, Q_TOP, Q_LEFT }; + + for ( int i=0; ok && i < NB_QUAD_SIDES; ++i ) + { + SMESH_OrientedLink eBack = _side[ B_BACK ].edge( edgeBack[i] ); + SMESH_OrientedLink eAdja = _side[ adjacent[i] ].edge( edgeAdj[i] ); + ok = ( eBack == eAdja ); + } + return ok; + } + +} // namespace + +//======================================================================= +//function : StdMeshers_HexaFromSkin_3D +//purpose : +//======================================================================= + +StdMeshers_HexaFromSkin_3D::StdMeshers_HexaFromSkin_3D(int hypId, int studyId, SMESH_Gen* gen) + :SMESH_3D_Algo(hypId, studyId, gen) +{ + MESSAGE("StdMeshers_HexaFromSkin_3D::StdMeshers_HexaFromSkin_3D"); + _name = "HexaFromSkin_3D"; +} + +StdMeshers_HexaFromSkin_3D::~StdMeshers_HexaFromSkin_3D() +{ + MESSAGE("StdMeshers_HexaFromSkin_3D::~StdMeshers_HexaFromSkin_3D"); +} + +//================================================================================ +/*! + * \brief Main method, which generates hexaheda + */ +//================================================================================ + +bool StdMeshers_HexaFromSkin_3D::Compute(SMESH_Mesh & aMesh, SMESH_MesherHelper* aHelper) +{ + _Skin skin; + int nbBlocks = skin.findBlocks(aMesh); + if ( nbBlocks == 0 ) + return error( skin.error()); + + vector< vector< const SMDS_MeshNode* > > columns; + int x, xSize, y, ySize, z, zSize; + _Indexer colIndex; + + for ( int i = 0; i < nbBlocks; ++i ) + { + const _Block& block = skin.getBlock( i ); + + // ------------------------------------------ + // Fill columns of nodes with existing nodes + // ------------------------------------------ + + xSize = block.getSide(B_BOTTOM).getHoriSize(); + ySize = block.getSide(B_BOTTOM).getVertSize(); + zSize = block.getSide(B_FRONT ).getVertSize(); + int X = xSize - 1, Y = ySize - 1, Z = zSize - 1; + colIndex = _Indexer( xSize, ySize ); + columns.resize( colIndex.size() ); + + // fill node columns by front and back box sides + for ( x = 0; x < xSize; ++x ) { + vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( x, 0 )]; + vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( x, Y )]; + column0.resize( zSize ); + column1.resize( zSize ); + for ( z = 0; z < zSize; ++z ) { + column0[ z ] = block.getSide(B_FRONT).node( x, z ); + column1[ z ] = block.getSide(B_BACK) .node( x, z ); + } + } + // fill node columns by left and right box sides + for ( y = 1; y < ySize-1; ++y ) { + vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( 0, y )]; + vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( X, y )]; + column0.resize( zSize ); + column1.resize( zSize ); + for ( z = 0; z < zSize; ++z ) { + column0[ z ] = block.getSide(B_LEFT) .node( y, z ); + column1[ z ] = block.getSide(B_RIGHT).node( y, z ); + } + } + // get nodes from top and bottom box sides + for ( x = 1; x < xSize-1; ++x ) { + for ( y = 1; y < ySize-1; ++y ) { + vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )]; + column.resize( zSize ); + column.front() = block.getSide(B_BOTTOM).node( x, y ); + column.back() = block.getSide(B_TOP) .node( x, y ); + } + } + + // ---------------------------- + // Add internal nodes of a box + // ---------------------------- + // projection points of internal nodes on box sub-shapes by which + // coordinates of internal nodes are computed + vector pointOnShape( SMESH_Block::ID_Shell ); + + // projections on vertices are constant + pointOnShape[ SMESH_Block::ID_V000 ] = block.getSide(B_BOTTOM).xyz( 0, 0 ); + pointOnShape[ SMESH_Block::ID_V100 ] = block.getSide(B_BOTTOM).xyz( X, 0 ); + pointOnShape[ SMESH_Block::ID_V010 ] = block.getSide(B_BOTTOM).xyz( 0, Y ); + pointOnShape[ SMESH_Block::ID_V110 ] = block.getSide(B_BOTTOM).xyz( X, Y ); + pointOnShape[ SMESH_Block::ID_V001 ] = block.getSide(B_TOP).xyz( 0, 0 ); + pointOnShape[ SMESH_Block::ID_V101 ] = block.getSide(B_TOP).xyz( X, 0 ); + pointOnShape[ SMESH_Block::ID_V011 ] = block.getSide(B_TOP).xyz( 0, Y ); + pointOnShape[ SMESH_Block::ID_V111 ] = block.getSide(B_TOP).xyz( X, Y ); + + for ( x = 1; x < xSize-1; ++x ) + { + gp_XYZ params; // normalized parameters of internal node within a unit box + params.SetCoord( 1, x / double(X) ); + for ( y = 1; y < ySize-1; ++y ) + { + params.SetCoord( 2, y / double(Y) ); + // column to fill during z loop + vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )]; + // projections on horizontal edges + pointOnShape[ SMESH_Block::ID_Ex00 ] = block.getSide(B_BOTTOM).xyz( x, 0 ); + pointOnShape[ SMESH_Block::ID_Ex10 ] = block.getSide(B_BOTTOM).xyz( x, Y ); + pointOnShape[ SMESH_Block::ID_E0y0 ] = block.getSide(B_BOTTOM).xyz( 0, y ); + pointOnShape[ SMESH_Block::ID_E1y0 ] = block.getSide(B_BOTTOM).xyz( X, y ); + pointOnShape[ SMESH_Block::ID_Ex01 ] = block.getSide(B_TOP).xyz( x, 0 ); + pointOnShape[ SMESH_Block::ID_Ex11 ] = block.getSide(B_TOP).xyz( x, Y ); + pointOnShape[ SMESH_Block::ID_E0y1 ] = block.getSide(B_TOP).xyz( 0, y ); + pointOnShape[ SMESH_Block::ID_E1y1 ] = block.getSide(B_TOP).xyz( X, y ); + // projections on horizontal sides + pointOnShape[ SMESH_Block::ID_Fxy0 ] = block.getSide(B_BOTTOM).xyz( x, y ); + pointOnShape[ SMESH_Block::ID_Fxy1 ] = block.getSide(B_TOP) .xyz( x, y ); + for ( z = 1; z < zSize-1; ++z ) // z loop + { + params.SetCoord( 3, z / double(Z) ); + // projections on vertical edges + pointOnShape[ SMESH_Block::ID_E00z ] = block.getSide(B_FRONT).xyz( 0, z ); + pointOnShape[ SMESH_Block::ID_E10z ] = block.getSide(B_FRONT).xyz( X, z ); + pointOnShape[ SMESH_Block::ID_E01z ] = block.getSide(B_BACK).xyz( 0, z ); + pointOnShape[ SMESH_Block::ID_E11z ] = block.getSide(B_BACK).xyz( X, z ); + // projections on vertical sides + pointOnShape[ SMESH_Block::ID_Fx0z ] = block.getSide(B_FRONT).xyz( x, z ); + pointOnShape[ SMESH_Block::ID_Fx1z ] = block.getSide(B_BACK) .xyz( x, z ); + pointOnShape[ SMESH_Block::ID_F0yz ] = block.getSide(B_LEFT) .xyz( y, z ); + pointOnShape[ SMESH_Block::ID_F1yz ] = block.getSide(B_RIGHT).xyz( y, z ); + + // compute internal node coordinates + gp_XYZ coords; + SMESH_Block::ShellPoint( params, pointOnShape, coords ); + column[ z ] = aHelper->AddNode( coords.X(), coords.Y(), coords.Z() ); + +#ifdef DEB_GRID + // debug + //cout << "----------------------------------------------------------------------"<::max(); + bool isForw = true; + for ( int xMax = 0; xMax < 2; ++xMax ) + for ( int yMax = 0; yMax < 2; ++yMax ) + for ( int zMax = 0; zMax < 2; ++zMax ) + { + x = xMax ? xSize-1 : 1; + y = yMax ? ySize-1 : 1; + z = zMax ? zSize-1 : 1; + vector< const SMDS_MeshNode* >& col00 = columns[ colIndex( x-1, y-1 )]; + vector< const SMDS_MeshNode* >& col10 = columns[ colIndex( x , y-1 )]; + vector< const SMDS_MeshNode* >& col01 = columns[ colIndex( x-1, y )]; + vector< const SMDS_MeshNode* >& col11 = columns[ colIndex( x , y )]; + + const SMDS_MeshNode* n000 = col00[z-1]; + const SMDS_MeshNode* n100 = col10[z-1]; + const SMDS_MeshNode* n010 = col01[z-1]; + const SMDS_MeshNode* n110 = col11[z-1]; + const SMDS_MeshNode* n001 = col00[z]; + const SMDS_MeshNode* n101 = col10[z]; + const SMDS_MeshNode* n011 = col01[z]; + const SMDS_MeshNode* n111 = col11[z]; + SMDS_VolumeOfNodes probeVolume (n000,n010,n110,n100, + n001,n011,n111,n101); + SMDS_VolumeTool volTool( &probeVolume ); + double Nx=0.,Ny=0.,Nz=0.; + for ( int iFace = 0; iFace < volTool.NbFaces(); ++iFace ) + { + double nx,ny,nz; + volTool.GetFaceNormal( iFace, nx,ny,nz ); + Nx += nx; + Ny += ny; + Nz += nz; + } + double quality = Nx*Nx + Ny*Ny + Nz*Nz; + if ( quality < badness ) + { + badness = quality; + isForw = volTool.IsForward(); + } + } + + // add elements + for ( x = 0; x < xSize-1; ++x ) { + for ( y = 0; y < ySize-1; ++y ) { + vector< const SMDS_MeshNode* >& col00 = columns[ colIndex( x, y )]; + vector< const SMDS_MeshNode* >& col10 = columns[ colIndex( x+1, y )]; + vector< const SMDS_MeshNode* >& col01 = columns[ colIndex( x, y+1 )]; + vector< const SMDS_MeshNode* >& col11 = columns[ colIndex( x+1, y+1 )]; + // bottom face normal of a hexa mush point outside the volume + if ( isForw ) + for ( z = 0; z < zSize-1; ++z ) + aHelper->AddVolume(col00[z], col01[z], col11[z], col10[z], + col00[z+1], col01[z+1], col11[z+1], col10[z+1]); + else + for ( z = 0; z < zSize-1; ++z ) + aHelper->AddVolume(col00[z], col10[z], col11[z], col01[z], + col00[z+1], col10[z+1], col11[z+1], col01[z+1]); + } + } + } // loop on blocks + + return true; +} + +//================================================================================ +/*! + * \brief Evaluate nb of hexa + */ +//================================================================================ + +bool StdMeshers_HexaFromSkin_3D::Evaluate(SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap) +{ + _Skin skin; + int nbBlocks = skin.findBlocks(aMesh); + if ( nbBlocks == 0 ) + return error( skin.error()); + + bool secondOrder = aMesh.NbFaces( ORDER_QUADRATIC ); + + int entity = secondOrder ? SMDSEntity_Quad_Hexa : SMDSEntity_Hexa; + vector& nbByType = aResMap[ aMesh.GetSubMesh( aShape )]; + if ( entity >= nbByType.size() ) + nbByType.resize( SMDSEntity_Last, 0 ); + + for ( int i = 0; i < nbBlocks; ++i ) + { + const _Block& block = skin.getBlock( i ); + + int nbX = block.getSide(B_BOTTOM).getHoriSize(); + int nbY = block.getSide(B_BOTTOM).getVertSize(); + int nbZ = block.getSide(B_FRONT ).getVertSize(); + + int nbHexa = (nbX-1) * (nbY-1) * (nbZ-1); + int nbNodes = (nbX-2) * (nbY-2) * (nbZ-2); + if ( secondOrder ) + nbNodes += + (nbX-2) * (nbY-2) * (nbZ-1) + + (nbX-2) * (nbY-1) * (nbZ-2) + + (nbX-1) * (nbY-2) * (nbZ-2); + + + nbByType[ entity ] += nbHexa; + nbByType[ SMDSEntity_Node ] += nbNodes; + } + + return true; +} + +//================================================================================ +/*! + * \brief Abstract method must be defined but does nothing + */ +//================================================================================ + +bool StdMeshers_HexaFromSkin_3D::CheckHypothesis(SMESH_Mesh&, const TopoDS_Shape&, + Hypothesis_Status& aStatus) +{ + aStatus = SMESH_Hypothesis::HYP_OK; + return true; +} + +//================================================================================ +/*! + * \brief Abstract method must be defined but just reports an error as this + * algo is not intended to work with shapes + */ +//================================================================================ + +bool StdMeshers_HexaFromSkin_3D::Compute(SMESH_Mesh&, const TopoDS_Shape&) +{ + return error("Algorithm can't work with geometrical shapes"); +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Hexa_3D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Hexa_3D.cpp index 622d4106e905..1ad459448f59 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Hexa_3D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Hexa_3D.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Hexa_3D.cxx // Moved here from SMESH_Hexa_3D.cxx @@ -26,43 +27,46 @@ // Module : SMESH // #include "StdMeshers_Hexa_3D.hxx" + #include "StdMeshers_CompositeHexa_3D.hxx" #include "StdMeshers_FaceSide.hxx" +#include "StdMeshers_HexaFromSkin_3D.hxx" #include "StdMeshers_Penta_3D.hxx" #include "StdMeshers_Prism_3D.hxx" #include "StdMeshers_Quadrangle_2D.hxx" +#include "StdMeshers_ViscousLayers.hxx" +#include "SMESH_Comment.hxx" #include "SMESH_Gen.hxx" #include "SMESH_Mesh.hxx" +#include "SMESH_MesherHelper.hxx" #include "SMESH_subMesh.hxx" -#include "SMESH_Comment.hxx" -#include "SMDS_MeshElement.hxx" #include "SMDS_MeshNode.hxx" -#include "SMDS_FacePosition.hxx" -#include "SMDS_VolumeTool.hxx" -#include "SMDS_VolumeOfNodes.hxx" #include #include -#include -#include -#include +#include +#include #include -#include #include "utilities.h" -#include "SMESH_ExceptHandlers.hxx" +#include "Utils_ExceptHandlers.hxx" typedef SMESH_Comment TComm; using namespace std; -static SMESH_ComputeErrorPtr ComputePentahedralMesh(SMESH_Mesh &, const TopoDS_Shape &); +static SMESH_ComputeErrorPtr ComputePentahedralMesh(SMESH_Mesh &, + const TopoDS_Shape &, + SMESH_ProxyMesh* proxyMesh=0); + +static bool EvaluatePentahedralMesh(SMESH_Mesh &, const TopoDS_Shape &, + MapShapeNbElems &); //============================================================================= /*! - * + * Constructor */ //============================================================================= @@ -71,12 +75,14 @@ StdMeshers_Hexa_3D::StdMeshers_Hexa_3D(int hypId, int studyId, SMESH_Gen * gen) { MESSAGE("StdMeshers_Hexa_3D::StdMeshers_Hexa_3D"); _name = "Hexa_3D"; - _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID); // 1 bit /shape type + _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID); // 1 bit /shape type + _requireShape = false; + _compatibleHypothesis.push_back("ViscousLayers"); } //============================================================================= /*! - * + * Destructor */ //============================================================================= @@ -85,27 +91,9 @@ StdMeshers_Hexa_3D::~StdMeshers_Hexa_3D() MESSAGE("StdMeshers_Hexa_3D::~StdMeshers_Hexa_3D"); } -//================================================================================ -/*! - * \brief Clear fields and return the argument - * \param res - the value to return - * \retval bool - the argument value - */ -//================================================================================ - -bool StdMeshers_Hexa_3D::ClearAndReturn(FaceQuadStruct* theQuads[6], const bool res) -{ - for (int i = 0; i < 6; i++) { - delete theQuads[i]; - theQuads[i] = NULL; - } - return res; -} - - //============================================================================= /*! - * + * Retrieves defined hypotheses */ //============================================================================= @@ -124,922 +112,680 @@ bool StdMeshers_Hexa_3D::CheckHypothesis if ( nbFaces != 6 ) return false; */ - aStatus = SMESH_Hypothesis::HYP_OK; - return true; -} -//======================================================================= -//function : isCloser -//purpose : -//======================================================================= + _viscousLayersHyp = NULL; -inline bool isCloser(const int i, const int j, const int nbhoriz, - const FaceQuadStruct* quad, const gp_Pnt2d uv, - double & minDist) -{ - int ij = j * nbhoriz + i; - gp_Pnt2d uv2( quad->uv_grid[ij].u, quad->uv_grid[ij].v ); - double dist = uv.SquareDistance( uv2 ); - if ( dist < minDist ) { - minDist = dist; + const list& hyps = + GetUsedHypothesis(aMesh, aShape, /*ignoreAuxiliary=*/false); + list ::const_iterator h = hyps.begin(); + if ( h == hyps.end()) + { + aStatus = SMESH_Hypothesis::HYP_OK; return true; } - return false; -} -//======================================================================= -//function : findIJ -//purpose : return i,j of the node -//======================================================================= + // only StdMeshers_ViscousLayers can be used + aStatus = HYP_OK; + for ( ; h != hyps.end(); ++h ) + { + if ( !(_viscousLayersHyp = dynamic_cast< const StdMeshers_ViscousLayers*> ( *h ))) + break; + } + if ( !_viscousLayersHyp ) + aStatus = HYP_INCOMPATIBLE; + else + error( _viscousLayersHyp->CheckHypothesis( aMesh, aShape, aStatus )); + + return aStatus == HYP_OK; +} -static bool findIJ (const SMDS_MeshNode* node, const FaceQuadStruct * quad, int& I, int& J) +namespace { - const SMDS_FacePosition* fpos = - static_cast(node->GetPosition().get()); - if ( ! fpos ) return false; - gp_Pnt2d uv( fpos->GetUParameter(), fpos->GetVParameter() ); - - double minDist = DBL_MAX; - const int nbhoriz = quad->side[0]->NbPoints(); - const int nbvertic = quad->side[1]->NbPoints(); - I = nbhoriz/2; J = nbvertic/2; - int oldI, oldJ; - do { - oldI = I; oldJ = J; - while ( I + 2 < nbhoriz && isCloser( I + 1, J, nbhoriz, quad, uv, minDist )) - I += 1; - if ( I == oldI ) - while ( I - 1 > 0 && isCloser( I - 1, J, nbhoriz, quad, uv, minDist )) - I -= 1; - if ( minDist < DBL_MIN ) - break; + //============================================================================= - while ( J + 2 < nbvertic && isCloser( I, J + 1, nbhoriz, quad, uv, minDist )) - J += 1; - if ( J == oldJ ) - while ( J - 1 > 0 && isCloser( I, J - 1, nbhoriz, quad, uv, minDist )) - J -= 1; - if ( minDist < DBL_MIN ) - break; + typedef boost::shared_ptr< FaceQuadStruct > FaceQuadStructPtr; + + // symbolic names of box sides + enum EBoxSides{ B_BOTTOM=0, B_RIGHT, B_TOP, B_LEFT, B_FRONT, B_BACK, B_NB_SIDES }; + + // symbolic names of sides of quadrangle + enum EQuadSides{ Q_BOTTOM=0, Q_RIGHT, Q_TOP, Q_LEFT, Q_NB_SIDES }; + + //============================================================================= + /*! + * \brief Container of nodes of structured mesh on a qudrangular geom FACE + */ + struct _FaceGrid + { + // face sides + FaceQuadStructPtr _quad; + + // map of (node parameter on EDGE) to (column (vector) of nodes) + TParam2ColumnMap _u2nodesMap; + + // node column's taken form _u2nodesMap taking into account sub-shape orientation + vector _columns; + + // geometry of a cube side + TopoDS_Face _sideF; - } while ( I != oldI || J != oldJ ); + const SMDS_MeshNode* GetNode(int iCol, int iRow) const + { + return _columns[iCol][iRow]; + } + gp_XYZ GetXYZ(int iCol, int iRow) const + { + return SMESH_TNodeXYZ( GetNode( iCol, iRow )); + } + }; - if ( minDist > DBL_MIN ) { - for (int i = 1; i < nbhoriz - 1; i++) - for (int j = 1; j < nbvertic - 1; j++) - if ( isCloser( i, j, nbhoriz, quad, uv, minDist )) - I = i, J = j; + //================================================================================ + /*! + * \brief Convertor of a pair of integers to a sole index + */ + struct _Indexer + { + int _xSize, _ySize; + _Indexer( int xSize, int ySize ): _xSize(xSize), _ySize(ySize) {} + int size() const { return _xSize * _ySize; } + int operator()(const int x, const int y) const { return y * _xSize + x; } + }; + + //================================================================================ + /*! + * \brief Appends a range of node columns from a map to another map + */ + template< class TMapIterator > + void append( TParam2ColumnMap& toMap, TMapIterator from, TMapIterator to ) + { + const SMDS_MeshNode* lastNode = toMap.rbegin()->second[0]; + const SMDS_MeshNode* firstNode = from->second[0]; + if ( lastNode == firstNode ) + from++; + double u = toMap.rbegin()->first; + for (; from != to; ++from ) + { + u += 1; + TParam2ColumnMap::iterator u2nn = toMap.insert( toMap.end(), make_pair ( u, TNodeColumn())); + u2nn->second.swap( from->second ); + } } - return true; -} + //================================================================================ + /*! + * \brief Finds FaceQuadStruct having a side equal to a given one and rearranges + * the found FaceQuadStruct::side to have the given side at a Q_BOTTOM place + */ + FaceQuadStructPtr getQuadWithBottom( StdMeshers_FaceSidePtr side, + FaceQuadStructPtr quad[ 6 ]) + { + FaceQuadStructPtr foundQuad; + for ( int i = 1; i < 6; ++i ) + { + if ( !quad[i] ) continue; + for ( unsigned iS = 0; iS < quad[i]->side.size(); ++iS ) + { + const StdMeshers_FaceSidePtr side2 = quad[i]->side[iS]; + if (( side->FirstVertex().IsSame( side2->FirstVertex() ) || + side->FirstVertex().IsSame( side2->LastVertex() )) + && + ( side->LastVertex().IsSame( side2->FirstVertex() ) || + side->LastVertex().IsSame( side2->LastVertex() )) + ) + { + if ( iS != Q_BOTTOM ) + { + vector< FaceQuadStruct::Side > newSides; + for ( unsigned j = iS; j < quad[i]->side.size(); ++j ) + newSides.push_back( quad[i]->side[j] ); + for ( unsigned j = 0; j < iS; ++j ) + newSides.push_back( quad[i]->side[j] ); + quad[i]->side.swap( newSides ); + } + foundQuad.swap(quad[i]); + return foundQuad; + } + } + } + return foundQuad; + } + //================================================================================ + /*! + * \brief Returns true if the 1st base node of sideGrid1 belongs to sideGrid2 + */ + //================================================================================ + + bool beginsAtSide( const _FaceGrid& sideGrid1, + const _FaceGrid& sideGrid2, + SMESH_ProxyMesh::Ptr proxymesh ) + { + const TNodeColumn& col0 = sideGrid2._u2nodesMap.begin()->second; + const TNodeColumn& col1 = sideGrid2._u2nodesMap.rbegin()->second; + const SMDS_MeshNode* n00 = col0.front(); + const SMDS_MeshNode* n01 = col0.back(); + const SMDS_MeshNode* n10 = col1.front(); + const SMDS_MeshNode* n11 = col1.back(); + const SMDS_MeshNode* n = (sideGrid1._u2nodesMap.begin()->second)[0]; + if ( proxymesh ) + { + n00 = proxymesh->GetProxyNode( n00 ); + n10 = proxymesh->GetProxyNode( n10 ); + n01 = proxymesh->GetProxyNode( n01 ); + n11 = proxymesh->GetProxyNode( n11 ); + n = proxymesh->GetProxyNode( n ); + } + return ( n == n00 || n == n01 || n == n10 || n == n11 ); + } +} //============================================================================= /*! - * Hexahedron mesh on hexaedron like form - * -0. - shape and face mesh verification - * -1. - identify faces and vertices of the "cube" - * -2. - Algorithm from: - * "Application de l'interpolation transfinie à la création de maillages + * Generates hexahedron mesh on hexaedron like form using algorithm from + * "Application de l'interpolation transfinie � la cr�ation de maillages * C0 ou G1 continus sur des triangles, quadrangles, tetraedres, pentaedres - * et hexaedres déformés." + * et hexaedres d�form�s." * Alain PERONNET - 8 janvier 1999 */ //============================================================================= bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh & aMesh, - const TopoDS_Shape & aShape)// throw(SALOME_Exception) + const TopoDS_Shape & aShape) { // PAL14921. Enable catching std::bad_alloc and Standard_OutOfMemory outside //Unexpect aCatch(SalomeException); MESSAGE("StdMeshers_Hexa_3D::Compute"); SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); - // 0. - shape and face mesh verification - // 0.1 - shape must be a solid (or a shell) with 6 faces + // Shape verification + // ---------------------- - vector < SMESH_subMesh * >meshFaces; - for (TopExp_Explorer exp(aShape, TopAbs_FACE); exp.More(); exp.Next()) { - SMESH_subMesh *aSubMesh = aMesh.GetSubMeshContaining(exp.Current()); - ASSERT(aSubMesh); - meshFaces.push_back(aSubMesh); - } - if (meshFaces.size() != 6) { - //return error(COMPERR_BAD_SHAPE, TComm(meshFaces.size())<<" instead of 6 faces in a block"); - static StdMeshers_CompositeHexa_3D compositeHexa(-10, 0, aMesh.GetGen()); + // shape must be a solid (or a shell) with 6 faces + TopExp_Explorer exp(aShape,TopAbs_SHELL); + if ( !exp.More() ) + return error(COMPERR_BAD_SHAPE, "No SHELL in the geometry"); + if ( exp.Next(), exp.More() ) + return error(COMPERR_BAD_SHAPE, "More than one SHELL in the geometry"); + + TopTools_IndexedMapOfShape FF; + TopExp::MapShapes( aShape, TopAbs_FACE, FF); + if ( FF.Extent() != 6) + { + static StdMeshers_CompositeHexa_3D compositeHexa(_gen->GetANewId(), 0, _gen); if ( !compositeHexa.Compute( aMesh, aShape )) return error( compositeHexa.GetComputeError() ); return true; } - // 0.2 - is each face meshed with Quadrangle_2D? (so, with a wire of 4 edges) - - // tool for working with quadratic elements - SMESH_MesherHelper aTool (aMesh); - _quadraticMesh = aTool.IsQuadraticSubMesh(aShape); - - // cube structure - typedef struct cubeStruct - { - TopoDS_Vertex V000; - TopoDS_Vertex V001; - TopoDS_Vertex V010; - TopoDS_Vertex V011; - TopoDS_Vertex V100; - TopoDS_Vertex V101; - TopoDS_Vertex V110; - TopoDS_Vertex V111; - faceQuadStruct* quad_X0; - faceQuadStruct* quad_X1; - faceQuadStruct* quad_Y0; - faceQuadStruct* quad_Y1; - faceQuadStruct* quad_Z0; - faceQuadStruct* quad_Z1; - Point3DStruct* np; // normalised 3D coordinates - } CubeStruct; - - CubeStruct aCube; - - // bounding faces - FaceQuadStruct* aQuads[6]; - for (int i = 0; i < 6; i++) - aQuads[i] = 0; - - for (int i = 0; i < 6; i++) + // Find sides of a cube + // --------------------- + + FaceQuadStructPtr quad[ 6 ]; + StdMeshers_Quadrangle_2D quadAlgo( _gen->GetANewId(), GetStudyId(), _gen); + for ( int i = 0; i < 6; ++i ) { - TopoDS_Shape aFace = meshFaces[i]->GetSubShape(); - SMESH_Algo *algo = _gen->GetAlgo(aMesh, aFace); - string algoName = algo->GetName(); - bool isAllQuad = false; - if (algoName == "Quadrangle_2D") { - SMESHDS_SubMesh * sm = meshDS->MeshElements( aFace ); - if ( sm ) { - isAllQuad = true; - SMDS_ElemIteratorPtr eIt = sm->GetElements(); - while ( isAllQuad && eIt->more() ) { - const SMDS_MeshElement* elem = eIt->next(); - isAllQuad = ( elem->NbNodes()==4 ||(_quadraticMesh && elem->NbNodes()==8) ); - } - } - } - if ( ! isAllQuad ) { - SMESH_ComputeErrorPtr err = ComputePentahedralMesh(aMesh, aShape); - return ClearAndReturn( aQuads, error(err)); - } - StdMeshers_Quadrangle_2D *quadAlgo = - dynamic_cast < StdMeshers_Quadrangle_2D * >(algo); - ASSERT(quadAlgo); - try { - aQuads[i] = quadAlgo->CheckAnd2Dcompute(aMesh, aFace, _quadraticMesh); - if(!aQuads[i]) { - return error( quadAlgo->GetComputeError()); - } - } - catch(SMESH_Exception & S_ex) { - return ClearAndReturn( aQuads, error(COMPERR_SLM_EXCEPTION,TComm(S_ex.what()) << - " Raised by StdMeshers_Quadrangle_2D " - " on face #" << meshDS->ShapeToIndex( aFace ))); - } - - // 0.2.1 - number of points on the opposite edges must be the same - if (aQuads[i]->side[0]->NbPoints() != aQuads[i]->side[2]->NbPoints() || - aQuads[i]->side[1]->NbPoints() != aQuads[i]->side[3]->NbPoints() - /*aQuads[i]->side[0]->NbEdges() != 1 || - aQuads[i]->side[1]->NbEdges() != 1 || - aQuads[i]->side[2]->NbEdges() != 1 || - aQuads[i]->side[3]->NbEdges() != 1*/) { - MESSAGE("different number of points on the opposite edges of face " << i); - // Try to go into penta algorithm 'cause it has been improved. - SMESH_ComputeErrorPtr err = ComputePentahedralMesh(aMesh, aShape); - return ClearAndReturn( aQuads, error(err)); - } + if ( !( quad[i] = FaceQuadStructPtr( quadAlgo.CheckNbEdges( aMesh, FF( i+1 ))))) + return error( quadAlgo.GetComputeError() ); + if ( quad[i]->side.size() != 4 ) + return error( COMPERR_BAD_SHAPE, "Not a quadrangular box side" ); } - // 1. - identify faces and vertices of the "cube" - // 1.1 - ancestor maps vertex->edges in the cube - -// TopTools_IndexedDataMapOfShapeListOfShape MS; -// TopExp::MapShapesAndAncestors(aShape, TopAbs_VERTEX, TopAbs_EDGE, MS); - - // 1.2 - first face is choosen as face Y=0 of the unit cube - - const TopoDS_Shape & aFace = meshFaces[0]->GetSubShape(); - //const TopoDS_Face & F = TopoDS::Face(aFace); - - // 1.3 - identify the 4 vertices of the face Y=0: V000, V100, V101, V001 - - aCube.V000 = aQuads[0]->side[0]->FirstVertex(); // will be (0,0,0) on the unit cube - aCube.V100 = aQuads[0]->side[0]->LastVertex(); // will be (1,0,0) on the unit cube - aCube.V001 = aQuads[0]->side[2]->FirstVertex(); // will be (0,0,1) on the unit cube - aCube.V101 = aQuads[0]->side[2]->LastVertex(); // will be (1,0,1) on the unit cube - - TopTools_IndexedMapOfShape MV0; - TopExp::MapShapes(aFace, TopAbs_VERTEX, MV0); - - aCube.V010 = OppositeVertex( aCube.V000, MV0, aQuads); - aCube.V110 = OppositeVertex( aCube.V100, MV0, aQuads); - aCube.V011 = OppositeVertex( aCube.V001, MV0, aQuads); - aCube.V111 = OppositeVertex( aCube.V101, MV0, aQuads); - - // 1.6 - find remaining faces given 4 vertices - - int _indY0 = 0; - int _indY1 = GetFaceIndex(aMesh, aShape, meshFaces, - aCube.V010, aCube.V011, aCube.V110, aCube.V111); - int _indZ0 = GetFaceIndex(aMesh, aShape, meshFaces, - aCube.V000, aCube.V010, aCube.V100, aCube.V110); - int _indZ1 = GetFaceIndex(aMesh, aShape, meshFaces, - aCube.V001, aCube.V011, aCube.V101, aCube.V111); - int _indX0 = GetFaceIndex(aMesh, aShape, meshFaces, - aCube.V000, aCube.V001, aCube.V010, aCube.V011); - int _indX1 = GetFaceIndex(aMesh, aShape, meshFaces, - aCube.V100, aCube.V101, aCube.V110, aCube.V111); - - // IPAL21120: SIGSEGV on Meshing attached Compound with Automatic Hexadralization - if ( _indY1 < 1 || _indZ0 < 1 || _indZ1 < 1 || _indX0 < 1 || _indX1 < 1 ) - return error(COMPERR_BAD_SHAPE); - - aCube.quad_Y0 = aQuads[_indY0]; - aCube.quad_Y1 = aQuads[_indY1]; - aCube.quad_Z0 = aQuads[_indZ0]; - aCube.quad_Z1 = aQuads[_indZ1]; - aCube.quad_X0 = aQuads[_indX0]; - aCube.quad_X1 = aQuads[_indX1]; - - // 1.7 - get convertion coefs from face 2D normalized to 3D normalized - - Conv2DStruct cx0; // for face X=0 - Conv2DStruct cx1; // for face X=1 - Conv2DStruct cy0; - Conv2DStruct cy1; - Conv2DStruct cz0; - Conv2DStruct cz1; - - GetConv2DCoefs(*aCube.quad_X0, meshFaces[_indX0]->GetSubShape(), - aCube.V000, aCube.V010, aCube.V011, aCube.V001, cx0); - GetConv2DCoefs(*aCube.quad_X1, meshFaces[_indX1]->GetSubShape(), - aCube.V100, aCube.V110, aCube.V111, aCube.V101, cx1); - GetConv2DCoefs(*aCube.quad_Y0, meshFaces[_indY0]->GetSubShape(), - aCube.V000, aCube.V100, aCube.V101, aCube.V001, cy0); - GetConv2DCoefs(*aCube.quad_Y1, meshFaces[_indY1]->GetSubShape(), - aCube.V010, aCube.V110, aCube.V111, aCube.V011, cy1); - GetConv2DCoefs(*aCube.quad_Z0, meshFaces[_indZ0]->GetSubShape(), - aCube.V000, aCube.V100, aCube.V110, aCube.V010, cz0); - GetConv2DCoefs(*aCube.quad_Z1, meshFaces[_indZ1]->GetSubShape(), - aCube.V001, aCube.V101, aCube.V111, aCube.V011, cz1); - - // 1.8 - create a 3D structure for normalized values - - int nbx = aCube.quad_Z0->side[0]->NbPoints(); - if (cz0.a1 == 0.) nbx = aCube.quad_Z0->side[1]->NbPoints(); - - int nby = aCube.quad_X0->side[0]->NbPoints(); - if (cx0.a1 == 0.) nby = aCube.quad_X0->side[1]->NbPoints(); - - int nbz = aCube.quad_Y0->side[0]->NbPoints(); - if (cy0.a1 != 0.) nbz = aCube.quad_Y0->side[1]->NbPoints(); + _FaceGrid aCubeSide[ 6 ]; - int i1, j1, nbxyz = nbx * nby * nbz; - Point3DStruct *np = new Point3DStruct[nbxyz]; + swap( aCubeSide[B_BOTTOM]._quad, quad[0] ); + swap( aCubeSide[B_BOTTOM]._quad->side[ Q_RIGHT],// direct the normal of bottom quad inside cube + aCubeSide[B_BOTTOM]._quad->side[ Q_LEFT ] ); - // 1.9 - store node indexes of faces + aCubeSide[B_FRONT]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_BOTTOM], quad ); + aCubeSide[B_RIGHT]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_RIGHT ], quad ); + aCubeSide[B_BACK ]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_TOP ], quad ); + aCubeSide[B_LEFT ]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_LEFT ], quad ); + if ( aCubeSide[B_FRONT ]._quad ) + aCubeSide[B_TOP]._quad = getQuadWithBottom( aCubeSide[B_FRONT ]._quad->side[Q_TOP ], quad ); - { - const TopoDS_Face & F = TopoDS::Face(meshFaces[_indX0]->GetSubShape()); - - faceQuadStruct *quad = aCube.quad_X0; - int i = 0; // j = x/face , k = y/face - int nbdown = quad->side[0]->NbPoints(); - int nbright = quad->side[1]->NbPoints(); - - SMDS_NodeIteratorPtr itf= aMesh.GetSubMesh(F)->GetSubMeshDS()->GetNodes(); - - while(itf->more()) { - const SMDS_MeshNode * node = itf->next(); - if(aTool.IsMedium(node)) - continue; - if ( !findIJ( node, quad, i1, j1 )) - return ClearAndReturn( aQuads, false ); - int ij1 = j1 * nbdown + i1; - quad->uv_grid[ij1].node = node; - } + for ( int i = 1; i < 6; ++i ) + if ( !aCubeSide[i]._quad ) + return error( COMPERR_BAD_SHAPE ); - for (int i1 = 0; i1 < nbdown; i1++) - for (int j1 = 0; j1 < nbright; j1++) { - int ij1 = j1 * nbdown + i1; - int j = cx0.ia * i1 + cx0.ib * j1 + cx0.ic; // j = x/face - int k = cx0.ja * i1 + cx0.jb * j1 + cx0.jc; // k = y/face - int ijk = k * nbx * nby + j * nbx + i; - //MESSAGE(" "<uv_grid[ij1].node; - //SCRUTE(np[ijk].nodeId); - } - } + // Make viscous layers + // -------------------- + SMESH_ProxyMesh::Ptr proxymesh; + if ( _viscousLayersHyp ) { - const TopoDS_Face & F = TopoDS::Face(meshFaces[_indX1]->GetSubShape()); - - SMDS_NodeIteratorPtr itf= aMesh.GetSubMesh(F)->GetSubMeshDS()->GetNodes(); - - faceQuadStruct *quad = aCube.quad_X1; - int i = nbx - 1; // j = x/face , k = y/face - int nbdown = quad->side[0]->NbPoints(); - int nbright = quad->side[1]->NbPoints(); - - while(itf->more()) { - const SMDS_MeshNode * node = itf->next(); - if(aTool.IsMedium(node)) - continue; - if ( !findIJ( node, quad, i1, j1 )) - return ClearAndReturn( aQuads, false ); - int ij1 = j1 * nbdown + i1; - quad->uv_grid[ij1].node = node; - } - - for (int i1 = 0; i1 < nbdown; i1++) - for (int j1 = 0; j1 < nbright; j1++) { - int ij1 = j1 * nbdown + i1; - int j = cx1.ia * i1 + cx1.ib * j1 + cx1.ic; // j = x/face - int k = cx1.ja * i1 + cx1.jb * j1 + cx1.jc; // k = y/face - int ijk = k * nbx * nby + j * nbx + i; - //MESSAGE(" "<uv_grid[ij1].node; - //SCRUTE(np[ijk].nodeId); - } + proxymesh = _viscousLayersHyp->Compute( aMesh, aShape, /*makeN2NMap=*/ true ); + if ( !proxymesh ) + return false; } - { - const TopoDS_Face & F = TopoDS::Face(meshFaces[_indY0]->GetSubShape()); - - SMDS_NodeIteratorPtr itf= aMesh.GetSubMesh(F)->GetSubMeshDS()->GetNodes(); - - faceQuadStruct *quad = aCube.quad_Y0; - int j = 0; // i = x/face , k = y/face - int nbdown = quad->side[0]->NbPoints(); - int nbright = quad->side[1]->NbPoints(); - - while(itf->more()) { - const SMDS_MeshNode * node = itf->next(); - if(aTool.IsMedium(node)) - continue; - if ( !findIJ( node, quad, i1, j1 )) - return ClearAndReturn( aQuads, false ); - int ij1 = j1 * nbdown + i1; - quad->uv_grid[ij1].node = node; - } + // Check if there are triangles on cube sides + // ------------------------------------------- - for (int i1 = 0; i1 < nbdown; i1++) - for (int j1 = 0; j1 < nbright; j1++) { - int ij1 = j1 * nbdown + i1; - int i = cy0.ia * i1 + cy0.ib * j1 + cy0.ic; // i = x/face - int k = cy0.ja * i1 + cy0.jb * j1 + cy0.jc; // k = y/face - int ijk = k * nbx * nby + j * nbx + i; - //MESSAGE(" "<uv_grid[ij1].node; - //SCRUTE(np[ijk].nodeId); + if ( aMesh.NbTriangles() > 0 ) + { + for ( int i = 0; i < 6; ++i ) + { + const TopoDS_Face& sideF = aCubeSide[i]._quad->face; + const SMESHDS_SubMesh* smDS = + proxymesh ? proxymesh->GetSubMesh( sideF ) : meshDS->MeshElements( sideF ); + if ( !SMESH_MesherHelper::IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE, + /*nullSubMeshRes=*/false )) + { + SMESH_ComputeErrorPtr err = ComputePentahedralMesh(aMesh, aShape, proxymesh.get()); + return error( err ); } + } } - { - const TopoDS_Face & F = TopoDS::Face(meshFaces[_indY1]->GetSubShape()); - - SMDS_NodeIteratorPtr itf= aMesh.GetSubMesh(F)->GetSubMeshDS()->GetNodes(); - - faceQuadStruct *quad = aCube.quad_Y1; - int j = nby - 1; // i = x/face , k = y/face - int nbdown = quad->side[0]->NbPoints(); - int nbright = quad->side[1]->NbPoints(); - - while(itf->more()) { - const SMDS_MeshNode * node = itf->next(); - if(aTool.IsMedium(node)) - continue; - if ( !findIJ( node, quad, i1, j1 )) - return ClearAndReturn( aQuads, false ); - int ij1 = j1 * nbdown + i1; - quad->uv_grid[ij1].node = node; - } + // Check presence of regular grid mesh on FACEs of the cube + // ------------------------------------------------------------ - for (int i1 = 0; i1 < nbdown; i1++) - for (int j1 = 0; j1 < nbright; j1++) { - int ij1 = j1 * nbdown + i1; - int i = cy1.ia * i1 + cy1.ib * j1 + cy1.ic; // i = x/face - int k = cy1.ja * i1 + cy1.jb * j1 + cy1.jc; // k = y/face - int ijk = k * nbx * nby + j * nbx + i; - //MESSAGE(" "<uv_grid[ij1].node; - //SCRUTE(np[ijk].nodeId); - } - } + // tool creating quadratic elements if needed + SMESH_MesherHelper helper (aMesh); + _quadraticMesh = helper.IsQuadraticSubMesh(aShape); + for ( int i = 0; i < 6; ++i ) { - const TopoDS_Face & F = TopoDS::Face(meshFaces[_indZ0]->GetSubShape()); - - SMDS_NodeIteratorPtr itf= aMesh.GetSubMesh(F)->GetSubMeshDS()->GetNodes(); - - faceQuadStruct *quad = aCube.quad_Z0; - int k = 0; // i = x/face , j = y/face - int nbdown = quad->side[0]->NbPoints(); - int nbright = quad->side[1]->NbPoints(); - - while(itf->more()) { - const SMDS_MeshNode * node = itf->next(); - if(aTool.IsMedium(node)) - continue; - if ( !findIJ( node, quad, i1, j1 )) - return ClearAndReturn( aQuads, false ); - int ij1 = j1 * nbdown + i1; - quad->uv_grid[ij1].node = node; + const TopoDS_Face& F = aCubeSide[i]._quad->face; + StdMeshers_FaceSidePtr baseQuadSide = aCubeSide[i]._quad->side[ Q_BOTTOM ]; + list baseEdges( baseQuadSide->Edges().begin(), baseQuadSide->Edges().end() ); + + // assure correctness of node positions on baseE: + // helper.GetNodeU() will fix positions if they are wrong + helper.ToFixNodeParameters( true ); + for ( int iE = 0; iE < baseQuadSide->NbEdges(); ++iE ) + { + const TopoDS_Edge& baseE = baseQuadSide->Edge( iE ); + if ( SMESHDS_SubMesh* smDS = meshDS->MeshElements( baseE )) + { + bool ok; + helper.SetSubShape( baseE ); + SMDS_ElemIteratorPtr eIt = smDS->GetElements(); + while ( eIt->more() ) + { + const SMDS_MeshElement* e = eIt->next(); + // expect problems on a composite side + try { helper.GetNodeU( baseE, e->GetNode(0), e->GetNode(1), &ok); } + catch (...) {} + try { helper.GetNodeU( baseE, e->GetNode(1), e->GetNode(0), &ok); } + catch (...) {} + } + } } - for (int i1 = 0; i1 < nbdown; i1++) - for (int j1 = 0; j1 < nbright; j1++) { - int ij1 = j1 * nbdown + i1; - int i = cz0.ia * i1 + cz0.ib * j1 + cz0.ic; // i = x/face - int j = cz0.ja * i1 + cz0.jb * j1 + cz0.jc; // j = y/face - int ijk = k * nbx * nby + j * nbx + i; - //MESSAGE(" "<uv_grid[ij1].node; - //SCRUTE(np[ijk].nodeId); - } + // load grid + bool ok = + helper.LoadNodeColumns( aCubeSide[i]._u2nodesMap, F, baseEdges, meshDS, proxymesh.get()); + if ( ok ) + { + // check if the loaded grid corresponds to nb of quadrangles on the FACE + const SMESHDS_SubMesh* faceSubMesh = + proxymesh ? proxymesh->GetSubMesh( F ) : meshDS->MeshElements( F ); + const int nbQuads = faceSubMesh->NbElements(); + const int nbHor = aCubeSide[i]._u2nodesMap.size() - 1; + const int nbVer = aCubeSide[i]._u2nodesMap.begin()->second.size() - 1; + ok = ( nbQuads == nbHor * nbVer ); + } + if ( !ok ) + { + SMESH_ComputeErrorPtr err = ComputePentahedralMesh(aMesh, aShape, proxymesh.get()); + return error( err ); + } } + // Orient loaded grids of cube sides along axis of the unitary cube coord system + bool isReverse[6]; + isReverse[B_BOTTOM] = beginsAtSide( aCubeSide[B_BOTTOM], aCubeSide[B_RIGHT ], proxymesh ); + isReverse[B_TOP ] = beginsAtSide( aCubeSide[B_TOP ], aCubeSide[B_RIGHT ], proxymesh ); + isReverse[B_FRONT ] = beginsAtSide( aCubeSide[B_FRONT ], aCubeSide[B_RIGHT ], proxymesh ); + isReverse[B_BACK ] = beginsAtSide( aCubeSide[B_BACK ], aCubeSide[B_RIGHT ], proxymesh ); + isReverse[B_LEFT ] = beginsAtSide( aCubeSide[B_LEFT ], aCubeSide[B_BACK ], proxymesh ); + isReverse[B_RIGHT ] = beginsAtSide( aCubeSide[B_RIGHT ], aCubeSide[B_BACK ], proxymesh ); + for ( int i = 0; i < 6; ++i ) { - const TopoDS_Face & F = TopoDS::Face(meshFaces[_indZ1]->GetSubShape()); - - SMDS_NodeIteratorPtr itf= aMesh.GetSubMesh(F)->GetSubMeshDS()->GetNodes(); - - faceQuadStruct *quad = aCube.quad_Z1; - int k = nbz - 1; // i = x/face , j = y/face - int nbdown = quad->side[0]->NbPoints(); - int nbright = quad->side[1]->NbPoints(); - - while(itf->more()) { - const SMDS_MeshNode * node = itf->next(); - if(aTool.IsMedium(node)) - continue; - if ( !findIJ( node, quad, i1, j1 )) - return ClearAndReturn( aQuads, false ); - int ij1 = j1 * nbdown + i1; - quad->uv_grid[ij1].node = node; - } + aCubeSide[i]._columns.resize( aCubeSide[i]._u2nodesMap.size() ); - for (int i1 = 0; i1 < nbdown; i1++) - for (int j1 = 0; j1 < nbright; j1++) { - int ij1 = j1 * nbdown + i1; - int i = cz1.ia * i1 + cz1.ib * j1 + cz1.ic; // i = x/face - int j = cz1.ja * i1 + cz1.jb * j1 + cz1.jc; // j = y/face - int ijk = k * nbx * nby + j * nbx + i; - //MESSAGE(" "<uv_grid[ij1].node; - //SCRUTE(np[ijk].nodeId); - } - } + int iFwd = 0, iRev = aCubeSide[i]._columns.size()-1; + int* pi = isReverse[i] ? &iRev : &iFwd; + TParam2ColumnMap::iterator u2nn = aCubeSide[i]._u2nodesMap.begin(); + for ( ; iFwd < aCubeSide[i]._columns.size(); --iRev, ++iFwd, ++u2nn ) + aCubeSide[i]._columns[ *pi ].swap( u2nn->second ); - // 2.0 - for each node of the cube: - // - get the 8 points 3D = 8 vertices of the cube - // - get the 12 points 3D on the 12 edges of the cube - // - get the 6 points 3D on the 6 faces with their ID - // - compute the point 3D - // - store the point 3D in SMESHDS, store its ID in 3D structure - - int shapeID = meshDS->ShapeToIndex( aShape ); - - Pt3 p000, p001, p010, p011, p100, p101, p110, p111; - Pt3 px00, px01, px10, px11; - Pt3 p0y0, p0y1, p1y0, p1y1; - Pt3 p00z, p01z, p10z, p11z; - Pt3 pxy0, pxy1, px0z, px1z, p0yz, p1yz; - - GetPoint(p000, 0, 0, 0, nbx, nby, nbz, np, meshDS); - GetPoint(p001, 0, 0, nbz - 1, nbx, nby, nbz, np, meshDS); - GetPoint(p010, 0, nby - 1, 0, nbx, nby, nbz, np, meshDS); - GetPoint(p011, 0, nby - 1, nbz - 1, nbx, nby, nbz, np, meshDS); - GetPoint(p100, nbx - 1, 0, 0, nbx, nby, nbz, np, meshDS); - GetPoint(p101, nbx - 1, 0, nbz - 1, nbx, nby, nbz, np, meshDS); - GetPoint(p110, nbx - 1, nby - 1, 0, nbx, nby, nbz, np, meshDS); - GetPoint(p111, nbx - 1, nby - 1, nbz - 1, nbx, nby, nbz, np, meshDS); - - for (int i = 1; i < nbx - 1; i++) { - for (int j = 1; j < nby - 1; j++) { - for (int k = 1; k < nbz - 1; k++) { - // *** seulement maillage regulier - // 12 points on edges - GetPoint(px00, i, 0, 0, nbx, nby, nbz, np, meshDS); - GetPoint(px01, i, 0, nbz - 1, nbx, nby, nbz, np, meshDS); - GetPoint(px10, i, nby - 1, 0, nbx, nby, nbz, np, meshDS); - GetPoint(px11, i, nby - 1, nbz - 1, nbx, nby, nbz, np, meshDS); - - GetPoint(p0y0, 0, j, 0, nbx, nby, nbz, np, meshDS); - GetPoint(p0y1, 0, j, nbz - 1, nbx, nby, nbz, np, meshDS); - GetPoint(p1y0, nbx - 1, j, 0, nbx, nby, nbz, np, meshDS); - GetPoint(p1y1, nbx - 1, j, nbz - 1, nbx, nby, nbz, np, meshDS); - - GetPoint(p00z, 0, 0, k, nbx, nby, nbz, np, meshDS); - GetPoint(p01z, 0, nby - 1, k, nbx, nby, nbz, np, meshDS); - GetPoint(p10z, nbx - 1, 0, k, nbx, nby, nbz, np, meshDS); - GetPoint(p11z, nbx - 1, nby - 1, k, nbx, nby, nbz, np, meshDS); - - // 12 points on faces - GetPoint(pxy0, i, j, 0, nbx, nby, nbz, np, meshDS); - GetPoint(pxy1, i, j, nbz - 1, nbx, nby, nbz, np, meshDS); - GetPoint(px0z, i, 0, k, nbx, nby, nbz, np, meshDS); - GetPoint(px1z, i, nby - 1, k, nbx, nby, nbz, np, meshDS); - GetPoint(p0yz, 0, j, k, nbx, nby, nbz, np, meshDS); - GetPoint(p1yz, nbx - 1, j, k, nbx, nby, nbz, np, meshDS); - - int ijk = k * nbx * nby + j * nbx + i; - double x = double (i) / double (nbx - 1); // *** seulement - double y = double (j) / double (nby - 1); // *** maillage - double z = double (k) / double (nbz - 1); // *** regulier - - Pt3 X; - for (int i = 0; i < 3; i++) { - X[i] = (1 - x) * p0yz[i] + x * p1yz[i] - + (1 - y) * px0z[i] + y * px1z[i] - + (1 - z) * pxy0[i] + z * pxy1[i] - - (1 - x) * ((1 - y) * p00z[i] + y * p01z[i]) - - x * ((1 - y) * p10z[i] + y * p11z[i]) - - (1 - y) * ((1 - z) * px00[i] + z * px01[i]) - - y * ((1 - z) * px10[i] + z * px11[i]) - - (1 - z) * ((1 - x) * p0y0[i] + x * p1y0[i]) - - z * ((1 - x) * p0y1[i] + x * p1y1[i]) - + (1 - x) * ((1 - y) * ((1 - z) * p000[i] + z * p001[i]) - + y * ((1 - z) * p010[i] + z * p011[i])) - + x * ((1 - y) * ((1 - z) * p100[i] + z * p101[i]) - + y * ((1 - z) * p110[i] + z * p111[i])); + aCubeSide[i]._u2nodesMap.clear(); + } + + if ( proxymesh ) + for ( int i = 0; i < 6; ++i ) + for ( unsigned j = 0; j < aCubeSide[i]._columns.size(); ++j) + for ( unsigned k = 0; k < aCubeSide[i]._columns[j].size(); ++k) + { + const SMDS_MeshNode* & n = aCubeSide[i]._columns[j][k]; + n = proxymesh->GetProxyNode( n ); } - SMDS_MeshNode * node = meshDS->AddNode(X[0], X[1], X[2]); - np[ijk].node = node; - meshDS->SetNodeInVolume(node, shapeID); - } + // 4) Create internal nodes of the cube + // ------------------------------------- + + helper.SetSubShape( aShape ); + helper.SetElementsOnShape(true); + + // shortcuts to sides + _FaceGrid* fBottom = & aCubeSide[ B_BOTTOM ]; + _FaceGrid* fRight = & aCubeSide[ B_RIGHT ]; + _FaceGrid* fTop = & aCubeSide[ B_TOP ]; + _FaceGrid* fLeft = & aCubeSide[ B_LEFT ]; + _FaceGrid* fFront = & aCubeSide[ B_FRONT ]; + _FaceGrid* fBack = & aCubeSide[ B_BACK ]; + + // cube size measured in nb of nodes + int x, xSize = fBottom->_columns.size() , X = xSize - 1; + int y, ySize = fLeft->_columns.size() , Y = ySize - 1; + int z, zSize = fLeft->_columns[0].size(), Z = zSize - 1; + + // columns of internal nodes "rising" from nodes of fBottom + _Indexer colIndex( xSize, ySize ); + vector< vector< const SMDS_MeshNode* > > columns( colIndex.size() ); + + // fill node columns by front and back box sides + for ( x = 0; x < xSize; ++x ) { + vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( x, 0 )]; + vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( x, Y )]; + column0.resize( zSize ); + column1.resize( zSize ); + for ( z = 0; z < zSize; ++z ) { + column0[ z ] = fFront->GetNode( x, z ); + column1[ z ] = fBack ->GetNode( x, z ); } } - - // find orientation of furute volumes according to MED convention - vector< bool > forward( nbx * nby ); - SMDS_VolumeTool vTool; - for (int i = 0; i < nbx - 1; i++) { - for (int j = 0; j < nby - 1; j++) { - int n1 = j * nbx + i; - int n2 = j * nbx + i + 1; - int n3 = (j + 1) * nbx + i + 1; - int n4 = (j + 1) * nbx + i; - int n5 = nbx * nby + j * nbx + i; - int n6 = nbx * nby + j * nbx + i + 1; - int n7 = nbx * nby + (j + 1) * nbx + i + 1; - int n8 = nbx * nby + (j + 1) * nbx + i; - - SMDS_VolumeOfNodes tmpVol (np[n1].node,np[n2].node,np[n3].node,np[n4].node, - np[n5].node,np[n6].node,np[n7].node,np[n8].node); - vTool.Set( &tmpVol ); - forward[ n1 ] = vTool.IsForward(); + // fill node columns by left and right box sides + for ( y = 1; y < ySize-1; ++y ) { + vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( 0, y )]; + vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( X, y )]; + column0.resize( zSize ); + column1.resize( zSize ); + for ( z = 0; z < zSize; ++z ) { + column0[ z ] = fLeft ->GetNode( y, z ); + column1[ z ] = fRight->GetNode( y, z ); + } + } + // get nodes from top and bottom box sides + for ( x = 1; x < xSize-1; ++x ) { + for ( y = 1; y < ySize-1; ++y ) { + vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )]; + column.resize( zSize ); + column.front() = fBottom->GetNode( x, y ); + column.back() = fTop ->GetNode( x, y ); } } - //2.1 - for each node of the cube (less 3 *1 Faces): - // - store hexahedron in SMESHDS - MESSAGE("Storing hexahedron into the DS"); - for (int i = 0; i < nbx - 1; i++) { - for (int j = 0; j < nby - 1; j++) { - bool isForw = forward.at( j * nbx + i ); - for (int k = 0; k < nbz - 1; k++) { - int n1 = k * nbx * nby + j * nbx + i; - int n2 = k * nbx * nby + j * nbx + i + 1; - int n3 = k * nbx * nby + (j + 1) * nbx + i + 1; - int n4 = k * nbx * nby + (j + 1) * nbx + i; - int n5 = (k + 1) * nbx * nby + j * nbx + i; - int n6 = (k + 1) * nbx * nby + j * nbx + i + 1; - int n7 = (k + 1) * nbx * nby + (j + 1) * nbx + i + 1; - int n8 = (k + 1) * nbx * nby + (j + 1) * nbx + i; - - SMDS_MeshVolume * elt; - if ( isForw ) { - elt = aTool.AddVolume(np[n1].node, np[n2].node, - np[n3].node, np[n4].node, - np[n5].node, np[n6].node, - np[n7].node, np[n8].node); - } - else { - elt = aTool.AddVolume(np[n1].node, np[n4].node, - np[n3].node, np[n2].node, - np[n5].node, np[n8].node, - np[n7].node, np[n6].node); - } - - meshDS->SetMeshElementOnShape(elt, shapeID); + // projection points of the internal node on cube sub-shapes by which + // coordinates of the internal node are computed + vector pointsOnShapes( SMESH_Block::ID_Shell ); + + // projections on vertices are constant + pointsOnShapes[ SMESH_Block::ID_V000 ] = fBottom->GetXYZ( 0, 0 ); + pointsOnShapes[ SMESH_Block::ID_V100 ] = fBottom->GetXYZ( X, 0 ); + pointsOnShapes[ SMESH_Block::ID_V010 ] = fBottom->GetXYZ( 0, Y ); + pointsOnShapes[ SMESH_Block::ID_V110 ] = fBottom->GetXYZ( X, Y ); + pointsOnShapes[ SMESH_Block::ID_V001 ] = fTop->GetXYZ( 0, 0 ); + pointsOnShapes[ SMESH_Block::ID_V101 ] = fTop->GetXYZ( X, 0 ); + pointsOnShapes[ SMESH_Block::ID_V011 ] = fTop->GetXYZ( 0, Y ); + pointsOnShapes[ SMESH_Block::ID_V111 ] = fTop->GetXYZ( X, Y ); + + for ( x = 1; x < xSize-1; ++x ) + { + gp_XYZ params; // normalized parameters of internal node within a unit box + params.SetCoord( 1, x / double(X) ); + for ( y = 1; y < ySize-1; ++y ) + { + params.SetCoord( 2, y / double(Y) ); + // a column to fill in during z loop + vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )]; + // projection points on horizontal edges + pointsOnShapes[ SMESH_Block::ID_Ex00 ] = fBottom->GetXYZ( x, 0 ); + pointsOnShapes[ SMESH_Block::ID_Ex10 ] = fBottom->GetXYZ( x, Y ); + pointsOnShapes[ SMESH_Block::ID_E0y0 ] = fBottom->GetXYZ( 0, y ); + pointsOnShapes[ SMESH_Block::ID_E1y0 ] = fBottom->GetXYZ( X, y ); + pointsOnShapes[ SMESH_Block::ID_Ex01 ] = fTop->GetXYZ( x, 0 ); + pointsOnShapes[ SMESH_Block::ID_Ex11 ] = fTop->GetXYZ( x, Y ); + pointsOnShapes[ SMESH_Block::ID_E0y1 ] = fTop->GetXYZ( 0, y ); + pointsOnShapes[ SMESH_Block::ID_E1y1 ] = fTop->GetXYZ( X, y ); + // projection points on horizontal faces + pointsOnShapes[ SMESH_Block::ID_Fxy0 ] = fBottom->GetXYZ( x, y ); + pointsOnShapes[ SMESH_Block::ID_Fxy1 ] = fTop ->GetXYZ( x, y ); + for ( z = 1; z < zSize-1; ++z ) // z loop + { + params.SetCoord( 3, z / double(Z) ); + // projection points on vertical edges + pointsOnShapes[ SMESH_Block::ID_E00z ] = fFront->GetXYZ( 0, z ); + pointsOnShapes[ SMESH_Block::ID_E10z ] = fFront->GetXYZ( X, z ); + pointsOnShapes[ SMESH_Block::ID_E01z ] = fBack->GetXYZ( 0, z ); + pointsOnShapes[ SMESH_Block::ID_E11z ] = fBack->GetXYZ( X, z ); + // projection points on vertical faces + pointsOnShapes[ SMESH_Block::ID_Fx0z ] = fFront->GetXYZ( x, z ); + pointsOnShapes[ SMESH_Block::ID_Fx1z ] = fBack ->GetXYZ( x, z ); + pointsOnShapes[ SMESH_Block::ID_F0yz ] = fLeft ->GetXYZ( y, z ); + pointsOnShapes[ SMESH_Block::ID_F1yz ] = fRight->GetXYZ( y, z ); + + // compute internal node coordinates + gp_XYZ coords; + SMESH_Block::ShellPoint( params, pointsOnShapes, coords ); + column[ z ] = helper.AddNode( coords.X(), coords.Y(), coords.Z() ); + } } } - if ( np ) delete [] np; - return ClearAndReturn( aQuads, true ); -} -//============================================================================= -/*! - * - */ -//============================================================================= - -void StdMeshers_Hexa_3D::GetPoint(Pt3 p, int i, int j, int k, int nbx, int nby, int nbz, - Point3DStruct * np, const SMESHDS_Mesh * meshDS) -{ - int ijk = k * nbx * nby + j * nbx + i; - const SMDS_MeshNode * node = np[ijk].node; - p[0] = node->X(); - p[1] = node->Y(); - p[2] = node->Z(); - //MESSAGE(" "<& col00 = columns[ colIndex( x, y )]; + vector< const SMDS_MeshNode* >& col10 = columns[ colIndex( x+1, y )]; + vector< const SMDS_MeshNode* >& col01 = columns[ colIndex( x, y+1 )]; + vector< const SMDS_MeshNode* >& col11 = columns[ colIndex( x+1, y+1 )]; + for ( z = 0; z < zSize-1; ++z ) + { + // bottom face normal of a hexa mush point outside the volume + helper.AddVolume(col00[z], col01[z], col11[z], col10[z], + col00[z+1], col01[z+1], col11[z+1], col10[z+1]); + } + } + } + return true; } //============================================================================= /*! - * + * Evaluate */ //============================================================================= -int StdMeshers_Hexa_3D::GetFaceIndex(SMESH_Mesh & aMesh, - const TopoDS_Shape & aShape, - const vector < SMESH_subMesh * >&meshFaces, - const TopoDS_Vertex & V0, - const TopoDS_Vertex & V1, - const TopoDS_Vertex & V2, const TopoDS_Vertex & V3) +bool StdMeshers_Hexa_3D::Evaluate(SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap) { - //MESSAGE("StdMeshers_Hexa_3D::GetFaceIndex"); - int faceIndex = -1; - for (int i = 1; i < 6; i++) - { - const TopoDS_Shape & aFace = meshFaces[i]->GetSubShape(); - //const TopoDS_Face& F = TopoDS::Face(aFace); - TopTools_IndexedMapOfShape M; - TopExp::MapShapes(aFace, TopAbs_VERTEX, M); - bool verticesInShape = false; - if (M.Contains(V0)) - if (M.Contains(V1)) - if (M.Contains(V2)) - if (M.Contains(V3)) - verticesInShape = true; - if (verticesInShape) - { - faceIndex = i; - break; - } - } - //IPAL21120 ASSERT(faceIndex > 0); - //SCRUTE(faceIndex); - return faceIndex; -} - -//============================================================================= -/*! - * - */ -//============================================================================= + vector < SMESH_subMesh * >meshFaces; + TopTools_SequenceOfShape aFaces; + for (TopExp_Explorer exp(aShape, TopAbs_FACE); exp.More(); exp.Next()) { + aFaces.Append(exp.Current()); + SMESH_subMesh *aSubMesh = aMesh.GetSubMeshContaining(exp.Current()); + ASSERT(aSubMesh); + meshFaces.push_back(aSubMesh); + } + if (meshFaces.size() != 6) { + //return error(COMPERR_BAD_SHAPE, TComm(meshFaces.size())<<" instead of 6 faces in a block"); + static StdMeshers_CompositeHexa_3D compositeHexa(-10, 0, aMesh.GetGen()); + return compositeHexa.Evaluate(aMesh, aShape, aResMap); + } + + int i = 0; + for(; i<6; i++) { + //TopoDS_Shape aFace = meshFaces[i]->GetSubShape(); + TopoDS_Shape aFace = aFaces.Value(i+1); + SMESH_Algo *algo = _gen->GetAlgo(aMesh, aFace); + if( !algo ) { + std::vector aResVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; iGetComputeError(); + smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); + return false; + } + string algoName = algo->GetName(); + bool isAllQuad = false; + if (algoName == "Quadrangle_2D") { + MapShapeNbElemsItr anIt = aResMap.find(meshFaces[i]); + if( anIt == aResMap.end() ) continue; + std::vector aVec = (*anIt).second; + int nbtri = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]); + if( nbtri == 0 ) + isAllQuad = true; + } + if ( ! isAllQuad ) { + return EvaluatePentahedralMesh(aMesh, aShape, aResMap); + } + } + + // find number of 1d elems for 1 face + int nb1d = 0; + TopTools_MapOfShape Edges1; + bool IsQuadratic = false; + bool IsFirst = true; + for (TopExp_Explorer exp(aFaces.Value(1), TopAbs_EDGE); exp.More(); exp.Next()) { + Edges1.Add(exp.Current()); + SMESH_subMesh *sm = aMesh.GetSubMesh(exp.Current()); + if( sm ) { + MapShapeNbElemsItr anIt = aResMap.find(sm); + if( anIt == aResMap.end() ) continue; + std::vector aVec = (*anIt).second; + nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]); + if(IsFirst) { + IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]); + IsFirst = false; + } + } + } + // find face opposite to 1 face + int OppNum = 0; + for(i=2; i<=6; i++) { + bool IsOpposite = true; + for(TopExp_Explorer exp(aFaces.Value(i), TopAbs_EDGE); exp.More(); exp.Next()) { + if( Edges1.Contains(exp.Current()) ) { + IsOpposite = false; + break; + } + } + if(IsOpposite) { + OppNum = i; + break; + } + } + // find number of 2d elems on side faces + int nb2d = 0; + for(i=2; i<=6; i++) { + if( i == OppNum ) continue; + MapShapeNbElemsItr anIt = aResMap.find( meshFaces[i-1] ); + if( anIt == aResMap.end() ) continue; + std::vector aVec = (*anIt).second; + nb2d += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); + } + + MapShapeNbElemsItr anIt = aResMap.find( meshFaces[0] ); + std::vector aVec = (*anIt).second; + int nb2d_face0 = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); + int nb0d_face0 = aVec[SMDSEntity_Node]; + + std::vector aResVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; i 0); - TopoDS_Vertex VA, VB; -// if (isForward) -// { -// VA = VFirst; -// VB = VLast; -// } -// else -// { -// VA = VLast; -// VB = VFirst; -// } - VA = quad.side[0]->FirstVertex(); - VB = quad.side[0]->LastVertex(); - - int a1, b1, c1, a2, b2, c2; - if (VA.IsSame(V0)) - { - if (VB.IsSame(V1)) - { - a1 = 1; - b1 = 0; - c1 = 0; // x - a2 = 0; - b2 = 1; - c2 = 0; // y - } - else - { - ASSERT(VB.IsSame(V3)); - a1 = 0; - b1 = 1; - c1 = 0; // y - a2 = 1; - b2 = 0; - c2 = 0; // x - } - } - if (VA.IsSame(V1)) - { - if (VB.IsSame(V2)) - { - a1 = 0; - b1 = -1; - c1 = 1; // 1-y - a2 = 1; - b2 = 0; - c2 = 0; // x - } - else - { - ASSERT(VB.IsSame(V0)); - a1 = -1; - b1 = 0; - c1 = 1; // 1-x - a2 = 0; - b2 = 1; - c2 = 0; // y - } - } - if (VA.IsSame(V2)) - { - if (VB.IsSame(V3)) - { - a1 = -1; - b1 = 0; - c1 = 1; // 1-x - a2 = 0; - b2 = -1; - c2 = 1; // 1-y - } - else - { - ASSERT(VB.IsSame(V1)); - a1 = 0; - b1 = -1; - c1 = 1; // 1-y - a2 = -1; - b2 = 0; - c2 = 1; // 1-x - } - } - if (VA.IsSame(V3)) - { - if (VB.IsSame(V0)) - { - a1 = 0; - b1 = 1; - c1 = 0; // y - a2 = -1; - b2 = 0; - c2 = 1; // 1-x - } - else - { - ASSERT(VB.IsSame(V2)); - a1 = 1; - b1 = 0; - c1 = 0; // x - a2 = 0; - b2 = -1; - c2 = 1; // 1-y - } - } -// MESSAGE("X = " << c1 << "+ " << a1 << "*x + " << b1 << "*y"); -// MESSAGE("Y = " << c2 << "+ " << a2 << "*x + " << b2 << "*y"); - conv.a1 = a1; - conv.b1 = b1; - conv.c1 = c1; - conv.a2 = a2; - conv.b2 = b2; - conv.c2 = c2; - - int nbdown = quad.side[0]->NbPoints(); - int nbright = quad.side[1]->NbPoints(); - conv.ia = int (a1); - conv.ib = int (b1); - conv.ic = - int (c1 * a1 * a1) * (nbdown - 1) + int (c1 * b1 * b1) * (nbright - 1); - conv.ja = int (a2); - conv.jb = int (b2); - conv.jc = - int (c2 * a2 * a2) * (nbdown - 1) + int (c2 * b2 * b2) * (nbright - 1); -// MESSAGE("I " << conv.ia << " " << conv.ib << " " << conv.ic); -// MESSAGE("J " << conv.ja << " " << conv.jb << " " << conv.jc); + static StdMeshers_HexaFromSkin_3D * algo = 0; + if ( !algo ) { + SMESH_Gen* gen = aMesh.GetGen(); + algo = new StdMeshers_HexaFromSkin_3D( gen->GetANewId(), 0, gen ); + } + algo->InitComputeError(); + algo->Compute( aMesh, aHelper ); + return error( algo->GetComputeError()); } //================================================================================ /*! - * \brief Find a vertex opposite to the given vertex of aQuads[0] - * \param aVertex - the vertex - * \param aFace - the face aVertex belongs to - * \param aQuads - quads - * \retval TopoDS_Vertex - found vertex + * \brief Return true if the algorithm can mesh this shape + * \param [in] aShape - shape to check + * \param [in] toCheckAll - if true, this check returns OK if all shapes are OK, + * else, returns OK if at least one shape is OK */ //================================================================================ -TopoDS_Vertex StdMeshers_Hexa_3D::OppositeVertex(const TopoDS_Vertex& aVertex, - const TopTools_IndexedMapOfShape& aQuads0Vertices, - FaceQuadStruct* aQuads[6]) +bool StdMeshers_Hexa_3D::IsApplicable( const TopoDS_Shape & aShape, bool toCheckAll ) { - int i, j; - for ( i = 1; i < 6; ++i ) + TopExp_Explorer exp0( aShape, TopAbs_SOLID ); + if ( !exp0.More() ) return false; + + for ( ; exp0.More(); exp0.Next() ) { - TopoDS_Vertex VV[] = { aQuads[i]->side[0]->FirstVertex(), - aQuads[i]->side[0]->LastVertex() , - aQuads[i]->side[2]->LastVertex() , - aQuads[i]->side[2]->FirstVertex() }; - for ( j = 0; j < 4; ++j ) - if ( aVertex.IsSame( VV[ j ])) - break; - if ( j < 4 ) { - int jPrev = j ? j - 1 : 3; - int jNext = (j + 1) % 4; - if ( aQuads0Vertices.Contains( VV[ jPrev ] )) - return VV[ jNext ]; - else - return VV[ jPrev ]; - } + int nbFoundShells = 0; + TopExp_Explorer exp1( exp0.Current(), TopAbs_SHELL ); + for ( ; exp1.More(); exp1.Next(), ++nbFoundShells) + if ( nbFoundShells == 2 ) break; + if ( nbFoundShells != 1 ) { + if ( toCheckAll ) return false; + continue; + } + exp1.Init( exp0.Current(), TopAbs_FACE ); + int nbEdges = SMESH_MesherHelper::Count( exp1.Current(), TopAbs_EDGE, /*ignoreSame=*/true ); + bool ok = ( nbEdges > 3 ); + if ( toCheckAll && !ok ) return false; + if ( !toCheckAll && ok ) return true; } - return TopoDS_Vertex(); -} - -//modified by NIZNHY-PKV Wed Nov 17 15:34:13 2004 f -/////////////////////////////////////////////////////////////////////////////// -//ZZ -//#include + return toCheckAll; +}; //======================================================================= //function : ComputePentahedralMesh //purpose : //======================================================================= -SMESH_ComputeErrorPtr ComputePentahedralMesh(SMESH_Mesh & aMesh, - const TopoDS_Shape & aShape) +SMESH_ComputeErrorPtr ComputePentahedralMesh(SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + SMESH_ProxyMesh* proxyMesh) { - //printf(" ComputePentahedralMesh HERE\n"); - // - bool bOK; SMESH_ComputeErrorPtr err = SMESH_ComputeError::New(); - //int iErr; + if ( proxyMesh ) + { + err->myName = COMPERR_BAD_INPUT_MESH; + err->myComment = "Can't build pentahedral mesh on viscous layers"; + return err; + } + bool bOK; StdMeshers_Penta_3D anAlgo; // bOK=anAlgo.Compute(aMesh, aShape); @@ -1055,6 +801,7 @@ SMESH_ComputeErrorPtr ComputePentahedralMesh(SMESH_Mesh & aMesh, } SMESH_Hypothesis::Hypothesis_Status aStatus; if ( aPrism3D->CheckHypothesis( aMesh, aShape, aStatus ) ) { + aPrism3D->InitComputeError(); bOK = aPrism3D->Compute( aMesh, aShape ); err = aPrism3D->GetComputeError(); } @@ -1063,3 +810,31 @@ SMESH_ComputeErrorPtr ComputePentahedralMesh(SMESH_Mesh & aMesh, } +//======================================================================= +//function : EvaluatePentahedralMesh +//purpose : +//======================================================================= + +bool EvaluatePentahedralMesh(SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap) +{ + StdMeshers_Penta_3D anAlgo; + bool bOK = anAlgo.Evaluate(aMesh, aShape, aResMap); + + //err = anAlgo.GetComputeError(); + //if ( !bOK && anAlgo.ErrorStatus() == 5 ) + if( !bOK ) { + static StdMeshers_Prism_3D * aPrism3D = 0; + if ( !aPrism3D ) { + SMESH_Gen* gen = aMesh.GetGen(); + aPrism3D = new StdMeshers_Prism_3D( gen->GetANewId(), 0, gen ); + } + SMESH_Hypothesis::Hypothesis_Status aStatus; + if ( aPrism3D->CheckHypothesis( aMesh, aShape, aStatus ) ) { + return aPrism3D->Evaluate(aMesh, aShape, aResMap); + } + } + + return bOK; +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ImportSource.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ImportSource.cpp new file mode 100644 index 000000000000..7ed56e331598 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ImportSource.cpp @@ -0,0 +1,497 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH StdMeshers_ImportSource1D : implementaion of SMESH idl descriptions +// File : StdMeshers_ImportSource1D.cxx +// Module : SMESH +// +#include "StdMeshers_ImportSource.hxx" + +#include "SMESHDS_GroupOnGeom.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_Algo.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_Group.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_subMeshEventListener.hxx" + +#include "utilities.h" + +#include + +#include + +using namespace std; + +//============================================================================= +/*! + * Creates StdMeshers_ImportSource1D + */ +//============================================================================= + +StdMeshers_ImportSource1D::StdMeshers_ImportSource1D(int hypId, + int studyId, + SMESH_Gen * gen) + :SMESH_Hypothesis(hypId, studyId, gen), + _toCopyMesh(false), + _toCopyGroups(false) +{ + _name = "ImportSource1D"; + _param_algo_dim = 1; // is used by StdMeshers_Import_1D; +} + +//============================================================================= +/*! + * Creates StdMeshers_ImportSource2D + */ +//============================================================================= + +StdMeshers_ImportSource2D::StdMeshers_ImportSource2D(int hypId, + int studyId, + SMESH_Gen * gen) + :StdMeshers_ImportSource1D(hypId, studyId, gen) +{ + _name = "ImportSource2D"; + _param_algo_dim = 2; // is used by StdMeshers_Import_2D; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +StdMeshers_ImportSource1D::~StdMeshers_ImportSource1D() +{ +} +//============================================================================= +/*! + * Sets groups to import elements from + */ +//============================================================================= + +void StdMeshers_ImportSource1D::SetGroups(const std::vector& groups) +{ + if (_groups != groups) + { + _groups = groups; + NotifySubMeshesHypothesisModification(); + } +} + +void StdMeshers_ImportSource1D::SetCopySourceMesh(bool toCopyMesh, bool toCopyGroups) +{ + if ( !toCopyMesh ) toCopyGroups = false; + if ( _toCopyMesh != toCopyMesh || _toCopyGroups != toCopyGroups ) + { + _toCopyMesh = toCopyMesh; _toCopyGroups = toCopyGroups; + NotifySubMeshesHypothesisModification(); + } +} +void StdMeshers_ImportSource1D::GetCopySourceMesh(bool& toCopyMesh, bool& toCopyGroups) const +{ + toCopyMesh = _toCopyMesh; toCopyGroups = _toCopyGroups; +} + +namespace +{ + //================================================================================ + /*! + * \brief Return only alive groups + */ + //================================================================================ + + vector getValidGroups(const vector& groups, + StudyContextStruct* studyContext, + bool loaded=false) + { + vector okGroups; + for ( int i = 0; i < groups.size(); ++i ) + { + try + { + // we expect SIGSEGV on a dead group + OCC_CATCH_SIGNALS; + SMESH_Group* okGroup = 0; + map::iterator itm = itm = studyContext->mapMesh.begin(); + for ( ; !okGroup && itm != studyContext->mapMesh.end(); itm++) + { + SMESH_Mesh::GroupIteratorPtr gIt = itm->second->GetGroups(); + while ( gIt->more() && !okGroup ) + if ( gIt->next() == groups[i] ) + { + okGroup = groups[i]; + if ( loaded ) + itm->second->Load(); + } + } + if ( okGroup ) + okGroups.push_back( okGroup ); + } + catch(...) + { + } + } + return okGroups; + } + //================================================================================ + /*! + * \brief Pack meshes into a pair of ints + */ + //================================================================================ + + pair getResMapKey(const SMESHDS_Mesh& srcMesh, const SMESHDS_Mesh& tgtMesh) + { + return make_pair( srcMesh.GetPersistentId() , tgtMesh.GetPersistentId() ); + } + //================================================================================ + /*! + * \brief Return a target mesh by a pair of ints + */ + //================================================================================ + + SMESH_Mesh* getTgtMeshByKey( const pair & resMapKey, + StudyContextStruct* studyContext) + { + int tgtID = resMapKey.second; + SMESH_Mesh* tgtMesh = 0; + map::iterator itm = itm = studyContext->mapMesh.begin(); + for ( ; !tgtMesh && itm != studyContext->mapMesh.end(); itm++) + { + tgtMesh = (*itm).second; + if ( tgtMesh->GetMeshDS()->GetPersistentId() != tgtID ) + tgtMesh = 0; + } + return tgtMesh; + } + //================================================================================ + /*! + * \brief Return a target mesh by a pair of ints + */ + //================================================================================ + + int getSrcMeshID( const pair & resMapKey ) + { + return resMapKey.first; + } +} + +//============================================================================= +/*! + * Returns groups to import elements from + * \param [in] loaded - if \c true, meshes holding the groups are loaded + */ +//============================================================================= + +const std::vector& StdMeshers_ImportSource1D::GetGroups(bool loaded) const +{ + // filter off deleted groups + vector okGroups = getValidGroups( _groups, + _gen->GetStudyContext(_studyId), + loaded); + if ( okGroups.size() != _groups.size() ) + ((StdMeshers_ImportSource1D*)this)->_groups = okGroups; + + return _groups; +} + +//================================================================================ +/*! + * \brief Return source meshes + */ +//================================================================================ + +std::vector StdMeshers_ImportSource1D::GetSourceMeshes() const +{ + // GetPersistentId()'s of meshes + set meshIDs; + const vector& groups = GetGroups(); + if ( !groups.empty() ) + { + for ( unsigned i = 0; i < groups.size(); ++i ) + { + const SMESHDS_GroupBase* gDS = groups[i]->GetGroupDS(); + int id = gDS->GetMesh()->GetPersistentId(); + meshIDs.insert( id ); + } + } + else + { + if ( _resultGroups.empty() ) + ((StdMeshers_ImportSource1D*)this)->RestoreGroups(_groups); + TResGroupMap::const_iterator key_groups = _resultGroups.begin(); + for ( ; key_groups != _resultGroups.end(); ++key_groups ) + meshIDs.insert( getSrcMeshID( key_groups->first )); + } + + // Find corresponding meshes + vector meshes; + if ( !meshIDs.empty() ) + { + StudyContextStruct* studyContext = _gen->GetStudyContext(_studyId); + for ( set::iterator id = meshIDs.begin(); id != meshIDs.end(); ++id ) + { + map::iterator itm = itm = studyContext->mapMesh.begin(); + for ( ; itm != studyContext->mapMesh.end(); itm++) + { + SMESH_Mesh* mesh = (*itm).second; + if ( mesh->GetMeshDS()->GetPersistentId() == *id ) + { + meshes.push_back( mesh ); + break; + } + } + } + } + return meshes; +} + +//================================================================================ +/*! + * \brief Return submeshes whose events affect the target mesh + */ +//================================================================================ + +std::vector +StdMeshers_ImportSource1D::GetSourceSubMeshes(const SMESH_Mesh* srcMesh) const +{ + if ( !srcMesh->HasShapeToMesh() ) + { + SMESH_Mesh* srcM = const_cast< SMESH_Mesh* >( srcMesh ); + return vector(1, srcM->GetSubMesh( srcM->GetShapeToMesh())); + } + set shapeIDs; + const vector& groups = GetGroups(); + const SMESHDS_Mesh * srcMeshDS = srcMesh->GetMeshDS(); + for ( size_t i = 0; i < groups.size(); ++i ) + { + SMESHDS_GroupBase * grDS = groups[i]->GetGroupDS(); + if ( grDS->GetMesh() != srcMeshDS ) + continue; + if ( SMESHDS_GroupOnGeom* gog = dynamic_cast( grDS )) + { + shapeIDs.insert( srcMeshDS->ShapeToIndex( gog->GetShape() )); + } + else + { + SMDS_ElemIteratorPtr elIt = grDS->GetElements(); + while ( elIt->more() ) + shapeIDs.insert( elIt->next()->getshapeId() ); + } + } + if ( !shapeIDs.empty() && *shapeIDs.begin() < 1 ) + { + shapeIDs.erase( shapeIDs.begin() ); + shapeIDs.insert( 1 ); + } + + vector smVec( shapeIDs.size()); + set::iterator sID = shapeIDs.begin(); + for ( int i = 0; sID != shapeIDs.end(); ++sID, ++i ) + smVec[i] = srcMesh->GetSubMeshContaining( *sID ); + + return smVec; +} + +//============================================================================= +/*! + * Save _toCopyMesh and _toCopyGroups to a stream + */ +//============================================================================= + +ostream & StdMeshers_ImportSource1D::SaveTo(ostream & save) +{ + resultGroupsToIntVec(); + + save << " " << _toCopyMesh << " " << _toCopyGroups; + save << " " << _resultGroupsStorage.size(); + for ( unsigned i = 0; i < _resultGroupsStorage.size(); ++i ) + save << " " << _resultGroupsStorage[i]; + + return save; +} + +//============================================================================= +/*! + * Load _toCopyMesh and _toCopyGroups from a stream + */ +//============================================================================= + +istream & StdMeshers_ImportSource1D::LoadFrom(istream & load) +{ + load >> _toCopyMesh >> _toCopyGroups; + + _resultGroupsStorage.clear(); + int val; + if ( load >> val ) + { + _resultGroupsStorage.reserve(val); + while ( _resultGroupsStorage.size() < _resultGroupsStorage.capacity() && load >> val ) + _resultGroupsStorage.push_back( val ); + } + return load; +} + +//================================================================================ +/*! + * \brief Convert result groups into _resultGroupsStorage + */ +//================================================================================ + +void StdMeshers_ImportSource1D::resultGroupsToIntVec() +{ + _resultGroupsStorage.clear(); + + // store result groups + TResGroupMap::iterator key2groups = _resultGroups.begin(); + for ( ; key2groups != _resultGroups.end(); ++key2groups ) + { + const pair& key = key2groups->first; + const vector& groups = key2groups->second; + // mesh ids, nb groups + _resultGroupsStorage.push_back( key.first ); + _resultGroupsStorage.push_back( key.second ); + _resultGroupsStorage.push_back( groups.size() ); + for ( unsigned i = 0; i < groups.size(); ++i ) + { + // store group names as sequence of ints each standing for a char + // of a name; that is to avoid pb with names containing white spaces + string name = groups[i]->GetGroupDS()->GetStoreName(); + _resultGroupsStorage.push_back( name.size() ); + for ( unsigned j = 0; j < name.size(); ++j ) + _resultGroupsStorage.push_back( name[j] ); + } + } +} + +//================================================================================ +/*! + * \brief Restore source groups and result groups by _resultGroupsStorage + */ +//================================================================================ + +void StdMeshers_ImportSource1D::RestoreGroups(const std::vector& groups) +{ + _groups = groups; + + _resultGroups.clear(); + int i = 0; + while ( i < _resultGroupsStorage.size() ) + { + int key1 = _resultGroupsStorage[i++]; + int key2 = _resultGroupsStorage[i++]; + pair resMapKey( key1, key2 ); + SMESH_Mesh* mesh = getTgtMeshByKey( resMapKey, _gen->GetStudyContext(_studyId)); + // restore mesh ids at least + _resultGroups.insert( make_pair (resMapKey,vector() )); + + int nbGroups = _resultGroupsStorage[i++]; + for ( int j = 0; j < nbGroups; ++j ) + { + string::size_type nameSize = _resultGroupsStorage[i++]; + string groupName(nameSize, '\0'); + for ( unsigned k = 0; k < nameSize; ++k ) + groupName[k] = (char) _resultGroupsStorage[i++]; + + // find a group by name + if ( mesh ) + { + SMESH_Group* group = 0; + SMESH_Mesh::GroupIteratorPtr gIt = mesh->GetGroups(); + while ( !group && gIt->more() ) + { + group = gIt->next(); + if ( !group->GetGroupDS() || groupName != group->GetGroupDS()->GetStoreName() ) + group = 0; + } + if ( group ) + _resultGroups[ resMapKey ].push_back( group ); + } + } + } +} + +//================================================================================ +/*! + * \brief Remember groups imported from other mesh + * \param groups - result groups + * \param srcMesh - source mesh + * \param tgtMesh - destination mesh + */ +//================================================================================ + +void StdMeshers_ImportSource1D::StoreResultGroups(const std::vector& groups, + const SMESHDS_Mesh& srcMesh, + const SMESHDS_Mesh& tgtMesh) +{ + _resultGroups[ getResMapKey(srcMesh,tgtMesh) ] = groups; +} + +//================================================================================ +/*! + * \brief Return groups imported from other mesh + * \param srcMesh - source mesh + * \param tgtMesh - destination mesh + * \retval const std::vector& - groups + */ +//================================================================================ + +std::vector* +StdMeshers_ImportSource1D::GetResultGroups(const SMESHDS_Mesh& srcMesh, + const SMESHDS_Mesh& tgtMesh) +{ + TResGroupMap::iterator key2groups = _resultGroups.find( getResMapKey(srcMesh,tgtMesh )); + if ( key2groups == _resultGroups.end() ) + return 0; + vector vec = getValidGroups((*key2groups).second, + _gen->GetStudyContext(_studyId) ); + if ( vec.size() != key2groups->second.size()) + key2groups->second = vec; + + return & key2groups->second; +} + +//================================================================================ +/*! + * \brief Initialize ImportSource value 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 + */ +//================================================================================ + +bool StdMeshers_ImportSource1D::SetParametersByMesh(const SMESH_Mesh*, const TopoDS_Shape&) +{ + return false; +} + +//================================================================================ +/*! + * \brief Initialize my parameter values by default parameters. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_ImportSource1D::SetParametersByDefaults(const TDefaults&, const SMESH_Mesh* ) +{ + return false; +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Import_1D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Import_1D.cpp new file mode 100644 index 000000000000..083f055f206a --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Import_1D.cpp @@ -0,0 +1,1100 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// File : StdMeshers_Import_1D.cxx +// Module : SMESH +// +#include "StdMeshers_Import_1D.hxx" +#include "StdMeshers_ImportSource.hxx" + +#include "SMDS_MeshElement.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMESHDS_Group.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_Comment.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_Group.hxx" +#include "SMESH_HypoFilter.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_subMeshEventListener.hxx" + +#include "Utils_SALOME_Exception.hxx" +#include "utilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +//============================================================================= +/*! + * Creates StdMeshers_Import_1D + */ +//============================================================================= + +StdMeshers_Import_1D::StdMeshers_Import_1D(int hypId, int studyId, SMESH_Gen * gen) + :SMESH_1D_Algo(hypId, studyId, gen), _sourceHyp(0) +{ + MESSAGE("StdMeshers_Import_1D::StdMeshers_Import_1D"); + _name = "Import_1D"; + _shapeType = (1 << TopAbs_EDGE); + + _compatibleHypothesis.push_back("ImportSource1D"); +} + +//================================================================================ +namespace // INTERNAL STUFF +//================================================================================ +{ + int getSubmeshIDForCopiedMesh(const SMESHDS_Mesh* srcMeshDS, SMESH_Mesh* tgtMesh); + + enum _ListenerDataType + { + WAIT_HYP_MODIF=1, // data indicating awaiting for valid parameters of src hyp + LISTEN_SRC_MESH, // data storing submesh depending on source mesh state + SRC_HYP // data storing ImportSource hyp + }; + //================================================================================ + /*! + * \brief _ListenerData holding ImportSource hyp holding in its turn + * imported groups + */ + struct _ListenerData : public SMESH_subMeshEventListenerData + { + const StdMeshers_ImportSource1D* _srcHyp; + _ListenerData(const StdMeshers_ImportSource1D* h, _ListenerDataType type=SRC_HYP): + SMESH_subMeshEventListenerData(/*isDeletable=*/true), _srcHyp(h) + { + myType = type; + } + }; + //================================================================================ + /*! + * \brief Comparator of sub-meshes + */ + struct _SubLess + { + bool operator()(const SMESH_subMesh* sm1, const SMESH_subMesh* sm2 ) const + { + if ( sm1 == sm2 ) return false; + if ( !sm1 || !sm2 ) return sm1 < sm2; + const TopoDS_Shape& s1 = sm1->GetSubShape(); + const TopoDS_Shape& s2 = sm2->GetSubShape(); + TopAbs_ShapeEnum t1 = s1.IsNull() ? TopAbs_SHAPE : s1.ShapeType(); + TopAbs_ShapeEnum t2 = s2.IsNull() ? TopAbs_SHAPE : s2.ShapeType(); + if ( t1 == t2) + return (sm1 < sm2); + return t1 < t2; // to have: face < edge + } + }; + //================================================================================ + /*! + * \brief Container of data dedicated to one source mesh + */ + struct _ImportData + { + const SMESH_Mesh* _srcMesh; + StdMeshers_Import_1D::TNodeNodeMap _n2n; + StdMeshers_Import_1D::TElemElemMap _e2e; + + set< SMESH_subMesh*, _SubLess > _subM; // submeshes relating to this srcMesh + set< SMESH_subMesh*, _SubLess > _copyMeshSubM; // submeshes requesting mesh copying + set< SMESH_subMesh*, _SubLess > _copyGroupSubM; // submeshes requesting group copying + set< SMESH_subMesh*, _SubLess > _computedSubM; + + SMESHDS_SubMesh* _importMeshSubDS; // submesh storing a copy of _srcMesh + int _importMeshSubID; // id of _importMeshSubDS + + _ImportData(const SMESH_Mesh* srcMesh=0): + _srcMesh(srcMesh), _importMeshSubDS(0),_importMeshSubID(-1) {} + + void removeImportedMesh( SMESHDS_Mesh* meshDS ) + { + if ( !_importMeshSubDS ) return; + SMDS_ElemIteratorPtr eIt = _importMeshSubDS->GetElements(); + while ( eIt->more() ) + meshDS->RemoveFreeElement( eIt->next(), 0, /*fromGroups=*/false ); + SMDS_NodeIteratorPtr nIt = _importMeshSubDS->GetNodes(); + while ( nIt->more() ) + meshDS->RemoveFreeNode( nIt->next(), 0, /*fromGroups=*/false ); + _importMeshSubDS->Clear(); + _n2n.clear(); + _e2e.clear(); + } + void removeGroups( SMESH_subMesh* subM, const StdMeshers_ImportSource1D* srcHyp ) + { + if ( !srcHyp ) return; + SMESH_Mesh* tgtMesh = subM->GetFather(); + const SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS(); + const SMESHDS_Mesh* srcMeshDS = _srcMesh->GetMeshDS(); + vector* groups = + const_cast(srcHyp)->GetResultGroups(*srcMeshDS,*tgtMeshDS); + if ( groups ) + { + for ( unsigned i = 0; i < groups->size(); ++i ) + tgtMesh->RemoveGroup( groups->at(i)->GetGroupDS()->GetID() ); + groups->clear(); + } + } + void trackHypParams( SMESH_subMesh* sm, const StdMeshers_ImportSource1D* srcHyp ) + { + if ( !srcHyp ) return; + bool toCopyMesh, toCopyGroups; + srcHyp->GetCopySourceMesh(toCopyMesh, toCopyGroups); + + if ( toCopyMesh )_copyMeshSubM.insert( sm ); + else _copyMeshSubM.erase( sm ); + + if ( toCopyGroups ) _copyGroupSubM.insert( sm ); + else _copyGroupSubM.erase( sm ); + } + void addComputed( SMESH_subMesh* sm ) + { + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true, + /*complexShapeFirst=*/true); + while ( smIt->more() ) + { + sm = smIt->next(); + switch ( sm->GetSubShape().ShapeType() ) + { + case TopAbs_EDGE: + if ( SMESH_Algo::isDegenerated( TopoDS::Edge( sm->GetSubShape() ))) + continue; + case TopAbs_FACE: + _subM.insert( sm ); + if ( !sm->IsEmpty() ) + _computedSubM.insert( sm ); + case TopAbs_VERTEX: + break; + default:; + } + } + } + }; + //================================================================================ + /*! + * Listener notified on events relating to imported submesh + */ + class _Listener : public SMESH_subMeshEventListener + { + typedef map< SMESH_Mesh*, list< _ImportData > > TMesh2ImpData; + TMesh2ImpData _tgtMesh2ImportData; + + _Listener():SMESH_subMeshEventListener(/*isDeletable=*/false, + "StdMeshers_Import_1D::_Listener") {} + + public: + // return poiter to a static listener + static _Listener* get() { static _Listener theListener; return &theListener; } + + static _ImportData* getImportData(const SMESH_Mesh* srcMesh, SMESH_Mesh* tgtMesh); + + static void storeImportSubmesh(SMESH_subMesh* importSub, + const SMESH_Mesh* srcMesh, + const StdMeshers_ImportSource1D* srcHyp); + + virtual void ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* subMesh, + SMESH_subMeshEventListenerData* data, + const SMESH_Hypothesis* hyp); + void removeSubmesh( SMESH_subMesh* sm, _ListenerData* data ); + void clearSubmesh ( SMESH_subMesh* sm, _ListenerData* data, bool clearAllSub ); + void clearN2N ( SMESH_Mesh* tgtMesh ); + + // mark sm as missing src hyp with valid groups + static void waitHypModification(SMESH_subMesh* sm) + { + sm->SetEventListener + (get(), SMESH_subMeshEventListenerData::MakeData( sm, WAIT_HYP_MODIF ), sm); + } + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Find or create ImportData for given meshes + */ + _ImportData* _Listener::getImportData(const SMESH_Mesh* srcMesh, + SMESH_Mesh* tgtMesh) + { + list< _ImportData >& dList = get()->_tgtMesh2ImportData[tgtMesh]; + list< _ImportData >::iterator d = dList.begin(); + for ( ; d != dList.end(); ++d ) + if ( d->_srcMesh == srcMesh ) + return &*d; + dList.push_back(_ImportData(srcMesh)); + return &dList.back(); + } + + //-------------------------------------------------------------------------------- + /*! + * \brief Remember an imported sub-mesh and set needed even listeners + * \param importSub - submesh computed by Import algo + * \param srcMesh - source mesh + * \param srcHyp - ImportSource hypothesis + */ + void _Listener::storeImportSubmesh(SMESH_subMesh* importSub, + const SMESH_Mesh* srcMesh, + const StdMeshers_ImportSource1D* srcHyp) + { + // set listener to hear events of the submesh computed by "Import" algo + importSub->SetEventListener( get(), new _ListenerData(srcHyp), importSub ); + + // set listeners to hear events of the source mesh + SMESH_subMesh* smToNotify = importSub; + vector smToListen = srcHyp->GetSourceSubMeshes( srcMesh ); + for ( size_t i = 0; i < smToListen.size(); ++i ) + { + SMESH_subMeshEventListenerData* data = new _ListenerData(srcHyp, LISTEN_SRC_MESH); + data->mySubMeshes.push_back( smToNotify ); + importSub->SetEventListener( get(), data, smToListen[i] ); + } + // remember the submesh importSub and its sub-submeshes + _ImportData* iData = _Listener::getImportData( srcMesh, importSub->GetFather()); + iData->trackHypParams( importSub, srcHyp ); + iData->addComputed( importSub ); + if ( !iData->_copyMeshSubM.empty() && iData->_importMeshSubID < 1 ) + { + SMESH_Mesh* tgtMesh = importSub->GetFather(); + iData->_importMeshSubID = getSubmeshIDForCopiedMesh( srcMesh->GetMeshDS(),tgtMesh); + iData->_importMeshSubDS = tgtMesh->GetMeshDS()->NewSubMesh( iData->_importMeshSubID ); + } + } + //-------------------------------------------------------------------------------- + /*! + * \brief Remove imported mesh and/or groups if needed + * \param sm - submesh loosing Import algo + * \param data - data holding imported groups + */ + void _Listener::removeSubmesh( SMESH_subMesh* sm, _ListenerData* data ) + { + list< _ImportData > & dList = _tgtMesh2ImportData[ sm->GetFather() ]; + list< _ImportData >::iterator d = dList.begin(); + for ( ; d != dList.end(); ++d ) + if ( (*d)._subM.erase( sm )) + { + d->_computedSubM.erase( sm ); + bool rmMesh = d->_copyMeshSubM.erase( sm ) && d->_copyMeshSubM.empty(); + bool rmGroups = (d->_copyGroupSubM.erase( sm ) && d->_copyGroupSubM.empty()) || rmMesh; + if ( rmMesh ) + d->removeImportedMesh( sm->GetFather()->GetMeshDS() ); + if ( rmGroups && data && data->myType == SRC_HYP ) + d->removeGroups( sm, data->_srcHyp ); + } + } + //-------------------------------------------------------------------------------- + /*! + * \brief Clear _ImportData::_n2n. + * _n2n is usefull within one mesh.Compute() only + */ + void _Listener::clearN2N( SMESH_Mesh* tgtMesh ) + { + list< _ImportData >& dList = get()->_tgtMesh2ImportData[tgtMesh]; + list< _ImportData >::iterator d = dList.begin(); + for ( ; d != dList.end(); ++d ) + d->_n2n.clear(); + } + //-------------------------------------------------------------------------------- + /*! + * \brief Clear submeshes and remove imported mesh and/or groups if necessary + * \param sm - cleared submesh + * \param data - data holding imported groups + */ + void _Listener::clearSubmesh(SMESH_subMesh* sm, _ListenerData* data, bool clearAllSub) + { + list< _ImportData > & dList = _tgtMesh2ImportData[ sm->GetFather() ]; + list< _ImportData >::iterator d = dList.begin(); + for ( ; d != dList.end(); ++d ) + { + if ( !d->_subM.count( sm )) continue; + if ( (*d)._computedSubM.erase( sm ) ) + { + bool copyMesh = !d->_copyMeshSubM.empty(); + if ( copyMesh || clearAllSub ) + { + // remove imported mesh and groups + d->removeImportedMesh( sm->GetFather()->GetMeshDS() ); + + if ( data && data->myType == SRC_HYP ) + d->removeGroups( sm, data->_srcHyp ); + + // clear the rest submeshes + if ( !d->_computedSubM.empty() ) + { + d->_computedSubM.clear(); + set< SMESH_subMesh*, _SubLess>::iterator sub = d->_subM.begin(); + for ( ; sub != d->_subM.end(); ++sub ) + { + SMESH_subMesh* subM = *sub; + _ListenerData* hypData = (_ListenerData*) subM->GetEventListenerData( get() ); + if ( hypData && hypData->myType == SRC_HYP ) + d->removeGroups( sm, hypData->_srcHyp ); + + subM->ComputeStateEngine( SMESH_subMesh::CLEAN ); + if ( subM->GetSubShape().ShapeType() == TopAbs_FACE ) + subM->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN ); + } + } + } + sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); + if ( sm->GetSubShape().ShapeType() == TopAbs_FACE ) + sm->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN ); + } + if ( data && data->myType == SRC_HYP ) + d->trackHypParams( sm, data->_srcHyp ); + d->_n2n.clear(); + d->_e2e.clear(); + } + } + //-------------------------------------------------------------------------------- + /*! + * \brief Remove imported mesh and/or groups + */ + void _Listener::ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* subMesh, + SMESH_subMeshEventListenerData* data, + const SMESH_Hypothesis* /*hyp*/) + { + if ( data && data->myType == WAIT_HYP_MODIF ) + { + // event of Import submesh + if ( SMESH_subMesh::MODIF_HYP == event && + SMESH_subMesh::ALGO_EVENT == eventType ) + { + // re-call SetEventListener() to take into account valid parameters + // of ImportSource hypothesis + if ( SMESH_Algo* algo = subMesh->GetAlgo() ) + algo->SetEventListener( subMesh ); + } + } + else if ( data && data->myType == LISTEN_SRC_MESH ) + { + // event of source mesh + if ( SMESH_subMesh::COMPUTE_EVENT == eventType ) + { + switch ( event ) { + case SMESH_subMesh::CLEAN: + // source mesh cleaned -> clean target mesh + clearSubmesh( data->mySubMeshes.front(), (_ListenerData*) data, /*all=*/true ); + break; + case SMESH_subMesh::SUBMESH_COMPUTED: { + // source mesh computed -> reset FAILED state of Import submeshes to + // READY_TO_COMPUTE + SMESH_Mesh* srcMesh = subMesh->GetFather(); + if ( srcMesh->NbEdges() > 0 || srcMesh->NbFaces() > 0 ) + { + SMESH_Mesh* m = data->mySubMeshes.front()->GetFather(); + if ( SMESH_subMesh* sm1 = m->GetSubMeshContaining(1)) + { + sm1->ComputeStateEngine(SMESH_subMesh::SUBMESH_COMPUTED ); + sm1->ComputeSubMeshStateEngine( SMESH_subMesh::SUBMESH_COMPUTED ); + } + } + break; + } + default:; + } + } + if ( !data->mySubMeshes.empty() ) + clearN2N( data->mySubMeshes.front()->GetFather() ); + } + else // event of Import submesh + { + // find out what happens: import hyp modified or removed + bool removeImport = false, modifHyp = false; + if ( SMESH_subMesh::ALGO_EVENT == eventType ) + modifHyp = true; + if ( subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK ) + { + removeImport = true; + } + else if (( SMESH_subMesh::REMOVE_ALGO == event || + SMESH_subMesh::REMOVE_FATHER_ALGO == event ) && + SMESH_subMesh::ALGO_EVENT == eventType ) + { + SMESH_Algo* algo = subMesh->GetAlgo(); + removeImport = ( strncmp( "Import", algo->GetName(), 6 ) != 0 ); + } + + if ( removeImport ) + { + // treate removal of Import algo from subMesh + removeSubmesh( subMesh, (_ListenerData*) data ); + } + else if ( modifHyp || + ( SMESH_subMesh::CLEAN == event && + SMESH_subMesh::COMPUTE_EVENT == eventType)) + { + // treate modification of ImportSource hypothesis + clearSubmesh( subMesh, (_ListenerData*) data, /*all=*/false ); + } + else if ( SMESH_subMesh::CHECK_COMPUTE_STATE == event && + SMESH_subMesh::COMPUTE_EVENT == eventType ) + { + // check compute state of all submeshes impoting from same src mesh; + // this is to take into account 1D computed submeshes hidden by 2D import algo; + // else source mesh is not copied as _subM.size != _computedSubM.size() + list< _ImportData > & dList = _tgtMesh2ImportData[ subMesh->GetFather() ]; + list< _ImportData >::iterator d = dList.begin(); + for ( ; d != dList.end(); ++d ) + if ( d->_subM.count( subMesh )) + { + set::iterator smIt = d->_subM.begin(); + for( ; smIt != d->_subM.end(); ++smIt ) + if ( (*smIt)->IsMeshComputed() ) + d->_computedSubM.insert( *smIt); + } + } + // Clear _ImportData::_n2n if it's no more useful, i.e. when + // the event is not within mesh.Compute() + if ( SMESH_subMesh::ALGO_EVENT == eventType ) + clearN2N( subMesh->GetFather() ); + } + } + + //================================================================================ + /*! + * \brief Return an ID of submesh to store nodes and elements of a copied mesh + */ + //================================================================================ + + int getSubmeshIDForCopiedMesh(const SMESHDS_Mesh* srcMeshDS, + SMESH_Mesh* tgtMesh) + { + // To get SMESH_subMesh corresponding to srcMeshDS we need to have a shape + // for which SMESHDS_Mesh::IsGroupOfSubShapes() returns true. + // And this shape must be different from sub-shapes of the main shape. + // So we create a compound containing + // 1) some sub-shapes of SMESH_Mesh::PseudoShape() corresponding to + // srcMeshDS->GetPersistentId() + // 2) the 1-st vertex of the main shape to assure + // SMESHDS_Mesh::IsGroupOfSubShapes(shape)==true + TopoDS_Shape shapeForSrcMesh; + TopTools_IndexedMapOfShape pseudoSubShapes; + TopExp::MapShapes( SMESH_Mesh::PseudoShape(), pseudoSubShapes ); + + // index of pseudoSubShapes corresponding to srcMeshDS + int subIndex = 1 + srcMeshDS->GetPersistentId() % pseudoSubShapes.Extent(); + int nbSubShapes = 1 + srcMeshDS->GetPersistentId() / pseudoSubShapes.Extent(); + + // try to find already present shapeForSrcMesh + SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS(); + for ( int i = tgtMeshDS->MaxShapeIndex(); i > 0 && shapeForSrcMesh.IsNull(); --i ) + { + const TopoDS_Shape& s = tgtMeshDS->IndexToShape(i); + if ( s.ShapeType() != TopAbs_COMPOUND ) break; + TopoDS_Iterator sSubIt( s ); + for ( int iSub = 0; iSub < nbSubShapes && sSubIt.More(); ++iSub, sSubIt.Next() ) + if ( pseudoSubShapes( subIndex+iSub ).IsSame( sSubIt.Value())) + if ( iSub+1 == nbSubShapes ) + { + shapeForSrcMesh = s; + break; + } + } + if ( shapeForSrcMesh.IsNull() ) + { + // make a new shapeForSrcMesh + BRep_Builder aBuilder; + TopoDS_Compound comp; + aBuilder.MakeCompound( comp ); + shapeForSrcMesh = comp; + for ( int iSub = 0; iSub < nbSubShapes; ++iSub ) + if ( subIndex+iSub <= pseudoSubShapes.Extent() ) + aBuilder.Add( comp, pseudoSubShapes( subIndex+iSub )); + TopExp_Explorer vExp( tgtMeshDS->ShapeToMesh(), TopAbs_VERTEX ); + aBuilder.Add( comp, vExp.Current() ); + } + SMESH_subMesh* sm = tgtMesh->GetSubMesh( shapeForSrcMesh ); + SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); + if ( !smDS ) + smDS = tgtMeshDS->NewSubMesh( sm->GetId() ); + + // make ordinary submesh from a complex one + if ( smDS->IsComplexSubmesh() ) + { + list< const SMESHDS_SubMesh* > subSM; + SMESHDS_SubMeshIteratorPtr smIt = smDS->GetSubMeshIterator(); + while ( smIt->more() ) subSM.push_back( smIt->next() ); + list< const SMESHDS_SubMesh* >::iterator sub = subSM.begin(); + for ( ; sub != subSM.end(); ++sub) + smDS->RemoveSubMesh( *sub ); + } + return sm->GetId(); + } + + //================================================================================ + /*! + * \brief Return a submesh to store nodes and elements of a copied mesh + * and set event listeners in order to clear + * imported mesh and groups as soon as submesh state requires it + */ + //================================================================================ + + SMESHDS_SubMesh* getSubmeshForCopiedMesh(const SMESH_Mesh* srcMesh, + SMESH_Mesh* tgtMesh, + const TopoDS_Shape& tgtShape, + StdMeshers_Import_1D::TNodeNodeMap*& n2n, + StdMeshers_Import_1D::TElemElemMap*& e2e, + bool & toCopyGroups) + { + StdMeshers_Import_1D::getMaps( srcMesh, tgtMesh, n2n,e2e ); + + _ImportData* iData = _Listener::getImportData(srcMesh,tgtMesh); + + SMESH_subMesh* importedSM = tgtMesh->GetSubMesh( tgtShape ); + iData->addComputed( importedSM ); + if ( iData->_computedSubM.size() != iData->_subM.size() ) + return 0; // not all submeshes computed yet + + toCopyGroups = !iData->_copyGroupSubM.empty(); + + if ( !iData->_copyMeshSubM.empty()) + { + // make submesh to store a copied mesh + int smID = getSubmeshIDForCopiedMesh( srcMesh->GetMeshDS(), tgtMesh ); + SMESHDS_SubMesh* subDS = tgtMesh->GetMeshDS()->NewSubMesh( smID ); + + iData->_importMeshSubID = smID; + iData->_importMeshSubDS = subDS; + return subDS; + } + return 0; + } + +} // namespace + +//============================================================================= +/*! + * Check presence of a hypothesis + */ +//============================================================================= + +bool StdMeshers_Import_1D::CheckHypothesis + (SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus) +{ + _sourceHyp = 0; + + const list &hyps = GetUsedHypothesis(aMesh, aShape); + if ( hyps.size() == 0 ) + { + aStatus = SMESH_Hypothesis::HYP_MISSING; + return false; // can't work with no hypothesis + } + + if ( hyps.size() > 1 ) + { + aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST; + return false; + } + + const SMESHDS_Hypothesis *theHyp = hyps.front(); + + string hypName = theHyp->GetName(); + + if (hypName == _compatibleHypothesis.front()) + { + _sourceHyp = (StdMeshers_ImportSource1D *)theHyp; + aStatus = _sourceHyp->GetGroups().empty() ? HYP_BAD_PARAMETER : HYP_OK; + if ( aStatus == HYP_BAD_PARAMETER ) + _Listener::waitHypModification( aMesh.GetSubMesh( aShape )); + return aStatus == HYP_OK; + } + + aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + return false; +} + +//============================================================================= +/*! + * Import elements from the other mesh + */ +//============================================================================= + +bool StdMeshers_Import_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & theShape) +{ + if ( !_sourceHyp ) return false; + + //MESSAGE("---------> StdMeshers_Import_1D::Compute"); + const vector& srcGroups = _sourceHyp->GetGroups(/*loaded=*/true); + if ( srcGroups.empty() ) + return error("Invalid source groups"); + + SMESH_MesherHelper helper(theMesh); + helper.SetSubShape(theShape); + SMESHDS_Mesh* tgtMesh = theMesh.GetMeshDS(); + + const TopoDS_Edge& geomEdge = TopoDS::Edge( theShape ); + const double edgeTol = BRep_Tool::Tolerance( geomEdge ); + const int shapeID = tgtMesh->ShapeToIndex( geomEdge ); + + set subShapeIDs; + subShapeIDs.insert( shapeID ); + + // get nodes on vertices + list < SMESH_TNodeXYZ > vertexNodes; + list < SMESH_TNodeXYZ >::iterator vNIt; + TopExp_Explorer vExp( theShape, TopAbs_VERTEX ); + for ( ; vExp.More(); vExp.Next() ) + { + const TopoDS_Vertex& v = TopoDS::Vertex( vExp.Current() ); + if ( !subShapeIDs.insert( tgtMesh->ShapeToIndex( v )).second ) + continue; // closed edge + const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, tgtMesh ); + if ( !n ) + { + _gen->Compute(theMesh,v,/*anUpward=*/true); + n = SMESH_Algo::VertexNode( v, tgtMesh ); + //MESSAGE("_gen->Compute " << n); + if ( !n ) return false; // very strange + } + vertexNodes.push_back( SMESH_TNodeXYZ( n )); + //MESSAGE("SMESH_Algo::VertexNode " << n->GetID() << " " << n->X() << " " << n->Y() << " " << n->Z() ); + } + + // import edges from groups + TNodeNodeMap* n2n; + TElemElemMap* e2e; + for ( int iG = 0; iG < srcGroups.size(); ++iG ) + { + const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS(); + + const int meshID = srcGroup->GetMesh()->GetPersistentId(); + const SMESH_Mesh* srcMesh = GetMeshByPersistentID( meshID ); + if ( !srcMesh ) continue; + getMaps( srcMesh, &theMesh, n2n, e2e ); + + SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements(); + vector newNodes; + SMDS_MeshNode *tmpNode = helper.AddNode(0,0,0); + double u = 0.314159; // "random" value between 0 and 1, avoid 0 and 1, false detection possible on edge restrictions + while ( srcElems->more() ) // loop on group contents + { + const SMDS_MeshElement* edge = srcElems->next(); + // find or create nodes of a new edge + newNodes.resize( edge->NbNodes() ); + //MESSAGE("edge->NbNodes " << edge->NbNodes()); + newNodes.back() = 0; + SMDS_MeshElement::iterator node = edge->begin_nodes(); + SMESH_TNodeXYZ a(edge->GetNode(0)); + // --- define a tolerance relative to the length of an edge + double mytol = a.Distance(edge->GetNode(edge->NbNodes()-1))/25; + //mytol = max(1.E-5, 10*edgeTol); // too strict and not necessary + //MESSAGE("mytol = " << mytol); + for ( unsigned i = 0; i < newNodes.size(); ++i, ++node ) + { + TNodeNodeMap::iterator n2nIt = n2n->insert( make_pair( *node, (SMDS_MeshNode*)0 )).first; + if ( n2nIt->second ) + { + if ( !subShapeIDs.count( n2nIt->second->getshapeId() )) + break; + } + else + { + // find an existing vertex node + double checktol = max(1.E-10, 10*edgeTol*edgeTol); + for ( vNIt = vertexNodes.begin(); vNIt != vertexNodes.end(); ++vNIt) + if ( vNIt->SquareDistance( *node ) < checktol) + { + //MESSAGE("SquareDistance " << vNIt->SquareDistance( *node ) << " checktol " << checktol <<" "<X()<<" "<Y()<<" "<Z()); + (*n2nIt).second = vNIt->_node; + vertexNodes.erase( vNIt ); + break; + } + else if ( vNIt->SquareDistance( *node ) < 10*checktol) + MESSAGE("SquareDistance missed" << vNIt->SquareDistance( *node ) << " checktol " << checktol <<" "<X()<<" "<Y()<<" "<Z()); + } + if ( !n2nIt->second ) + { + // find out if node lies on theShape + //double dxyz[4]; + tmpNode->setXYZ( (*node)->X(), (*node)->Y(), (*node)->Z()); + if ( helper.CheckNodeU( geomEdge, tmpNode, u, mytol, /*force=*/true)) // , dxyz )) // dxyz used for debug purposes + { + SMDS_MeshNode* newNode = tgtMesh->AddNode( (*node)->X(), (*node)->Y(), (*node)->Z()); + n2nIt->second = newNode; + tgtMesh->SetNodeOnEdge( newNode, shapeID, u ); + //MESSAGE("u=" << u << " " << newNode->X()<< " " << newNode->Y()<< " " << newNode->Z()); + //MESSAGE("d=" << dxyz[0] << " " << dxyz[1] << " " << dxyz[2] << " " << dxyz[3]); + } + } + if ( !(newNodes[i] = n2nIt->second )) + break; + } + if ( !newNodes.back() ) + { + //MESSAGE("not all nodes of edge lie on theShape"); + continue; // not all nodes of edge lie on theShape + } + + // make a new edge + SMDS_MeshElement * newEdge; + if ( newNodes.size() == 3 ) + newEdge = tgtMesh->AddEdge( newNodes[0], newNodes[1], newNodes[2] ); + else + newEdge = tgtMesh->AddEdge( newNodes[0], newNodes[1]); + //MESSAGE("add Edge " << newNodes[0]->GetID() << " " << newNodes[1]->GetID()); + tgtMesh->SetMeshElementOnShape( newEdge, shapeID ); + e2e->insert( make_pair( edge, newEdge )); + } + helper.GetMeshDS()->RemoveNode(tmpNode); + } + if ( n2n->empty()) + return error("Empty source groups"); + + // check if the whole geom edge is covered by imported segments; + // the check consist in passing by segments from one vetrex node to another + bool isEdgeMeshed = false; + if ( SMESHDS_SubMesh* tgtSM = tgtMesh->MeshElements( theShape )) + { + const TopoDS_Vertex& v = ( vExp.ReInit(), TopoDS::Vertex( vExp.Current() )); + const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, tgtMesh ); + const SMDS_MeshElement* seg = 0; + SMDS_ElemIteratorPtr segIt = n->GetInverseElementIterator(SMDSAbs_Edge); + while ( segIt->more() && !seg ) + if ( !tgtSM->Contains( seg = segIt->next())) + seg = 0; + int nbPassedSegs = 0; + while ( seg ) + { + ++nbPassedSegs; + const SMDS_MeshNode* n2 = seg->GetNode(0); + n = ( n2 == n ? seg->GetNode(1) : n2 ); + if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX ) + break; + const SMDS_MeshElement* seg2 = 0; + segIt = n->GetInverseElementIterator(SMDSAbs_Edge); + while ( segIt->more() && !seg2 ) + if ( seg == ( seg2 = segIt->next())) + seg2 = 0; + seg = seg2; + } + if (nbPassedSegs > 0 && tgtSM->NbElements() > nbPassedSegs ) + return error( "Source elements overlap one another"); + + isEdgeMeshed = ( tgtSM->NbElements() == nbPassedSegs && + n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX ); + } + if ( !isEdgeMeshed ) + return error( "Source elements don't cover totally the geometrical edge" ); + + // copy meshes + vector srcMeshes = _sourceHyp->GetSourceMeshes(); + for ( unsigned i = 0; i < srcMeshes.size(); ++i ) + importMesh( srcMeshes[i], theMesh, _sourceHyp, theShape ); + + return true; +} + +//================================================================================ +/*! + * \brief Copy mesh and groups + */ +//================================================================================ + +void StdMeshers_Import_1D::importMesh(const SMESH_Mesh* srcMesh, + SMESH_Mesh & tgtMesh, + StdMeshers_ImportSource1D* srcHyp, + const TopoDS_Shape& tgtShape) +{ + // get submesh to store the imported mesh + TNodeNodeMap* n2n; + TElemElemMap* e2e; + bool toCopyGroups; + SMESHDS_SubMesh* tgtSubMesh = + getSubmeshForCopiedMesh( srcMesh, &tgtMesh, tgtShape, n2n, e2e, toCopyGroups ); + if ( !tgtSubMesh || tgtSubMesh->NbNodes() + tgtSubMesh->NbElements() > 0 ) + return; // not to copy srcMeshDS twice + + SMESHDS_Mesh* tgtMeshDS = tgtMesh.GetMeshDS(); + SMESH_MeshEditor additor( &tgtMesh ); + + // 1. Copy mesh + + SMESH_MeshEditor::ElemFeatures elemType; + vector newNodes; + const SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS(); + SMDS_ElemIteratorPtr eIt = srcMeshDS->elementsIterator(); + while ( eIt->more() ) + { + const SMDS_MeshElement* elem = eIt->next(); + TElemElemMap::iterator e2eIt = e2e->insert( make_pair( elem, (SMDS_MeshElement*)0 )).first; + if ( e2eIt->second ) continue; // already copied by Compute() + newNodes.resize( elem->NbNodes() ); + SMDS_MeshElement::iterator node = elem->begin_nodes(); + for ( unsigned i = 0; i < newNodes.size(); ++i, ++node ) + { + TNodeNodeMap::iterator n2nIt = n2n->insert( make_pair( *node, (SMDS_MeshNode*)0 )).first; + if ( !n2nIt->second ) + { + (*n2nIt).second = tgtMeshDS->AddNode( (*node)->X(), (*node)->Y(), (*node)->Z()); + tgtSubMesh->AddNode( n2nIt->second ); + } + newNodes[i] = n2nIt->second; + } + const SMDS_MeshElement* newElem = + tgtMeshDS->FindElement( newNodes, elem->GetType(), /*noMedium=*/false ); + if ( !newElem ) + { + newElem = additor.AddElement( newNodes, elemType.Init( elem, /*basicOnly=*/false )); + tgtSubMesh->AddElement( newElem ); + } + if ( toCopyGroups ) + (*e2eIt).second = newElem; + } + // copy free nodes + if ( srcMeshDS->NbNodes() > n2n->size() ) + { + SMDS_NodeIteratorPtr nIt = srcMeshDS->nodesIterator(); + while( nIt->more() ) + { + const SMDS_MeshNode* node = nIt->next(); + if ( node->NbInverseElements() == 0 ) + { + const SMDS_MeshNode* newNode = tgtMeshDS->AddNode( node->X(), node->Y(), node->Z()); + n2n->insert( make_pair( node, newNode )); + tgtSubMesh->AddNode( newNode ); + } + } + } + + // 2. Copy groups + + vector resultGroups; + if ( toCopyGroups ) + { + // collect names of existing groups to assure uniqueness of group names within a type + map< SMDSAbs_ElementType, set > namesByType; + SMESH_Mesh::GroupIteratorPtr groupIt = tgtMesh.GetGroups(); + while ( groupIt->more() ) + { + SMESH_Group* tgtGroup = groupIt->next(); + namesByType[ tgtGroup->GetGroupDS()->GetType() ].insert( tgtGroup->GetName() ); + } + if (srcMesh) + { + SMESH_Mesh::GroupIteratorPtr groupIt = srcMesh->GetGroups(); + while ( groupIt->more() ) + { + SMESH_Group* srcGroup = groupIt->next(); + SMESHDS_GroupBase* srcGroupDS = srcGroup->GetGroupDS(); + string name = srcGroup->GetName(); + int nb = 1; + while ( !namesByType[ srcGroupDS->GetType() ].insert( name ).second ) + name = SMESH_Comment(srcGroup->GetName()) << "_imported_" << nb++; + SMESH_Group* newGroup = tgtMesh.AddGroup( srcGroupDS->GetType(), name.c_str(), nb ); + SMESHDS_Group* newGroupDS = (SMESHDS_Group*)newGroup->GetGroupDS(); + resultGroups.push_back( newGroup ); + + eIt = srcGroupDS->GetElements(); + if ( srcGroupDS->GetType() == SMDSAbs_Node ) + while (eIt->more()) + { + TNodeNodeMap::iterator n2nIt = n2n->find((const SMDS_MeshNode*) eIt->next() ); + if ( n2nIt != n2n->end() && n2nIt->second ) + newGroupDS->SMDSGroup().Add((*n2nIt).second ); + } + else + while (eIt->more()) + { + TElemElemMap::iterator e2eIt = e2e->find( eIt->next() ); + if ( e2eIt != e2e->end() && e2eIt->second ) + newGroupDS->SMDSGroup().Add((*e2eIt).second ); + } + } + } + } + n2n->clear(); + e2e->clear(); + + // Remember created groups in order to remove them as soon as the srcHyp is + // modified or something other similar happens. This imformation must be persistent, + // for that store them in a hypothesis as it stores its values in the file anyway + srcHyp->StoreResultGroups( resultGroups, *srcMeshDS, *tgtMeshDS ); +} + +//============================================================================= +/*! + * \brief Set needed event listeners and create a submesh for a copied mesh + * + * This method is called only if a submesh has HYP_OK algo_state. + */ +//============================================================================= + +void StdMeshers_Import_1D::setEventListener(SMESH_subMesh* subMesh, + StdMeshers_ImportSource1D* sourceHyp) +{ + if ( sourceHyp ) + { + vector srcMeshes = sourceHyp->GetSourceMeshes(); + if ( srcMeshes.empty() ) + _Listener::waitHypModification( subMesh ); + for ( unsigned i = 0; i < srcMeshes.size(); ++i ) + // set a listener to remove the imported mesh and groups + _Listener::storeImportSubmesh( subMesh, srcMeshes[i], sourceHyp ); + } +} +void StdMeshers_Import_1D::SetEventListener(SMESH_subMesh* subMesh) +{ + if ( !_sourceHyp ) + { + const TopoDS_Shape& tgtShape = subMesh->GetSubShape(); + SMESH_Mesh* tgtMesh = subMesh->GetFather(); + Hypothesis_Status aStatus; + CheckHypothesis( *tgtMesh, tgtShape, aStatus ); + } + setEventListener( subMesh, _sourceHyp ); +} + +void StdMeshers_Import_1D::SubmeshRestored(SMESH_subMesh* subMesh) +{ + SetEventListener(subMesh); +} + +//============================================================================= +/*! + * Predict nb of mesh entities created by Compute() + */ +//============================================================================= + +bool StdMeshers_Import_1D::Evaluate(SMESH_Mesh & theMesh, + const TopoDS_Shape & theShape, + MapShapeNbElems& aResMap) +{ + if ( !_sourceHyp ) return false; + + const vector& srcGroups = _sourceHyp->GetGroups(); + if ( srcGroups.empty() ) + return error("Invalid source groups"); + + vector aVec(SMDSEntity_Last,0); + + bool toCopyMesh, toCopyGroups; + _sourceHyp->GetCopySourceMesh(toCopyMesh, toCopyGroups); + if ( toCopyMesh ) // the whole mesh is copied + { + vector srcMeshes = _sourceHyp->GetSourceMeshes(); + for ( unsigned i = 0; i < srcMeshes.size(); ++i ) + { + SMESH_subMesh* sm = getSubMeshOfCopiedMesh( theMesh, *srcMeshes[i]); + if ( !sm || aResMap.count( sm )) continue; // already counted + aVec.assign( SMDSEntity_Last, 0); + const SMDS_MeshInfo& aMeshInfo = srcMeshes[i]->GetMeshDS()->GetMeshInfo(); + for (int i = 0; i < SMDSEntity_Last; i++) + aVec[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i); + } + } + else + { + SMESH_MesherHelper helper(theMesh); + + const TopoDS_Edge& geomEdge = TopoDS::Edge( theShape ); + const double edgeTol = helper.MaxTolerance( geomEdge ); + + // take into account nodes on vertices + TopExp_Explorer vExp( theShape, TopAbs_VERTEX ); + for ( ; vExp.More(); vExp.Next() ) + theMesh.GetSubMesh( vExp.Current())->Evaluate( aResMap ); + + // count edges imported from groups + int nbEdges = 0, nbQuadEdges = 0; + for ( int iG = 0; iG < srcGroups.size(); ++iG ) + { + const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS(); + SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements(); + SMDS_MeshNode *tmpNode = helper.AddNode(0,0,0); + while ( srcElems->more() ) // loop on group contents + { + const SMDS_MeshElement* edge = srcElems->next(); + // find out if edge is located on geomEdge by projecting + // a middle of edge to geomEdge + SMESH_TNodeXYZ p1( edge->GetNode(0)); + SMESH_TNodeXYZ p2( edge->GetNode(1)); + gp_XYZ middle = ( p1 + p2 ) / 2.; + tmpNode->setXYZ( middle.X(), middle.Y(), middle.Z()); + double u = 0; + if ( helper.CheckNodeU( geomEdge, tmpNode, u, 10 * edgeTol, /*force=*/true )) + ++( edge->IsQuadratic() ? nbQuadEdges : nbEdges); + } + helper.GetMeshDS()->RemoveNode(tmpNode); + } + + int nbNodes = nbEdges + 2 * nbQuadEdges - 1; + + aVec[SMDSEntity_Node ] = nbNodes; + aVec[SMDSEntity_Edge ] = nbEdges; + aVec[SMDSEntity_Quad_Edge] = nbQuadEdges; + } + + SMESH_subMesh * sm = theMesh.GetSubMesh(theShape); + aResMap.insert(make_pair(sm,aVec)); + + return true; +} + +//================================================================================ +/*! + * \brief Return node-node and element-element maps for import of geiven source mesh + */ +//================================================================================ + +void StdMeshers_Import_1D::getMaps(const SMESH_Mesh* srcMesh, + SMESH_Mesh* tgtMesh, + TNodeNodeMap*& n2n, + TElemElemMap*& e2e) +{ + _ImportData* iData = _Listener::getImportData(srcMesh,tgtMesh); + n2n = &iData->_n2n; + e2e = &iData->_e2e; + if ( iData->_copyMeshSubM.empty() ) + { + // n2n->clear(); -- for sharing nodes on EDGEs + e2e->clear(); + } +} + +//================================================================================ +/*! + * \brief Return submesh corresponding to the copied mesh + */ +//================================================================================ + +SMESH_subMesh* StdMeshers_Import_1D::getSubMeshOfCopiedMesh( SMESH_Mesh& tgtMesh, + SMESH_Mesh& srcMesh ) +{ + _ImportData* iData = _Listener::getImportData(&srcMesh,&tgtMesh); + if ( iData->_copyMeshSubM.empty() ) return 0; + SMESH_subMesh* sm = tgtMesh.GetSubMeshContaining( iData->_importMeshSubID ); + return sm; +} + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Import_1D2D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Import_1D2D.cpp new file mode 100644 index 000000000000..60b776254489 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Import_1D2D.cpp @@ -0,0 +1,920 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// File : StdMeshers_Import_1D2D.cxx +// Module : SMESH +// +#include "StdMeshers_Import_1D2D.hxx" + +#include "StdMeshers_Import_1D.hxx" +#include "StdMeshers_ImportSource.hxx" + +#include "SMDS_MeshElement.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMESHDS_Group.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_Comment.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_Group.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_OctreeNode.hxx" +#include "SMESH_subMesh.hxx" + +#include "Utils_SALOME_Exception.hxx" +#include "utilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +namespace +{ + double getMinElemSize2( const SMESHDS_GroupBase* srcGroup ) + { + double minSize2 = 1e100; + SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements(); + while ( srcElems->more() ) // loop on group contents + { + const SMDS_MeshElement* face = srcElems->next(); + int nbN = face->NbCornerNodes(); + + SMESH_TNodeXYZ prevN( face->GetNode( nbN-1 )); + for ( int i = 0; i < nbN; ++i ) + { + SMESH_TNodeXYZ n( face->GetNode( i ) ); + double size2 = ( n - prevN ).SquareModulus(); + minSize2 = std::min( minSize2, size2 ); + prevN = n; + } + } + return minSize2; + } +} + +//============================================================================= +/*! + * Creates StdMeshers_Import_1D2D + */ +//============================================================================= + +StdMeshers_Import_1D2D::StdMeshers_Import_1D2D(int hypId, int studyId, SMESH_Gen * gen) + :SMESH_2D_Algo(hypId, studyId, gen), _sourceHyp(0) +{ + MESSAGE("StdMeshers_Import_1D2D::StdMeshers_Import_1D2D"); + _name = "Import_1D2D"; + _shapeType = (1 << TopAbs_FACE); + + _compatibleHypothesis.push_back("ImportSource2D"); + _requireDiscreteBoundary = false; + _supportSubmeshes = true; +} + +//============================================================================= +/*! + * Check presence of a hypothesis + */ +//============================================================================= + +bool StdMeshers_Import_1D2D::CheckHypothesis + (SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus) +{ + _sourceHyp = 0; + + const list &hyps = GetUsedHypothesis(aMesh, aShape); + if ( hyps.size() == 0 ) + { + aStatus = SMESH_Hypothesis::HYP_MISSING; + return false; // can't work with no hypothesis + } + + if ( hyps.size() > 1 ) + { + aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST; + return false; + } + + const SMESHDS_Hypothesis *theHyp = hyps.front(); + + string hypName = theHyp->GetName(); + + if (hypName == _compatibleHypothesis.front()) + { + _sourceHyp = (StdMeshers_ImportSource1D *)theHyp; + aStatus = SMESH_Hypothesis::HYP_OK; + return true; + } + + aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + return true; +} + +namespace +{ + /*! + * \brief OrientedLink additionally storing a medium node + */ + struct TLink : public SMESH_OrientedLink + { + const SMDS_MeshNode* _medium; + TLink( const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* medium=0) + : SMESH_OrientedLink( n1,n2 ), _medium( medium ) {} + }; +} + +//============================================================================= +/*! + * Import elements from the other mesh + */ +//============================================================================= + +bool StdMeshers_Import_1D2D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & theShape) +{ + if ( !_sourceHyp ) return false; + + const vector& srcGroups = _sourceHyp->GetGroups(/*loaded=*/true); + if ( srcGroups.empty() ) + return error("Invalid source groups"); + + bool allGroupsEmpty = true; + for ( size_t iG = 0; iG < srcGroups.size() && allGroupsEmpty; ++iG ) + allGroupsEmpty = srcGroups[iG]->GetGroupDS()->IsEmpty(); + if ( allGroupsEmpty ) + return error("No faces in source groups"); + + SMESH_MesherHelper helper(theMesh); + helper.SetSubShape(theShape); + SMESHDS_Mesh* tgtMesh = theMesh.GetMeshDS(); + + const TopoDS_Face& geomFace = TopoDS::Face( theShape ); + const double faceTol = helper.MaxTolerance( geomFace ); + const int shapeID = tgtMesh->ShapeToIndex( geomFace ); + const bool toCheckOri = (helper.NbAncestors( geomFace, theMesh, TopAbs_SOLID ) == 1 ); + + + Handle(Geom_Surface) surface = BRep_Tool::Surface( geomFace ); + const bool reverse = + ( helper.GetSubShapeOri( tgtMesh->ShapeToMesh(), geomFace ) == TopAbs_REVERSED ); + gp_Pnt p; gp_Vec du, dv; + + // BRepClass_FaceClassifier is most time consuming, so minimize its usage + BRepClass_FaceClassifier classifier; + Bnd_B2d bndBox2d; + Bnd_Box bndBox3d; + { + Standard_Real umin,umax,vmin,vmax; + BRepTools::UVBounds(geomFace,umin,umax,vmin,vmax); + gp_XY pmin( umin,vmin ), pmax( umax,vmax ); + bndBox2d.Add( pmin ); + bndBox2d.Add( pmax ); + if ( helper.HasSeam() ) + { + const int i = helper.GetPeriodicIndex(); + pmin.SetCoord( i, helper.GetOtherParam( pmin.Coord( i ))); + pmax.SetCoord( i, helper.GetOtherParam( pmax.Coord( i ))); + bndBox2d.Add( pmin ); + bndBox2d.Add( pmax ); + } + bndBox2d.Enlarge( 1e-2 * Sqrt( bndBox2d.SquareExtent() )); + + BRepBndLib::Add( geomFace, bndBox3d ); + bndBox3d.Enlarge( 1e-5 * sqrt( bndBox3d.SquareExtent() )); + } + + set subShapeIDs; + subShapeIDs.insert( shapeID ); + + // nodes already existing on sub-shapes of the FACE + TIDSortedNodeSet existingNodes; + + // get/make nodes on vertices and add them to existingNodes + TopExp_Explorer exp( theShape, TopAbs_VERTEX ); + for ( ; exp.More(); exp.Next() ) + { + const TopoDS_Vertex& v = TopoDS::Vertex( exp.Current() ); + if ( !subShapeIDs.insert( tgtMesh->ShapeToIndex( v )).second ) + continue; + const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, tgtMesh ); + if ( !n ) + { + _gen->Compute(theMesh,v,/*anUpward=*/true); + n = SMESH_Algo::VertexNode( v, tgtMesh ); + if ( !n ) return false; // very strange + } + existingNodes.insert( n ); + } + + // get EDGEs and their ids and get existing nodes on EDGEs + vector< TopoDS_Edge > edges; + for ( exp.Init( theShape, TopAbs_EDGE ); exp.More(); exp.Next() ) + { + const TopoDS_Edge & edge = TopoDS::Edge( exp.Current() ); + if ( !SMESH_Algo::isDegenerated( edge )) + if ( subShapeIDs.insert( tgtMesh->ShapeToIndex( edge )).second ) + { + edges.push_back( edge ); + if ( SMESHDS_SubMesh* eSM = tgtMesh->MeshElements( edge )) + { + typedef SMDS_StdIterator< const SMDS_MeshNode*, SMDS_NodeIteratorPtr > iterator; + existingNodes.insert( iterator( eSM->GetNodes() ), iterator() ); + } + } + } + // octree to find existing nodes + SMESH_OctreeNode existingNodeOcTr( existingNodes ); + std::map dist2foundNodes; + + // to count now many times a link between nodes encounters + map linkCount; + map::iterator link2Nb; + double minGroupTol = Precision::Infinite(); + + // ========================= + // Import faces from groups + // ========================= + + StdMeshers_Import_1D::TNodeNodeMap* n2n; + StdMeshers_Import_1D::TElemElemMap* e2e; + vector nodeState; + vector newNodes; // of a face + set bndNodes; // nodes classified ON + vector isNodeIn; // nodes classified IN, by node ID + + for ( size_t iG = 0; iG < srcGroups.size(); ++iG ) + { + const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS(); + + const int meshID = srcGroup->GetMesh()->GetPersistentId(); + const SMESH_Mesh* srcMesh = GetMeshByPersistentID( meshID ); + if ( !srcMesh ) continue; + StdMeshers_Import_1D::getMaps( srcMesh, &theMesh, n2n, e2e ); + + const double groupTol = 0.5 * sqrt( getMinElemSize2( srcGroup )); + minGroupTol = std::min( groupTol, minGroupTol ); + + //GeomAdaptor_Surface S( surface ); + // const double clsfTol = Min( S.UResolution( 0.1 * groupTol ), -- issue 0023092 + // S.VResolution( 0.1 * groupTol )); + const double clsfTol = BRep_Tool::Tolerance( geomFace ); + + StdMeshers_Import_1D::TNodeNodeMap::iterator n2nIt; + pair< StdMeshers_Import_1D::TNodeNodeMap::iterator, bool > it_isnew; + + SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements(); + while ( srcElems->more() ) // loop on group contents + { + const SMDS_MeshElement* face = srcElems->next(); + + SMDS_MeshElement::iterator node = face->begin_nodes(); + if ( bndBox3d.IsOut( SMESH_TNodeXYZ( *node ))) + continue; + + // find or create nodes of a new face + nodeState.resize( face->NbNodes() ); + newNodes.resize( nodeState.size() ); + newNodes.back() = 0; + int nbCreatedNodes = 0; + bool isOut = false, isIn = false; // if at least one node isIn - do not classify other nodes + for ( size_t i = 0; i < newNodes.size(); ++i, ++node ) + { + SMESH_TNodeXYZ nXYZ = *node; + nodeState[ i ] = TopAbs_UNKNOWN; + newNodes [ i ] = 0; + + it_isnew = n2n->insert( make_pair( *node, (SMDS_MeshNode*)0 )); + n2nIt = it_isnew.first; + + const SMDS_MeshNode* & newNode = n2nIt->second; + if ( !it_isnew.second && !newNode ) + break; // a node is mapped to NULL - it is OUT of the FACE + + if ( newNode ) + { + if ( !subShapeIDs.count( newNode->getshapeId() )) + break; // node is Imported onto other FACE + if ( newNode->GetID() < (int) isNodeIn.size() && + isNodeIn[ newNode->GetID() ]) + isIn = true; + if ( !isIn && bndNodes.count( *node )) + nodeState[ i ] = TopAbs_ON; + } + else + { + // find a node pre-existing on EDGE or VERTEX + dist2foundNodes.clear(); + existingNodeOcTr.NodesAround( nXYZ, dist2foundNodes, groupTol ); + if ( !dist2foundNodes.empty() ) + { + newNode = dist2foundNodes.begin()->second; + nodeState[ i ] = TopAbs_ON; + } + } + + if ( !newNode ) + { + // find out if node lies on the surface of theShape + gp_XY uv( Precision::Infinite(), 0 ); + isOut = ( !helper.CheckNodeUV( geomFace, *node, uv, groupTol, /*force=*/true ) || + bndBox2d.IsOut( uv )); + if ( !isOut && !isIn ) // classify + { + classifier.Perform( geomFace, uv, clsfTol ); + nodeState[i] = classifier.State(); + isOut = ( nodeState[i] == TopAbs_OUT ); + } + if ( !isOut ) // create a new node + { + newNode = tgtMesh->AddNode( nXYZ.X(), nXYZ.Y(), nXYZ.Z()); + tgtMesh->SetNodeOnFace( newNode, shapeID, uv.X(), uv.Y() ); + nbCreatedNodes++; + if ( newNode->GetID() >= (int) isNodeIn.size() ) + { + isNodeIn.push_back( false ); // allow allocate more than newNode->GetID() + isNodeIn.resize( newNode->GetID() + 1, false ); + } + if ( nodeState[i] == TopAbs_ON ) + bndNodes.insert( *node ); + else + isNodeIn[ newNode->GetID() ] = isIn = true; + } + } + if ( !(newNodes[i] = newNode ) || isOut ) + break; + } + + if ( !newNodes.back() ) + continue; // not all nodes of the face lie on theShape + + if ( !isIn ) // if all nodes are on FACE boundary, a mesh face can be OUT + { + // check state of nodes created for other faces + for ( size_t i = 0; i < nodeState.size() && !isIn; ++i ) + { + if ( nodeState[i] != TopAbs_UNKNOWN ) continue; + gp_XY uv = helper.GetNodeUV( geomFace, newNodes[i] ); + classifier.Perform( geomFace, uv, clsfTol ); + nodeState[i] = classifier.State(); + isIn = ( nodeState[i] == TopAbs_IN ); + } + if ( !isIn ) // classify face center + { + gp_XYZ gc( 0., 0., 0 ); + for ( size_t i = 0; i < newNodes.size(); ++i ) + gc += SMESH_TNodeXYZ( newNodes[i] ); + gc /= newNodes.size(); + + TopLoc_Location loc; + GeomAPI_ProjectPointOnSurf& proj = helper.GetProjector( geomFace, + loc, + helper.MaxTolerance( geomFace )); + if ( !loc.IsIdentity() ) loc.Transformation().Inverted().Transforms( gc ); + proj.Perform( gc ); + if ( !proj.IsDone() || proj.NbPoints() < 1 ) + continue; + Quantity_Parameter U,V; + proj.LowerDistanceParameters(U,V); + gp_XY uv( U,V ); + classifier.Perform( geomFace, uv, clsfTol ); + if ( classifier.State() != TopAbs_IN ) + continue; + } + } + + // try to find already created face + SMDS_MeshElement * newFace = 0; + if ( nbCreatedNodes == 0 && + tgtMesh->FindElement(newNodes, SMDSAbs_Face, /*noMedium=*/false)) + continue; // repeated face in source groups already created + + // check future face orientation + const int nbCorners = face->NbCornerNodes(); + const bool isQuad = ( nbCorners != (int) newNodes.size() ); + if ( toCheckOri ) + { + int iNode = -1; + gp_Vec geomNorm; + do + { + gp_XY uv = helper.GetNodeUV( geomFace, newNodes[++iNode] ); + surface->D1( uv.X(),uv.Y(), p, du,dv ); + geomNorm = reverse ? dv^du : du^dv; + } + while ( geomNorm.SquareMagnitude() < 1e-6 && iNode+1 < nbCorners ); + + int iNext = helper.WrapIndex( iNode+1, nbCorners ); + int iPrev = helper.WrapIndex( iNode-1, nbCorners ); + + SMESH_TNodeXYZ prevNode( newNodes[iPrev] ); + SMESH_TNodeXYZ curNode ( newNodes[iNode] ); + SMESH_TNodeXYZ nextNode( newNodes[iNext] ); + gp_Vec n1n0( prevNode - curNode); + gp_Vec n1n2( nextNode - curNode ); + gp_Vec meshNorm = n1n2 ^ n1n0; + + if ( geomNorm * meshNorm < 0 ) + SMDS_MeshCell::applyInterlace + ( SMDS_MeshCell::reverseSmdsOrder( face->GetEntityType(), newNodes.size() ), newNodes ); + } + + // make a new face + if ( face->IsPoly() ) + newFace = tgtMesh->AddPolygonalFace( newNodes ); + else + switch ( newNodes.size() ) + { + case 3: + newFace = tgtMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] ); + break; + case 4: + newFace = tgtMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] ); + break; + case 6: + newFace = tgtMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], + newNodes[3], newNodes[4], newNodes[5]); + break; + case 8: + newFace = tgtMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3], + newNodes[4], newNodes[5], newNodes[6], newNodes[7]); + break; + default: continue; + } + tgtMesh->SetMeshElementOnShape( newFace, shapeID ); + e2e->insert( make_pair( face, newFace )); + + // collect links + const SMDS_MeshNode* medium = 0; + for ( int i = 0; i < nbCorners; ++i ) + { + const SMDS_MeshNode* n1 = newNodes[i]; + const SMDS_MeshNode* n2 = newNodes[ (i+1)%nbCorners ]; + if ( isQuad ) // quadratic face + medium = newNodes[i+nbCorners]; + link2Nb = linkCount.insert( make_pair( TLink( n1, n2, medium ), 0)).first; + ++link2Nb->second; + // if ( link2Nb->second == 1 ) + // { + // // measure link length + // double len2 = SMESH_TNodeXYZ( n1 ).SquareDistance( n2 ); + // if ( len2 < minGroupTol ) + // minGroupTol = len2; + // } + } + } + // Remove OUT nodes from n2n map + for ( n2nIt = n2n->begin(); n2nIt != n2n->end(); ) + if ( !n2nIt->second ) + n2n->erase( n2nIt++ ); + else + ++n2nIt; + } + + + // ========================================================== + // Put nodes on geom edges and create edges on them; + // check if the whole geom face is covered by imported faces + // ========================================================== + + // use large tolerance for projection of nodes to edges because of + // BLSURF mesher specifics (issue 0020918, Study2.hdf) + const double projTol = minGroupTol; + + bool isFaceMeshed = false; + SMESHDS_SubMesh* tgtFaceSM = tgtMesh->MeshElements( theShape ); + if ( tgtFaceSM ) + { + // the imported mesh is valid if all external links (encountered once) + // lie on geom edges + subShapeIDs.erase( shapeID ); // to contain edges and vertices only + double u, f, l; + for ( link2Nb = linkCount.begin(); link2Nb != linkCount.end(); ++link2Nb) + { + const TLink& link = (*link2Nb).first; + int nbFaces = link2Nb->second; + if ( nbFaces == 1 ) + { + // check if a not shared link lies on face boundary + bool nodesOnBoundary = true; + list< TopoDS_Shape > bndShapes; + for ( int is1stN = 0; is1stN < 2 && nodesOnBoundary; ++is1stN ) + { + const SMDS_MeshNode* n = is1stN ? link.node1() : link.node2(); + if ( !subShapeIDs.count( n->getshapeId() )) // n is assigned to FACE + { + for ( size_t iE = 0; iE < edges.size(); ++iE ) + if ( helper.CheckNodeU( edges[iE], n, u=0, projTol, /*force=*/true )) + { + BRep_Tool::Range(edges[iE],f,l); + if ( Abs(u-f) < 2 * faceTol || Abs(u-l) < 2 * faceTol ) + // duplicated node on vertex + return error("Source elements overlap one another"); + tgtFaceSM->RemoveNode( n, /*isNodeDeleted=*/false ); + tgtMesh->SetNodeOnEdge( n, edges[iE], u ); + break; + } + nodesOnBoundary = subShapeIDs.count( n->getshapeId()); + } + if ( nodesOnBoundary ) + { + TopoDS_Shape s = helper.GetSubShapeByNode( n, tgtMesh ); + if ( s.ShapeType() == TopAbs_VERTEX ) + bndShapes.push_front( s ); // vertex first + else + bndShapes.push_back( s ); // edges last + } + } + if ( !nodesOnBoundary ) + { + error("free internal link"); // just for an easier debug + break; + } + if ( bndShapes.front().ShapeType() == TopAbs_EDGE && // all link nodes are on EDGEs + bndShapes.front() != bndShapes.back() ) + // link nodes on different geom edges + return error(COMPERR_BAD_INPUT_MESH, "Source nodes mismatch target vertices"); + + // find geom edge the link is on + if ( bndShapes.back().ShapeType() != TopAbs_EDGE ) // all link nodes are on VERTEXes + { + // find geom edge by two vertices + TopoDS_Shape geomEdge = helper.GetCommonAncestor( bndShapes.back(), + bndShapes.front(), + theMesh, TopAbs_EDGE ); + if ( geomEdge.IsNull() ) + { + error("free internal link"); + break; // vertices belong to different edges + } + bndShapes.push_back( geomEdge ); + } + + // create an edge if not yet exists + newNodes.resize(2); + newNodes[0] = link.node1(), newNodes[1] = link.node2(); + const SMDS_MeshElement* edge = tgtMesh->FindElement( newNodes, SMDSAbs_Edge ); + if ( edge ) continue; + + if ( link._reversed ) std::swap( newNodes[0], newNodes[1] ); + if ( link._medium ) + { + edge = tgtMesh->AddEdge( newNodes[0], newNodes[1], link._medium ); + + TopoDS_Edge geomEdge = TopoDS::Edge(bndShapes.back()); + helper.CheckNodeU( geomEdge, link._medium, u, projTol, /*force=*/true ); + tgtFaceSM->RemoveNode( link._medium, /*isNodeDeleted=*/false ); + tgtMesh->SetNodeOnEdge( (SMDS_MeshNode*)link._medium, geomEdge, u ); + } + else + { + edge = tgtMesh->AddEdge( newNodes[0], newNodes[1]); + } + if ( !edge ) + return false; + + tgtMesh->SetMeshElementOnShape( edge, bndShapes.back() ); + } + else if ( nbFaces > 2 ) + { + return error( COMPERR_BAD_INPUT_MESH, "Non-manifold source mesh"); + } + } + isFaceMeshed = ( link2Nb == linkCount.end() && !linkCount.empty()); + if ( isFaceMeshed ) + { + // check that source faces do not overlap: + // there must be only two edges sharing each vertex and bound to sub-edges of theShape + SMESH_MeshEditor editor( &theMesh ); + set::iterator subID = subShapeIDs.begin(); + for ( ; subID != subShapeIDs.end(); ++subID ) + { + const TopoDS_Shape& s = tgtMesh->IndexToShape( *subID ); + if ( s.ShapeType() != TopAbs_VERTEX ) continue; + const SMDS_MeshNode* n = SMESH_Algo::VertexNode( TopoDS::Vertex(s), tgtMesh ); + SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator(SMDSAbs_Edge); + int nbEdges = 0; + while ( eIt->more() ) + { + const SMDS_MeshElement* edge = eIt->next(); + int sId = editor.FindShape( edge ); + nbEdges += subShapeIDs.count( sId ); + } + if ( nbEdges < 2 && !helper.IsRealSeam( s )) + return false; // weird + if ( nbEdges > 2 ) + return error( COMPERR_BAD_INPUT_MESH, "Source elements overlap one another"); + } + } + } + if ( !isFaceMeshed ) + return error( COMPERR_BAD_INPUT_MESH, + "Source elements don't cover totally the geometrical face" ); + + if ( helper.HasSeam() ) + { + // links on seam edges are shared by two faces, so no edges were created on them + // by the previous detection of 2D mesh boundary + for ( size_t iE = 0; iE < edges.size(); ++iE ) + { + if ( !helper.IsRealSeam( edges[iE] )) continue; + const TopoDS_Edge& seamEdge = edges[iE]; + // to find nodes lying on the seamEdge we check nodes of mesh faces sharing a node on one + // of its vertices; after finding another node on seamEdge we continue the same way + // until finding all nodes. + TopoDS_Vertex seamVertex = helper.IthVertex( 0, seamEdge ); + const SMDS_MeshNode* vertNode = SMESH_Algo::VertexNode( seamVertex, tgtMesh ); + set< const SMDS_MeshNode* > checkedNodes; checkedNodes.insert( vertNode ); + set< const SMDS_MeshElement* > checkedFaces; + // as a face can have more than one node on the seamEdge, there is a difficulty in selecting + // one of those nodes to treat next; so we simply find all nodes on the seamEdge and + // then sort them by U on edge + typedef list< pair< double, const SMDS_MeshNode* > > TUNodeList; + TUNodeList nodesOnSeam; + double u = helper.GetNodeU( seamEdge, vertNode ); + nodesOnSeam.push_back( make_pair( u, vertNode )); + TUNodeList::iterator u2nIt = nodesOnSeam.begin(); + for ( ; u2nIt != nodesOnSeam.end(); ++u2nIt ) + { + const SMDS_MeshNode* startNode = (*u2nIt).second; + SMDS_ElemIteratorPtr faceIt = startNode->GetInverseElementIterator( SMDSAbs_Face ); + while ( faceIt->more() ) + { + const SMDS_MeshElement* face = faceIt->next(); + if ( !checkedFaces.insert( face ).second ) continue; + for ( int i = 0, nbNodes = face->NbCornerNodes(); i < nbNodes; ++i ) + { + const SMDS_MeshNode* n = face->GetNode( i ); + if ( n == startNode || !checkedNodes.insert( n ).second ) continue; + if ( helper.CheckNodeU( seamEdge, n, u=0, projTol, /*force=*/true )) + nodesOnSeam.push_back( make_pair( u, n )); + } + } + } + // sort the found nodes by U on the seamEdge; most probably they are in a good order, + // so we can use the hint to spead-up map filling + map< double, const SMDS_MeshNode* > u2nodeMap; + for ( u2nIt = nodesOnSeam.begin(); u2nIt != nodesOnSeam.end(); ++u2nIt ) + u2nodeMap.insert( u2nodeMap.end(), *u2nIt ); + + // create edges + { + SMESH_MesherHelper seamHelper( theMesh ); + seamHelper.SetSubShape( edges[ iE ]); + seamHelper.SetElementsOnShape( true ); + + if ( !checkedFaces.empty() && (*checkedFaces.begin())->IsQuadratic() ) + for ( set< const SMDS_MeshElement* >::iterator fIt = checkedFaces.begin(); + fIt != checkedFaces.end(); ++fIt ) + seamHelper.AddTLinks( static_cast( *fIt )); + + map< double, const SMDS_MeshNode* >::iterator n1, n2, u2nEnd = u2nodeMap.end(); + for ( n2 = u2nodeMap.begin(), n1 = n2++; n2 != u2nEnd; ++n1, ++n2 ) + { + const SMDS_MeshNode* node1 = n1->second; + const SMDS_MeshNode* node2 = n2->second; + seamHelper.AddEdge( node1, node2 ); + if ( node2->getshapeId() == helper.GetSubShapeID() ) + { + tgtFaceSM->RemoveNode( node2, /*isNodeDeleted=*/false ); + tgtMesh->SetNodeOnEdge( const_cast( node2 ), seamEdge, n2->first ); + } + } + } + } // loop on edges to find seam ones + } // if ( helper.HasSeam() ) + + // notify sub-meshes of edges on computation + for ( size_t iE = 0; iE < edges.size(); ++iE ) + { + SMESH_subMesh * sm = theMesh.GetSubMesh( edges[iE] ); + // if ( SMESH_Algo::isDegenerated( edges[iE] )) + // sm->SetIsAlwaysComputed( true ); + sm->ComputeStateEngine(SMESH_subMesh::CHECK_COMPUTE_STATE); + if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK ) + return error(SMESH_Comment("Failed to create segments on the edge #") << sm->GetId()); + } + + // ============ + // Copy meshes + // ============ + + vector srcMeshes = _sourceHyp->GetSourceMeshes(); + for ( size_t i = 0; i < srcMeshes.size(); ++i ) + StdMeshers_Import_1D::importMesh( srcMeshes[i], theMesh, _sourceHyp, theShape ); + + return true; +} + +//============================================================================= +/*! + * \brief Set needed event listeners and create a submesh for a copied mesh + * + * This method is called only if a submesh has HYP_OK algo_state. + */ +//============================================================================= + +void StdMeshers_Import_1D2D::SetEventListener(SMESH_subMesh* subMesh) +{ + if ( !_sourceHyp ) + { + const TopoDS_Shape& tgtShape = subMesh->GetSubShape(); + SMESH_Mesh* tgtMesh = subMesh->GetFather(); + Hypothesis_Status aStatus; + CheckHypothesis( *tgtMesh, tgtShape, aStatus ); + } + StdMeshers_Import_1D::setEventListener( subMesh, _sourceHyp ); +} +void StdMeshers_Import_1D2D::SubmeshRestored(SMESH_subMesh* subMesh) +{ + SetEventListener(subMesh); +} + +//============================================================================= +/*! + * Predict nb of mesh entities created by Compute() + */ +//============================================================================= + +bool StdMeshers_Import_1D2D::Evaluate(SMESH_Mesh & theMesh, + const TopoDS_Shape & theShape, + MapShapeNbElems& aResMap) +{ + if ( !_sourceHyp ) return false; + + const vector& srcGroups = _sourceHyp->GetGroups(); + if ( srcGroups.empty() ) + return error("Invalid source groups"); + + vector aVec(SMDSEntity_Last,0); + + bool toCopyMesh, toCopyGroups; + _sourceHyp->GetCopySourceMesh(toCopyMesh, toCopyGroups); + if ( toCopyMesh ) // the whole mesh is copied + { + vector srcMeshes = _sourceHyp->GetSourceMeshes(); + for ( unsigned i = 0; i < srcMeshes.size(); ++i ) + { + SMESH_subMesh* sm = StdMeshers_Import_1D::getSubMeshOfCopiedMesh( theMesh, *srcMeshes[i]); + if ( !sm || aResMap.count( sm )) continue; // already counted + const SMDS_MeshInfo& aMeshInfo = srcMeshes[i]->GetMeshDS()->GetMeshInfo(); + for (int i = 0; i < SMDSEntity_Last; i++) + aVec[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i); + } + } + else + { + // std-like iterator used to get coordinates of nodes of mesh element + typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator; + + SMESH_MesherHelper helper(theMesh); + helper.SetSubShape(theShape); + + const TopoDS_Face& geomFace = TopoDS::Face( theShape ); + + // take into account nodes on vertices + TopExp_Explorer exp( theShape, TopAbs_VERTEX ); + for ( ; exp.More(); exp.Next() ) + theMesh.GetSubMesh( exp.Current())->Evaluate( aResMap ); + + // to count now many times a link between nodes encounters, + // negative nb additionally means that a link is quadratic + map linkCount; + map::iterator link2Nb; + + // count faces and nodes imported from groups + set allNodes; + gp_XY uv; + double minGroupTol = 1e100; + for ( int iG = 0; iG < srcGroups.size(); ++iG ) + { + const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS(); + const double groupTol = 0.5 * sqrt( getMinElemSize2( srcGroup )); + minGroupTol = std::min( groupTol, minGroupTol ); + SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements(); + SMDS_MeshNode *tmpNode =helper.AddNode(0,0,0); + while ( srcElems->more() ) // loop on group contents + { + const SMDS_MeshElement* face = srcElems->next(); + // find out if face is located on geomEdge by projecting + // a gravity center of face to geomFace + gp_XYZ gc(0,0,0); + gc = accumulate( TXyzIterator(face->nodesIterator()), TXyzIterator(), gc)/face->NbNodes(); + tmpNode->setXYZ( gc.X(), gc.Y(), gc.Z()); + if ( helper.CheckNodeUV( geomFace, tmpNode, uv, groupTol, /*force=*/true )) + { + ++aVec[ face->GetEntityType() ]; + + // collect links + int nbConers = face->NbCornerNodes(); + for ( int i = 0; i < face->NbNodes(); ++i ) + { + const SMDS_MeshNode* n1 = face->GetNode(i); + allNodes.insert( n1 ); + if ( i < nbConers ) + { + const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbConers ); + link2Nb = linkCount.insert( make_pair( SMESH_TLink( n1, n2 ), 0)).first; + if ( (*link2Nb).second ) + link2Nb->second += (link2Nb->second < 0 ) ? -1 : 1; + else + link2Nb->second += ( face->IsQuadratic() ) ? -1 : 1; + } + } + } + } + helper.GetMeshDS()->RemoveNode(tmpNode); + } + + int nbNodes = allNodes.size(); + allNodes.clear(); + + // count nodes and edges on geom edges + + double u; + for ( exp.Init(theShape, TopAbs_EDGE); exp.More(); exp.Next() ) + { + TopoDS_Edge geomEdge = TopoDS::Edge( exp.Current() ); + SMESH_subMesh* sm = theMesh.GetSubMesh( geomEdge ); + vector& edgeVec = aResMap[sm]; + if ( edgeVec.empty() ) + { + edgeVec.resize(SMDSEntity_Last,0); + for ( link2Nb = linkCount.begin(); link2Nb != linkCount.end(); ) + { + const SMESH_TLink& link = (*link2Nb).first; + int nbFacesOfLink = Abs( link2Nb->second ); + bool eraseLink = ( nbFacesOfLink != 1 ); + if ( nbFacesOfLink == 1 ) + { + if ( helper.CheckNodeU( geomEdge, link.node1(), u, minGroupTol, /*force=*/true )&& + helper.CheckNodeU( geomEdge, link.node2(), u, minGroupTol, /*force=*/true )) + { + bool isQuadratic = ( link2Nb->second < 0 ); + ++edgeVec[ isQuadratic ? SMDSEntity_Quad_Edge : SMDSEntity_Edge ]; + ++edgeVec[ SMDSEntity_Node ]; + --nbNodes; + eraseLink = true; + } + } + if ( eraseLink ) + linkCount.erase(link2Nb++); + else + link2Nb++; + } + if ( edgeVec[ SMDSEntity_Node] > 0 ) + --edgeVec[ SMDSEntity_Node ]; // for one node on vertex + } + else if ( !helper.IsSeamShape( geomEdge ) || + geomEdge.Orientation() == TopAbs_FORWARD ) + { + nbNodes -= 1+edgeVec[ SMDSEntity_Node ]; + } + } + + aVec[SMDSEntity_Node] = nbNodes; + } + + SMESH_subMesh * sm = theMesh.GetSubMesh(theShape); + aResMap.insert(make_pair(sm,aVec)); + + return true; +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LayerDistribution.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LayerDistribution.cpp index ce120f861288..03bb2c7f51a5 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LayerDistribution.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LayerDistribution.cpp @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : idl implementation based on 'SMESH' unit's classes // File : StdMeshers_LayerDistribution.cxx // Author : Edward AGAPOV // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_LayerDistribution.cxx,v 1.2.2.1 2008/11/27 13:03:49 abd Exp $ // #include "StdMeshers_LayerDistribution.hxx" @@ -70,11 +70,11 @@ StdMeshers_LayerDistribution::~StdMeshers_LayerDistribution() //============================================================================= void StdMeshers_LayerDistribution::SetLayerDistribution(SMESH_Hypothesis* hyp1D) - throw ( SMESH_Exception ) + throw ( SALOME_Exception ) { if ( myHyp != hyp1D ) { if ( myHyp && hyp1D->GetDim() != 1 ) - throw SMESH_Exception(LOCALIZED("1D hypothesis is expected")); + throw SALOME_Exception(LOCALIZED("1D hypothesis is expected")); myHyp = hyp1D; } std::ostringstream os; @@ -145,7 +145,6 @@ bool StdMeshers_LayerDistribution::SetParametersByMesh(const SMESH_Mesh* , { return false; } - //================================================================================ /*! * \brief Initialize my parameter values by default parameters. diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LayerDistribution2D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LayerDistribution2D.cpp new file mode 100644 index 000000000000..6204a765bc41 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LayerDistribution2D.cpp @@ -0,0 +1,59 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : idl implementation based on 'SMESH' unit's classes +// File : StdMeshers_LayerDistribution2D.cxx +// Author : Edward AGAPOV +// Module : SMESH +// +#include "StdMeshers_LayerDistribution2D.hxx" + +#include "utilities.h" + + +//============================================================================= +/*! + * StdMeshers_LayerDistribution2D::StdMeshers_LayerDistribution2D + * + * Constructor + */ +//============================================================================= + +StdMeshers_LayerDistribution2D::StdMeshers_LayerDistribution2D(int hypId, + int studyId, + SMESH_Gen * gen) + : StdMeshers_LayerDistribution(hypId, studyId, gen) +{ + _name = "LayerDistribution2D"; // used by RadialQuadrangle_1D2D + _param_algo_dim = 2; // 2D + myHyp = 0; +} + +//============================================================================= +/*! + * StdMeshers_LayerDistribution2D::~StdMeshers_LayerDistribution2D + * + * Destructor + */ +//============================================================================= + +StdMeshers_LayerDistribution2D::~StdMeshers_LayerDistribution2D() +{ + MESSAGE( "StdMeshers_LayerDistribution2D::~StdMeshers_LayerDistribution2D" ); +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LengthFromEdges.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LengthFromEdges.cpp index 5e350d90dcec..81d13de012a1 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LengthFromEdges.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LengthFromEdges.cpp @@ -1,30 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_LengthFromEdges.cxx // Moved here from SMESH_LengthFromEdges.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_LengthFromEdges.cxx,v 1.8.2.1 2008/11/27 13:03:49 abd Exp $ // #include "StdMeshers_LengthFromEdges.hxx" @@ -63,11 +63,11 @@ StdMeshers_LengthFromEdges::~StdMeshers_LengthFromEdges() //============================================================================= void StdMeshers_LengthFromEdges::SetMode(int mode) - throw (SMESH_Exception) + throw (SALOME_Exception) { int oldMode = _mode; if (mode <= 0) - throw SMESH_Exception(LOCALIZED("mode must be positive")); + throw SALOME_Exception(LOCALIZED("mode must be positive")); _mode = mode; if (oldMode != _mode) NotifySubMeshesHypothesisModification(); @@ -104,9 +104,9 @@ ostream & StdMeshers_LengthFromEdges::SaveTo(ostream & save) istream & StdMeshers_LengthFromEdges::LoadFrom(istream & load) { - bool isOK = true; + bool isOK = (bool)true; int a; - isOK = !(load >> a).bad(); + isOK = (bool)(load >> a); if (isOK) this->_mode = a; else @@ -152,7 +152,6 @@ bool StdMeshers_LengthFromEdges::SetParametersByMesh(const SMESH_Mesh* /*theMesh { return false; } - //================================================================================ /*! * \brief Initialize my parameter values by default parameters. @@ -165,4 +164,3 @@ bool StdMeshers_LengthFromEdges::SetParametersByDefaults(const TDefaults& /*dfl { return true; } - diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LocalLength.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LocalLength.cpp index 2ca825caf150..82eb861badfd 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LocalLength.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_LocalLength.cpp @@ -1,30 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_LocalLength.cxx // Moved here from SMESH_LocalLength.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_LocalLength.cxx,v 1.8.2.1 2008/11/27 13:03:50 abd Exp $ // #include "StdMeshers_LocalLength.hxx" @@ -77,11 +77,11 @@ StdMeshers_LocalLength::~StdMeshers_LocalLength() */ //============================================================================= -void StdMeshers_LocalLength::SetLength(double length) throw(SMESH_Exception) +void StdMeshers_LocalLength::SetLength(double length) throw(SALOME_Exception) { double oldLength = _length; if (length <= 0) - throw SMESH_Exception(LOCALIZED("length must be positive")); + throw SALOME_Exception(LOCALIZED("length must be positive")); _length = length; const double precision = 1e-7; if (fabs(oldLength - _length) > precision) @@ -104,11 +104,11 @@ double StdMeshers_LocalLength::GetLength() const * */ //============================================================================= -void StdMeshers_LocalLength::SetPrecision (double thePrecision) throw(SMESH_Exception) +void StdMeshers_LocalLength::SetPrecision (double thePrecision) throw(SALOME_Exception) { double oldPrecision = _precision; if (_precision < 0) - throw SMESH_Exception(LOCALIZED("precision cannot be negative")); + throw SALOME_Exception(LOCALIZED("precision cannot be negative")); _precision = thePrecision; const double precision = 1e-8; if (fabs(oldPrecision - _precision) > precision) @@ -148,13 +148,13 @@ istream & StdMeshers_LocalLength::LoadFrom(istream & load) bool isOK = true; double a; - isOK = !(load >> a).bad(); + isOK = (bool)(load >> a); if (isOK) this->_length = a; else load.clear(ios::badbit | load.rdstate()); - isOK = !(load >> a).bad(); + isOK = (bool)(load >> a); if (isOK) this->_precision = a; else @@ -216,7 +216,9 @@ bool StdMeshers_LocalLength::SetParametersByMesh(const SMESH_Mesh* theMesh, { const TopoDS_Edge& edge = TopoDS::Edge( edgeMap( iE )); Handle(Geom_Curve) C = BRep_Tool::Curve( edge, L, UMin, UMax ); - GeomAdaptor_Curve AdaptCurve(C); + if ( C.IsNull() ) + continue; + GeomAdaptor_Curve AdaptCurve(C, UMin, UMax); vector< double > params; SMESHDS_Mesh* aMeshDS = const_cast< SMESH_Mesh* >( theMesh )->GetMeshDS(); @@ -234,7 +236,6 @@ bool StdMeshers_LocalLength::SetParametersByMesh(const SMESH_Mesh* theMesh, return nbEdges; } - //================================================================================ /*! * \brief Initialize my parameter values by default parameters. @@ -247,3 +248,4 @@ bool StdMeshers_LocalLength::SetParametersByDefaults(const TDefaults& dflts, { return ( _length = dflts._elemLength ); } + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MEFISTO_2D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MEFISTO_2D.cpp index 2fab2cd13742..264189170074 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MEFISTO_2D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MEFISTO_2D.cpp @@ -1,58 +1,59 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_MEFISTO_2D.cxx // Moved here from SMESH_MEFISTO_2D.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_MEFISTO_2D.cxx,v 1.11.2.3 2008/11/27 13:03:49 abd Exp $ // #include "StdMeshers_MEFISTO_2D.hxx" +#include "SMDS_EdgePosition.hxx" +#include "SMDS_MeshElement.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMESH_Comment.hxx" #include "SMESH_Gen.hxx" #include "SMESH_Mesh.hxx" -#include "SMESH_subMesh.hxx" -#include "SMESH_Block.hxx" #include "SMESH_MesherHelper.hxx" -#include "SMESH_Comment.hxx" - +#include "SMESH_subMesh.hxx" #include "StdMeshers_FaceSide.hxx" -#include "StdMeshers_MaxElementArea.hxx" #include "StdMeshers_LengthFromEdges.hxx" +#include "StdMeshers_MaxElementArea.hxx" +#include "StdMeshers_ViscousLayers2D.hxx" + +#include "utilities.h" #include "Rn.h" #include "aptrte.h" -#include "SMDS_MeshElement.hxx" -#include "SMDS_MeshNode.hxx" -#include "SMDS_EdgePosition.hxx" -#include "SMDS_FacePosition.hxx" - -#include "utilities.h" - +#include #include #include +#include #include +#include #include +#include #include #include #include @@ -62,10 +63,15 @@ #include #include #include +#include #include using namespace std; +#ifdef _DEBUG_ +//#define DUMP_POINTS // to print coordinates of MEFISTO input +#endif + //============================================================================= /*! * @@ -80,12 +86,13 @@ StdMeshers_MEFISTO_2D::StdMeshers_MEFISTO_2D(int hypId, int studyId, SMESH_Gen * _shapeType = (1 << TopAbs_FACE); _compatibleHypothesis.push_back("MaxElementArea"); _compatibleHypothesis.push_back("LengthFromEdges"); + _compatibleHypothesis.push_back("ViscousLayers2D"); _edgeLength = 0; _maxElementArea = 0; _hypMaxElementArea = NULL; _hypLengthFromEdges = NULL; - myTool = 0; + _helper = 0; } //============================================================================= @@ -115,6 +122,9 @@ bool StdMeshers_MEFISTO_2D::CheckHypothesis _edgeLength = 0; _maxElementArea = 0; + if ( !error( StdMeshers_ViscousLayers2D::CheckHypothesis( aMesh, aShape, aStatus ))) + return false; + list ::const_iterator itl; const SMESHDS_Hypothesis *theHyp; @@ -184,15 +194,21 @@ bool StdMeshers_MEFISTO_2D::Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aSh // helper builds quadratic mesh if necessary SMESH_MesherHelper helper(aMesh); - myTool = &helper; - _quadraticMesh = myTool->IsQuadraticSubMesh(aShape); - const bool ignoreMediumNodes = _quadraticMesh; + _helper = &helper; + _quadraticMesh = _helper->IsQuadraticSubMesh(aShape); + const bool skipMediumNodes = _quadraticMesh; + + // build viscous layers if required + SMESH_ProxyMesh::Ptr proxyMesh = StdMeshers_ViscousLayers2D::Compute( aMesh, F ); + if ( !proxyMesh ) + return false; // get all edges of a face TError problem; - TWireVector wires = StdMeshers_FaceSide::GetFaceWires( F, aMesh, ignoreMediumNodes, problem ); + TWireVector wires = + StdMeshers_FaceSide::GetFaceWires( F, aMesh, skipMediumNodes, problem, proxyMesh ); int nbWires = wires.size(); - if ( (problem!=NULL) && !problem->IsOK() ) return error( problem ); + if ( problem && !problem->IsOK() ) return error( problem ); if ( nbWires == 0 ) return error( "Problem in StdMeshers_FaceSide::GetFaceWires()"); if ( wires[0]->NbSegments() < 3 ) // ex: a circle with 2 segments return error(COMPERR_BAD_INPUT_MESH, @@ -231,6 +247,8 @@ bool StdMeshers_MEFISTO_2D::Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aSh Z nutysu = 1; // 1: il existe un fonction areteideale_() // Z nutysu=0; // 0: on utilise aretmx R aretmx = _edgeLength; // longueur max aretes future triangulation + if ( _hypMaxElementArea ) + aretmx *= 1.5; nblf = nbWires; @@ -283,6 +301,90 @@ bool StdMeshers_MEFISTO_2D::Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aSh return isOk; } + +//============================================================================= +/*! + * + */ +//============================================================================= + +bool StdMeshers_MEFISTO_2D::Evaluate(SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap) +{ + MESSAGE("StdMeshers_MEFISTO_2D::Evaluate"); + + TopoDS_Face F = TopoDS::Face(aShape.Oriented(TopAbs_FORWARD)); + + double aLen = 0.0; + int NbSeg = 0; + bool IsQuadratic = false; + bool IsFirst = true; + TopExp_Explorer exp(F,TopAbs_EDGE); + for(; exp.More(); exp.Next()) { + TopoDS_Edge E = TopoDS::Edge(exp.Current()); + MapShapeNbElemsItr anIt = aResMap.find( aMesh.GetSubMesh(E) ); + if( anIt == aResMap.end() ) continue; + std::vector aVec = (*anIt).second; + int nbe = Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]); + NbSeg += nbe; + if(IsFirst) { + IsQuadratic = ( aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge] ); + IsFirst = false; + } + double a,b; + TopLoc_Location L; + Handle(Geom_Curve) C = BRep_Tool::Curve(E,L,a,b); + gp_Pnt P1; + C->D0(a,P1); + double dp = (b-a)/nbe; + for(int i=1; i<=nbe; i++) { + gp_Pnt P2; + C->D0(a+i*dp,P2); + aLen += P1.Distance(P2); + P1 = P2; + } + } + if(NbSeg<1) { + std::vector aResVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; iGetComputeError(); + smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED, + "Submesh can not be evaluated",this)); + return false; + } + aLen = aLen/NbSeg; // middle length + + _edgeLength = Precision::Infinite(); + double tmpLength = Min( _edgeLength, aLen ); + + GProp_GProps G; + BRepGProp::SurfaceProperties(aShape,G); + double anArea = G.Mass(); + + int nbFaces = Precision::IsInfinite( tmpLength ) ? 0 : + (int)( anArea/(tmpLength*tmpLength*sqrt(3.)/4) ); + int nbNodes = (int) ( nbFaces*3 - (NbSeg-1)*2 ) / 6; + + std::vector aVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; i(node->GetPosition().get()); + static_cast(node->GetPosition()); double u = epos->GetUParameter(); if ( u < umin ) umin = u; @@ -482,7 +584,7 @@ bool StdMeshers_MEFISTO_2D::LoadPoints(TWireVector & wires, TopTools_IndexedDataMapOfShapeListOfShape VWMap; if ( wires.size() > 1 ) { - F = TopoDS::Face( myTool->GetSubShape() ); + F = TopoDS::Face( _helper->GetSubShape() ); TopExp::MapShapesAndAncestors( F, TopAbs_VERTEX, TopAbs_WIRE, VWMap ); int nbVertices = 0; for ( int iW = 0; iW < wires.size(); ++iW ) @@ -505,7 +607,7 @@ bool StdMeshers_MEFISTO_2D::LoadPoints(TWireVector & wires, MESSAGE("Wrong mefistoToDS.size: "< mOnVertex; vector::const_iterator uvPt = uvPtVec.begin(); for ( ++uvPt; uvPt != uvPtVec.end(); ++uvPt ) @@ -515,8 +617,31 @@ bool StdMeshers_MEFISTO_2D::LoadPoints(TWireVector & wires, // set UV uvslf[m].x = uvPt->u * scalex; uvslf[m].y = uvPt->v * scaley; - if ( uvPt->node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX ) + switch ( uvPt->node->GetPosition()->GetTypeOfPosition()) + { + case SMDS_TOP_VERTEX: mOnVertex.push_back( m ); + break; + case SMDS_TOP_EDGE: + // In order to detect degenerated faces easily, we replace + // nodes on a degenerated edge by node on the vertex of that edge + if ( _helper->IsDegenShape( uvPt->node->getshapeId() )) + { + int edgeID = uvPt->node->getshapeId(); + SMESH_subMesh* edgeSM = _helper->GetMesh()->GetSubMeshContaining( edgeID ); + SMESH_subMeshIteratorPtr smIt = edgeSM->getDependsOnIterator( /*includeSelf=*/0, + /*complexShapeFirst=*/0); + if ( smIt->more() ) + { + SMESH_subMesh* vertexSM = smIt->next(); + SMDS_NodeIteratorPtr nIt = vertexSM->GetSubMeshDS()->GetNodes(); + if ( nIt->more() ) + mefistoToDS[m] = nIt->next(); + } + } + break; + default:; + } m++; } @@ -527,9 +652,9 @@ bool StdMeshers_MEFISTO_2D::LoadPoints(TWireVector & wires, int m = *mIt; if ( iW && !VWMap.IsEmpty()) { // except outer wire // avoid passing same uv point for a vertex common to 2 wires - int vID = mefistoToDS[m]->GetPosition()->GetShapeId(); - TopoDS_Vertex V = TopoDS::Vertex( myTool->GetMeshDS()->IndexToShape( vID )); - if ( fixCommonVertexUV( uvslf[m], V, F, VWMap, *myTool->GetMesh(), + int vID = mefistoToDS[m]->getshapeId(); + TopoDS_Vertex V = TopoDS::Vertex( _helper->GetMeshDS()->IndexToShape( vID )); + if ( fixCommonVertexUV( uvslf[m], V, F, VWMap, *_helper->GetMesh(), scalex, scaley, _quadraticMesh )) { myNodesOnCommonV.push_back( mefistoToDS[m] ); continue; @@ -544,6 +669,13 @@ bool StdMeshers_MEFISTO_2D::LoadPoints(TWireVector & wires, } } +#ifdef DUMP_POINTS + cout << "MEFISTO INPUT************" << endl; + for ( int i =0; i < m; ++i ) + cout << i << ": \t" << uvslf[i].x << ", " << uvslf[i].y + << " Node " << mefistoToDS[i]->GetID()<< endl; +#endif + return true; } @@ -564,7 +696,7 @@ void StdMeshers_MEFISTO_2D::ComputeScaleOnFace(SMESH_Mesh & aMesh, double xmax = -1.e300; double ymin = 1.e300; double ymax = -1.e300; - int nbp = 23; + const int nbp = 23; scalex = 1; scaley = 1; @@ -588,13 +720,8 @@ void StdMeshers_MEFISTO_2D::ComputeScaleOnFace(SMESH_Mesh & aMesh, ymin = p.Y(); if (p.Y() > ymax) ymax = p.Y(); - // MESSAGE(" "<< f<<" "< maxratio) { - SCRUTE( scaley ); scaley *= xyratio / maxratio; - SCRUTE( scaley ); } else if (xyratio < 1./maxratio) { - SCRUTE( scalex ); scalex *= 1 / xyratio / maxratio; - SCRUTE( scalex ); } - ASSERT(scalex); - ASSERT(scaley); } +// namespace +// { +// bool isDegenTria( const SMDS_MeshNode * nn[3] ) +// { +// SMESH_TNodeXYZ p1( nn[0] ); +// SMESH_TNodeXYZ p2( nn[1] ); +// SMESH_TNodeXYZ p3( nn[2] ); +// gp_XYZ vec1 = p2 - p1; +// gp_XYZ vec2 = p3 - p1; +// gp_XYZ cross = vec1 ^ vec2; +// const double eps = 1e-100; +// return ( fabs( cross.X() ) < eps && +// fabs( cross.Y() ) < eps && +// fabs( cross.Z() ) < eps ); +// } +// } + //============================================================================= /*! * @@ -651,12 +786,13 @@ void StdMeshers_MEFISTO_2D::StoreResult(Z nbst, R2 * uvst, Z nbt, Z * nust, vector< const SMDS_MeshNode*>&mefistoToDS, double scalex, double scaley) { - SMESHDS_Mesh * meshDS = myTool->GetMeshDS(); - int faceID = myTool->GetSubShapeID(); + _helper->SetElementsOnShape( true ); - TopoDS_Face F = TopoDS::Face( myTool->GetSubShape() ); + TopoDS_Face F = TopoDS::Face( _helper->GetSubShape() ); Handle(Geom_Surface) S = BRep_Tool::Surface( F ); + //const size_t nbInputNodes = mefistoToDS.size(); + Z n = mefistoToDS.size(); // nb input points mefistoToDS.resize( nbst ); for ( ; n < nbst; n++) @@ -667,12 +803,7 @@ void StdMeshers_MEFISTO_2D::StoreResult(Z nbst, R2 * uvst, Z nbt, Z * nust, double v = uvst[n][1] / scaley; gp_Pnt P = S->Value(u, v); - SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z()); - meshDS->SetNodeOnFace(node, faceID, u, v); - - //MESSAGE(P.X()<<" "<AddNode( P.X(), P.Y(), P.Z(), 0, u, v ); } } @@ -681,22 +812,32 @@ void StdMeshers_MEFISTO_2D::StoreResult(Z nbst, R2 * uvst, Z nbt, Z * nust, // triangle points must be in trigonometric order if face is Forward // else they must be put clockwise - bool triangleIsWellOriented = ( F.Orientation() == TopAbs_FORWARD ); + int i1 = 1, i2 = 2; + if ( F.Orientation() != TopAbs_FORWARD ) + std::swap( i1, i2 ); + const SMDS_MeshNode * nn[3]; for (n = 1; n <= nbt; n++) { - const SMDS_MeshNode * n1 = mefistoToDS[ nust[m++] - 1 ]; - const SMDS_MeshNode * n2 = mefistoToDS[ nust[m++] - 1 ]; - const SMDS_MeshNode * n3 = mefistoToDS[ nust[m++] - 1 ]; + // const bool allNodesAreOld = ( nust[m + 0] <= nbInputNodes && + // nust[m + 1] <= nbInputNodes && + // nust[m + 2] <= nbInputNodes ); + nn[ 0 ] = mefistoToDS[ nust[m++] - 1 ]; + nn[ 1 ] = mefistoToDS[ nust[m++] - 1 ]; + nn[ 2 ] = mefistoToDS[ nust[m++] - 1 ]; + m++; - SMDS_MeshElement * elt; - if (triangleIsWellOriented) - elt = myTool->AddFace(n1, n2, n3); - else - elt = myTool->AddFace(n1, n3, n2); + // avoid creating degenetrated faces + bool isDegen = ( _helper->HasDegeneratedEdges() && + ( nn[0] == nn[1] || nn[1] == nn[2] || nn[2] == nn[0] )); - meshDS->SetMeshElementOnShape(elt, faceID); - m++; + // It was an attemp to fix a problem of a zero area face whose all nodes + // are on one staight EDGE. But omitting this face makes a hole in the mesh :( + // if ( !isDegen && allNodesAreOld ) + // isDegen = isDegenTria( nn ); + + if ( !isDegen ) + _helper->AddFace( nn[0], nn[i1], nn[i2] ); } // remove bad elements built on vertices shared by wires @@ -716,7 +857,7 @@ void StdMeshers_MEFISTO_2D::StoreResult(Z nbst, R2 * uvst, Z nbt, Z * nust, nbSame++; if (nbSame > 1) { MESSAGE( "RM bad element " << elem->GetID()); - meshDS->RemoveElement( elem ); + _helper->GetMeshDS()->RemoveElement( elem ); } } } diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MaxElementArea.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MaxElementArea.cpp index cc776a47abe3..82ae19ea5d8d 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MaxElementArea.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MaxElementArea.cpp @@ -1,30 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_MaxElementArea.cxx // Moved here from SMESH_MaxElementArea.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_MaxElementArea.cxx,v 1.8.2.1 2008/11/27 13:03:49 abd Exp $ // #include "StdMeshers_MaxElementArea.hxx" @@ -71,11 +71,11 @@ StdMeshers_MaxElementArea::~StdMeshers_MaxElementArea() //============================================================================= void StdMeshers_MaxElementArea::SetMaxArea(double maxArea) - throw (SMESH_Exception) + throw (SALOME_Exception) { double oldArea = _maxArea; if (maxArea <= 0) - throw SMESH_Exception(LOCALIZED("maxArea must be positive")); + throw SALOME_Exception(LOCALIZED("maxArea must be positive")); _maxArea = maxArea; if (_maxArea != oldArea) NotifySubMeshesHypothesisModification(); @@ -114,7 +114,7 @@ istream & StdMeshers_MaxElementArea::LoadFrom(istream & load) { bool isOK = true; double a; - isOK = !(load >> a).bad(); + isOK = (bool)(load >> a); if (isOK) this->_maxArea = a; else @@ -185,7 +185,6 @@ bool StdMeshers_MaxElementArea::SetParametersByMesh(const SMESH_Mesh* theMesh, } return _maxArea > 0; } - //================================================================================ /*! * \brief Initialize my parameter values by default parameters. @@ -198,3 +197,4 @@ bool StdMeshers_MaxElementArea::SetParametersByDefaults(const TDefaults& dflts, { return ( _maxArea = dflts._elemLength*dflts._elemLength ); } + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MaxElementVolume.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MaxElementVolume.cpp index d4369c69126c..65407be33c0e 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MaxElementVolume.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MaxElementVolume.cpp @@ -1,30 +1,30 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_MaxElementVolume.cxx // Moved here from SMESH_MaxElementVolume.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_MaxElementVolume.cxx,v 1.8.2.1 2008/11/27 13:03:50 abd Exp $ // #include "StdMeshers_MaxElementVolume.hxx" @@ -73,11 +73,11 @@ StdMeshers_MaxElementVolume::~StdMeshers_MaxElementVolume() //============================================================================= void StdMeshers_MaxElementVolume::SetMaxVolume(double maxVolume) - throw (SMESH_Exception) + throw (SALOME_Exception) { double oldVolume = _maxVolume; if (maxVolume <= 0) - throw SMESH_Exception(LOCALIZED("maxVolume must be positive")); + throw SALOME_Exception(LOCALIZED("maxVolume must be positive")); _maxVolume = maxVolume; if (_maxVolume != oldVolume) NotifySubMeshesHypothesisModification(); @@ -116,7 +116,7 @@ istream & StdMeshers_MaxElementVolume::LoadFrom(istream & load) { bool isOK = true; double a; - isOK = !(load >> a).bad(); + isOK = (bool)(load >> a); if (isOK) this->_maxVolume = a; else @@ -197,7 +197,6 @@ bool StdMeshers_MaxElementVolume::SetParametersByMesh(const SMESH_Mesh* theMes } return _maxVolume > 0; } - //================================================================================ /*! * \brief Initialize my parameter values by default parameters. @@ -210,3 +209,4 @@ bool StdMeshers_MaxElementVolume::SetParametersByDefaults(const TDefaults& dflt { return ( _maxVolume = dflts._elemLength*dflts._elemLength*dflts._elemLength ); } + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MaxLength.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MaxLength.cpp index 21d1bb012b98..a5c87e7fc496 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MaxLength.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_MaxLength.cpp @@ -1,27 +1,26 @@ -// SMESH SMESH : implementaion of SMESH idl descriptions +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 // -// 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 // + +// SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_MaxLength.cxx // Module : SMESH - +// #include "StdMeshers_MaxLength.hxx" #include "SMESH_Mesh.hxx" @@ -74,10 +73,10 @@ StdMeshers_MaxLength::~StdMeshers_MaxLength() */ //============================================================================= -void StdMeshers_MaxLength::SetLength(double length) throw(SMESH_Exception) +void StdMeshers_MaxLength::SetLength(double length) throw(SALOME_Exception) { if (length <= 0) - throw SMESH_Exception(LOCALIZED("length must be positive")); + throw SALOME_Exception(LOCALIZED("length must be positive")); if ( _length != length ) { _length = length; NotifySubMeshesHypothesisModification(); @@ -159,20 +158,20 @@ istream & StdMeshers_MaxLength::LoadFrom(istream & load) bool isOK = true; double a; - isOK = !(load >> a).bad(); + isOK = (bool)(load >> a); if (isOK) _length = a; else load.clear(ios::badbit | load.rdstate()); - isOK = !(load >> a).bad(); + isOK = (bool)(load >> a); if (isOK) _preestimated = a; else load.clear(ios::badbit | load.rdstate()); bool pre; - isOK = !(load >> pre).bad(); + isOK = (bool)(load >> pre); if ( isOK ) _preestimation = pre; else @@ -208,7 +207,7 @@ bool StdMeshers_MaxLength::SetParametersByMesh(const SMESH_Mesh* theMesh, { const TopoDS_Edge& edge = TopoDS::Edge( edgeMap( iE )); Handle(Geom_Curve) C = BRep_Tool::Curve( edge, L, UMin, UMax ); - GeomAdaptor_Curve AdaptCurve(C); + GeomAdaptor_Curve AdaptCurve(C, UMin, UMax); vector< double > params; SMESHDS_Mesh* aMeshDS = const_cast< SMESH_Mesh* >( theMesh )->GetMeshDS(); diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NotConformAllowed.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NotConformAllowed.cpp index bba78e43abde..ab3a3e6bc49b 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NotConformAllowed.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NotConformAllowed.cpp @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH StdMeshers : implementaion of SMESH idl descriptions // File : StdMeshers_NotConformAllowed.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_NotConformAllowed.cxx,v 1.8.2.1 2008/11/27 13:03:49 abd Exp $ // #include "StdMeshers_NotConformAllowed.hxx" #include "utilities.h" @@ -112,7 +112,6 @@ bool StdMeshers_NotConformAllowed::SetParametersByMesh(const SMESH_Mesh* /*theMe { return true; } - //================================================================================ /*! * \brief Initialize my parameter values by default parameters. @@ -125,3 +124,4 @@ bool StdMeshers_NotConformAllowed::SetParametersByDefaults(const TDefaults& /*d { return true; } + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NumberOfLayers.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NumberOfLayers.cpp index 187cbae78e8b..bb9d6f99ce1a 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NumberOfLayers.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NumberOfLayers.cpp @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : idl implementation based on 'SMESH' unit's classes // File : StdMeshers_NumberOfLayers.cxx // Author : Edward AGAPOV // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_NumberOfLayers.cxx,v 1.2.2.1 2008/11/27 13:03:49 abd Exp $ // #include "StdMeshers_NumberOfLayers.hxx" @@ -73,11 +73,11 @@ StdMeshers_NumberOfLayers::~StdMeshers_NumberOfLayers() //============================================================================= void StdMeshers_NumberOfLayers::SetNumberOfLayers(int numberOfLayers) - throw ( SMESH_Exception ) + throw ( SALOME_Exception ) { if ( _nbLayers != numberOfLayers ) { if ( numberOfLayers <= 0 ) - throw SMESH_Exception(LOCALIZED("numberOfLayers must be positive")); + throw SALOME_Exception(LOCALIZED("numberOfLayers must be positive")); _nbLayers = numberOfLayers; NotifySubMeshesHypothesisModification(); @@ -118,7 +118,7 @@ ostream & StdMeshers_NumberOfLayers::SaveTo(ostream & save) istream & StdMeshers_NumberOfLayers::LoadFrom(istream & load) { bool isOK = true; - isOK = !(load >> _nbLayers).bad(); + isOK = (bool)(load >> _nbLayers); if (!isOK) load.clear(ios::badbit | load.rdstate()); return load; @@ -175,3 +175,4 @@ bool StdMeshers_NumberOfLayers::SetParametersByDefaults(const TDefaults& dflts, return theMesh ? (_nbLayers = int( theMesh->GetShapeDiagonalSize() / dflts._elemLength/ 2.)) : 0; return false; } + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NumberOfLayers2D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NumberOfLayers2D.cpp new file mode 100644 index 000000000000..ba5ce63173d7 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NumberOfLayers2D.cpp @@ -0,0 +1,60 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : idl implementation based on 'SMESH' unit's classes +// File : StdMeshers_NumberOfLayers2D.cxx +// Author : Edward AGAPOV +// Module : SMESH +// +#include "StdMeshers_NumberOfLayers2D.hxx" + +#include "utilities.h" + + +//============================================================================= +/*! + * StdMeshers_NumberOfLayers2D::StdMeshers_NumberOfLayers2D + * + * Constructor + */ +//============================================================================= + +StdMeshers_NumberOfLayers2D::StdMeshers_NumberOfLayers2D(int hypId, + int studyId, + SMESH_Gen * gen) + : StdMeshers_NumberOfLayers(hypId, studyId, gen) +{ + _name = "NumberOfLayers2D"; // used by RadialQuadrangle_1D2D + _param_algo_dim = 2; // 2D + _nbLayers = 1; +} + +//============================================================================= +/*! + * StdMeshers_NumberOfLayers2D::~StdMeshers_NumberOfLayers2D + * + * Destructor + */ +//============================================================================= + +StdMeshers_NumberOfLayers2D::~StdMeshers_NumberOfLayers2D() +{ + MESSAGE( "StdMeshers_NumberOfLayers2D::~StdMeshers_NumberOfLayers2D" ); +} + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NumberOfSegments.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NumberOfSegments.cpp index c1c1c7398fab..6a530a924d93 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NumberOfSegments.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_NumberOfSegments.cpp @@ -1,36 +1,37 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_NumberOfSegments.cxx // Moved here from SMESH_NumberOfSegments.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_NumberOfSegments.cxx,v 1.13.2.1 2008/11/27 13:03:49 abd Exp $ // #include "StdMeshers_NumberOfSegments.hxx" #include "StdMeshers_Distribution.hxx" #include "SMESHDS_SubMesh.hxx" #include "SMESH_Mesh.hxx" +#include "SMESH_Comment.hxx" #include #include @@ -50,6 +51,9 @@ #include #endif +#include + +using namespace StdMeshers; using namespace std; const double PRECISION = 1e-7; @@ -90,7 +94,7 @@ StdMeshers_NumberOfSegments::~StdMeshers_NumberOfSegments() //============================================================================= const vector& StdMeshers_NumberOfSegments::BuildDistributionExpr( const char* expr,int nbSeg,int conv ) - throw ( SMESH_Exception ) + throw ( SALOME_Exception ) { if( !buildDistribution( TCollection_AsciiString( ( Standard_CString )expr ), conv, 0.0, 1.0, nbSeg, _distr, 1E-4 ) ) _distr.resize( 0 ); @@ -101,7 +105,7 @@ const vector& StdMeshers_NumberOfSegments::BuildDistributionTab( const vector& tab, int nbSeg, int conv ) - throw ( SMESH_Exception ) + throw ( SALOME_Exception ) { if( !buildDistribution( tab, conv, 0.0, 1.0, nbSeg, _distr, 1E-4 ) ) _distr.resize( 0 ); @@ -115,11 +119,11 @@ StdMeshers_NumberOfSegments::BuildDistributionTab( const vector& tab, //============================================================================= void StdMeshers_NumberOfSegments::SetNumberOfSegments(int segmentsNumber) -throw(SMESH_Exception) +throw(SALOME_Exception) { int oldNumberOfSegments = _numberOfSegments; if (segmentsNumber <= 0) - throw SMESH_Exception(LOCALIZED("number of segments must be positive")); + throw SALOME_Exception(LOCALIZED("number of segments must be positive")); _numberOfSegments = segmentsNumber; if (oldNumberOfSegments != _numberOfSegments) @@ -144,10 +148,10 @@ int StdMeshers_NumberOfSegments::GetNumberOfSegments() const //================================================================================ void StdMeshers_NumberOfSegments::SetDistrType(DistrType typ) - throw(SMESH_Exception) + throw(SALOME_Exception) { if (typ < DT_Regular || typ > DT_ExprFunc) - throw SMESH_Exception(LOCALIZED("distribution type is out of range")); + throw SALOME_Exception(LOCALIZED("distribution type is out of range")); if (typ != _distrType) { @@ -174,15 +178,15 @@ StdMeshers_NumberOfSegments::DistrType StdMeshers_NumberOfSegments::GetDistrType //================================================================================ void StdMeshers_NumberOfSegments::SetScaleFactor(double scaleFactor) - throw(SMESH_Exception) + throw(SALOME_Exception) { if (_distrType != DT_Scale) _distrType = DT_Scale; - //throw SMESH_Exception(LOCALIZED("not a scale distribution")); + //throw SALOME_Exception(LOCALIZED("not a scale distribution")); if (scaleFactor < PRECISION) - throw SMESH_Exception(LOCALIZED("scale factor must be positive")); - //if (fabs(scaleFactor - 1.0) < PRECISION) - // throw SMESH_Exception(LOCALIZED("scale factor must not be equal to 1")); + throw SALOME_Exception(LOCALIZED("scale factor must be positive")); + if (fabs(scaleFactor - 1.0) < PRECISION) + _distrType = DT_Regular; if (fabs(_scaleFactor - scaleFactor) > PRECISION) { @@ -198,10 +202,10 @@ void StdMeshers_NumberOfSegments::SetScaleFactor(double scaleFactor) //================================================================================ double StdMeshers_NumberOfSegments::GetScaleFactor() const - throw(SMESH_Exception) + throw(SALOME_Exception) { if (_distrType != DT_Scale) - throw SMESH_Exception(LOCALIZED("not a scale distribution")); + throw SALOME_Exception(LOCALIZED("not a scale distribution")); return _scaleFactor; } @@ -212,13 +216,13 @@ double StdMeshers_NumberOfSegments::GetScaleFactor() const //================================================================================ void StdMeshers_NumberOfSegments::SetTableFunction(const vector& table) - throw(SMESH_Exception) + throw(SALOME_Exception) { if (_distrType != DT_TabFunc) _distrType = DT_TabFunc; - //throw SMESH_Exception(LOCALIZED("not a table function distribution")); + //throw SALOME_Exception(LOCALIZED("not a table function distribution")); if ( (table.size() % 2) != 0 ) - throw SMESH_Exception(LOCALIZED("odd size of vector of table function")); + throw SALOME_Exception(LOCALIZED("odd size of vector of table function")); int i; double prev = -PRECISION; @@ -234,22 +238,22 @@ void StdMeshers_NumberOfSegments::SetTableFunction(const vector& table) #ifdef NO_CAS_CATCH OCC_CATCH_SIGNALS; #endif - val = pow( 10.0, val ); + val = pow( 10.0, val ); } catch(Standard_Failure) { - Handle(Standard_Failure) aFail = Standard_Failure::Caught(); - throw SMESH_Exception( LOCALIZED( "invalid value")); - return; + Handle(Standard_Failure) aFail = Standard_Failure::Caught(); + throw SALOME_Exception( LOCALIZED( "invalid value")); + return; } } else if( _convMode==1 && val<0.0 ) val = 0.0; if ( par<0 || par > 1) - throw SMESH_Exception(LOCALIZED("parameter of table function is out of range [0,1]")); + throw SALOME_Exception(LOCALIZED("parameter of table function is out of range [0,1]")); if ( fabs(par-prev)PRECISION ) pos = true; if (isSame) @@ -263,7 +267,7 @@ void StdMeshers_NumberOfSegments::SetTableFunction(const vector& table) } if( !pos ) - throw SMESH_Exception(LOCALIZED("value of table function is not positive")); + throw SALOME_Exception(LOCALIZED("value of table function is not positive")); if( pos && !isSame ) { @@ -279,10 +283,10 @@ void StdMeshers_NumberOfSegments::SetTableFunction(const vector& table) //================================================================================ const vector& StdMeshers_NumberOfSegments::GetTableFunction() const - throw(SMESH_Exception) + throw(SALOME_Exception) { if (_distrType != DT_TabFunc) - throw SMESH_Exception(LOCALIZED("not a table function distribution")); + throw SALOME_Exception(LOCALIZED("not a table function distribution")); return _table; } @@ -304,7 +308,7 @@ bool isCorrectArg( const Handle( Expr_GeneralExpression )& expr ) if( !name.IsNull() ) { if( name->GetName()!="t" ) - res = false; + res = false; } else res = isCorrectArg( sub ); @@ -318,10 +322,12 @@ bool isCorrectArg( const Handle( Expr_GeneralExpression )& expr ) */ //================================================================================ bool process( const TCollection_AsciiString& str, int convMode, - bool& syntax, bool& args, - bool& non_neg, bool& non_zero, - bool& singulars, double& sing_point ) + bool& syntax, bool& args, + bool& non_neg, bool& non_zero, + bool& singulars, double& sing_point ) { + Kernel_Utils::Localizer loc; + bool parsed_ok = true; Handle( ExprIntrp_GenExp ) myExpr; try { @@ -360,19 +366,20 @@ bool process( const TCollection_AsciiString& str, int convMode, double t = double(i)/double(max), val; if( !f.value( t, val ) ) { - sing_point = t; - singulars = true; - break; + sing_point = t; + singulars = true; + break; } if( val<0 ) { - non_neg = false; - break; + non_neg = false; + break; } if( val>PRECISION ) - non_zero = true; + non_zero = true; } } + return res && non_neg && non_zero && ( !singulars ); } @@ -383,14 +390,33 @@ bool process( const TCollection_AsciiString& str, int convMode, //================================================================================ void StdMeshers_NumberOfSegments::SetExpressionFunction(const char* expr) - throw(SMESH_Exception) + throw(SALOME_Exception) { if (_distrType != DT_ExprFunc) _distrType = DT_ExprFunc; - //throw SMESH_Exception(LOCALIZED("not an expression function distribution")); + //throw SALOME_Exception(LOCALIZED("not an expression function distribution")); + + string func = CheckExpressionFunction( expr, _convMode ); + if( _func != func ) + { + _func = func; + NotifySubMeshesHypothesisModification(); + } +} + +//======================================================================= +//function : CheckExpressionFunction +//purpose : Checks validity of the expression of the function f(t), e.g. "sin(t)". +// In case of validity returns a cleaned expression +//======================================================================= +std::string +StdMeshers_NumberOfSegments::CheckExpressionFunction( const std::string& expr, + const int convMode) + throw (SALOME_Exception) +{ // remove white spaces - TCollection_AsciiString str((Standard_CString)expr); + TCollection_AsciiString str((Standard_CString)expr.c_str()); str.RemoveAll(' '); str.RemoveAll('\t'); str.RemoveAll('\r'); @@ -398,33 +424,26 @@ void StdMeshers_NumberOfSegments::SetExpressionFunction(const char* expr) bool syntax, args, non_neg, singulars, non_zero; double sing_point; - bool res = process( str, _convMode, syntax, args, non_neg, non_zero, singulars, sing_point ); + bool res = process( str, convMode, syntax, args, non_neg, non_zero, singulars, sing_point ); if( !res ) { if( !syntax ) - throw SMESH_Exception(LOCALIZED("invalid expression syntax")); + throw SALOME_Exception(SMESH_Comment("invalid expression syntax: ") << str ); if( !args ) - throw SMESH_Exception(LOCALIZED("only 't' may be used as function argument")); + throw SALOME_Exception(LOCALIZED("only 't' may be used as function argument")); if( !non_neg ) - throw SMESH_Exception(LOCALIZED("only non-negative function can be used as density")); + throw SALOME_Exception(LOCALIZED("only non-negative function can be used")); if( singulars ) { char buf[1024]; sprintf( buf, "Function has singular point in %.3f", sing_point ); - throw SMESH_Exception( buf ); + throw SALOME_Exception( buf ); } if( !non_zero ) - throw SMESH_Exception(LOCALIZED("f(t)=0 cannot be used as density")); - - return; - } - - string func = expr; - if( _func != func ) - { - _func = func; - NotifySubMeshesHypothesisModification(); + throw SALOME_Exception(LOCALIZED("f(t)=0 cannot be used")); } + + return str.ToCString(); } //================================================================================ @@ -434,10 +453,10 @@ void StdMeshers_NumberOfSegments::SetExpressionFunction(const char* expr) //================================================================================ const char* StdMeshers_NumberOfSegments::GetExpressionFunction() const - throw(SMESH_Exception) + throw(SALOME_Exception) { if (_distrType != DT_ExprFunc) - throw SMESH_Exception(LOCALIZED("not an expression function distribution")); + throw SALOME_Exception(LOCALIZED("not an expression function distribution")); return _func.c_str(); } @@ -448,10 +467,10 @@ const char* StdMeshers_NumberOfSegments::GetExpressionFunction() const //================================================================================ void StdMeshers_NumberOfSegments::SetConversionMode( int conv ) - throw(SMESH_Exception) + throw(SALOME_Exception) { // if (_distrType != DT_TabFunc && _distrType != DT_ExprFunc) -// throw SMESH_Exception(LOCALIZED("not a functional distribution")); +// throw SALOME_Exception(LOCALIZED("not a functional distribution")); if( conv != _convMode ) { @@ -467,10 +486,10 @@ void StdMeshers_NumberOfSegments::SetConversionMode( int conv ) //================================================================================ int StdMeshers_NumberOfSegments::ConversionMode() const - throw(SMESH_Exception) + throw(SALOME_Exception) { // if (_distrType != DT_TabFunc && _distrType != DT_ExprFunc) -// throw SMESH_Exception(LOCALIZED("not a functional distribution")); +// throw SALOME_Exception(LOCALIZED("not a functional distribution")); return _convMode; } @@ -482,6 +501,7 @@ int StdMeshers_NumberOfSegments::ConversionMode() const ostream & StdMeshers_NumberOfSegments::SaveTo(ostream & save) { + int listSize = _edgeIDs.size(); save << _numberOfSegments << " " << (int)_distrType; switch (_distrType) { @@ -504,6 +524,13 @@ ostream & StdMeshers_NumberOfSegments::SaveTo(ostream & save) if (_distrType == DT_TabFunc || _distrType == DT_ExprFunc) save << " " << _convMode; + + if ( _distrType != DT_Regular && listSize > 0 ) { + save << " " << listSize; + for ( int i = 0; i < listSize; i++ ) + save << " " << _edgeIDs[i]; + save << " " << _objEntry; + } return save; } @@ -520,7 +547,7 @@ istream & StdMeshers_NumberOfSegments::LoadFrom(istream & load) int a; // read number of segments - isOK = !(load >> a).bad(); + isOK = (bool)(load >> a); if (isOK) _numberOfSegments = a; else @@ -533,7 +560,7 @@ istream & StdMeshers_NumberOfSegments::LoadFrom(istream & load) // (nb.segments, distr.type, some other params.), // we wait here the ditribution type, which is integer double scale_factor; - isOK = !(load >> scale_factor).bad(); + isOK = (bool)(load >> scale_factor); a = (int)scale_factor; // try to interprete ditribution type, @@ -554,7 +581,7 @@ istream & StdMeshers_NumberOfSegments::LoadFrom(istream & load) { case DT_Scale: { - isOK = !(load >> b).bad(); + isOK = (bool)(load >> b); if (isOK) _scaleFactor = b; else @@ -568,14 +595,14 @@ istream & StdMeshers_NumberOfSegments::LoadFrom(istream & load) break; case DT_TabFunc: { - isOK = !(load >> a).bad(); + isOK = (bool)(load >> a); if (isOK) { _table.resize(a, 0.); int i; for (i=0; i < _table.size(); i++) { - isOK = !(load >> b).bad(); + isOK = (bool)(load >> b); if (isOK) _table[i] = b; else @@ -594,7 +621,7 @@ istream & StdMeshers_NumberOfSegments::LoadFrom(istream & load) case DT_ExprFunc: { string str; - isOK = !(load >> str).bad(); + isOK = (bool)(load >> str); if (isOK) _func = str; else @@ -613,13 +640,25 @@ istream & StdMeshers_NumberOfSegments::LoadFrom(istream & load) if (_distrType == DT_TabFunc || _distrType == DT_ExprFunc) { - isOK = !(load >> a).bad(); + isOK = (bool)(load >> a); if (isOK) _convMode = a; else load.clear(ios::badbit | load.rdstate()); } + // load reversed edges IDs + int intVal; + isOK = (bool)(load >> intVal); + if ( isOK && _distrType != DT_Regular && intVal > 0 ) { + _edgeIDs.reserve( intVal ); + for (int i = 0; i < _edgeIDs.capacity() && isOK; i++) { + isOK = (bool)(load >> intVal); + if ( isOK ) _edgeIDs.push_back( intVal ); + } + isOK = (bool)(load >> _objEntry); + } + return load; } @@ -683,7 +722,6 @@ bool StdMeshers_NumberOfSegments::SetParametersByMesh(const SMESH_Mesh* theMes return nbEdges; } - //================================================================================ /*! * \brief Initialize my parameter values by default parameters. @@ -696,3 +734,19 @@ bool StdMeshers_NumberOfSegments::SetParametersByDefaults(const TDefaults& dflt { return (_numberOfSegments = dflts._nbSegments ); } + +//============================================================================= +/*! + * + */ +//============================================================================= + +void StdMeshers_NumberOfSegments::SetReversedEdges( std::vector& ids ) +{ + if ( ids != _edgeIDs ) { + _edgeIDs = ids; + + NotifySubMeshesHypothesisModification(); + } +} + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Penta_3D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Penta_3D.cpp index f1d71e6d23db..6d99a44de3a3 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Penta_3D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Penta_3D.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH StdMeshers_Penta_3D implementaion of SMESH idl descriptions // File : StdMeshers_Penta_3D.cxx // Module : SMESH @@ -26,18 +27,19 @@ #include "StdMeshers_Penta_3D.hxx" #include "utilities.h" -#include "SMESH_ExceptHandlers.hxx" +#include "Utils_ExceptHandlers.hxx" #include "SMDS_EdgePosition.hxx" #include "SMDS_MeshElement.hxx" #include "SMDS_VolumeOfNodes.hxx" #include "SMDS_VolumeTool.hxx" #include "SMESHDS_SubMesh.hxx" +#include "SMESH_Comment.hxx" #include "SMESH_Mesh.hxx" +#include "SMESH_MeshAlgos.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_subMesh.hxx" #include "SMESH_subMeshEventListener.hxx" -#include "SMESH_Comment.hxx" #include #include @@ -46,6 +48,8 @@ #include #include #include +#include +#include #include #include #include @@ -67,7 +71,7 @@ enum { NB_WALL_FACES = 4 }; //purpose : //======================================================================= StdMeshers_Penta_3D::StdMeshers_Penta_3D() -: myErrorStatus(SMESH_ComputeError::New()) + : myErrorStatus(SMESH_ComputeError::New()) { myTol3D=0.1; myWallNodesMaps.resize( SMESH_Block::NbFaces() ); @@ -89,7 +93,7 @@ StdMeshers_Penta_3D::~StdMeshers_Penta_3D() //purpose : //======================================================================= bool StdMeshers_Penta_3D::Compute(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape) + const TopoDS_Shape& aShape) { MESSAGE("StdMeshers_Penta_3D::Compute()"); // @@ -232,7 +236,7 @@ void StdMeshers_Penta_3D::MakeNodes() // if ( SMESH_Block::IsEdgeID (aSID)) { const SMDS_EdgePosition* epos = - static_cast(aNode->GetPosition().get()); + static_cast(aNode->GetPosition()); myBlock.ComputeParameters( epos->GetUParameter(), aS, aCoords ); } else { @@ -260,11 +264,11 @@ void StdMeshers_Penta_3D::MakeNodes() SMESH_Block::TShapeID wallFaceID[ NB_WALL_FACES ] = { SMESH_Block::ID_Fx0z, SMESH_Block::ID_Fx1z, SMESH_Block::ID_F0yz, SMESH_Block::ID_F1yz - }; + }; SMESH_Block::TShapeID baseEdgeID[ NB_WALL_FACES ] = { SMESH_Block::ID_Ex00, SMESH_Block::ID_Ex10, SMESH_Block::ID_E0y0, SMESH_Block::ID_E1y0 - }; + }; for ( i = 0; i < NB_WALL_FACES ; ++i ) { int fIndex = SMESH_Block::ShapeIndex( wallFaceID[ i ]); bool ok = LoadIJNodes (myWallNodesMaps[ fIndex ], @@ -422,7 +426,7 @@ void StdMeshers_Penta_3D::MakeNodes() ShapeSupportID(bIsUpperLayer, aBNSSID, aSSID); if (!myErrorStatus->IsOK()) { MESSAGE("StdMeshers_Penta_3D::MakeNodes() "); - return; + return; } // aTN.SetShapeSupportID(aSSID); @@ -430,13 +434,13 @@ void StdMeshers_Penta_3D::MakeNodes() aTN.SetBaseNodeID(iBNID); // if (aSSID!=SMESH_Block::ID_NONE){ - // try to find the node - const TopoDS_Shape& aS=myBlock.Shape((int)aSSID); - FindNodeOnShape(aS, aCoords, i, aTN); + // try to find the node + const TopoDS_Shape& aS=myBlock.Shape((int)aSSID); + FindNodeOnShape(aS, aCoords, i, aTN); } else{ - // create node and get it id - CreateNode (bIsUpperLayer, aCoords, aTN); + // create node and get its id + CreateNode (bIsUpperLayer, aCoords, aTN); // if ( bIsUpperLayer ) { const SMDS_MeshNode* n = aTN.Node(); @@ -469,39 +473,12 @@ void StdMeshers_Penta_3D::MakeNodes() } if (!myErrorStatus->IsOK()) { MESSAGE("StdMeshers_Penta_3D::MakeNodes() "); - return; + return; } // myTNodes[ij]=aTN; } } - //DEB - /* - { - int iSSID, iBNID, aID; - // - for (i=0; iGetID(); - aX=aNode->X(); - aY=aNode->Y(); - aZ=aNode->Z(); - printf("*** j:%d BNID#%d iSSID:%d ID:%d { %lf %lf %lf }, { %lf %lf %lf }\n", - j, iBNID, iSSID, aID, aXYZ.X(), aXYZ.Y(), aXYZ.Z(), aX, aY, aZ); - } - } - } - */ - //DEB t } @@ -511,9 +488,9 @@ void StdMeshers_Penta_3D::MakeNodes() //======================================================================= void StdMeshers_Penta_3D::FindNodeOnShape(const TopoDS_Shape& aS, - const gp_XYZ& aParams, + const gp_XYZ& aParams, const int z, - StdMeshers_TNode& aTN) + StdMeshers_TNode& aTN) { double aX, aY, aZ, aD, aTol2, minD; gp_Pnt aP1, aP2; @@ -632,16 +609,16 @@ double StdMeshers_Penta_3D::SetHorizEdgeXYZ(const gp_XYZ& aBase } else { // this variant is better for other cases -// SMESH_MesherHelper helper( *GetMesh() ); -// const TopoDS_Edge & edge = TopoDS::Edge( myBlock.Shape( edgeVec[ TOP ])); -// double u1 = helper.GetNodeU( edge, n1 ); -// double u2 = helper.GetNodeU( edge, n2 ); -// double u = ( 1. - r ) * u1 + r * u2; -// gp_XYZ topNodeParams; -// myBlock.Block().EdgeParameters( edgeVec[ TOP ], u, topNodeParams ); -// myBlock.Block().EdgePoint( edgeVec[ TOP ], -// topNodeParams, -// myShapeXYZ[ edgeVec[ TOP ]]); + // SMESH_MesherHelper helper( *GetMesh() ); + // const TopoDS_Edge & edge = TopoDS::Edge( myBlock.Shape( edgeVec[ TOP ])); + // double u1 = helper.GetNodeU( edge, n1 ); + // double u2 = helper.GetNodeU( edge, n2 ); + // double u = ( 1. - r ) * u1 + r * u2; + // gp_XYZ topNodeParams; + // myBlock.Block().EdgeParameters( edgeVec[ TOP ], u, topNodeParams ); + // myBlock.Block().EdgePoint( edgeVec[ TOP ], + // topNodeParams, + // myShapeXYZ[ edgeVec[ TOP ]]); } // base edge @@ -673,14 +650,14 @@ void StdMeshers_Penta_3D::MakeVolumeMesh() const StdMeshers_TNode& aTN = myTNodes[ij]; aSSID=aTN.ShapeSupportID(); if (aSSID==SMESH_Block::ID_NONE) { - SMDS_MeshNode* aNode = (SMDS_MeshNode*)aTN.Node(); - meshDS->SetNodeInVolume(aNode, shapeID); + SMDS_MeshNode* aNode = (SMDS_MeshNode*)aTN.Node(); + meshDS->SetNodeInVolume(aNode, shapeID); } } } // // 2. Make pentahedrons - int aID0, k , aJ[3]; + int aID0, k , aJ[4]; vector aN; // SMDS_ElemIteratorPtr itf, aItNodes; @@ -700,22 +677,16 @@ void StdMeshers_Penta_3D::MakeVolumeMesh() if ( aN.size() < nbFaceNodes * 2 ) aN.resize( nbFaceNodes * 2 ); // - k=0; - aItNodes=pE0->nodesIterator(); - while (aItNodes->more()) { - //const SMDS_MeshElement* pNode = aItNodes->next(); - const SMDS_MeshNode* pNode = - static_cast (aItNodes->next()); - if(myTool->IsMedium(pNode)) - continue; + for ( k=0; kGetNode(k); +// if(myTool->IsMedium(pNode)) +// continue; aID0 = pNode->GetID(); aJ[k] = GetIndexOnLayer(aID0); if (!myErrorStatus->IsOK()) { MESSAGE("StdMeshers_Penta_3D::MakeVolumeMesh"); - return; + return; } - // - ++k; } // bool forward = true; @@ -723,15 +694,15 @@ void StdMeshers_Penta_3D::MakeVolumeMesh() i1=i; i2=i+1; for(j=0; jGetNodes(); aNbNodes = aSM0->NbNodes(); //printf("** aNbNodes=%d\n", aNbNodes); - + myTool->SetSubShape( aFxy1 ); // to set medium nodes to aFxy1 // // set elements on aFxy1 vector aNodes1; @@ -829,7 +800,7 @@ void StdMeshers_Penta_3D::MakeMeshOnFxy1() while(itf->more()) { const SMDS_MeshElement* pE0 = itf->next(); aElementType = pE0->GetType(); - if (aElementType!=SMDSAbs_Face) { + if (!aElementType==SMDSAbs_Face) { continue; } aNbNodes = pE0->NbNodes(); @@ -849,7 +820,7 @@ void StdMeshers_Penta_3D::MakeMeshOnFxy1() aJ = GetIndexOnLayer(aID0); if (!myErrorStatus->IsOK()) { MESSAGE("StdMeshers_Penta_3D::MakeMeshOnFxy1() "); - return; + return; } // ij = aLevel*myJSize + aJ; @@ -871,6 +842,7 @@ void StdMeshers_Penta_3D::MakeMeshOnFxy1() } meshDS->SetMeshElementOnShape(face, aFxy1); } + myTool->SetSubShape( myShape ); // update compute state of top face submesh aSubMesh1->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); @@ -878,7 +850,8 @@ void StdMeshers_Penta_3D::MakeMeshOnFxy1() // assure that mesh on the top face will be cleaned when it is cleaned // on the bottom face SMESH_subMesh* volSM = pMesh->GetSubMesh( myTool->GetSubShape() ); - volSM->SetEventListener( new SMESH_subMeshEventListener(true), + volSM->SetEventListener( new SMESH_subMeshEventListener(true, // deletable by SMESH_subMesh + "StdMeshers_Penta_3D"), SMESH_subMeshEventListenerData::MakeData( aSubMesh1 ), aSubMesh0 ); // translate CLEAN event of aSubMesh0 to aSubMesh1 } @@ -937,8 +910,8 @@ void StdMeshers_Penta_3D::MakeConnectingMap() //purpose : //======================================================================= void StdMeshers_Penta_3D::CreateNode(const bool bIsUpperLayer, - const gp_XYZ& aParams, - StdMeshers_TNode& aTN) + const gp_XYZ& aParams, + StdMeshers_TNode& aTN) { double aX, aY, aZ; // @@ -947,15 +920,15 @@ void StdMeshers_Penta_3D::CreateNode(const bool bIsUpperLayer, SMDS_MeshNode* pNode=NULL; aTN.SetNode(pNode); // -// if (bIsUpperLayer) { -// // point on face Fxy1 -// const TopoDS_Shape& aS=myBlock.Shape(SMESH_Block::ID_Fxy1); -// myBlock.Point(aParams, aS, aP); -// } -// else { -// // point inside solid -// myBlock.Point(aParams, aP); -// } + // if (bIsUpperLayer) { + // // point on face Fxy1 + // const TopoDS_Shape& aS=myBlock.Shape(SMESH_Block::ID_Fxy1); + // myBlock.Point(aParams, aS, aP); + // } + // else { + // // point inside solid + // myBlock.Point(aParams, aP); + // } if (bIsUpperLayer) { double u = aParams.X(), v = aParams.Y(); double u1 = ( 1. - u ), v1 = ( 1. - v ); @@ -973,11 +946,11 @@ void StdMeshers_Penta_3D::CreateNode(const bool bIsUpperLayer, SMESH_Block::ShellPoint( aParams, myShapeXYZ, aP.ChangeCoord() ); } // -// iErr=myBlock.ErrorStatus(); -// if (iErr) { -// myErrorStatus=12; // can not find the node point; -// return; -// } + // iErr=myBlock.ErrorStatus(); + // if (iErr) { + // myErrorStatus=12; // can not find the node point; + // return; + // } // aX=aP.X(); aY=aP.Y(); aZ=aP.Z(); // @@ -985,7 +958,7 @@ void StdMeshers_Penta_3D::CreateNode(const bool bIsUpperLayer, SMESHDS_Mesh* pMeshDS = pMesh->GetMeshDS(); // pNode = pMeshDS->AddNode(aX, aY, aZ); - + aTN.SetNode(pNode); } @@ -994,42 +967,42 @@ void StdMeshers_Penta_3D::CreateNode(const bool bIsUpperLayer, //purpose : //======================================================================= void StdMeshers_Penta_3D::ShapeSupportID(const bool bIsUpperLayer, - const SMESH_Block::TShapeID aBNSSID, - SMESH_Block::TShapeID& aSSID) + const SMESH_Block::TShapeID aBNSSID, + SMESH_Block::TShapeID& aSSID) { switch (aBNSSID) { - case SMESH_Block::ID_V000: - aSSID=(bIsUpperLayer) ? SMESH_Block::ID_V001 : SMESH_Block::ID_E00z; - break; - case SMESH_Block::ID_V100: - aSSID=(bIsUpperLayer) ? SMESH_Block::ID_V101 : SMESH_Block::ID_E10z; - break; - case SMESH_Block::ID_V110: - aSSID=(bIsUpperLayer) ? SMESH_Block::ID_V111 : SMESH_Block::ID_E11z; - break; - case SMESH_Block::ID_V010: - aSSID=(bIsUpperLayer) ? SMESH_Block::ID_V011 : SMESH_Block::ID_E01z; - break; - case SMESH_Block::ID_Ex00: - aSSID=(bIsUpperLayer) ? SMESH_Block::ID_Ex01 : SMESH_Block::ID_Fx0z; - break; - case SMESH_Block::ID_Ex10: - aSSID=(bIsUpperLayer) ? SMESH_Block::ID_Ex11 : SMESH_Block::ID_Fx1z; - break; - case SMESH_Block::ID_E0y0: - aSSID=(bIsUpperLayer) ? SMESH_Block::ID_E0y1 : SMESH_Block::ID_F0yz; - break; - case SMESH_Block::ID_E1y0: - aSSID=(bIsUpperLayer) ? SMESH_Block::ID_E1y1 : SMESH_Block::ID_F1yz; - break; - case SMESH_Block::ID_Fxy0: - aSSID=SMESH_Block::ID_NONE;//(bIsUpperLayer) ? Shape_ID_Fxy1 : Shape_ID_NONE; - break; - default: - aSSID=SMESH_Block::ID_NONE; - myErrorStatus->myName=10; // Can not find supporting shape ID - myErrorStatus->myComment = "Internal error of StdMeshers_Penta_3D"; - break; + case SMESH_Block::ID_V000: + aSSID=(bIsUpperLayer) ? SMESH_Block::ID_V001 : SMESH_Block::ID_E00z; + break; + case SMESH_Block::ID_V100: + aSSID=(bIsUpperLayer) ? SMESH_Block::ID_V101 : SMESH_Block::ID_E10z; + break; + case SMESH_Block::ID_V110: + aSSID=(bIsUpperLayer) ? SMESH_Block::ID_V111 : SMESH_Block::ID_E11z; + break; + case SMESH_Block::ID_V010: + aSSID=(bIsUpperLayer) ? SMESH_Block::ID_V011 : SMESH_Block::ID_E01z; + break; + case SMESH_Block::ID_Ex00: + aSSID=(bIsUpperLayer) ? SMESH_Block::ID_Ex01 : SMESH_Block::ID_Fx0z; + break; + case SMESH_Block::ID_Ex10: + aSSID=(bIsUpperLayer) ? SMESH_Block::ID_Ex11 : SMESH_Block::ID_Fx1z; + break; + case SMESH_Block::ID_E0y0: + aSSID=(bIsUpperLayer) ? SMESH_Block::ID_E0y1 : SMESH_Block::ID_F0yz; + break; + case SMESH_Block::ID_E1y0: + aSSID=(bIsUpperLayer) ? SMESH_Block::ID_E1y1 : SMESH_Block::ID_F1yz; + break; + case SMESH_Block::ID_Fxy0: + aSSID=SMESH_Block::ID_NONE;//(bIsUpperLayer) ? Shape_ID_Fxy1 : Shape_ID_NONE; + break; + default: + aSSID=SMESH_Block::ID_NONE; + myErrorStatus->myName=10; // Can not find supporting shape ID + myErrorStatus->myComment = "Internal error of StdMeshers_Penta_3D"; + break; } return; } @@ -1066,25 +1039,25 @@ void StdMeshers_Penta_3D::MakeBlock() const SMDS_MeshElement * pElement = itf->next(); aElementType = pElement->GetType(); if (aElementType==SMDSAbs_Face) { - iNbNodes = pElement->NbNodes(); - if ( iNbNodes==3 || (pElement->IsQuadratic() && iNbNodes==6) ) { - aFTr = aF; - ++iCnt; - if (iCnt>1) { - // \begin{E.A.} - // The current algorithm fails if there is more that one - // face wich contains triangles ... - // In that case, replace return by break to try another - // method (coded in "if (iCnt != 1) { ... }") - // + iNbNodes = pElement->NbNodes(); + if ( iNbNodes==3 || (pElement->IsQuadratic() && iNbNodes==6) ) { + aFTr = aF; + ++iCnt; + if (iCnt>1) { + // \begin{E.A.} + // The current algorithm fails if there is more that one + // face wich contains triangles ... + // In that case, replace return by break to try another + // method (coded in "if (iCnt != 1) { ... }") + // // MESSAGE("StdMeshers_Penta_3D::MakeBlock() "); - // myErrorStatus=5; // more than one face has triangulation - // return; - break; - // \end{E.A.} - } - break; // next face - } + // myErrorStatus=5; // more than one face has triangulation + // return; + break; + // \end{E.A.} + } + break; // next face + } } } } @@ -1153,85 +1126,85 @@ void StdMeshers_Penta_3D::MakeBlock() int has_only_quad_f6 = 1; // for (i=1; i<=iNbF; ++i) { - int ok = 1; - const TopoDS_Shape& aF = aM(i); - SMESH_subMesh *aSubMesh = pMesh->GetSubMeshContaining(aF); - SMESHDS_SubMesh *aSM = aSubMesh->GetSubMeshDS(); - SMDS_ElemIteratorPtr itf = aSM->GetElements(); - while(itf->more()) { - const SMDS_MeshElement * pElement = itf->next(); - aElementType = pElement->GetType(); - if (aElementType==SMDSAbs_Face) { - iNbNodes = pElement->NbNodes(); - if ( iNbNodes!=4 ) { - ok = 0; - break ; - } - } - } - if (i==1) has_only_quad_f1 = ok ; - if (i==2) has_only_quad_f2 = ok ; - if (i==3) has_only_quad_f3 = ok ; - if (i==4) has_only_quad_f4 = ok ; - if (i==5) has_only_quad_f5 = ok ; - if (i==6) has_only_quad_f6 = ok ; + int ok = 1; + const TopoDS_Shape& aF = aM(i); + SMESH_subMesh *aSubMesh = pMesh->GetSubMeshContaining(aF); + SMESHDS_SubMesh *aSM = aSubMesh->GetSubMeshDS(); + SMDS_ElemIteratorPtr itf = aSM->GetElements(); + while(itf->more()) { + const SMDS_MeshElement * pElement = itf->next(); + aElementType = pElement->GetType(); + if (aElementType==SMDSAbs_Face) { + iNbNodes = pElement->NbNodes(); + if ( iNbNodes!=4 ) { + ok = 0; + break ; + } + } + } + if (i==1) has_only_quad_f1 = ok ; + if (i==2) has_only_quad_f2 = ok ; + if (i==3) has_only_quad_f3 = ok ; + if (i==4) has_only_quad_f4 = ok ; + if (i==5) has_only_quad_f5 = ok ; + if (i==6) has_only_quad_f6 = ok ; } // TopTools_IndexedMapOfShape aE; TopExp::MapShapes(myShape, TopAbs_EDGE, aE); int iNbE = aE.Extent(); if (iNbE == 12) { - // - int nb_e01 = pMesh->GetSubMeshContaining(aE(1))->GetSubMeshDS()->NbElements(); - int nb_e02 = pMesh->GetSubMeshContaining(aE(2))->GetSubMeshDS()->NbElements(); - int nb_e03 = pMesh->GetSubMeshContaining(aE(3))->GetSubMeshDS()->NbElements(); - int nb_e04 = pMesh->GetSubMeshContaining(aE(4))->GetSubMeshDS()->NbElements(); - int nb_e05 = pMesh->GetSubMeshContaining(aE(5))->GetSubMeshDS()->NbElements(); - int nb_e06 = pMesh->GetSubMeshContaining(aE(6))->GetSubMeshDS()->NbElements(); - int nb_e07 = pMesh->GetSubMeshContaining(aE(7))->GetSubMeshDS()->NbElements(); - int nb_e08 = pMesh->GetSubMeshContaining(aE(8))->GetSubMeshDS()->NbElements(); - int nb_e09 = pMesh->GetSubMeshContaining(aE(9))->GetSubMeshDS()->NbElements(); - int nb_e10 = pMesh->GetSubMeshContaining(aE(10))->GetSubMeshDS()->NbElements(); - int nb_e11 = pMesh->GetSubMeshContaining(aE(11))->GetSubMeshDS()->NbElements(); - int nb_e12 = pMesh->GetSubMeshContaining(aE(12))->GetSubMeshDS()->NbElements(); - // - int nb_ok = 0 ; - // - if ( (nb_e01==nb_e03) && (nb_e03==nb_e05) && (nb_e05==nb_e07) ) { - if ( has_only_quad_f1 && has_only_quad_f2 && has_only_quad_f3 && has_only_quad_f4 ) { - if ( (nb_e09==nb_e10) && (nb_e08==nb_e06) && (nb_e11==nb_e12) && (nb_e04==nb_e02) ) { - if (nb_f5==nb_f6) { - nb_ok += 1; - aFTr = aM(5); - } - } - } - } - if ( (nb_e02==nb_e04) && (nb_e04==nb_e06) && (nb_e06==nb_e08) ) { - if ( has_only_quad_f1 && has_only_quad_f2 && has_only_quad_f5 && has_only_quad_f6 ) { - if ( (nb_e01==nb_e03) && (nb_e10==nb_e12) && (nb_e05==nb_e07) && (nb_e09==nb_e11) ) { - if (nb_f3==nb_f4) { - nb_ok += 1; - aFTr = aM(3); - } - } - } - } - if ( (nb_e09==nb_e10) && (nb_e10==nb_e11) && (nb_e11==nb_e12) ) { - if ( has_only_quad_f3 && has_only_quad_f4 && has_only_quad_f5 && has_only_quad_f6 ) { - if ( (nb_e01==nb_e05) && (nb_e02==nb_e06) && (nb_e03==nb_e07) && (nb_e04==nb_e08) ) { - if (nb_f1==nb_f2) { - nb_ok += 1; - aFTr = aM(1); - } - } - } - } - // - if ( nb_ok == 1 ) { - isOK = 1; - } - // + // + int nb_e01 = pMesh->GetSubMeshContaining(aE(1))->GetSubMeshDS()->NbElements(); + int nb_e02 = pMesh->GetSubMeshContaining(aE(2))->GetSubMeshDS()->NbElements(); + int nb_e03 = pMesh->GetSubMeshContaining(aE(3))->GetSubMeshDS()->NbElements(); + int nb_e04 = pMesh->GetSubMeshContaining(aE(4))->GetSubMeshDS()->NbElements(); + int nb_e05 = pMesh->GetSubMeshContaining(aE(5))->GetSubMeshDS()->NbElements(); + int nb_e06 = pMesh->GetSubMeshContaining(aE(6))->GetSubMeshDS()->NbElements(); + int nb_e07 = pMesh->GetSubMeshContaining(aE(7))->GetSubMeshDS()->NbElements(); + int nb_e08 = pMesh->GetSubMeshContaining(aE(8))->GetSubMeshDS()->NbElements(); + int nb_e09 = pMesh->GetSubMeshContaining(aE(9))->GetSubMeshDS()->NbElements(); + int nb_e10 = pMesh->GetSubMeshContaining(aE(10))->GetSubMeshDS()->NbElements(); + int nb_e11 = pMesh->GetSubMeshContaining(aE(11))->GetSubMeshDS()->NbElements(); + int nb_e12 = pMesh->GetSubMeshContaining(aE(12))->GetSubMeshDS()->NbElements(); + // + int nb_ok = 0 ; + // + if ( (nb_e01==nb_e03) && (nb_e03==nb_e05) && (nb_e05==nb_e07) ) { + if ( has_only_quad_f1 && has_only_quad_f2 && has_only_quad_f3 && has_only_quad_f4 ) { + if ( (nb_e09==nb_e10) && (nb_e08==nb_e06) && (nb_e11==nb_e12) && (nb_e04==nb_e02) ) { + if (nb_f5==nb_f6) { + nb_ok += 1; + aFTr = aM(5); + } + } + } + } + if ( (nb_e02==nb_e04) && (nb_e04==nb_e06) && (nb_e06==nb_e08) ) { + if ( has_only_quad_f1 && has_only_quad_f2 && has_only_quad_f5 && has_only_quad_f6 ) { + if ( (nb_e01==nb_e03) && (nb_e10==nb_e12) && (nb_e05==nb_e07) && (nb_e09==nb_e11) ) { + if (nb_f3==nb_f4) { + nb_ok += 1; + aFTr = aM(3); + } + } + } + } + if ( (nb_e09==nb_e10) && (nb_e10==nb_e11) && (nb_e11==nb_e12) ) { + if ( has_only_quad_f3 && has_only_quad_f4 && has_only_quad_f5 && has_only_quad_f6 ) { + if ( (nb_e01==nb_e05) && (nb_e02==nb_e06) && (nb_e03==nb_e07) && (nb_e04==nb_e08) ) { + if (nb_f1==nb_f2) { + nb_ok += 1; + aFTr = aM(1); + } + } + } + } + // + if ( nb_ok == 1 ) { + isOK = 1; + } + // } } if (!isOK) { @@ -1284,11 +1257,11 @@ void StdMeshers_Penta_3D::MakeBlock() const TopoDS_Edge& aE=TopoDS::Edge(aEx); TopExp::Vertices(aE, aV[0], aV[1]); for (i=0; i<2; ++i) { - if (!aV[i].IsSame(aV000)) { - aV001=aV[i]; - bFound=!bFound; - break; - } + if (!aV[i].IsSame(aV000)) { + aV001=aV[i]; + bFound=!bFound; + break; + } } } } @@ -1365,8 +1338,8 @@ void StdMeshers_Penta_3D::CheckData() iNb=aM.Extent(); if (iNb!=iNbEx[i]){ MESSAGE("StdMeshers_Penta_3D::CheckData() "); - myErrorStatus->myName=4; // number of subshape is not compatible - myErrorStatus->myComment="Wrong number of subshapes of a block"; + myErrorStatus->myName=4; // number of sub-shape is not compatible + myErrorStatus->myComment="Wrong number of sub-shapes of a block"; return; } } @@ -1432,7 +1405,7 @@ bool StdMeshers_Penta_3D::LoadIJNodes(StdMeshers_IJNodeMap & theIJNodes, SMESHDS_SubMesh* smVft = theMesh->MeshElements( vft ); if (!smFace || !smb || !smt || !sm1 || !sm2 || !smVfb || !smVlb || !smVft ) { MESSAGE( "NULL submesh " <NbNodes() != smt->NbNodes() || sm1->NbNodes() != sm2->NbNodes() ) { @@ -1453,13 +1426,13 @@ bool StdMeshers_Penta_3D::LoadIJNodes(StdMeshers_IJNodeMap & theIJNodes, int nf = sm1->NbNodes()*smb->NbNodes() - n3*n4; if( nf != smFace->NbNodes() ) { MESSAGE( "Wrong nb face nodes: " << - sm1->NbNodes()<<" "<NbNodes()<<" "<NbNodes()); + sm1->NbNodes()<<" "<NbNodes()<<" "<NbNodes()); return false; } } else { MESSAGE( "Wrong nb face nodes: " << - sm1->NbNodes()<<" "<NbNodes()<<" "<NbNodes()); + sm1->NbNodes()<<" "<NbNodes()<<" "<NbNodes()); return false; } } @@ -1494,7 +1467,7 @@ bool StdMeshers_Penta_3D::LoadIJNodes(StdMeshers_IJNodeMap & theIJNodes, if(myTool->IsMedium(node)) continue; const SMDS_EdgePosition* pos = - dynamic_cast( node->GetPosition().get() ); + dynamic_cast( node->GetPosition() ); if ( !pos ) { return false; } @@ -1517,7 +1490,7 @@ bool StdMeshers_Penta_3D::LoadIJNodes(StdMeshers_IJNodeMap & theIJNodes, if(myTool->IsMedium(node)) continue; const SMDS_EdgePosition* pos = - dynamic_cast( node->GetPosition().get() ); + dynamic_cast( node->GetPosition() ); if ( !pos ) { return false; } @@ -1561,7 +1534,7 @@ bool StdMeshers_Penta_3D::LoadIJNodes(StdMeshers_IJNodeMap & theIJNodes, const SMDS_MeshElement* face = 0; do { // look for a face by 2 nodes - face = SMESH_MeshEditor::FindFaceInSet( n1, n2, allFaces, foundFaces ); + face = SMESH_MeshAlgos::FindFaceInSet( n1, n2, allFaces, foundFaces ); if ( face ) { int nbFaceNodes = face->NbNodes(); if ( (!myCreateQuadratic && nbFaceNodes>4) || @@ -1594,7 +1567,7 @@ bool StdMeshers_Penta_3D::LoadIJNodes(StdMeshers_IJNodeMap & theIJNodes, } } else if ( (nbFaceNodes==3 || (myCreateQuadratic && nbFaceNodes==6) ) && - n3 == par_nVec_1->second[ row ] ) { + n3 == par_nVec_1->second[ row ] ) { n1 = n3; } else { @@ -1678,7 +1651,7 @@ SMESH_ComputeErrorPtr StdMeshers_SMESHBlock::GetError() const case 3: text = "Internal error of StdMeshers_Penta_3D"; break; case 4: text = "Can't compute normalized parameters of a point inside a block"; break; case 5: text = "Can't compute coordinates by normalized parameters inside a block"; break; - case 6: text = "Can't detect block subshapes. Not a block?"; break; + case 6: text = "Can't detect block sub-shapes. Not a block?"; break; } if (!text.empty()) err->myName = myErrorStatus; @@ -1701,8 +1674,8 @@ void StdMeshers_SMESHBlock::Load(const TopoDS_Shell& theShell) //purpose : //======================================================================= void StdMeshers_SMESHBlock::Load(const TopoDS_Shell& theShell, - const TopoDS_Vertex& theV000, - const TopoDS_Vertex& theV001) + const TopoDS_Vertex& theV000, + const TopoDS_Vertex& theV001) { myErrorStatus=0; // @@ -1723,7 +1696,7 @@ void StdMeshers_SMESHBlock::Load(const TopoDS_Shell& theShell, //purpose : //======================================================================= void StdMeshers_SMESHBlock::ComputeParameters(const gp_Pnt& thePnt, - gp_XYZ& theXYZ) + gp_XYZ& theXYZ) { ComputeParameters(thePnt, myShell, theXYZ); } @@ -1733,7 +1706,7 @@ void StdMeshers_SMESHBlock::ComputeParameters(const gp_Pnt& thePnt, //purpose : //======================================================================= void StdMeshers_SMESHBlock::ComputeParameters(const gp_Pnt& thePnt, - const TopoDS_Shape& theShape, + const TopoDS_Shape& theShape, gp_XYZ& theXYZ) { myErrorStatus=0; @@ -1771,7 +1744,7 @@ void StdMeshers_SMESHBlock::ComputeParameters(const double& theU, return; } if ( SMESH_Block::IsEdgeID( aID )) - bOk = myTBlock.EdgeParameters( aID, theU, theXYZ ); + bOk = myTBlock.EdgeParameters( aID, theU, theXYZ ); if (!bOk) { myErrorStatus=4; // problems with computation Parameters return; @@ -1782,8 +1755,7 @@ void StdMeshers_SMESHBlock::ComputeParameters(const double& theU, //function : Point //purpose : //======================================================================= - void StdMeshers_SMESHBlock::Point(const gp_XYZ& theParams, - gp_Pnt& aP3D) +void StdMeshers_SMESHBlock::Point(const gp_XYZ& theParams, gp_Pnt& aP3D) { TopoDS_Shape aS; // @@ -1794,9 +1766,9 @@ void StdMeshers_SMESHBlock::ComputeParameters(const double& theU, //function : Point //purpose : //======================================================================= - void StdMeshers_SMESHBlock::Point(const gp_XYZ& theParams, - const TopoDS_Shape& theShape, - gp_Pnt& aP3D) +void StdMeshers_SMESHBlock::Point(const gp_XYZ& theParams, + const TopoDS_Shape& theShape, + gp_Pnt& aP3D) { myErrorStatus = 0; // @@ -1882,3 +1854,112 @@ const TopoDS_Shape& StdMeshers_SMESHBlock::Shape(const int theID) } +//======================================================================= +//function : Evaluate +//purpose : +//======================================================================= +bool StdMeshers_Penta_3D::Evaluate(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + MapShapeNbElems& aResMap) +{ + MESSAGE("StdMeshers_Penta_3D::Evaluate()"); + + // find face contains only triangles + vector < SMESH_subMesh * >meshFaces; + TopTools_SequenceOfShape aFaces; + int NumBase = 0, i = 0; + for (TopExp_Explorer exp(aShape, TopAbs_FACE); exp.More(); exp.Next()) { + i++; + aFaces.Append(exp.Current()); + SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current()); + meshFaces.push_back(aSubMesh); + MapShapeNbElemsItr anIt = aResMap.find(meshFaces[i]); + if( anIt == aResMap.end() ) { + NumBase = 0; + break; + } + std::vector aVec = (*anIt).second; + int nbtri = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]); + int nbqua = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); + if( nbtri>0 && nbqua==0 ) { + NumBase = i; + } + } + + if(NumBase==0) { + std::vector aResVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; imyName = COMPERR_ALGO_FAILED; + myErrorStatus->myComment = "Submesh can not be evaluated"; + return false; + } + + // find number of 1d elems for base face + int nb1d = 0; + TopTools_MapOfShape Edges1; + for (TopExp_Explorer exp(aFaces.Value(NumBase), TopAbs_EDGE); exp.More(); exp.Next()) { + Edges1.Add(exp.Current()); + SMESH_subMesh *sm = aMesh.GetSubMesh(exp.Current()); + if( sm ) { + MapShapeNbElemsItr anIt = aResMap.find(sm); + if( anIt == aResMap.end() ) continue; + std::vector aVec = (*anIt).second; + nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]); + } + } + // find face opposite to base face + int OppNum = 0; + for(i=1; i<=6; i++) { + if(i==NumBase) continue; + bool IsOpposite = true; + for(TopExp_Explorer exp(aFaces.Value(i), TopAbs_EDGE); exp.More(); exp.Next()) { + if( Edges1.Contains(exp.Current()) ) { + IsOpposite = false; + break; + } + } + if(IsOpposite) { + OppNum = i; + break; + } + } + // find number of 2d elems on side faces + int nb2d = 0; + for(i=1; i<=6; i++) { + if( i==OppNum || i==NumBase ) continue; + MapShapeNbElemsItr anIt = aResMap.find( meshFaces[i-1] ); + if( anIt == aResMap.end() ) continue; + std::vector aVec = (*anIt).second; + nb2d += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); + } + + MapShapeNbElemsItr anIt = aResMap.find( meshFaces[NumBase-1] ); + std::vector aVec = (*anIt).second; + int nb2d_face0 = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); + int nb0d_face0 = aVec[SMDSEntity_Node]; + + anIt = aResMap.find( meshFaces[OppNum-1] ); + for(i=SMDSEntity_Node; i aResVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; i +#include + +#include +#include + +using namespace std; + +//======================================================================= +//function : StdMeshers_PolygonPerFace_2D +//purpose : +//======================================================================= + +StdMeshers_PolygonPerFace_2D::StdMeshers_PolygonPerFace_2D(int hypId, + int studyId, + SMESH_Gen* gen) + :SMESH_2D_Algo(hypId, studyId, gen) +{ + _name = "PolygonPerFace_2D"; +} + +//======================================================================= +//function : CheckHypothesis +//purpose : +//======================================================================= + +bool StdMeshers_PolygonPerFace_2D::CheckHypothesis(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + SMESH_Hypothesis::Hypothesis_Status& theStatus) +{ + theStatus = HYP_OK; + return true; +} + +//======================================================================= +//function : Compute +//purpose : +//======================================================================= + +bool StdMeshers_PolygonPerFace_2D::Compute(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape) +{ + const TopoDS_Face& face = TopoDS::Face( theShape ); + + SMESH_MesherHelper helper( theMesh ); + helper.SetElementsOnShape( true ); + _quadraticMesh = helper.IsQuadraticSubMesh( face ); + + SMESH_ProxyMesh::Ptr proxyMesh = StdMeshers_ViscousLayers2D::Compute( theMesh, face ); + if ( !proxyMesh ) + return false; + + TError erorr; + TSideVector wires = StdMeshers_FaceSide::GetFaceWires(face, theMesh, + /*skipMediumNodes=*/_quadraticMesh, + erorr, proxyMesh, + /*checkVertexNodes=*/false); + if ( wires.size() != 1 ) + return error( COMPERR_BAD_SHAPE, SMESH_Comment("One wire required, not ") << wires.size() ); + + vector nodes = wires[0]->GetOrderedNodes(); + int nbNodes = int( nodes.size() ) - 1; // 1st node is repeated at end + + switch ( nbNodes ) { + case 3: + helper.AddFace( nodes[0], nodes[1], nodes[2] ); + break; + case 4: + helper.AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); + break; + default: + if ( nbNodes < 3 ) + return error( COMPERR_BAD_INPUT_MESH, "Less that 3 nodes on the wire" ); + nodes.resize( nodes.size() - 1 ); + helper.AddPolygonalFace ( nodes ); + } + + return true; +} + +//======================================================================= +//function : Evaluate +//purpose : +//======================================================================= + +bool StdMeshers_PolygonPerFace_2D::Evaluate(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + MapShapeNbElems& theResMap) +{ + // count nb segments + int nbLinSegs = 0, nbQuadSegs = 0; + TopExp_Explorer edge( theShape, TopAbs_EDGE ); + for ( ; edge.More(); edge.Next() ) + { + SMESH_subMesh* sm = theMesh.GetSubMesh( edge.Current() ); + MapShapeNbElems::iterator sm2vec = theResMap.find( sm ); + if ( sm2vec == theResMap.end() ) + continue; + nbLinSegs += sm2vec->second.at( SMDSEntity_Edge ); + nbQuadSegs += sm2vec->second.at( SMDSEntity_Quad_Edge ); + } + + std::vector aVec( SMDSEntity_Last, 0 ); + switch ( nbLinSegs + nbQuadSegs ) { + case 3: + aVec[ nbQuadSegs ? SMDSEntity_Quad_Triangle : SMDSEntity_Triangle ] = 1; + break; + case 4: + aVec[ nbQuadSegs ? SMDSEntity_Quad_Quadrangle : SMDSEntity_Quadrangle ] = 1; + break; + default: + if ( nbLinSegs + nbQuadSegs < 3 ) + return error( COMPERR_BAD_INPUT_MESH, "Less that 3 nodes on the wire" ); + aVec[ nbQuadSegs ? SMDSEntity_Quad_Polygon : SMDSEntity_Polygon ] = 1; + } + + SMESH_subMesh * sm = theMesh.GetSubMesh(theShape); + theResMap.insert(std::make_pair(sm,aVec)); + + return true; +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Prism_3D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Prism_3D.cpp index 6374868c1434..547d25ba52e0 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Prism_3D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Prism_3D.cpp @@ -1,25 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMESH : implementaion of SMESH idl descriptions + // File : StdMeshers_Prism_3D.cxx // Module : SMESH // Created : Fri Oct 20 11:37:07 2006 @@ -27,34 +27,60 @@ // #include "StdMeshers_Prism_3D.hxx" -#include "StdMeshers_ProjectionUtils.hxx" -#include "SMESH_MesherHelper.hxx" -#include "SMDS_VolumeTool.hxx" -#include "SMDS_VolumeOfNodes.hxx" #include "SMDS_EdgePosition.hxx" +#include "SMDS_VolumeOfNodes.hxx" +#include "SMDS_VolumeTool.hxx" #include "SMESH_Comment.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_HypoFilter.hxx" +#include "SMESH_MesherHelper.hxx" +#include "StdMeshers_FaceSide.hxx" +#include "StdMeshers_ProjectionSource1D.hxx" +#include "StdMeshers_ProjectionSource2D.hxx" +#include "StdMeshers_ProjectionUtils.hxx" +#include "StdMeshers_Projection_1D.hxx" +#include "StdMeshers_Projection_1D2D.hxx" +#include "StdMeshers_Quadrangle_2D.hxx" #include "utilities.h" +#include #include +#include #include #include +#include +#include #include #include #include +#include +#include +#include #include +#include +#include + +#include using namespace std; #define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; } -#define gpXYZ(n) gp_XYZ(n->X(),n->Y(),n->Z()) -#define SHOWYXZ(msg, xyz) // {\ -// gp_Pnt p (xyz); \ -// cout << msg << " ("<< p.X() << "; " <GetANewId(), studyId, gen) + { + } + static StdMeshers_Quadrangle_2D* instance( SMESH_Algo* fatherAlgo, + SMESH_MesherHelper* helper=0) + { + static TQuadrangleAlgo* algo = new TQuadrangleAlgo( fatherAlgo->GetStudyId(), + fatherAlgo->GetGen() ); + if ( helper && + algo->myProxyMesh && + algo->myProxyMesh->GetMesh() != helper->GetMesh() ) + algo->myProxyMesh.reset( new SMESH_ProxyMesh( *helper->GetMesh() )); + + algo->myQuadList.clear(); + + if ( helper ) + algo->_quadraticMesh = helper->GetIsQuadratic(); + + return algo; + } + }; + //======================================================================= + /*! + * \brief Algorithm projecting 1D mesh + */ + struct TProjction1dAlgo : public StdMeshers_Projection_1D + { + StdMeshers_ProjectionSource1D myHyp; + + TProjction1dAlgo(int studyId, SMESH_Gen* gen) + : StdMeshers_Projection_1D( gen->GetANewId(), studyId, gen), + myHyp( gen->GetANewId(), studyId, gen) + { + StdMeshers_Projection_1D::_sourceHypo = & myHyp; + } + static TProjction1dAlgo* instance( SMESH_Algo* fatherAlgo ) + { + static TProjction1dAlgo* algo = new TProjction1dAlgo( fatherAlgo->GetStudyId(), + fatherAlgo->GetGen() ); + return algo; + } + }; + //======================================================================= + /*! + * \brief Algorithm projecting 2D mesh + */ + struct TProjction2dAlgo : public StdMeshers_Projection_1D2D + { + StdMeshers_ProjectionSource2D myHyp; + + TProjction2dAlgo(int studyId, SMESH_Gen* gen) + : StdMeshers_Projection_1D2D( gen->GetANewId(), studyId, gen), + myHyp( gen->GetANewId(), studyId, gen) + { + StdMeshers_Projection_2D::_sourceHypo = & myHyp; + } + static TProjction2dAlgo* instance( SMESH_Algo* fatherAlgo ) + { + static TProjction2dAlgo* algo = new TProjction2dAlgo( fatherAlgo->GetStudyId(), + fatherAlgo->GetGen() ); + return algo; + } + const NSProjUtils::TNodeNodeMap& GetNodesMap() + { + return _src2tgtNodes; + } + }; + //======================================================================= + /*! + * \brief Returns already computed EDGEs + */ + void getPrecomputedEdges( SMESH_MesherHelper& theHelper, + const TopoDS_Shape& theShape, + vector< TopoDS_Edge >& theEdges) + { + theEdges.clear(); + + SMESHDS_Mesh* meshDS = theHelper.GetMeshDS(); + SMESHDS_SubMesh* sm; + + TopTools_IndexedMapOfShape edges; + TopExp::MapShapes( theShape, TopAbs_EDGE, edges ); + for ( int iE = 1; iE <= edges.Extent(); ++iE ) + { + const TopoDS_Shape edge = edges( iE ); + if (( ! ( sm = meshDS->MeshElements( edge ))) || + ( sm->NbElements() == 0 )) + continue; + + // there must not be FACEs meshed with triangles and sharing a computed EDGE + // as the precomputed EDGEs are used for propagation other to 'vertical' EDGEs + bool faceFound = false; + PShapeIteratorPtr faceIt = + theHelper.GetAncestors( edge, *theHelper.GetMesh(), TopAbs_FACE ); + while ( const TopoDS_Shape* face = faceIt->next() ) + + if (( sm = meshDS->MeshElements( *face )) && + ( sm->NbElements() > 0 ) && + ( !theHelper.IsSameElemGeometry( sm, SMDSGeom_QUADRANGLE ) )) + { + faceFound = true; + break; + } + if ( !faceFound ) + theEdges.push_back( TopoDS::Edge( edge )); + } + } + + //================================================================================ + /*! + * \brief Make \a botE be the BOTTOM_SIDE of \a quad. + * Return false if the BOTTOM_SIDE is composite + */ + //================================================================================ + + bool setBottomEdge( const TopoDS_Edge& botE, + FaceQuadStruct::Ptr& quad, + const TopoDS_Shape& face) + { + quad->side[ QUAD_TOP_SIDE ].grid->Reverse(); + quad->side[ QUAD_LEFT_SIDE ].grid->Reverse(); + int edgeIndex = 0; + bool isComposite = false; + for ( size_t i = 0; i < quad->side.size(); ++i ) + { + StdMeshers_FaceSidePtr quadSide = quad->side[i]; + for ( int iE = 0; iE < quadSide->NbEdges(); ++iE ) + if ( botE.IsSame( quadSide->Edge( iE ))) + { + if ( quadSide->NbEdges() > 1 ) + isComposite = true; //return false; + edgeIndex = i; + i = quad->side.size(); // to quit from the outer loop + break; + } + } + if ( edgeIndex != QUAD_BOTTOM_SIDE ) + quad->shift( quad->side.size() - edgeIndex, /*keepUnitOri=*/false ); + + quad->face = TopoDS::Face( face ); + + return !isComposite; + } + //================================================================================ /*! * \brief Return iterator pointing to node column for the given parameter @@ -149,7 +326,213 @@ namespace { } params.push_back( parLast ); // 1. } -} + + //================================================================================ + /*! + * \brief Return coordinate system for z-th layer of nodes + */ + //================================================================================ + + gp_Ax2 getLayerCoordSys(const int z, + const vector< const TNodeColumn* >& columns, + int& xColumn) + { + // gravity center of a layer + gp_XYZ O(0,0,0); + int vertexCol = -1; + for ( int i = 0; i < columns.size(); ++i ) + { + O += gpXYZ( (*columns[ i ])[ z ]); + if ( vertexCol < 0 && + columns[ i ]->front()->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX ) + vertexCol = i; + } + O /= columns.size(); + + // Z axis + gp_Vec Z(0,0,0); + int iPrev = columns.size()-1; + for ( int i = 0; i < columns.size(); ++i ) + { + gp_Vec v1( O, gpXYZ( (*columns[ iPrev ])[ z ])); + gp_Vec v2( O, gpXYZ( (*columns[ i ] )[ z ])); + Z += v1 ^ v2; + iPrev = i; + } + + if ( vertexCol >= 0 ) + { + O = gpXYZ( (*columns[ vertexCol ])[ z ]); + } + if ( xColumn < 0 || xColumn >= columns.size() ) + { + // select a column for X dir + double maxDist = 0; + for ( int i = 0; i < columns.size(); ++i ) + { + double dist = ( O - gpXYZ((*columns[ i ])[ z ])).SquareModulus(); + if ( dist > maxDist ) + { + xColumn = i; + maxDist = dist; + } + } + } + + // X axis + gp_Vec X( O, gpXYZ( (*columns[ xColumn ])[ z ])); + + return gp_Ax2( O, Z, X); + } + + //================================================================================ + /*! + * \brief Removes submeshes that are or can be meshed with regular grid from given list + * \retval int - nb of removed submeshes + */ + //================================================================================ + + int removeQuasiQuads(list< SMESH_subMesh* >& notQuadSubMesh, + SMESH_MesherHelper* helper, + StdMeshers_Quadrangle_2D* quadAlgo) + { + int nbRemoved = 0; + //SMESHDS_Mesh* mesh = notQuadSubMesh.front()->GetFather()->GetMeshDS(); + list< SMESH_subMesh* >::iterator smIt = notQuadSubMesh.begin(); + while ( smIt != notQuadSubMesh.end() ) + { + SMESH_subMesh* faceSm = *smIt; + SMESHDS_SubMesh* faceSmDS = faceSm->GetSubMeshDS(); + int nbQuads = faceSmDS ? faceSmDS->NbElements() : 0; + bool toRemove; + if ( nbQuads > 0 ) + toRemove = helper->IsStructured( faceSm ); + else + toRemove = (bool)quadAlgo->CheckNbEdges( *helper->GetMesh(), + faceSm->GetSubShape() ); + nbRemoved += toRemove; + if ( toRemove ) + smIt = notQuadSubMesh.erase( smIt ); + else + ++smIt; + } + + return nbRemoved; + } + + //================================================================================ + /*! + * \brief Return and angle between two EDGEs + * \return double - the angle normalized so that + * >~ 0 -> 2.0 + * PI/2 -> 1.0 + * PI -> 0.0 + * -PI/2 -> -1.0 + * <~ 0 -> -2.0 + */ + //================================================================================ + + // double normAngle(const TopoDS_Edge & E1, const TopoDS_Edge & E2, const TopoDS_Face & F) + // { + // return SMESH_MesherHelper::GetAngle( E1, E2, F ) / ( 0.5 * M_PI ); + // } + + //================================================================================ + /*! + * Consider continuous straight EDGES as one side - mark them to unite + */ + //================================================================================ + + int countNbSides( const Prism_3D::TPrismTopo & thePrism, + vector & nbUnitePerEdge, + vector< double > & edgeLength) + { + int nbEdges = thePrism.myNbEdgesInWires.front(); // nb outer edges + int nbSides = nbEdges; + + + list< TopoDS_Edge >::const_iterator edgeIt = thePrism.myBottomEdges.begin(); + std::advance( edgeIt, nbEdges-1 ); + TopoDS_Edge prevE = *edgeIt; + // bool isPrevStraight = SMESH_Algo::IsStraight( prevE ); + int iPrev = nbEdges - 1; + + int iUnite = -1; // the first of united EDGEs + + // analyse angles between EDGEs + int nbCorners = 0; + vector< bool > isCorner( nbEdges ); + edgeIt = thePrism.myBottomEdges.begin(); + for ( int iE = 0; iE < nbEdges; ++iE, ++edgeIt ) + { + const TopoDS_Edge& curE = *edgeIt; + edgeLength[ iE ] = SMESH_Algo::EdgeLength( curE ); + + // double normAngle = normAngle( prevE, curE, thePrism.myBottom ); + // isCorner[ iE ] = false; + // if ( normAngle < 2.0 ) + // { + // if ( normAngle < 0.001 ) // straight or obtuse angle + // { + // // unite EDGEs in order not to put a corner of the unit quadrangle at this VERTEX + // if ( iUnite < 0 ) + // iUnite = iPrev; + // nbUnitePerEdge[ iUnite ]++; + // nbUnitePerEdge[ iE ] = -1; + // --nbSides; + // } + // else + // { + // isCorner[ iE ] = true; + // nbCorners++; + // iUnite = -1; + // } + // } + // prevE = curE; + } + + if ( nbCorners > 4 ) + { + // define which of corners to put on a side of the unit quadrangle + } + // edgeIt = thePrism.myBottomEdges.begin(); + // for ( int iE = 0; iE < nbEdges; ++iE, ++edgeIt ) + // { + // const TopoDS_Edge& curE = *edgeIt; + // edgeLength[ iE ] = SMESH_Algo::EdgeLength( curE ); + + // const bool isCurStraight = SMESH_Algo::IsStraight( curE ); + // if ( isPrevStraight && isCurStraight && SMESH_Algo::IsContinuous( prevE, curE )) + // { + // if ( iUnite < 0 ) + // iUnite = iPrev; + // nbUnitePerEdge[ iUnite ]++; + // nbUnitePerEdge[ iE ] = -1; + // --nbSides; + // } + // else + // { + // iUnite = -1; + // } + // prevE = curE; + // isPrevStraight = isCurStraight; + // iPrev = iE; + // } + + return nbSides; + } + + void pointsToPython(const std::vector& p) + { +#ifdef _DEBUG_ + for ( int i = SMESH_Block::ID_V000; i < p.size(); ++i ) + { + cout << "mesh.AddNode( " << p[i].X() << ", "<< p[i].Y() << ", "<< p[i].Z() << ") # " << i <<" " ; + SMESH_Block::DumpShapeID( i, cout ) << endl; + } +#endif + } +} // namespace //======================================================================= //function : StdMeshers_Prism_3D @@ -159,9 +542,16 @@ namespace { StdMeshers_Prism_3D::StdMeshers_Prism_3D(int hypId, int studyId, SMESH_Gen* gen) :SMESH_3D_Algo(hypId, studyId, gen) { - _name = "Prism_3D"; - _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID); // 1 bit per shape type - myProjectTriangles = false; + _name = "Prism_3D"; + _shapeType = (1 << TopAbs_SOLID); // 1 bit per shape type + _onlyUnaryInput = false; // mesh all SOLIDs at once + _requireDiscreteBoundary = false; // mesh FACEs and EDGEs by myself + _supportSubmeshes = true; // "source" FACE must be meshed by other algo + _neededLowerHyps[ 1 ] = true; // suppress warning on hiding a global 1D algo + _neededLowerHyps[ 2 ] = true; // suppress warning on hiding a global 2D algo + + //myProjectTriangles = false; + mySetErrorToSM = true; // to pass an error to a sub-mesh of a current solid or not } //================================================================================ @@ -193,12 +583,12 @@ bool StdMeshers_Prism_3D::CheckHypothesis(SMESH_Mesh& a for ( ; exp.More(); exp.Next() ) { ++nbFace; const TopoDS_Shape& face = exp.Current(); - nbEdge = TAssocTool::Count( face, TopAbs_EDGE, 0 ); - nbWire = TAssocTool::Count( face, TopAbs_WIRE, 0 ); + nbEdge = NSProjUtils::Count( face, TopAbs_EDGE, 0 ); + nbWire = NSProjUtils::Count( face, TopAbs_WIRE, 0 ); if ( nbEdge!= 4 || nbWire!= 1 ) { if ( !notQuadFaces.empty() ) { - if ( TAssocTool::Count( notQuadFaces.back(), TopAbs_EDGE, 0 ) != nbEdge || - TAssocTool::Count( notQuadFaces.back(), TopAbs_WIRE, 0 ) != nbWire ) + if ( NSProjUtils::Count( notQuadFaces.back(), TopAbs_EDGE, 0 ) != nbEdge || + NSProjUtils::Count( notQuadFaces.back(), TopAbs_WIRE, 0 ) != nbWire ) RETURN_BAD_RESULT("Different not quad faces"); } notQuadFaces.push_back( face ); @@ -210,7 +600,7 @@ bool StdMeshers_Prism_3D::CheckHypothesis(SMESH_Mesh& a RETURN_BAD_RESULT("Bad nb not quad faces: " << notQuadFaces.size()); // check total nb faces - nbEdge = TAssocTool::Count( notQuadFaces.back(), TopAbs_EDGE, 0 ); + nbEdge = NSProjUtils::Count( notQuadFaces.back(), TopAbs_EDGE, 0 ); if ( nbFace != nbEdge + 2 ) RETURN_BAD_RESULT("Bad nb of faces: " << nbFace << " but must be " << nbEdge + 2); } @@ -222,7 +612,7 @@ bool StdMeshers_Prism_3D::CheckHypothesis(SMESH_Mesh& a //======================================================================= //function : Compute -//purpose : +//purpose : Compute mesh on a COMPOUND of SOLIDs //======================================================================= bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape) @@ -230,247 +620,1307 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh SMESH_MesherHelper helper( theMesh ); myHelper = &helper; - myHelper->IsQuadraticSubMesh( theShape ); - - // Analyse mesh and geomerty to find block subshapes and submeshes - if ( !myBlock.Init( myHelper, theShape )) - return error( myBlock.GetError()); + int nbSolids = helper.Count( theShape, TopAbs_SOLID, /*skipSame=*/false ); + if ( nbSolids < 1 ) + return true; - SMESHDS_Mesh* meshDS = theMesh.GetMeshDS(); - - int volumeID = meshDS->ShapeToIndex( theShape ); + TopTools_IndexedDataMapOfShapeListOfShape faceToSolids; + TopExp::MapShapesAndAncestors( theShape, TopAbs_FACE, TopAbs_SOLID, faceToSolids ); + // look for meshed FACEs ("source" FACEs) that must be prism bottoms + list< TopoDS_Face > meshedFaces, notQuadMeshedFaces, notQuadFaces; + const bool meshHasQuads = ( theMesh.NbQuadrangles() > 0 ); + //StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this ); + for ( int iF = 1; iF <= faceToSolids.Extent(); ++iF ) + { + const TopoDS_Face& face = TopoDS::Face( faceToSolids.FindKey( iF )); + SMESH_subMesh* faceSM = theMesh.GetSubMesh( face ); + if ( !faceSM->IsEmpty() ) + { + if ( !meshHasQuads || + !helper.IsSameElemGeometry( faceSM->GetSubMeshDS(), SMDSGeom_QUADRANGLE ) || + !helper.IsStructured( faceSM ) + ) + notQuadMeshedFaces.push_front( face ); + else if ( myHelper->Count( face, TopAbs_EDGE, /*ignoreSame=*/false ) != 4 ) + meshedFaces.push_front( face ); + else + meshedFaces.push_back( face ); + } + // not add not quadrilateral FACE as we can't compute it + // else if ( !quadAlgo->CheckNbEdges( theMesh, face )) + // // not add not quadrilateral FACE as it can be a prism side + // // else if ( myHelper->Count( face, TopAbs_EDGE, /*ignoreSame=*/false ) != 4 ) + // { + // notQuadFaces.push_back( face ); + // } + } + // notQuadFaces are of medium priority, put them before ordinary meshed faces + meshedFaces.splice( meshedFaces.begin(), notQuadFaces ); + // notQuadMeshedFaces are of highest priority, put them before notQuadFaces + meshedFaces.splice( meshedFaces.begin(), notQuadMeshedFaces ); - // To compute coordinates of a node inside a block, it is necessary to know - // 1. normalized parameters of the node by which - // 2. coordinates of node projections on all block sub-shapes are computed + Prism_3D::TPrismTopo prism; + myPropagChains = 0; + bool selectBottom = meshedFaces.empty(); - // So we fill projections on vertices at once as they are same for all nodes - myShapeXYZ.resize( myBlock.NbSubShapes() ); - for ( int iV = SMESH_Block::ID_FirstV; iV < SMESH_Block::ID_FirstE; ++iV ) { - myBlock.VertexPoint( iV, myShapeXYZ[ iV ]); - SHOWYXZ("V point " < computedEdges; + getPrecomputedEdges( helper, theShape, computedEdges ); + myPropagChains = new TopTools_IndexedMapOfShape[ computedEdges.size() + 1 ]; + SMESHUtils::ArrayDeleter< TopTools_IndexedMapOfShape > pcDel( myPropagChains ); + for ( size_t i = 0, nb = 0; i < computedEdges.size(); ++i ) + { + StdMeshers_ProjectionUtils::GetPropagationEdge( &theMesh, TopoDS_Edge(), + computedEdges[i], myPropagChains + nb ); + if ( myPropagChains[ nb ].Extent() < 2 ) // an empty map is a termination sign + myPropagChains[ nb ].Clear(); + else + nb++; + } - // Create nodes inside the block + TopTools_MapOfShape meshedSolids; + list< Prism_3D::TPrismTopo > meshedPrism; + list< TopoDS_Face > suspectSourceFaces; + TopTools_ListIteratorOfListOfShape solidIt; - // loop on nodes inside the bottom face - TNode2ColumnMap::iterator bot_column = myBotToColumnMap.begin(); - for ( ; bot_column != myBotToColumnMap.end(); ++bot_column ) - { - const TNode& tBotNode = bot_column->first; // bottom TNode - if ( tBotNode.GetPositionType() != SMDS_TOP_FACE ) - continue; // node is not inside face - - // column nodes; middle part of the column are zero pointers - TNodeColumn& column = bot_column->second; - - // bottom node parameters and coords - myShapeXYZ[ ID_BOT_FACE ] = tBotNode.GetCoords(); - gp_XYZ botParams = tBotNode.GetParams(); - - // compute top node parameters - myShapeXYZ[ ID_TOP_FACE ] = gpXYZ( column.back() ); - gp_XYZ topParams = botParams; - topParams.SetZ( 1 ); - if ( column.size() > 2 ) { - gp_Pnt topCoords = myShapeXYZ[ ID_TOP_FACE ]; - if ( !myBlock.ComputeParameters( topCoords, topParams, ID_TOP_FACE, topParams )) - return error(TCom("Can't compute normalized parameters ") - << "for node " << column.back()->GetID() - << " on the face #"<< column.back()->GetPosition()->GetShapeId() ); - } - - // vertical loop - TNodeColumn::iterator columnNodes = column.begin(); - for ( int z = 0; columnNodes != column.end(); ++columnNodes, ++z) - { - const SMDS_MeshNode* & node = *columnNodes; - if ( node ) continue; // skip bottom or top node - - // params of a node to create - double rz = (double) z / (double) ( column.size() - 1 ); - gp_XYZ params = botParams * ( 1 - rz ) + topParams * rz; - - // set coords on all faces and nodes - const int nbSideFaces = 4; - int sideFaceIDs[nbSideFaces] = { SMESH_Block::ID_Fx0z, - SMESH_Block::ID_Fx1z, - SMESH_Block::ID_F0yz, - SMESH_Block::ID_F1yz }; - for ( int iF = 0; iF < nbSideFaces; ++iF ) - if ( !setFaceAndEdgesXYZ( sideFaceIDs[ iF ], params, z )) - return false; + while ( meshedSolids.Extent() < nbSolids ) + { + if ( _computeCanceled ) + return toSM( error( SMESH_ComputeError::New(COMPERR_CANCELED))); - // compute coords for a new node - gp_XYZ coords; - if ( !SMESH_Block::ShellPoint( params, myShapeXYZ, coords )) - return error("Can't compute coordinates by normalized parameters"); + // compute prisms having avident computed source FACE + while ( !meshedFaces.empty() ) + { + TopoDS_Face face = meshedFaces.front(); + meshedFaces.pop_front(); + TopTools_ListOfShape& solidList = faceToSolids.ChangeFromKey( face ); + while ( !solidList.IsEmpty() ) + { + TopoDS_Shape solid = solidList.First(); + solidList.RemoveFirst(); + if ( meshedSolids.Add( solid )) + { + prism.Clear(); + prism.myBottom = face; + if ( !initPrism( prism, solid, selectBottom ) || + !compute( prism )) + return false; + + SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( prism.myTop ); + if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE )) + { + meshedFaces.push_front( prism.myTop ); + } + else + { + suspectSourceFaces.push_back( prism.myTop ); + } + meshedPrism.push_back( prism ); + } + } + } + if ( meshedSolids.Extent() == nbSolids ) + break; - SHOWYXZ("TOPFacePoint ",myShapeXYZ[ ID_TOP_FACE]); - SHOWYXZ("BOT Node "<< tBotNode.myNode->GetID(),gpXYZ(tBotNode.myNode)); - SHOWYXZ("ShellPoint ",coords); + // below in the loop we try to find source FACEs somehow - // create a node - node = meshDS->AddNode( coords.X(), coords.Y(), coords.Z() ); - meshDS->SetNodeInVolume( node, volumeID ); + // project mesh from source FACEs of computed prisms to + // prisms sharing wall FACEs + list< Prism_3D::TPrismTopo >::iterator prismIt = meshedPrism.begin(); + for ( ; prismIt != meshedPrism.end(); ++prismIt ) + { + for ( size_t iW = 0; iW < prismIt->myWallQuads.size(); ++iW ) + { + Prism_3D::TQuadList::iterator wQuad = prismIt->myWallQuads[iW].begin(); + for ( ; wQuad != prismIt->myWallQuads[iW].end(); ++ wQuad ) + { + const TopoDS_Face& wFace = (*wQuad)->face; + TopTools_ListOfShape& solidList = faceToSolids.ChangeFromKey( wFace ); + solidIt.Initialize( solidList ); + while ( solidIt.More() ) + { + const TopoDS_Shape& solid = solidIt.Value(); + if ( meshedSolids.Contains( solid )) { + solidList.Remove( solidIt ); + continue; // already computed prism + } + if ( myHelper->IsBlock( solid )) { + solidIt.Next(); + continue; // too trivial + } + // find a source FACE of the SOLID: it's a FACE sharing a bottom EDGE with wFace + const TopoDS_Edge& wEdge = (*wQuad)->side[ QUAD_TOP_SIDE ].grid->Edge(0); + PShapeIteratorPtr faceIt = myHelper->GetAncestors( wEdge, *myHelper->GetMesh(), + TopAbs_FACE); + while ( const TopoDS_Shape* f = faceIt->next() ) + { + const TopoDS_Face& candidateF = TopoDS::Face( *f ); + if ( candidateF.IsSame( wFace )) continue; + // select a source FACE: prismIt->myBottom or prismIt->myTop + TopoDS_Face sourceF = prismIt->myBottom; + for ( TopExp_Explorer v( prismIt->myTop, TopAbs_VERTEX ); v.More(); v.Next() ) + if ( myHelper->IsSubShape( v.Current(), candidateF )) { + sourceF = prismIt->myTop; + break; + } + prism.Clear(); + prism.myBottom = candidateF; + mySetErrorToSM = false; + if ( !myHelper->IsSubShape( candidateF, prismIt->myShape3D ) && + myHelper ->IsSubShape( candidateF, solid ) && + !myHelper->GetMesh()->GetSubMesh( candidateF )->IsMeshComputed() && + initPrism( prism, solid, /*selectBottom=*/false ) && + !myHelper->GetMesh()->GetSubMesh( prism.myTop )->IsMeshComputed() && + !myHelper->GetMesh()->GetSubMesh( prism.myBottom )->IsMeshComputed() && + project2dMesh( sourceF, prism.myBottom )) + { + mySetErrorToSM = true; + if ( !compute( prism )) + return false; + SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( prism.myTop ); + if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE )) + { + meshedFaces.push_front( prism.myTop ); + meshedFaces.push_front( prism.myBottom ); + selectBottom = false; + } + meshedPrism.push_back( prism ); + meshedSolids.Add( solid ); + } + InitComputeError(); + } + mySetErrorToSM = true; + InitComputeError(); + if ( meshedSolids.Contains( solid )) + solidList.Remove( solidIt ); + else + solidIt.Next(); + } + } + } + if ( !meshedFaces.empty() ) + break; // to compute prisms with avident sources } - } // loop on bottom nodes + if ( meshedFaces.empty() ) + { + meshedFaces.splice( meshedFaces.end(), suspectSourceFaces ); + selectBottom = true; + } - // Create volumes + // find FACEs with local 1D hyps, which has to be computed by now, + // or at least any computed FACEs + if ( meshedFaces.empty() ) + { + int prevNbFaces = 0; + for ( int iF = 1; iF <= faceToSolids.Extent(); ++iF ) + { + const TopoDS_Face& face = TopoDS::Face( faceToSolids.FindKey( iF )); + const TopTools_ListOfShape& solidList = faceToSolids.FindFromKey( face ); + if ( solidList.IsEmpty() ) continue; + SMESH_subMesh* faceSM = theMesh.GetSubMesh( face ); + if ( !faceSM->IsEmpty() ) + { + int nbFaces = faceSM->GetSubMeshDS()->NbElements(); + if ( prevNbFaces < nbFaces ) + { + if ( !meshedFaces.empty() ) meshedFaces.pop_back(); + meshedFaces.push_back( face ); // lower priority + selectBottom = true; + prevNbFaces = nbFaces; + } + } + else + { + bool allSubMeComputed = true; + SMESH_subMeshIteratorPtr smIt = faceSM->getDependsOnIterator(false,true); + while ( smIt->more() && allSubMeComputed ) + allSubMeComputed = smIt->next()->IsMeshComputed(); + if ( allSubMeComputed ) + { + faceSM->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + if ( !faceSM->IsEmpty() ) { + meshedFaces.push_front( face ); // higher priority + selectBottom = true; + break; + } + else { + faceSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + } + } + } + } - SMESHDS_SubMesh* smDS = myBlock.SubMeshDS( ID_BOT_FACE ); - if ( !smDS ) return error(COMPERR_BAD_INPUT_MESH, "Null submesh"); - // loop on bottom mesh faces - SMDS_ElemIteratorPtr faceIt = smDS->GetElements(); - while ( faceIt->more() ) - { - const SMDS_MeshElement* face = faceIt->next(); - if ( !face || face->GetType() != SMDSAbs_Face ) - continue; - int nbNodes = face->NbNodes(); - if ( face->IsQuadratic() ) - nbNodes /= 2; + // TODO. there are other ways to find out the source FACE: + // propagation, topological similarity, ect. - // find node columns for each node - vector< const TNodeColumn* > columns( nbNodes ); - for ( int i = 0; i < nbNodes; ++i ) + // simply try to mesh all not meshed SOLIDs + if ( meshedFaces.empty() ) { - const SMDS_MeshNode* n = face->GetNode( i ); - if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) { - bot_column = myBotToColumnMap.find( n ); - if ( bot_column == myBotToColumnMap.end() ) - return error(TCom("No nodes found above node ") << n->GetID() ); - columns[ i ] = & bot_column->second; - } - else { - columns[ i ] = myBlock.GetNodeColumn( n ); - if ( !columns[ i ] ) - return error(TCom("No side nodes found above node ") << n->GetID() ); + for ( TopExp_Explorer solid( theShape, TopAbs_SOLID ); solid.More(); solid.Next() ) + { + mySetErrorToSM = false; + prism.Clear(); + if ( !meshedSolids.Contains( solid.Current() ) && + initPrism( prism, solid.Current() )) + { + mySetErrorToSM = true; + if ( !compute( prism )) + return false; + meshedFaces.push_front( prism.myTop ); + meshedFaces.push_front( prism.myBottom ); + meshedPrism.push_back( prism ); + meshedSolids.Add( solid.Current() ); + selectBottom = true; + } + mySetErrorToSM = true; } } - // create prisms - AddPrisms( columns, myHelper ); - } // loop on bottom mesh faces - - return true; + if ( meshedFaces.empty() ) // set same error to 10 not-computed solids + { + SMESH_ComputeErrorPtr err = SMESH_ComputeError::New + ( COMPERR_BAD_INPUT_MESH, "No meshed source face found", this ); + + const int maxNbErrors = 10; // limit nb errors not to overload the Compute dialog + TopExp_Explorer solid( theShape, TopAbs_SOLID ); + for ( int i = 0; ( i < maxNbErrors && solid.More() ); ++i, solid.Next() ) + if ( !meshedSolids.Contains( solid.Current() )) + { + SMESH_subMesh* sm = theMesh.GetSubMesh( solid.Current() ); + sm->GetComputeError() = err; + } + return error( err ); + } + } + return error( COMPERR_OK ); } //================================================================================ /*! - * \brief Create prisms - * \param columns - columns of nodes generated from nodes of a mesh face - * \param helper - helper initialized by mesh and shape to add prisms to + * \brief Find wall faces by bottom edges */ //================================================================================ -void StdMeshers_Prism_3D::AddPrisms( vector & columns, - SMESH_MesherHelper* helper) +bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism, + const int totalNbFaces) { - SMESHDS_Mesh * meshDS = helper->GetMeshDS(); - int shapeID = helper->GetSubShapeID(); + thePrism.myWallQuads.clear(); - int nbNodes = columns.size(); - int nbZ = columns[0]->size(); - if ( nbZ < 2 ) return; + SMESH_Mesh* mesh = myHelper->GetMesh(); - // find out orientation - bool isForward = true; - SMDS_VolumeTool vTool; - int z = 1; - switch ( nbNodes ) { - case 3: { - const SMDS_MeshNode* botNodes[3] = { (*columns[0])[z-1], - (*columns[1])[z-1], - (*columns[2])[z-1] }; - const SMDS_MeshNode* topNodes[3] = { (*columns[0])[z], - (*columns[1])[z], - (*columns[2])[z] }; - SMDS_VolumeOfNodes tmpVol ( botNodes[0], botNodes[1], botNodes[2], - topNodes[0], topNodes[1], topNodes[2]); - vTool.Set( &tmpVol ); - isForward = vTool.IsForward(); - break; - } - case 4: { - const SMDS_MeshNode* botNodes[4] = { (*columns[0])[z-1], (*columns[1])[z-1], - (*columns[2])[z-1], (*columns[3])[z-1] }; - const SMDS_MeshNode* topNodes[4] = { (*columns[0])[z], (*columns[1])[z], - (*columns[2])[z], (*columns[3])[z] }; - SMDS_VolumeOfNodes tmpVol ( botNodes[0], botNodes[1], botNodes[2], botNodes[3], - topNodes[0], topNodes[1], topNodes[2], topNodes[3]); - vTool.Set( &tmpVol ); - isForward = vTool.IsForward(); - break; - } - } + StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this, myHelper ); - // vertical loop on columns - for ( z = 1; z < nbZ; ++z ) - { - SMDS_MeshElement* vol = 0; - switch ( nbNodes ) { + TopTools_MapOfShape faceMap; + TopTools_IndexedDataMapOfShapeListOfShape edgeToFaces; + TopExp::MapShapesAndAncestors( thePrism.myShape3D, + TopAbs_EDGE, TopAbs_FACE, edgeToFaces ); - case 3: { - const SMDS_MeshNode* botNodes[3] = { (*columns[0])[z-1], - (*columns[1])[z-1], - (*columns[2])[z-1] }; - const SMDS_MeshNode* topNodes[3] = { (*columns[0])[z], - (*columns[1])[z], - (*columns[2])[z] }; - if ( isForward ) - vol = helper->AddVolume( botNodes[0], botNodes[1], botNodes[2], - topNodes[0], topNodes[1], topNodes[2]); - else - vol = helper->AddVolume( topNodes[0], topNodes[1], topNodes[2], - botNodes[0], botNodes[1], botNodes[2]); - break; - } - case 4: { - const SMDS_MeshNode* botNodes[4] = { (*columns[0])[z-1], (*columns[1])[z-1], - (*columns[2])[z-1], (*columns[3])[z-1] }; - const SMDS_MeshNode* topNodes[4] = { (*columns[0])[z], (*columns[1])[z], - (*columns[2])[z], (*columns[3])[z] }; - if ( isForward ) - vol = helper->AddVolume( botNodes[0], botNodes[1], botNodes[2], botNodes[3], - topNodes[0], topNodes[1], topNodes[2], topNodes[3]); - else - vol = helper->AddVolume( topNodes[0], topNodes[1], topNodes[2], topNodes[3], - botNodes[0], botNodes[1], botNodes[2], botNodes[3]); - break; - } - default: - // polyhedron - vector nodes( 2*nbNodes + 4*nbNodes); - vector quantities( 2 + nbNodes, 4 ); - quantities[0] = quantities[1] = nbNodes; - columns.resize( nbNodes + 1 ); - columns[ nbNodes ] = columns[ 0 ]; - for ( int i = 0; i < nbNodes; ++i ) { - nodes[ i ] = (*columns[ i ])[z-1]; // bottom - nodes[ i+nbNodes ] = (*columns[ i ])[z ]; // top - // side - int di = 2*nbNodes + 4*i - 1; - nodes[ di ] = (*columns[i ])[z-1]; - nodes[ di+1 ] = (*columns[i+1])[z-1]; - nodes[ di+2 ] = (*columns[i+1])[z ]; - nodes[ di+3 ] = (*columns[i ])[z ]; - } - vol = meshDS->AddPolyhedralVolume( nodes, quantities ); + // ------------------------------ + // Get the 1st row of wall FACEs + // ------------------------------ + + list< TopoDS_Edge >::iterator edge = thePrism.myBottomEdges.begin(); + std::list< int >::iterator nbE = thePrism.myNbEdgesInWires.begin(); + int iE = 0; + double f,l; + while ( edge != thePrism.myBottomEdges.end() ) + { + ++iE; + if ( BRep_Tool::Curve( *edge, f,l ).IsNull() ) + { + edge = thePrism.myBottomEdges.erase( edge ); + --iE; + --(*nbE); + } + else + { + TopTools_ListIteratorOfListOfShape faceIt( edgeToFaces.FindFromKey( *edge )); + for ( ; faceIt.More(); faceIt.Next() ) + { + const TopoDS_Face& face = TopoDS::Face( faceIt.Value() ); + if ( !thePrism.myBottom.IsSame( face )) + { + Prism_3D::TQuadList quadList( 1, quadAlgo->CheckNbEdges( *mesh, face )); + if ( !quadList.back() ) + return toSM( error(TCom("Side face #") << shapeID( face ) + << " not meshable with quadrangles")); + bool isCompositeBase = ! setBottomEdge( *edge, quadList.back(), face ); + if ( isCompositeBase ) + { + // it's OK if all EDGEs of the bottom side belongs to the bottom FACE + StdMeshers_FaceSidePtr botSide = quadList.back()->side[ QUAD_BOTTOM_SIDE ]; + for ( int iE = 0; iE < botSide->NbEdges(); ++iE ) + if ( !myHelper->IsSubShape( botSide->Edge(iE), thePrism.myBottom )) + return toSM( error(TCom("Composite 'horizontal' edges are not supported"))); + } + if ( faceMap.Add( face )) + thePrism.myWallQuads.push_back( quadList ); + break; + } + } + ++edge; + } + if ( iE == *nbE ) + { + iE = 0; + ++nbE; + } + } + + // ------------------------- + // Find the rest wall FACEs + // ------------------------- + + // Compose a vector of indixes of right neighbour FACE for each wall FACE + // that is not so evident in case of several WIREs in the bottom FACE + thePrism.myRightQuadIndex.clear(); + for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i ) + thePrism.myRightQuadIndex.push_back( i+1 ); + list< int >::iterator nbEinW = thePrism.myNbEdgesInWires.begin(); + for ( int iLeft = 0; nbEinW != thePrism.myNbEdgesInWires.end(); ++nbEinW ) + { + thePrism.myRightQuadIndex[ iLeft + *nbEinW - 1 ] = iLeft; // 1st EDGE index of a current WIRE + iLeft += *nbEinW; + } + + while ( totalNbFaces - faceMap.Extent() > 2 ) + { + // find wall FACEs adjacent to each of wallQuads by the right side EDGE + int nbKnownFaces; + do { + nbKnownFaces = faceMap.Extent(); + StdMeshers_FaceSidePtr rightSide, topSide; // sides of the quad + for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i ) + { + rightSide = thePrism.myWallQuads[i].back()->side[ QUAD_RIGHT_SIDE ]; + for ( int iE = 0; iE < rightSide->NbEdges(); ++iE ) // rightSide can be composite + { + const TopoDS_Edge & rightE = rightSide->Edge( iE ); + TopTools_ListIteratorOfListOfShape face( edgeToFaces.FindFromKey( rightE )); + for ( ; face.More(); face.Next() ) + if ( faceMap.Add( face.Value() )) + { + // a new wall FACE encountered, store it in thePrism.myWallQuads + const int iRight = thePrism.myRightQuadIndex[i]; + topSide = thePrism.myWallQuads[ iRight ].back()->side[ QUAD_TOP_SIDE ]; + const TopoDS_Edge& newBotE = topSide->Edge(0); + const TopoDS_Shape& newWallF = face.Value(); + thePrism.myWallQuads[ iRight ].push_back( quadAlgo->CheckNbEdges( *mesh, newWallF )); + if ( !thePrism.myWallQuads[ iRight ].back() ) + return toSM( error(TCom("Side face #") << shapeID( newWallF ) << + " not meshable with quadrangles")); + if ( ! setBottomEdge( newBotE, thePrism.myWallQuads[ iRight ].back(), newWallF )) + return toSM( error(TCom("Composite 'horizontal' edges are not supported"))); + } + } + } + } while ( nbKnownFaces != faceMap.Extent() ); + + // find wall FACEs adjacent to each of thePrism.myWallQuads by the top side EDGE + if ( totalNbFaces - faceMap.Extent() > 2 ) + { + const int nbFoundWalls = faceMap.Extent(); + for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i ) + { + StdMeshers_FaceSidePtr topSide = thePrism.myWallQuads[i].back()->side[ QUAD_TOP_SIDE ]; + const TopoDS_Edge & topE = topSide->Edge( 0 ); + if ( topSide->NbEdges() > 1 ) + return toSM( error(COMPERR_BAD_SHAPE, TCom("Side face #") << + shapeID( thePrism.myWallQuads[i].back()->face ) + << " has a composite top edge")); + TopTools_ListIteratorOfListOfShape faceIt( edgeToFaces.FindFromKey( topE )); + for ( ; faceIt.More(); faceIt.Next() ) + if ( faceMap.Add( faceIt.Value() )) + { + // a new wall FACE encountered, store it in wallQuads + thePrism.myWallQuads[ i ].push_back( quadAlgo->CheckNbEdges( *mesh, faceIt.Value() )); + if ( !thePrism.myWallQuads[ i ].back() ) + return toSM( error(TCom("Side face #") << shapeID( faceIt.Value() ) << + " not meshable with quadrangles")); + if ( ! setBottomEdge( topE, thePrism.myWallQuads[ i ].back(), faceIt.Value() )) + return toSM( error(TCom("Composite 'horizontal' edges are not supported"))); + if ( totalNbFaces - faceMap.Extent() == 2 ) + { + i = thePrism.myWallQuads.size(); // to quit from the outer loop + break; + } + } + } + if ( nbFoundWalls == faceMap.Extent() ) + return toSM( error("Failed to find wall faces")); + + } + } // while ( totalNbFaces - faceMap.Extent() > 2 ) + + // ------------------ + // Find the top FACE + // ------------------ + + if ( thePrism.myTop.IsNull() ) + { + // now only top and bottom FACEs are not in the faceMap + faceMap.Add( thePrism.myBottom ); + for ( TopExp_Explorer f( thePrism.myShape3D, TopAbs_FACE );f.More(); f.Next() ) + if ( !faceMap.Contains( f.Current() )) { + thePrism.myTop = TopoDS::Face( f.Current() ); + break; + } + if ( thePrism.myTop.IsNull() ) + return toSM( error("Top face not found")); + } + + // Check that the top FACE shares all the top EDGEs + for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i ) + { + StdMeshers_FaceSidePtr topSide = thePrism.myWallQuads[i].back()->side[ QUAD_TOP_SIDE ]; + const TopoDS_Edge & topE = topSide->Edge( 0 ); + if ( !myHelper->IsSubShape( topE, thePrism.myTop )) + return toSM( error( TCom("Wrong source face: #") << shapeID( thePrism.myBottom ))); + } + + return true; +} + +//======================================================================= +//function : compute +//purpose : Compute mesh on a SOLID +//======================================================================= + +bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) +{ + myHelper->IsQuadraticSubMesh( thePrism.myShape3D ); + if ( _computeCanceled ) + return toSM( error( SMESH_ComputeError::New(COMPERR_CANCELED))); + + // Assure the bottom is meshed + SMESH_subMesh * botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); + if (( botSM->IsEmpty() ) && + ( ! botSM->GetAlgo() || + ! _gen->Compute( *botSM->GetFather(), botSM->GetSubShape(), /*shapeOnly=*/true ))) + return error( COMPERR_BAD_INPUT_MESH, + TCom( "No mesher defined to compute the face #") + << shapeID( thePrism.myBottom )); + + // Make all side FACEs of thePrism meshed with quads + if ( !computeWalls( thePrism )) + return false; + + // Analyse mesh and geometry to find all block sub-shapes and submeshes + // (after fixing IPAL52499 myBlock is used as a holder of boundary nodes + // and for 2D projection in hard cases where StdMeshers_Projection_2D fails; + // location of internal nodes is usually computed by StdMeshers_Sweeper) + if ( !myBlock.Init( myHelper, thePrism )) + return toSM( error( myBlock.GetError())); + + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + + int volumeID = meshDS->ShapeToIndex( thePrism.myShape3D ); + + // Try to get gp_Trsf to get all nodes from bottom ones + vector trsf; + gp_Trsf bottomToTopTrsf; + // if ( !myBlock.GetLayersTransformation( trsf, thePrism )) + // trsf.clear(); + // else if ( !trsf.empty() ) + // bottomToTopTrsf = trsf.back(); + + // To compute coordinates of a node inside a block, it is necessary to know + // 1. normalized parameters of the node by which + // 2. coordinates of node projections on all block sub-shapes are computed + + // So we fill projections on vertices at once as they are same for all nodes + myShapeXYZ.resize( myBlock.NbSubShapes() ); + for ( int iV = SMESH_Block::ID_FirstV; iV < SMESH_Block::ID_FirstE; ++iV ) { + myBlock.VertexPoint( iV, myShapeXYZ[ iV ]); + SHOWYXZ("V point " <::const_iterator edge = thePrism.myBottomEdges.begin(); + for ( ; edge != thePrism.myBottomEdges.end(); ++edge ) + { + int edgeID = meshDS->ShapeToIndex( *edge ); + TParam2ColumnMap* u2col = const_cast + ( myBlock.GetParam2ColumnMap( edgeID, dummy )); + TParam2ColumnMap::iterator u2colIt = u2col->begin(); + for ( ; u2colIt != u2col->end(); ++u2colIt ) + sweeper.myBndColumns.push_back( & u2colIt->second ); + } + // load node columns inside the bottom face + TNode2ColumnMap::iterator bot_column = myBotToColumnMap.begin(); + for ( ; bot_column != myBotToColumnMap.end(); ++bot_column ) + sweeper.myIntColumns.push_back( & bot_column->second ); + + tol = getSweepTolerance( thePrism ); + allowHighBndError = !isSimpleBottom( thePrism ); + } + + if ( !myUseBlock && sweeper.ComputeNodes( *myHelper, tol, allowHighBndError )) + { + } + else // use block approach + { + // loop on nodes inside the bottom face + Prism_3D::TNode prevBNode; + TNode2ColumnMap::iterator bot_column = myBotToColumnMap.begin(); + for ( ; bot_column != myBotToColumnMap.end(); ++bot_column ) + { + const Prism_3D::TNode& tBotNode = bot_column->first; // bottom TNode + if ( tBotNode.GetPositionType() != SMDS_TOP_FACE ) + continue; // node is not inside the FACE + + // column nodes; middle part of the column are zero pointers + TNodeColumn& column = bot_column->second; + + gp_XYZ botParams, topParams; + if ( !tBotNode.HasParams() ) + { + // compute bottom node parameters + gp_XYZ paramHint(-1,-1,-1); + if ( prevBNode.IsNeighbor( tBotNode )) + paramHint = prevBNode.GetParams(); + if ( !myBlock.ComputeParameters( tBotNode.GetCoords(), tBotNode.ChangeParams(), + ID_BOT_FACE, paramHint )) + return toSM( error(TCom("Can't compute normalized parameters for node ") + << tBotNode.myNode->GetID() << " on the face #" + << myBlock.SubMesh( ID_BOT_FACE )->GetId() )); + prevBNode = tBotNode; + + botParams = topParams = tBotNode.GetParams(); + topParams.SetZ( 1 ); + + // compute top node parameters + if ( column.size() > 2 ) { + gp_Pnt topCoords = gpXYZ( column.back() ); + if ( !myBlock.ComputeParameters( topCoords, topParams, ID_TOP_FACE, topParams )) + return toSM( error(TCom("Can't compute normalized parameters ") + << "for node " << column.back()->GetID() + << " on the face #"<< column.back()->getshapeId() )); + } + } + else // top nodes are created by projection using parameters + { + botParams = topParams = tBotNode.GetParams(); + topParams.SetZ( 1 ); + } + + myShapeXYZ[ ID_BOT_FACE ] = tBotNode.GetCoords(); + myShapeXYZ[ ID_TOP_FACE ] = gpXYZ( column.back() ); + + // vertical loop + TNodeColumn::iterator columnNodes = column.begin(); + for ( int z = 0; columnNodes != column.end(); ++columnNodes, ++z) + { + const SMDS_MeshNode* & node = *columnNodes; + if ( node ) continue; // skip bottom or top node + + // params of a node to create + double rz = (double) z / (double) ( column.size() - 1 ); + gp_XYZ params = botParams * ( 1 - rz ) + topParams * rz; + + // set coords on all faces and nodes + const int nbSideFaces = 4; + int sideFaceIDs[nbSideFaces] = { SMESH_Block::ID_Fx0z, + SMESH_Block::ID_Fx1z, + SMESH_Block::ID_F0yz, + SMESH_Block::ID_F1yz }; + for ( int iF = 0; iF < nbSideFaces; ++iF ) + if ( !setFaceAndEdgesXYZ( sideFaceIDs[ iF ], params, z )) + return false; + + // compute coords for a new node + gp_XYZ coords; + if ( !SMESH_Block::ShellPoint( params, myShapeXYZ, coords )) + return toSM( error("Can't compute coordinates by normalized parameters")); + + // if ( !meshDS->MeshElements( volumeID ) || + // meshDS->MeshElements( volumeID )->NbNodes() == 0 ) + // pointsToPython(myShapeXYZ); + SHOWYXZ("TOPFacePoint ",myShapeXYZ[ ID_TOP_FACE]); + SHOWYXZ("BOT Node "<< tBotNode.myNode->GetID(),gpXYZ(tBotNode.myNode)); + SHOWYXZ("ShellPoint ",coords); + + // create a node + node = meshDS->AddNode( coords.X(), coords.Y(), coords.Z() ); + meshDS->SetNodeInVolume( node, volumeID ); + + if ( _computeCanceled ) + return false; + } + } // loop on bottom nodes + } + + // Create volumes + + SMESHDS_SubMesh* smDS = myBlock.SubMeshDS( ID_BOT_FACE ); + if ( !smDS ) return toSM( error(COMPERR_BAD_INPUT_MESH, "Null submesh")); + + // loop on bottom mesh faces + SMDS_ElemIteratorPtr faceIt = smDS->GetElements(); + while ( faceIt->more() ) + { + const SMDS_MeshElement* face = faceIt->next(); + if ( !face || face->GetType() != SMDSAbs_Face ) + continue; + + // find node columns for each node + int nbNodes = face->NbCornerNodes(); + vector< const TNodeColumn* > columns( nbNodes ); + for ( int i = 0; i < nbNodes; ++i ) + { + const SMDS_MeshNode* n = face->GetNode( i ); + if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) { + TNode2ColumnMap::iterator bot_column = myBotToColumnMap.find( n ); + if ( bot_column == myBotToColumnMap.end() ) + return toSM( error(TCom("No nodes found above node ") << n->GetID() )); + columns[ i ] = & bot_column->second; + } + else { + columns[ i ] = myBlock.GetNodeColumn( n ); + if ( !columns[ i ] ) + return toSM( error(TCom("No side nodes found above node ") << n->GetID() )); + } + } + // create prisms + AddPrisms( columns, myHelper ); + + } // loop on bottom mesh faces + + // clear data + myBotToColumnMap.clear(); + myBlock.Clear(); + + // update state of sub-meshes (mostly in order to erase improper errors) + SMESH_subMesh* sm = myHelper->GetMesh()->GetSubMesh( thePrism.myShape3D ); + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/false); + while ( smIt->more() ) + { + sm = smIt->next(); + sm->GetComputeError().reset(); + sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + + return true; +} + +//======================================================================= +//function : computeWalls +//purpose : Compute 2D mesh on walls FACEs of a prism +//======================================================================= + +bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism) +{ + SMESH_Mesh* mesh = myHelper->GetMesh(); + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + DBGOUT( endl << "COMPUTE Prism " << meshDS->ShapeToIndex( thePrism.myShape3D )); + + TProjction1dAlgo* projector1D = TProjction1dAlgo::instance( this ); + StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this, myHelper ); + + // SMESH_HypoFilter hyp1dFilter( SMESH_HypoFilter::IsAlgo(),/*not=*/true); + // hyp1dFilter.And( SMESH_HypoFilter::HasDim( 1 )); + // hyp1dFilter.And( SMESH_HypoFilter::IsMoreLocalThan( thePrism.myShape3D, *mesh )); + + // Discretize equally 'vertical' EDGEs + // ----------------------------------- + // find source FACE sides for projection: either already computed ones or + // the 'most composite' ones + const size_t nbWalls = thePrism.myWallQuads.size(); + vector< int > wgt( nbWalls, 0 ); // "weight" of a wall + for ( size_t iW = 0; iW != nbWalls; ++iW ) + { + Prism_3D::TQuadList::const_iterator quad = thePrism.myWallQuads[iW].begin(); + for ( ; quad != thePrism.myWallQuads[iW].end(); ++quad ) + { + StdMeshers_FaceSidePtr lftSide = (*quad)->side[ QUAD_LEFT_SIDE ]; + for ( int i = 0; i < lftSide->NbEdges(); ++i ) + { + ++wgt[ iW ]; + const TopoDS_Edge& E = lftSide->Edge(i); + if ( mesh->GetSubMesh( E )->IsMeshComputed() ) + { + wgt[ iW ] += 100; + wgt[ myHelper->WrapIndex( iW+1, nbWalls)] += 10; + wgt[ myHelper->WrapIndex( iW-1, nbWalls)] += 10; + } + // else if ( mesh->GetHypothesis( E, hyp1dFilter, true )) // local hypothesis! + // wgt += 100; + } + } + // in quadratic mesh, pass ignoreMediumNodes to quad sides + if ( myHelper->GetIsQuadratic() ) + { + quad = thePrism.myWallQuads[iW].begin(); + for ( ; quad != thePrism.myWallQuads[iW].end(); ++quad ) + for ( int i = 0; i < NB_QUAD_SIDES; ++i ) + (*quad)->side[ i ].grid->SetIgnoreMediumNodes( true ); + } + } + multimap< int, int > wgt2quad; + for ( size_t iW = 0; iW != nbWalls; ++iW ) + wgt2quad.insert( make_pair( wgt[ iW ], iW )); + + // Project 'vertical' EDGEs, from left to right + multimap< int, int >::reverse_iterator w2q = wgt2quad.rbegin(); + for ( ; w2q != wgt2quad.rend(); ++w2q ) + { + const int iW = w2q->second; + const Prism_3D::TQuadList& quads = thePrism.myWallQuads[ iW ]; + Prism_3D::TQuadList::const_iterator quad = quads.begin(); + for ( ; quad != quads.end(); ++quad ) + { + StdMeshers_FaceSidePtr rgtSide = (*quad)->side[ QUAD_RIGHT_SIDE ]; // tgt + StdMeshers_FaceSidePtr lftSide = (*quad)->side[ QUAD_LEFT_SIDE ]; // src + bool swapLeftRight = ( lftSide->NbSegments( /*update=*/true ) == 0 && + rgtSide->NbSegments( /*update=*/true ) > 0 ); + if ( swapLeftRight ) + std::swap( lftSide, rgtSide ); + + // assure that all the source (left) EDGEs are meshed + int nbSrcSegments = 0; + for ( int i = 0; i < lftSide->NbEdges(); ++i ) + { + const TopoDS_Edge& srcE = lftSide->Edge(i); + SMESH_subMesh* srcSM = mesh->GetSubMesh( srcE ); + if ( !srcSM->IsMeshComputed() ) { + DBGOUT( "COMPUTE V edge " << srcSM->GetId() ); + TopoDS_Edge prpgSrcE = findPropagationSource( srcE ); + if ( !prpgSrcE.IsNull() ) { + srcSM->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE ); + projector1D->myHyp.SetSourceEdge( prpgSrcE ); + projector1D->Compute( *mesh, srcE ); + srcSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + else { + srcSM->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE ); + srcSM->ComputeStateEngine ( SMESH_subMesh::COMPUTE ); + } + if ( !srcSM->IsMeshComputed() ) + return toSM( error( "Can't compute 1D mesh" )); + } + nbSrcSegments += srcSM->GetSubMeshDS()->NbElements(); + } + // check target EDGEs + int nbTgtMeshed = 0, nbTgtSegments = 0; + vector< bool > isTgtEdgeComputed( rgtSide->NbEdges() ); + for ( int i = 0; i < rgtSide->NbEdges(); ++i ) + { + const TopoDS_Edge& tgtE = rgtSide->Edge(i); + SMESH_subMesh* tgtSM = mesh->GetSubMesh( tgtE ); + if ( !( isTgtEdgeComputed[ i ] = tgtSM->IsMeshComputed() )) { + tgtSM->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE ); + tgtSM->ComputeStateEngine ( SMESH_subMesh::COMPUTE ); + } + if ( tgtSM->IsMeshComputed() ) { + ++nbTgtMeshed; + nbTgtSegments += tgtSM->GetSubMeshDS()->NbElements(); + } + } + if ( rgtSide->NbEdges() == nbTgtMeshed ) // all tgt EDGEs meshed + { + if ( nbTgtSegments != nbSrcSegments ) + { + bool badMeshRemoved = false; + // remove just computed segments + for ( int i = 0; i < rgtSide->NbEdges(); ++i ) + if ( !isTgtEdgeComputed[ i ]) + { + const TopoDS_Edge& tgtE = rgtSide->Edge(i); + SMESH_subMesh* tgtSM = mesh->GetSubMesh( tgtE ); + tgtSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); + badMeshRemoved = true; + nbTgtMeshed--; + } + if ( !badMeshRemoved ) + { + for ( int i = 0; i < lftSide->NbEdges(); ++i ) + addBadInputElements( meshDS->MeshElements( lftSide->Edge( i ))); + for ( int i = 0; i < rgtSide->NbEdges(); ++i ) + addBadInputElements( meshDS->MeshElements( rgtSide->Edge( i ))); + return toSM( error( TCom("Different nb of segment on logically vertical edges #") + << shapeID( lftSide->Edge(0) ) << " and #" + << shapeID( rgtSide->Edge(0) ) << ": " + << nbSrcSegments << " != " << nbTgtSegments )); + } + } + else // if ( nbTgtSegments == nbSrcSegments ) + { + continue; + } + } + // Compute 'vertical projection' + if ( nbTgtMeshed == 0 ) + { + // compute nodes on target VERTEXes + const UVPtStructVec& srcNodeStr = lftSide->GetUVPtStruct(); + if ( srcNodeStr.size() == 0 ) + return toSM( error( TCom("Invalid node positions on edge #") << + shapeID( lftSide->Edge(0) ))); + vector< SMDS_MeshNode* > newNodes( srcNodeStr.size() ); + for ( int is2ndV = 0; is2ndV < 2; ++is2ndV ) + { + const TopoDS_Edge& E = rgtSide->Edge( is2ndV ? rgtSide->NbEdges()-1 : 0 ); + TopoDS_Vertex v = myHelper->IthVertex( is2ndV, E ); + mesh->GetSubMesh( v )->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, meshDS ); + newNodes[ is2ndV ? 0 : newNodes.size()-1 ] = (SMDS_MeshNode*) n; + } + + // compute nodes on target EDGEs + DBGOUT( "COMPUTE V edge (proj) " << shapeID( lftSide->Edge(0))); + rgtSide->Reverse(); // direct it same as the lftSide + myHelper->SetElementsOnShape( false ); // myHelper holds the prism shape + TopoDS_Edge tgtEdge; + for ( size_t iN = 1; iN < srcNodeStr.size()-1; ++iN ) // add nodes + { + gp_Pnt p = rgtSide->Value3d ( srcNodeStr[ iN ].normParam ); + double u = rgtSide->Parameter( srcNodeStr[ iN ].normParam, tgtEdge ); + newNodes[ iN ] = meshDS->AddNode( p.X(), p.Y(), p.Z() ); + meshDS->SetNodeOnEdge( newNodes[ iN ], tgtEdge, u ); + } + for ( size_t iN = 1; iN < srcNodeStr.size(); ++iN ) // add segments + { + // find an EDGE to set a new segment + std::pair id2type = + myHelper->GetMediumPos( newNodes[ iN-1 ], newNodes[ iN ] ); + if ( id2type.second != TopAbs_EDGE ) + { + // new nodes are on different EDGEs; put one of them on VERTEX + const int edgeIndex = rgtSide->EdgeIndex( srcNodeStr[ iN-1 ].normParam ); + const double vertexParam = rgtSide->LastParameter( edgeIndex ); + TopoDS_Vertex vertex = rgtSide->LastVertex( edgeIndex ); + const SMDS_MeshNode* vn = SMESH_Algo::VertexNode( vertex, meshDS ); + const gp_Pnt p = BRep_Tool::Pnt( vertex ); + const int isPrev = ( Abs( srcNodeStr[ iN-1 ].normParam - vertexParam ) < + Abs( srcNodeStr[ iN ].normParam - vertexParam )); + meshDS->UnSetNodeOnShape( newNodes[ iN-isPrev ] ); + meshDS->SetNodeOnVertex ( newNodes[ iN-isPrev ], vertex ); + meshDS->MoveNode ( newNodes[ iN-isPrev ], p.X(), p.Y(), p.Z() ); + id2type.first = newNodes[ iN-(1-isPrev) ]->getshapeId(); + if ( vn ) + { + SMESH_MeshEditor::TListOfListOfNodes lln( 1, list< const SMDS_MeshNode* >() ); + lln.back().push_back ( vn ); + lln.back().push_front( newNodes[ iN-isPrev ] ); // to keep + SMESH_MeshEditor( mesh ).MergeNodes( lln ); + } + } + SMDS_MeshElement* newEdge = myHelper->AddEdge( newNodes[ iN-1 ], newNodes[ iN ] ); + meshDS->SetMeshElementOnShape( newEdge, id2type.first ); + } + myHelper->SetElementsOnShape( true ); + for ( int i = 0; i < rgtSide->NbEdges(); ++i ) // update state of sub-meshes + { + const TopoDS_Edge& E = rgtSide->Edge( i ); + SMESH_subMesh* tgtSM = mesh->GetSubMesh( E ); + tgtSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + + // to continue projection from the just computed side as a source + if ( !swapLeftRight && rgtSide->NbEdges() > 1 && w2q->second == iW ) + { + std::pair wgt2quadKeyVal( w2q->first + 1, thePrism.myRightQuadIndex[ iW ]); + wgt2quad.insert( wgt2quadKeyVal ); // it will be skipped by ++w2q + wgt2quad.insert( wgt2quadKeyVal ); + w2q = wgt2quad.rbegin(); + } + } + else + { + // HOPE assigned hypotheses are OK, so that equal nb of segments will be generated + //return toSM( error("Partial projection not implemented")); + } + } // loop on quads of a composite wall side + } // loop on the ordered wall sides + + + + for ( size_t iW = 0; iW != thePrism.myWallQuads.size(); ++iW ) + { + Prism_3D::TQuadList::const_iterator quad = thePrism.myWallQuads[iW].begin(); + for ( ; quad != thePrism.myWallQuads[iW].end(); ++quad ) + { + const TopoDS_Face& face = (*quad)->face; + SMESH_subMesh* fSM = mesh->GetSubMesh( face ); + if ( ! fSM->IsMeshComputed() ) + { + // Top EDGEs must be projections from the bottom ones + // to compute stuctured quad mesh on wall FACEs + // --------------------------------------------------- + const TopoDS_Edge& botE = (*quad)->side[ QUAD_BOTTOM_SIDE ].grid->Edge(0); + const TopoDS_Edge& topE = (*quad)->side[ QUAD_TOP_SIDE ].grid->Edge(0); + SMESH_subMesh* botSM = mesh->GetSubMesh( botE ); + SMESH_subMesh* topSM = mesh->GetSubMesh( topE ); + SMESH_subMesh* srcSM = botSM; + SMESH_subMesh* tgtSM = topSM; + srcSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + tgtSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + if ( !srcSM->IsMeshComputed() && tgtSM->IsMeshComputed() ) + std::swap( srcSM, tgtSM ); + + if ( !srcSM->IsMeshComputed() ) + { + DBGOUT( "COMPUTE H edge " << srcSM->GetId()); + srcSM->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE ); // nodes on VERTEXes + srcSM->ComputeStateEngine( SMESH_subMesh::COMPUTE ); // segments on the EDGE + } + + if ( tgtSM->IsMeshComputed() && + tgtSM->GetSubMeshDS()->NbNodes() != srcSM->GetSubMeshDS()->NbNodes() ) + { + // the top EDGE is computed differently than the bottom one, + // try to clear a wrong mesh + bool isAdjFaceMeshed = false; + PShapeIteratorPtr fIt = myHelper->GetAncestors( tgtSM->GetSubShape(), + *mesh, TopAbs_FACE ); + while ( const TopoDS_Shape* f = fIt->next() ) + if (( isAdjFaceMeshed = mesh->GetSubMesh( *f )->IsMeshComputed() )) + break; + if ( isAdjFaceMeshed ) + return toSM( error( TCom("Different nb of segment on logically horizontal edges #") + << shapeID( botE ) << " and #" + << shapeID( topE ) << ": " + << tgtSM->GetSubMeshDS()->NbElements() << " != " + << srcSM->GetSubMeshDS()->NbElements() )); + tgtSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); + } + if ( !tgtSM->IsMeshComputed() ) + { + // compute nodes on VERTEXes + SMESH_subMeshIteratorPtr smIt = tgtSM->getDependsOnIterator(/*includeSelf=*/false); + while ( smIt->more() ) + smIt->next()->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + // project segments + DBGOUT( "COMPUTE H edge (proj) " << tgtSM->GetId()); + projector1D->myHyp.SetSourceEdge( TopoDS::Edge( srcSM->GetSubShape() )); + projector1D->InitComputeError(); + bool ok = projector1D->Compute( *mesh, tgtSM->GetSubShape() ); + if ( !ok ) + { + SMESH_ComputeErrorPtr err = projector1D->GetComputeError(); + if ( err->IsOK() ) err->myName = COMPERR_ALGO_FAILED; + tgtSM->GetComputeError() = err; + return false; + } + } + tgtSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + + + // Compute quad mesh on wall FACEs + // ------------------------------- + + // make all EDGES meshed + fSM->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE ); + if ( !fSM->SubMeshesComputed() ) + return toSM( error( COMPERR_BAD_INPUT_MESH, + "Not all edges have valid algorithm and hypothesis")); + // mesh the + quadAlgo->InitComputeError(); + DBGOUT( "COMPUTE Quad face " << fSM->GetId()); + bool ok = quadAlgo->Compute( *mesh, face ); + fSM->GetComputeError() = quadAlgo->GetComputeError(); + if ( !ok ) + return false; + fSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + if ( myHelper->GetIsQuadratic() ) + { + // fill myHelper with medium nodes built by quadAlgo + SMDS_ElemIteratorPtr fIt = fSM->GetSubMeshDS()->GetElements(); + while ( fIt->more() ) + myHelper->AddTLinks( dynamic_cast( fIt->next() )); + } + } + } + + return true; +} + +//======================================================================= +/*! + * \brief Returns a source EDGE of propagation to a given EDGE + */ +//======================================================================= + +TopoDS_Edge StdMeshers_Prism_3D::findPropagationSource( const TopoDS_Edge& E ) +{ + if ( myPropagChains ) + for ( size_t i = 0; !myPropagChains[i].IsEmpty(); ++i ) + if ( myPropagChains[i].Contains( E )) + return TopoDS::Edge( myPropagChains[i].FindKey( 1 )); + + return TopoDS_Edge(); +} + +//======================================================================= +//function : Evaluate +//purpose : +//======================================================================= + +bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + MapShapeNbElems& aResMap) +{ + if ( theShape.ShapeType() == TopAbs_COMPOUND ) + { + bool ok = true; + for ( TopoDS_Iterator it( theShape ); it.More(); it.Next() ) + ok &= Evaluate( theMesh, it.Value(), aResMap ); + return ok; + } + SMESH_MesherHelper helper( theMesh ); + myHelper = &helper; + myHelper->SetSubShape( theShape ); + + // find face contains only triangles + vector < SMESH_subMesh * >meshFaces; + TopTools_SequenceOfShape aFaces; + int NumBase = 0, i = 0, NbQFs = 0; + for (TopExp_Explorer exp(theShape, TopAbs_FACE); exp.More(); exp.Next()) { + i++; + aFaces.Append(exp.Current()); + SMESH_subMesh *aSubMesh = theMesh.GetSubMesh(exp.Current()); + meshFaces.push_back(aSubMesh); + MapShapeNbElemsItr anIt = aResMap.find(meshFaces[i-1]); + if( anIt==aResMap.end() ) + return toSM( error( "Submesh can not be evaluated")); + + std::vector aVec = (*anIt).second; + int nbtri = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]); + int nbqua = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); + if( nbtri==0 && nbqua>0 ) { + NbQFs++; + } + if( nbtri>0 ) { + NumBase = i; + } + } + + if(NbQFs<4) { + std::vector aResVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; i set 1 faces as base + + // find number of 1d elems for base face + int nb1d = 0; + TopTools_MapOfShape Edges1; + for (TopExp_Explorer exp(aFaces.Value(NumBase), TopAbs_EDGE); exp.More(); exp.Next()) { + Edges1.Add(exp.Current()); + SMESH_subMesh *sm = theMesh.GetSubMesh(exp.Current()); + if( sm ) { + MapShapeNbElemsItr anIt = aResMap.find(sm); + if( anIt == aResMap.end() ) continue; + std::vector aVec = (*anIt).second; + nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]); + } + } + // find face opposite to base face + int OppNum = 0; + for(i=1; i<=6; i++) { + if(i==NumBase) continue; + bool IsOpposite = true; + for(TopExp_Explorer exp(aFaces.Value(i), TopAbs_EDGE); exp.More(); exp.Next()) { + if( Edges1.Contains(exp.Current()) ) { + IsOpposite = false; + break; + } } - if ( vol && shapeID > 0 ) - meshDS->SetMeshElementOnShape( vol, shapeID ); + if(IsOpposite) { + OppNum = i; + break; + } + } + // find number of 2d elems on side faces + int nb2d = 0; + for(i=1; i<=6; i++) { + if( i==OppNum || i==NumBase ) continue; + MapShapeNbElemsItr anIt = aResMap.find( meshFaces[i-1] ); + if( anIt == aResMap.end() ) continue; + std::vector aVec = (*anIt).second; + nb2d += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); + } + + MapShapeNbElemsItr anIt = aResMap.find( meshFaces[NumBase-1] ); + std::vector aVec = (*anIt).second; + bool IsQuadratic = (aVec[SMDSEntity_Quad_Triangle]>aVec[SMDSEntity_Triangle]) || + (aVec[SMDSEntity_Quad_Quadrangle]>aVec[SMDSEntity_Quadrangle]); + int nb2d_face0_3 = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]); + int nb2d_face0_4 = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); + int nb0d_face0 = aVec[SMDSEntity_Node]; + int nb1d_face0_int = ( nb2d_face0_3*3 + nb2d_face0_4*4 - nb1d ) / 2; + + std::vector aResVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; i & columns, + SMESH_MesherHelper* helper) +{ + int nbNodes = columns.size(); + int nbZ = columns[0]->size(); + if ( nbZ < 2 ) return; + + // find out orientation + bool isForward = true; + SMDS_VolumeTool vTool; + int z = 1; + switch ( nbNodes ) { + case 3: { + SMDS_VolumeOfNodes tmpPenta ( (*columns[0])[z-1], // bottom + (*columns[1])[z-1], + (*columns[2])[z-1], + (*columns[0])[z], // top + (*columns[1])[z], + (*columns[2])[z] ); + vTool.Set( &tmpPenta ); + isForward = vTool.IsForward(); + break; + } + case 4: { + SMDS_VolumeOfNodes tmpHex( (*columns[0])[z-1], (*columns[1])[z-1], // bottom + (*columns[2])[z-1], (*columns[3])[z-1], + (*columns[0])[z], (*columns[1])[z], // top + (*columns[2])[z], (*columns[3])[z] ); + vTool.Set( &tmpHex ); + isForward = vTool.IsForward(); + break; + } + default: + const int di = (nbNodes+1) / 3; + SMDS_VolumeOfNodes tmpVol ( (*columns[0] )[z-1], + (*columns[di] )[z-1], + (*columns[2*di])[z-1], + (*columns[0] )[z], + (*columns[di] )[z], + (*columns[2*di])[z] ); + vTool.Set( &tmpVol ); + isForward = vTool.IsForward(); } + + // vertical loop on columns + + helper->SetElementsOnShape( true ); + + switch ( nbNodes ) { + + case 3: { // ---------- pentahedra + const int i1 = isForward ? 1 : 2; + const int i2 = isForward ? 2 : 1; + for ( z = 1; z < nbZ; ++z ) + helper->AddVolume( (*columns[0 ])[z-1], // bottom + (*columns[i1])[z-1], + (*columns[i2])[z-1], + (*columns[0 ])[z], // top + (*columns[i1])[z], + (*columns[i2])[z] ); + break; + } + case 4: { // ---------- hexahedra + const int i1 = isForward ? 1 : 3; + const int i3 = isForward ? 3 : 1; + for ( z = 1; z < nbZ; ++z ) + helper->AddVolume( (*columns[0])[z-1], (*columns[i1])[z-1], // bottom + (*columns[2])[z-1], (*columns[i3])[z-1], + (*columns[0])[z], (*columns[i1])[z], // top + (*columns[2])[z], (*columns[i3])[z] ); + break; + } + case 6: { // ---------- octahedra + const int iBase1 = isForward ? -1 : 0; + const int iBase2 = isForward ? 0 :-1; + for ( z = 1; z < nbZ; ++z ) + helper->AddVolume( (*columns[0])[z+iBase1], (*columns[1])[z+iBase1], // bottom or top + (*columns[2])[z+iBase1], (*columns[3])[z+iBase1], + (*columns[4])[z+iBase1], (*columns[5])[z+iBase1], + (*columns[0])[z+iBase2], (*columns[1])[z+iBase2], // top or bottom + (*columns[2])[z+iBase2], (*columns[3])[z+iBase2], + (*columns[4])[z+iBase2], (*columns[5])[z+iBase2] ); + break; + } + default: // ---------- polyhedra + vector quantities( 2 + nbNodes, 4 ); + quantities[0] = quantities[1] = nbNodes; + columns.resize( nbNodes + 1 ); + columns[ nbNodes ] = columns[ 0 ]; + const int i1 = isForward ? 1 : 3; + const int i3 = isForward ? 3 : 1; + const int iBase1 = isForward ? -1 : 0; + const int iBase2 = isForward ? 0 :-1; + vector nodes( 2*nbNodes + 4*nbNodes); + for ( z = 1; z < nbZ; ++z ) + { + for ( int i = 0; i < nbNodes; ++i ) { + nodes[ i ] = (*columns[ i ])[z+iBase1]; // bottom or top + nodes[ 2*nbNodes-i-1 ] = (*columns[ i ])[z+iBase2]; // top or bottom + // side + int di = 2*nbNodes + 4*i; + nodes[ di+0 ] = (*columns[i ])[z ]; + nodes[ di+i1] = (*columns[i+1])[z ]; + nodes[ di+2 ] = (*columns[i+1])[z-1]; + nodes[ di+i3] = (*columns[i ])[z-1]; + } + helper->AddPolyhedralVolume( nodes, quantities ); + } + + } // switch ( nbNodes ) } //================================================================================ @@ -482,81 +1932,133 @@ void StdMeshers_Prism_3D::AddPrisms( vector & columns, */ //================================================================================ -bool StdMeshers_Prism_3D::assocOrProjBottom2Top() +bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf, + const Prism_3D::TPrismTopo& thePrism) { - SMESH_subMesh * botSM = myBlock.SubMesh( ID_BOT_FACE ); - SMESH_subMesh * topSM = myBlock.SubMesh( ID_TOP_FACE ); + SMESH_subMesh * botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); + SMESH_subMesh * topSM = myHelper->GetMesh()->GetSubMesh( thePrism.myTop ); SMESHDS_SubMesh * botSMDS = botSM->GetSubMeshDS(); SMESHDS_SubMesh * topSMDS = topSM->GetSubMeshDS(); if ( !botSMDS || botSMDS->NbElements() == 0 ) - return error(TCom("No elememts on face #") << botSM->GetId()); + { + _gen->Compute( *myHelper->GetMesh(), botSM->GetSubShape(), /*aShapeOnly=*/true ); + botSMDS = botSM->GetSubMeshDS(); + if ( !botSMDS || botSMDS->NbElements() == 0 ) + return toSM( error(TCom("No elements on face #") << botSM->GetId() )); + } - bool needProject = false; - if ( !topSMDS || - botSMDS->NbElements() != topSMDS->NbElements() || - botSMDS->NbNodes() != topSMDS->NbNodes()) + bool needProject = !topSM->IsMeshComputed(); + if ( !needProject && + (botSMDS->NbElements() != topSMDS->NbElements() || + botSMDS->NbNodes() != topSMDS->NbNodes())) { - if ( myBlock.HasNotQuadElemOnTop() ) - return error(TCom("Mesh on faces #") << botSM->GetId() - <<" and #"<< topSM->GetId() << " seems different" ); - needProject = true; + MESSAGE("nb elem bot " << botSMDS->NbElements() << + " top " << ( topSMDS ? topSMDS->NbElements() : 0 )); + MESSAGE("nb node bot " << botSMDS->NbNodes() << + " top " << ( topSMDS ? topSMDS->NbNodes() : 0 )); + return toSM( error(TCom("Mesh on faces #") << botSM->GetId() + <<" and #"<< topSM->GetId() << " seems different" )); } if ( 0/*needProject && !myProjectTriangles*/ ) - return error(TCom("Mesh on faces #") << botSM->GetId() - <<" and #"<< topSM->GetId() << " seems different" ); + return toSM( error(TCom("Mesh on faces #") << botSM->GetId() + <<" and #"<< topSM->GetId() << " seems different" )); ///RETURN_BAD_RESULT("Need to project but not allowed"); + NSProjUtils::TNodeNodeMap n2nMap; + const NSProjUtils::TNodeNodeMap* n2nMapPtr = & n2nMap; if ( needProject ) { - return projectBottomToTop(); + if ( !projectBottomToTop( bottomToTopTrsf, thePrism )) + return false; + n2nMapPtr = & TProjction2dAlgo::instance( this )->GetNodesMap(); } - TopoDS_Face botFace = TopoDS::Face( myBlock.Shape( ID_BOT_FACE )); - TopoDS_Face topFace = TopoDS::Face( myBlock.Shape( ID_TOP_FACE )); - // associate top and bottom faces - TAssocTool::TShapeShapeMap shape2ShapeMap; - if ( !TAssocTool::FindSubShapeAssociation( botFace, myBlock.Mesh(), - topFace, myBlock.Mesh(), - shape2ShapeMap) ) - return error(TCom("Topology of faces #") << botSM->GetId() - <<" and #"<< topSM->GetId() << " seems different" ); + if ( !n2nMapPtr || n2nMapPtr->size() < botSMDS->NbNodes() ) + { + // associate top and bottom faces + NSProjUtils::TShapeShapeMap shape2ShapeMap; + const bool sameTopo = + NSProjUtils::FindSubShapeAssociation( thePrism.myBottom, myHelper->GetMesh(), + thePrism.myTop, myHelper->GetMesh(), + shape2ShapeMap); + if ( !sameTopo ) + for ( size_t iQ = 0; iQ < thePrism.myWallQuads.size(); ++iQ ) + { + const Prism_3D::TQuadList& quadList = thePrism.myWallQuads[iQ]; + StdMeshers_FaceSidePtr botSide = quadList.front()->side[ QUAD_BOTTOM_SIDE ]; + StdMeshers_FaceSidePtr topSide = quadList.back ()->side[ QUAD_TOP_SIDE ]; + if ( botSide->NbEdges() == topSide->NbEdges() ) + { + for ( int iE = 0; iE < botSide->NbEdges(); ++iE ) + { + NSProjUtils::InsertAssociation( botSide->Edge( iE ), + topSide->Edge( iE ), shape2ShapeMap ); + NSProjUtils::InsertAssociation( myHelper->IthVertex( 0, botSide->Edge( iE )), + myHelper->IthVertex( 0, topSide->Edge( iE )), + shape2ShapeMap ); + } + } + else + { + TopoDS_Vertex vb, vt; + StdMeshers_FaceSidePtr sideB, sideT; + vb = myHelper->IthVertex( 0, botSide->Edge( 0 )); + vt = myHelper->IthVertex( 0, topSide->Edge( 0 )); + sideB = quadList.front()->side[ QUAD_LEFT_SIDE ]; + sideT = quadList.back ()->side[ QUAD_LEFT_SIDE ]; + if ( vb.IsSame( sideB->FirstVertex() ) && + vt.IsSame( sideT->LastVertex() )) + { + NSProjUtils::InsertAssociation( botSide->Edge( 0 ), + topSide->Edge( 0 ), shape2ShapeMap ); + NSProjUtils::InsertAssociation( vb, vt, shape2ShapeMap ); + } + vb = myHelper->IthVertex( 1, botSide->Edge( botSide->NbEdges()-1 )); + vt = myHelper->IthVertex( 1, topSide->Edge( topSide->NbEdges()-1 )); + sideB = quadList.front()->side[ QUAD_RIGHT_SIDE ]; + sideT = quadList.back ()->side[ QUAD_RIGHT_SIDE ]; + if ( vb.IsSame( sideB->FirstVertex() ) && + vt.IsSame( sideT->LastVertex() )) + { + NSProjUtils::InsertAssociation( botSide->Edge( botSide->NbEdges()-1 ), + topSide->Edge( topSide->NbEdges()-1 ), + shape2ShapeMap ); + NSProjUtils::InsertAssociation( vb, vt, shape2ShapeMap ); + } + } + } - // Find matching nodes of top and bottom faces - TNodeNodeMap n2nMap; - if ( ! TAssocTool::FindMatchingNodesOnFaces( botFace, myBlock.Mesh(), - topFace, myBlock.Mesh(), - shape2ShapeMap, n2nMap )) - return error(TCom("Mesh on faces #") << botSM->GetId() - <<" and #"<< topSM->GetId() << " seems different" ); + // Find matching nodes of top and bottom faces + n2nMapPtr = & n2nMap; + if ( ! NSProjUtils::FindMatchingNodesOnFaces( thePrism.myBottom, myHelper->GetMesh(), + thePrism.myTop, myHelper->GetMesh(), + shape2ShapeMap, n2nMap )) + { + if ( sameTopo ) + return toSM( error(TCom("Mesh on faces #") << botSM->GetId() + <<" and #"<< topSM->GetId() << " seems different" )); + else + return toSM( error(TCom("Topology of faces #") << botSM->GetId() + <<" and #"<< topSM->GetId() << " seems different" )); + } + } // Fill myBotToColumnMap int zSize = myBlock.VerticalSize(); - TNode prevTNode; - TNodeNodeMap::iterator bN_tN = n2nMap.begin(); - for ( ; bN_tN != n2nMap.end(); ++bN_tN ) + TNodeNodeMap::const_iterator bN_tN = n2nMapPtr->begin(); + for ( ; bN_tN != n2nMapPtr->end(); ++bN_tN ) { const SMDS_MeshNode* botNode = bN_tN->first; const SMDS_MeshNode* topNode = bN_tN->second; if ( botNode->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE ) continue; // wall columns are contained in myBlock - // compute bottom node params - TNode bN( botNode ); - if ( zSize > 2 ) { - gp_XYZ paramHint(-1,-1,-1); - if ( prevTNode.IsNeighbor( bN )) - paramHint = prevTNode.GetParams(); - if ( !myBlock.ComputeParameters( bN.GetCoords(), bN.ChangeParams(), - ID_BOT_FACE, paramHint )) - return error(TCom("Can't compute normalized parameters for node ") - << botNode->GetID() << " on the face #"<< botSM->GetId() ); - prevTNode = bN; - } // create node column - TNode2ColumnMap::iterator bN_col = + Prism_3D::TNode bN( botNode ); + TNode2ColumnMap::iterator bN_col = myBotToColumnMap.insert( make_pair ( bN, TNodeColumn() )).first; TNodeColumn & column = bN_col->second; column.resize( zSize ); @@ -568,55 +2070,102 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top() //================================================================================ /*! - * \brief Remove quadrangles from the top face and - * create triangles there by projection from the bottom + * \brief Remove faces from the top face and re-create them by projection from the bottom * \retval bool - a success or not */ //================================================================================ -bool StdMeshers_Prism_3D::projectBottomToTop() +bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf & bottomToTopTrsf, + const Prism_3D::TPrismTopo& thePrism ) { - SMESH_subMesh * botSM = myBlock.SubMesh( ID_BOT_FACE ); - SMESH_subMesh * topSM = myBlock.SubMesh( ID_TOP_FACE ); + if ( project2dMesh( thePrism.myBottom, thePrism.myTop )) + { + return true; + } + NSProjUtils::TNodeNodeMap& n2nMap = + (NSProjUtils::TNodeNodeMap&) TProjction2dAlgo::instance( this )->GetNodesMap(); + n2nMap.clear(); + + myUseBlock = true; + + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + SMESH_subMesh * botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); + SMESH_subMesh * topSM = myHelper->GetMesh()->GetSubMesh( thePrism.myTop ); SMESHDS_SubMesh * botSMDS = botSM->GetSubMeshDS(); SMESHDS_SubMesh * topSMDS = topSM->GetSubMeshDS(); - if ( topSMDS ) - topSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); + if ( topSMDS && topSMDS->NbElements() > 0 ) + { + //topSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); -- avoid propagation of events + for ( SMDS_ElemIteratorPtr eIt = topSMDS->GetElements(); eIt->more(); ) + meshDS->RemoveFreeElement( eIt->next(), topSMDS, /*fromGroups=*/false ); + for ( SMDS_NodeIteratorPtr nIt = topSMDS->GetNodes(); nIt->more(); ) + meshDS->RemoveFreeNode( nIt->next(), topSMDS, /*fromGroups=*/false ); + } - SMESHDS_Mesh* meshDS = myBlock.MeshDS(); - int shapeID = myHelper->GetSubShapeID(); - int topFaceID = meshDS->ShapeToIndex( topSM->GetSubShape() ); + const TopoDS_Face& botFace = thePrism.myBottom; // oriented within + const TopoDS_Face& topFace = thePrism.myTop; // the 3D SHAPE + int topFaceID = meshDS->ShapeToIndex( thePrism.myTop ); + + SMESH_MesherHelper botHelper( *myHelper->GetMesh() ); + botHelper.SetSubShape( botFace ); + botHelper.ToFixNodeParameters( true ); + bool checkUV; + SMESH_MesherHelper topHelper( *myHelper->GetMesh() ); + topHelper.SetSubShape( topFace ); + topHelper.ToFixNodeParameters( true ); + double distXYZ[4], fixTol = 10 * topHelper.MaxTolerance( topFace ); // Fill myBotToColumnMap int zSize = myBlock.VerticalSize(); - TNode prevTNode; + Prism_3D::TNode prevTNode; SMDS_NodeIteratorPtr nIt = botSMDS->GetNodes(); while ( nIt->more() ) { const SMDS_MeshNode* botNode = nIt->next(); + const SMDS_MeshNode* topNode = 0; if ( botNode->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE ) continue; // strange - // compute bottom node params - TNode bN( botNode ); - gp_XYZ paramHint(-1,-1,-1); - if ( prevTNode.IsNeighbor( bN )) - paramHint = prevTNode.GetParams(); - if ( !myBlock.ComputeParameters( bN.GetCoords(), bN.ChangeParams(), - ID_BOT_FACE, paramHint )) - return error(TCom("Can't compute normalized parameters for node ") - << botNode->GetID() << " on the face #"<< botSM->GetId() ); - prevTNode = bN; - // compute top node coords - gp_XYZ topXYZ; gp_XY topUV; - if ( !myBlock.FacePoint( ID_TOP_FACE, bN.GetParams(), topXYZ ) || - !myBlock.FaceUV ( ID_TOP_FACE, bN.GetParams(), topUV )) - return error(TCom("Can't compute coordinates " - "by normalized parameters on the face #")<< topSM->GetId() ); - SMDS_MeshNode * topNode = meshDS->AddNode( topXYZ.X(),topXYZ.Y(),topXYZ.Z() ); - meshDS->SetNodeOnFace( topNode, topFaceID, topUV.X(), topUV.Y() ); + + Prism_3D::TNode bN( botNode ); + if ( bottomToTopTrsf.Form() == gp_Identity ) + { + // compute bottom node params + gp_XYZ paramHint(-1,-1,-1); + if ( prevTNode.IsNeighbor( bN )) + { + paramHint = prevTNode.GetParams(); + // double tol = 1e-2 * ( prevTNode.GetCoords() - bN.GetCoords() ).Modulus(); + // myBlock.SetTolerance( Min( myBlock.GetTolerance(), tol )); + } + if ( !myBlock.ComputeParameters( bN.GetCoords(), bN.ChangeParams(), + ID_BOT_FACE, paramHint )) + return toSM( error(TCom("Can't compute normalized parameters for node ") + << botNode->GetID() << " on the face #"<< botSM->GetId() )); + prevTNode = bN; + // compute top node coords + gp_XYZ topXYZ; gp_XY topUV; + if ( !myBlock.FacePoint( ID_TOP_FACE, bN.GetParams(), topXYZ ) || + !myBlock.FaceUV ( ID_TOP_FACE, bN.GetParams(), topUV )) + return toSM( error(TCom("Can't compute coordinates " + "by normalized parameters on the face #")<< topSM->GetId() )); + topNode = meshDS->AddNode( topXYZ.X(),topXYZ.Y(),topXYZ.Z() ); + meshDS->SetNodeOnFace( topNode, topFaceID, topUV.X(), topUV.Y() ); + } + else // use bottomToTopTrsf + { + gp_XYZ coords = bN.GetCoords(); + bottomToTopTrsf.Transforms( coords ); + topNode = meshDS->AddNode( coords.X(), coords.Y(), coords.Z() ); + gp_XY topUV = botHelper.GetNodeUV( botFace, botNode, 0, &checkUV ); + meshDS->SetNodeOnFace( topNode, topFaceID, topUV.X(), topUV.Y() ); + distXYZ[0] = -1; + if ( topHelper.CheckNodeUV( topFace, topNode, topUV, fixTol, /*force=*/false, distXYZ ) && + distXYZ[0] > fixTol && distXYZ[0] < fixTol * 1e+3 ) + meshDS->MoveNode( topNode, distXYZ[1], distXYZ[2], distXYZ[3] ); // transform can be inaccurate + } // create node column TNode2ColumnMap::iterator bN_col = myBotToColumnMap.insert( make_pair ( bN, TNodeColumn() )).first; @@ -624,114 +2173,720 @@ bool StdMeshers_Prism_3D::projectBottomToTop() column.resize( zSize ); column.front() = botNode; column.back() = topNode; + + n2nMap.insert( n2nMap.end(), make_pair( botNode, topNode )); + + if ( _computeCanceled ) + return toSM( error( SMESH_ComputeError::New(COMPERR_CANCELED))); } // Create top faces + const bool oldSetElemsOnShape = myHelper->SetElementsOnShape( false ); + + // care of orientation; + // if the bottom faces is orienetd OK then top faces must be reversed + bool reverseTop = true; + if ( myHelper->NbAncestors( botFace, *myBlock.Mesh(), TopAbs_SOLID ) > 1 ) + reverseTop = ! myHelper->IsReversedSubMesh( botFace ); + int iFrw, iRev, *iPtr = &( reverseTop ? iRev : iFrw ); + // loop on bottom mesh faces SMDS_ElemIteratorPtr faceIt = botSMDS->GetElements(); + vector< const SMDS_MeshNode* > nodes; while ( faceIt->more() ) { const SMDS_MeshElement* face = faceIt->next(); if ( !face || face->GetType() != SMDSAbs_Face ) continue; - int nbNodes = face->NbNodes(); - if ( face->IsQuadratic() ) - nbNodes /= 2; // find top node in columns for each bottom node - vector< const SMDS_MeshNode* > nodes( nbNodes ); - for ( int i = 0; i < nbNodes; ++i ) + int nbNodes = face->NbCornerNodes(); + nodes.resize( nbNodes ); + for ( iFrw = 0, iRev = nbNodes-1; iFrw < nbNodes; ++iFrw, --iRev ) { - const SMDS_MeshNode* n = face->GetNode( nbNodes - i - 1 ); + const SMDS_MeshNode* n = face->GetNode( *iPtr ); if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) { TNode2ColumnMap::iterator bot_column = myBotToColumnMap.find( n ); if ( bot_column == myBotToColumnMap.end() ) - return error(TCom("No nodes found above node ") << n->GetID() ); - nodes[ i ] = bot_column->second.back(); + return toSM( error(TCom("No nodes found above node ") << n->GetID() )); + nodes[ iFrw ] = bot_column->second.back(); } else { const TNodeColumn* column = myBlock.GetNodeColumn( n ); if ( !column ) - return error(TCom("No side nodes found above node ") << n->GetID() ); - nodes[ i ] = column->back(); + return toSM( error(TCom("No side nodes found above node ") << n->GetID() )); + nodes[ iFrw ] = column->back(); + } + } + SMDS_MeshElement* newFace = 0; + switch ( nbNodes ) { + + case 3: { + newFace = myHelper->AddFace(nodes[0], nodes[1], nodes[2]); + break; + } + case 4: { + newFace = myHelper->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); + break; + } + default: + newFace = meshDS->AddPolygonalFace( nodes ); + } + if ( newFace ) + meshDS->SetMeshElementOnShape( newFace, topFaceID ); + } + + myHelper->SetElementsOnShape( oldSetElemsOnShape ); + + // Check the projected mesh + + if ( thePrism.myNbEdgesInWires.size() > 1 && // there are holes + topHelper.IsDistorted2D( topSM, /*checkUV=*/false )) + { + SMESH_MeshEditor editor( topHelper.GetMesh() ); + + // smooth in 2D or 3D? + TopLoc_Location loc; + Handle(Geom_Surface) surface = BRep_Tool::Surface( topFace, loc ); + bool isPlanar = GeomLib_IsPlanarSurface( surface ).IsPlanar(); + + bool isFixed = false; + set fixedNodes; + for ( int iAttemp = 0; !isFixed && iAttemp < 10; ++iAttemp ) + { + TIDSortedElemSet faces; + for ( faceIt = topSMDS->GetElements(); faceIt->more(); ) + faces.insert( faces.end(), faceIt->next() ); + + SMESH_MeshEditor::SmoothMethod algo = + iAttemp ? SMESH_MeshEditor::CENTROIDAL : SMESH_MeshEditor::LAPLACIAN; + + // smoothing + editor.Smooth( faces, fixedNodes, algo, /*nbIterations=*/ 10, + /*theTgtAspectRatio=*/1.0, /*the2D=*/!isPlanar); + + isFixed = !topHelper.IsDistorted2D( topSM, /*checkUV=*/true ); + } + if ( !isFixed ) + return toSM( error( TCom("Projection from face #") << botSM->GetId() + << " to face #" << topSM->GetId() + << " failed: inverted elements created")); + } + + return true; +} + +//======================================================================= +//function : getSweepTolerance +//purpose : Compute tolerance to pass to StdMeshers_Sweeper +//======================================================================= + +double StdMeshers_Prism_3D::getSweepTolerance( const Prism_3D::TPrismTopo& thePrism ) +{ + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + SMESHDS_SubMesh * sm[2] = { meshDS->MeshElements( thePrism.myBottom ), + meshDS->MeshElements( thePrism.myTop ) }; + double minDist = 1e100; + + vector< SMESH_TNodeXYZ > nodes; + for ( int iSM = 0; iSM < 2; ++iSM ) + { + if ( !sm[ iSM ]) continue; + + SMDS_ElemIteratorPtr fIt = sm[ iSM ]->GetElements(); + while ( fIt->more() ) + { + const SMDS_MeshElement* face = fIt->next(); + const int nbNodes = face->NbCornerNodes(); + SMDS_ElemIteratorPtr nIt = face->nodesIterator(); + + nodes.resize( nbNodes + 1 ); + for ( int iN = 0; iN < nbNodes; ++iN ) + nodes[ iN ] = nIt->next(); + nodes.back() = nodes[0]; + + // loop on links + double dist2; + for ( int iN = 0; iN < nbNodes; ++iN ) + { + if ( nodes[ iN ]._node->GetPosition()->GetDim() < 2 && + nodes[ iN+1 ]._node->GetPosition()->GetDim() < 2 ) + { + // it's a boundary link; measure distance of other + // nodes to this link + gp_XYZ linkDir = nodes[ iN ] - nodes[ iN+1 ]; + double linkLen = linkDir.Modulus(); + bool isDegen = ( linkLen < numeric_limits::min() ); + if ( !isDegen ) linkDir /= linkLen; + for ( int iN2 = 0; iN2 < nbNodes; ++iN2 ) // loop on other nodes + { + if ( nodes[ iN2 ] == nodes[ iN ] || + nodes[ iN2 ] == nodes[ iN+1 ]) continue; + if ( isDegen ) + { + dist2 = ( nodes[ iN ] - nodes[ iN2 ]).SquareModulus(); + } + else + { + dist2 = linkDir.CrossSquareMagnitude( nodes[ iN ] - nodes[ iN2 ]); + } + if ( dist2 > numeric_limits::min() ) + minDist = Min ( minDist, dist2 ); + } + } + // measure length link + else if ( nodes[ iN ]._node < nodes[ iN+1 ]._node ) // not to measure same link twice + { + dist2 = ( nodes[ iN ] - nodes[ iN+1 ]).SquareModulus(); + if ( dist2 > numeric_limits::min() ) + minDist = Min ( minDist, dist2 ); + } + } + } + } + return 0.1 * Sqrt ( minDist ); +} + +//======================================================================= +//function : isSimpleQuad +//purpose : check if the bottom FACE is meshable with nice qudrangles, +// if so the block aproach can work rather fast. +// This is a temporary mean caused by problems in StdMeshers_Sweeper +//======================================================================= + +bool StdMeshers_Prism_3D::isSimpleBottom( const Prism_3D::TPrismTopo& thePrism ) +{ + // analyse angles between edges + double nbConcaveAng = 0, nbConvexAng = 0; + TopoDS_Face reverseBottom = TopoDS::Face( thePrism.myBottom.Reversed() ); // see initPrism() + TopoDS_Vertex commonV; + const list< TopoDS_Edge >& botEdges = thePrism.myBottomEdges; + list< TopoDS_Edge >::const_iterator edge = botEdges.begin(); + while ( edge != botEdges.end() ) + { + if ( SMESH_Algo::isDegenerated( *edge )) + return false; + TopoDS_Edge e1 = *edge++; + TopoDS_Edge e2 = ( edge == botEdges.end() ? botEdges.front() : *edge ); + if ( ! TopExp::CommonVertex( e1, e2, commonV )) + { + e2 = botEdges.front(); + if ( ! TopExp::CommonVertex( e1, e2, commonV )) + break; + } + double angle = myHelper->GetAngle( e1, e2, reverseBottom, commonV ); + if ( angle < -5 * M_PI/180 ) + if ( ++nbConcaveAng > 1 ) + return false; + if ( angle > 85 * M_PI/180 ) + if ( ++nbConvexAng > 4 ) + return false; + } + return true; +} + +//======================================================================= +//function : project2dMesh +//purpose : Project mesh faces from a source FACE of one prism (theSrcFace) +// to a source FACE of another prism (theTgtFace) +//======================================================================= + +bool StdMeshers_Prism_3D::project2dMesh(const TopoDS_Face& theSrcFace, + const TopoDS_Face& theTgtFace) +{ + TProjction2dAlgo* projector2D = TProjction2dAlgo::instance( this ); + projector2D->myHyp.SetSourceFace( theSrcFace ); + bool ok = projector2D->Compute( *myHelper->GetMesh(), theTgtFace ); + + SMESH_subMesh* tgtSM = myHelper->GetMesh()->GetSubMesh( theTgtFace ); + if ( !ok && tgtSM->GetSubMeshDS() ) { + //tgtSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); -- avoid propagation of events + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + SMESHDS_SubMesh* tgtSMDS = tgtSM->GetSubMeshDS(); + for ( SMDS_ElemIteratorPtr eIt = tgtSMDS->GetElements(); eIt->more(); ) + meshDS->RemoveFreeElement( eIt->next(), tgtSMDS, /*fromGroups=*/false ); + for ( SMDS_NodeIteratorPtr nIt = tgtSMDS->GetNodes(); nIt->more(); ) + meshDS->RemoveFreeNode( nIt->next(), tgtSMDS, /*fromGroups=*/false ); + } + tgtSM->ComputeStateEngine ( SMESH_subMesh::CHECK_COMPUTE_STATE ); + tgtSM->ComputeSubMeshStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + + return ok; +} + +//================================================================================ +/*! + * \brief Set projection coordinates of a node to a face and it's sub-shapes + * \param faceID - the face given by in-block ID + * \param params - node normalized parameters + * \retval bool - is a success + */ +//================================================================================ + +bool StdMeshers_Prism_3D::setFaceAndEdgesXYZ( const int faceID, const gp_XYZ& params, int z ) +{ + // find base and top edges of the face + enum { BASE = 0, TOP, LEFT, RIGHT }; + vector< int > edgeVec; // 0-base, 1-top + SMESH_Block::GetFaceEdgesIDs( faceID, edgeVec ); + + myBlock.EdgePoint( edgeVec[ BASE ], params, myShapeXYZ[ edgeVec[ BASE ]]); + myBlock.EdgePoint( edgeVec[ TOP ], params, myShapeXYZ[ edgeVec[ TOP ]]); + + SHOWYXZ("\nparams ", params); + SHOWYXZ("TOP is " <GetSubShape().IsNull() && + myHelper->GetSubShape().ShapeType() == TopAbs_SOLID) + { + SMESH_subMesh* sm = myHelper->GetMesh()->GetSubMesh( myHelper->GetSubShape() ); + sm->GetComputeError() = this->GetComputeError(); + // clear error in order not to return it twice + _error = COMPERR_OK; + _comment.clear(); + } + return isOK; +} + +//======================================================================= +//function : shapeID +//purpose : Return index of a shape +//======================================================================= + +int StdMeshers_Prism_3D::shapeID( const TopoDS_Shape& S ) +{ + if ( S.IsNull() ) return 0; + if ( !myHelper ) return -3; + return myHelper->GetMeshDS()->ShapeToIndex( S ); +} + +namespace // utils used by StdMeshers_Prism_3D::IsApplicable() +{ + struct EdgeWithNeighbors + { + TopoDS_Edge _edge; + int _iL, _iR; + EdgeWithNeighbors(const TopoDS_Edge& E, int iE, int nbE, int shift = 0 ): + _edge( E ), + _iL( SMESH_MesherHelper::WrapIndex( iE-1, nbE ) + shift ), + _iR( SMESH_MesherHelper::WrapIndex( iE+1, nbE ) + shift ) + { + } + EdgeWithNeighbors() {} + }; + struct PrismSide + { + TopoDS_Face _face; + TopTools_IndexedMapOfShape *_faces; // pointer because its copy constructor is private + TopoDS_Edge _topEdge; + vector< EdgeWithNeighbors >*_edges; + int _iBotEdge; + vector< bool > _isCheckedEdge; + int _nbCheckedEdges; // nb of EDGEs whose location is defined + PrismSide *_leftSide; + PrismSide *_rightSide; + const TopoDS_Edge& Edge( int i ) const + { + return (*_edges)[ i ]._edge; + } + int FindEdge( const TopoDS_Edge& E ) const + { + for ( size_t i = 0; i < _edges->size(); ++i ) + if ( E.IsSame( Edge( i ))) return i; + return -1; + } + bool IsSideFace( const TopoDS_Shape& face ) const + { + if ( _faces->Contains( face )) // avoid returning true for a prism top FACE + return ( !_face.IsNull() || !( face.IsSame( _faces->FindKey( _faces->Extent() )))); + return false; + } + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Return ordered edges of a face + */ + bool getEdges( const TopoDS_Face& face, + vector< EdgeWithNeighbors > & edges, + const bool noHolesAllowed) + { + list< TopoDS_Edge > ee; + list< int > nbEdgesInWires; + int nbW = SMESH_Block::GetOrderedEdges( face, ee, nbEdgesInWires ); + if ( nbW > 1 && noHolesAllowed ) + return false; + + int iE, nbTot = 0; + list< TopoDS_Edge >::iterator e = ee.begin(); + list< int >::iterator nbE = nbEdgesInWires.begin(); + for ( ; nbE != nbEdgesInWires.end(); ++nbE ) + for ( iE = 0; iE < *nbE; ++e, ++iE ) + if ( SMESH_Algo::isDegenerated( *e )) + { + e = --ee.erase( e ); + --(*nbE); + --iE; + } + else + { + e->Orientation( TopAbs_FORWARD ); // for operator==() to work + } + + edges.clear(); + e = ee.begin(); + for ( nbE = nbEdgesInWires.begin(); nbE != nbEdgesInWires.end(); ++nbE ) + { + for ( iE = 0; iE < *nbE; ++e, ++iE ) + edges.push_back( EdgeWithNeighbors( *e, iE, *nbE, nbTot )); + nbTot += *nbE; + } + return edges.size(); + } + //-------------------------------------------------------------------------------- + /*! + * \brief Return another faces sharing an edge + */ + const TopoDS_Shape & getAnotherFace( const TopoDS_Face& face, + const TopoDS_Edge& edge, + TopTools_IndexedDataMapOfShapeListOfShape& facesOfEdge) + { + TopTools_ListIteratorOfListOfShape faceIt( facesOfEdge.FindFromKey( edge )); + for ( ; faceIt.More(); faceIt.Next() ) + if ( !face.IsSame( faceIt.Value() )) + return faceIt.Value(); + return face; + } +} + +//================================================================================ +/*! + * \brief Return true if the algorithm can mesh this shape + * \param [in] aShape - shape to check + * \param [in] toCheckAll - if true, this check returns OK if all shapes are OK, + * else, returns OK if at least one shape is OK + */ +//================================================================================ + +bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckAll) +{ + TopExp_Explorer sExp( shape, TopAbs_SOLID ); + if ( !sExp.More() ) + return false; + + for ( ; sExp.More(); sExp.Next() ) + { + // check nb shells + TopoDS_Shape shell; + TopExp_Explorer shExp( sExp.Current(), TopAbs_SHELL ); + if ( shExp.More() ) { + shell = shExp.Current(); + shExp.Next(); + if ( shExp.More() ) + shell.Nullify(); + } + if ( shell.IsNull() ) { + if ( toCheckAll ) return false; + continue; + } + // get all faces + TopTools_IndexedMapOfShape allFaces; + TopExp::MapShapes( shell, TopAbs_FACE, allFaces ); + if ( allFaces.Extent() < 3 ) { + if ( toCheckAll ) return false; + continue; + } + // is a box? + if ( allFaces.Extent() == 6 ) + { + TopTools_IndexedMapOfOrientedShape map; + bool isBox = SMESH_Block::FindBlockShapes( TopoDS::Shell( shell ), + TopoDS_Vertex(), TopoDS_Vertex(), map ); + if ( isBox ) { + if ( !toCheckAll ) return true; + continue; + } + } +#ifdef _DEBUG_ + TopTools_IndexedMapOfShape allShapes; + TopExp::MapShapes( shape, allShapes ); +#endif + + TopTools_IndexedDataMapOfShapeListOfShape facesOfEdge; + TopTools_ListIteratorOfListOfShape faceIt; + TopExp::MapShapesAndAncestors( sExp.Current(), TopAbs_EDGE, TopAbs_FACE , facesOfEdge ); + if ( facesOfEdge.IsEmpty() ) { + if ( toCheckAll ) return false; + continue; + } + + typedef vector< EdgeWithNeighbors > TEdgeWithNeighborsVec; + vector< TEdgeWithNeighborsVec > faceEdgesVec( allFaces.Extent() + 1 ); + TopTools_IndexedMapOfShape* facesOfSide = new TopTools_IndexedMapOfShape[ faceEdgesVec.size() ]; + SMESHUtils::ArrayDeleter delFacesOfSide( facesOfSide ); + + // try to use each face as a bottom one + bool prismDetected = false; + for ( int iF = 1; iF < allFaces.Extent() && !prismDetected; ++iF ) + { + const TopoDS_Face& botF = TopoDS::Face( allFaces( iF )); + + TEdgeWithNeighborsVec& botEdges = faceEdgesVec[ iF ]; + if ( botEdges.empty() ) + if ( !getEdges( botF, botEdges, /*noHoles=*/false )) + break; + if ( allFaces.Extent()-1 <= (int) botEdges.size() ) + continue; // all faces are adjacent to botF - no top FACE + + // init data of side FACEs + vector< PrismSide > sides( botEdges.size() ); + for ( int iS = 0; iS < botEdges.size(); ++iS ) + { + sides[ iS ]._topEdge = botEdges[ iS ]._edge; + sides[ iS ]._face = botF; + sides[ iS ]._leftSide = & sides[ botEdges[ iS ]._iR ]; + sides[ iS ]._rightSide = & sides[ botEdges[ iS ]._iL ]; + sides[ iS ]._faces = & facesOfSide[ iS ]; + sides[ iS ]._faces->Clear(); + } + + bool isOK = true; // ok for a current botF + bool isAdvanced = true; // is new data found in a current loop + int nbFoundSideFaces = 0; + for ( int iLoop = 0; isOK && isAdvanced; ++iLoop ) + { + isAdvanced = false; + for ( size_t iS = 0; iS < sides.size() && isOK; ++iS ) + { + PrismSide& side = sides[ iS ]; + if ( side._face.IsNull() ) + continue; // probably the prism top face is the last of side._faces + + if ( side._topEdge.IsNull() ) + { + // find vertical EDGEs --- EGDEs shared with neighbor side FACEs + for ( int is2nd = 0; is2nd < 2 && isOK; ++is2nd ) // 2 adjacent neighbors + { + int di = is2nd ? 1 : -1; + const PrismSide* adjSide = is2nd ? side._rightSide : side._leftSide; + for ( size_t i = 1; i < side._edges->size(); ++i ) + { + int iE = SMESH_MesherHelper::WrapIndex( i*di + side._iBotEdge, side._edges->size()); + if ( side._isCheckedEdge[ iE ] ) continue; + const TopoDS_Edge& vertE = side.Edge( iE ); + const TopoDS_Shape& neighborF = getAnotherFace( side._face, vertE, facesOfEdge ); + bool isEdgeShared = adjSide->IsSideFace( neighborF ); + if ( isEdgeShared ) + { + isAdvanced = true; + side._isCheckedEdge[ iE ] = true; + side._nbCheckedEdges++; + int nbNotCheckedE = side._edges->size() - side._nbCheckedEdges; + if ( nbNotCheckedE == 1 ) + break; + } + else + { + if ( i == 1 && iLoop == 0 ) isOK = false; + break; + } + } + } + // find a top EDGE + int nbNotCheckedE = side._edges->size() - side._nbCheckedEdges; + if ( nbNotCheckedE == 1 ) + { + vector::iterator ii = std::find( side._isCheckedEdge.begin(), + side._isCheckedEdge.end(), false ); + if ( ii != side._isCheckedEdge.end() ) + { + size_t iE = std::distance( side._isCheckedEdge.begin(), ii ); + side._topEdge = side.Edge( iE ); + } + } + isOK = ( nbNotCheckedE >= 1 ); + } + else //if ( !side._topEdge.IsNull() ) + { + // get a next face of a side + const TopoDS_Shape& f = getAnotherFace( side._face, side._topEdge, facesOfEdge ); + side._faces->Add( f ); + bool stop = false; + if ( f.IsSame( side._face ) || // _topEdge is a seam + SMESH_MesherHelper::Count( f, TopAbs_WIRE, false ) != 1 ) + { + stop = true; + } + else if ( side._leftSide != & side ) // not closed side face + { + if ( side._leftSide->_faces->Contains( f )) + { + stop = true; // probably f is the prism top face + side._leftSide->_face.Nullify(); + side._leftSide->_topEdge.Nullify(); + } + if ( side._rightSide->_faces->Contains( f )) + { + stop = true; // probably f is the prism top face + side._rightSide->_face.Nullify(); + side._rightSide->_topEdge.Nullify(); + } + } + if ( stop ) + { + side._face.Nullify(); + side._topEdge.Nullify(); + continue; + } + side._face = TopoDS::Face( f ); + int faceID = allFaces.FindIndex( side._face ); + side._edges = & faceEdgesVec[ faceID ]; + if ( side._edges->empty() ) + if ( !getEdges( side._face, * side._edges, /*noHoles=*/true )) + break; + const int nbE = side._edges->size(); + if ( nbE >= 4 ) + { + isAdvanced = true; + ++nbFoundSideFaces; + side._iBotEdge = side.FindEdge( side._topEdge ); + side._isCheckedEdge.clear(); + side._isCheckedEdge.resize( nbE, false ); + side._isCheckedEdge[ side._iBotEdge ] = true; + side._nbCheckedEdges = 1; // bottom EDGE is known + } + side._topEdge.Nullify(); + isOK = ( !side._edges->empty() || side._faces->Extent() > 1 ); + + } //if ( !side._topEdge.IsNull() ) + + } // loop on prism sides + + if ( nbFoundSideFaces > allFaces.Extent() ) + { + isOK = false; + } + if ( iLoop > allFaces.Extent() * 10 ) + { + isOK = false; +#ifdef _DEBUG_ + cerr << "BUG: infinite loop in StdMeshers_Prism_3D::IsApplicable()" << endl; +#endif + } + } // while isAdvanced + + if ( isOK && sides[0]._faces->Extent() > 1 ) + { + const int nbFaces = sides[0]._faces->Extent(); + if ( botEdges.size() == 1 ) // cylinder + { + prismDetected = ( nbFaces == allFaces.Extent()-1 ); + } + else + { + const TopoDS_Shape& topFace = sides[0]._faces->FindKey( nbFaces ); + size_t iS; + for ( iS = 1; iS < sides.size(); ++iS ) + if ( !sides[ iS ]._faces->Contains( topFace )) + break; + prismDetected = ( iS == sides.size() ); + } } - } - // create a face, with reversed orientation - SMDS_MeshElement* newFace = 0; - switch ( nbNodes ) { + } // loop on allFaces - case 3: { - newFace = myHelper->AddFace(nodes[0], nodes[1], nodes[2]); - break; - } - case 4: { - newFace = myHelper->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); - break; - } - default: - newFace = meshDS->AddPolygonalFace( nodes ); - } - if ( newFace && shapeID > 0 ) - meshDS->SetMeshElementOnShape( newFace, shapeID ); - } + if ( !prismDetected && toCheckAll ) return false; + if ( prismDetected && !toCheckAll ) return true; - return true; -} + } // loop on solids -//================================================================================ -/*! - * \brief Set projection coordinates of a node to a face and it's subshapes - * \param faceID - the face given by in-block ID - * \param params - node normalized parameters - * \retval bool - is a success - */ -//================================================================================ + return toCheckAll; +} -bool StdMeshers_Prism_3D::setFaceAndEdgesXYZ( const int faceID, const gp_XYZ& params, int z ) +namespace Prism_3D { - // find base and top edges of the face - enum { BASE = 0, TOP, LEFT, RIGHT }; - vector< int > edgeVec; // 0-base, 1-top - SMESH_Block::GetFaceEdgesIDs( faceID, edgeVec ); - - myBlock.EdgePoint( edgeVec[ BASE ], params, myShapeXYZ[ edgeVec[ BASE ]]); - myBlock.EdgePoint( edgeVec[ TOP ], params, myShapeXYZ[ edgeVec[ TOP ]]); - - SHOWYXZ("\nparams ", params); - SHOWYXZ("TOP is "<GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + if ( fIt->next()->GetNodeIndex( myNode ) >= 0 ) + return true; + return false; } - myBlock.FacePoint( faceID, params, myShapeXYZ[ faceID ]); - SHOWYXZ("FacePoint "<GetInverseElementIterator(SMDSAbs_Face); - while ( fIt->more() ) - if ( fIt->next()->GetNodeIndex( myNode ) >= 0 ) - return true; - return false; -} + void TPrismTopo::SetUpsideDown() + { + std::swap( myBottom, myTop ); + myBottomEdges.clear(); + std::reverse( myBottomEdges.begin(), myBottomEdges.end() ); + for ( size_t i = 0; i < myWallQuads.size(); ++i ) + { + myWallQuads[i].reverse(); + TQuadList::iterator q = myWallQuads[i].begin(); + for ( ; q != myWallQuads[i].end(); ++q ) + { + (*q)->shift( 2, /*keepUnitOri=*/true ); + } + myBottomEdges.push_back( myWallQuads[i].front()->side[ QUAD_BOTTOM_SIDE ].grid->Edge(0) ); + } + } + +} // namespace Prism_3D //================================================================================ /*! @@ -746,236 +2901,180 @@ StdMeshers_PrismAsBlock::StdMeshers_PrismAsBlock() StdMeshers_PrismAsBlock::~StdMeshers_PrismAsBlock() { - if ( mySide ) { - delete mySide; mySide = 0; - } + Clear(); } - -//================================================================================ -/*! - * \brief Initialization. - * \param helper - helper loaded with mesh and 3D shape - * \param shape3D - a closed shell or solid - * \retval bool - false if a mesh or a shape are KO - */ -//================================================================================ - -bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, - const TopoDS_Shape& shape3D) +void StdMeshers_PrismAsBlock::Clear() { + myHelper = 0; + myShapeIDMap.Clear(); + myError.reset(); + if ( mySide ) { delete mySide; mySide = 0; } - vector< TSideFace* > sideFaces( NB_WALL_FACES, 0 ); - vector< pair< double, double> > params ( NB_WALL_FACES ); - mySide = new TSideFace( sideFaces, params ); - - myHelper = helper; - SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); - - SMESH_Block::init(); - myShapeIDMap.Clear(); + myParam2ColumnMaps.clear(); myShapeIndex2ColumnMap.clear(); - - int wallFaceIds[ NB_WALL_FACES ] = { // to walk around a block - SMESH_Block::ID_Fx0z, SMESH_Block::ID_F1yz, - SMESH_Block::ID_Fx1z, SMESH_Block::ID_F0yz - }; +} - myError = SMESH_ComputeError::New(); +//======================================================================= +//function : initPrism +//purpose : Analyse shape geometry and mesh. +// If there are triangles on one of faces, it becomes 'bottom'. +// thePrism.myBottom can be already set up. +//======================================================================= - // ------------------------------------------------------------- - // Look for top and bottom faces: not quadrangle ones or meshed - // with not quadrangle elements - // ------------------------------------------------------------- +bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, + const TopoDS_Shape& theShape3D, + const bool selectBottom) +{ + myHelper->SetSubShape( theShape3D ); + + SMESH_subMesh* mainSubMesh = myHelper->GetMesh()->GetSubMeshContaining( theShape3D ); + if ( !mainSubMesh ) return toSM( error(COMPERR_BAD_INPUT_MESH,"Null submesh of shape3D")); + // detect not-quad FACE sub-meshes of the 3D SHAPE list< SMESH_subMesh* > notQuadGeomSubMesh; list< SMESH_subMesh* > notQuadElemSubMesh; + list< SMESH_subMesh* > meshedSubMesh; int nbFaces = 0; // - SMESH_subMesh* mainSubMesh = myHelper->GetMesh()->GetSubMeshContaining( shape3D ); - if ( !mainSubMesh ) return error(COMPERR_BAD_INPUT_MESH,"Null submesh of shape3D"); - - // analyse face submeshes - SMESH_subMeshIteratorPtr smIt = mainSubMesh->getDependsOnIterator(false,false); + SMESH_subMesh* anyFaceSM = 0; + SMESH_subMeshIteratorPtr smIt = mainSubMesh->getDependsOnIterator(false,true); while ( smIt->more() ) { SMESH_subMesh* sm = smIt->next(); const TopoDS_Shape& face = sm->GetSubShape(); - if ( face.ShapeType() != TopAbs_FACE ) - continue; + if ( face.ShapeType() > TopAbs_FACE ) break; + else if ( face.ShapeType() < TopAbs_FACE ) continue; nbFaces++; + anyFaceSM = sm; - // is quadrangle face? + // is quadrangle FACE? list< TopoDS_Edge > orderedEdges; list< int > nbEdgesInWires; - TopoDS_Vertex V000; - int nbWires = GetOrderedEdges( TopoDS::Face( face ), - V000, orderedEdges, nbEdgesInWires ); + int nbWires = SMESH_Block::GetOrderedEdges( TopoDS::Face( face ), orderedEdges, + nbEdgesInWires ); if ( nbWires != 1 || nbEdgesInWires.front() != 4 ) notQuadGeomSubMesh.push_back( sm ); - // look for not quadrangle mesh elements - if ( SMESHDS_SubMesh* smDS = sm->GetSubMeshDS() ) { - bool hasNotQuad = false; - SMDS_ElemIteratorPtr eIt = smDS->GetElements(); - while ( eIt->more() && !hasNotQuad ) { - const SMDS_MeshElement* elem = eIt->next(); - if ( elem->GetType() == SMDSAbs_Face ) { - int nbNodes = elem->NbNodes(); - if ( elem->IsQuadratic() ) - nbNodes /= 2; - hasNotQuad = ( nbNodes != 4 ); - } - } - if ( hasNotQuad ) - notQuadElemSubMesh.push_back( sm ); - } - else { - return error(COMPERR_BAD_INPUT_MESH,TCom("Not meshed face #")<GetId()); - } - // check if a quadrangle face is meshed with a quadranglar grid - if ( notQuadGeomSubMesh.back() != sm && - notQuadElemSubMesh.back() != sm ) + // look for a not structured sub-mesh + if ( !sm->IsEmpty() ) { - // count nb edges on face sides - vector< int > nbEdges; - nbEdges.reserve( nbEdgesInWires.front() ); - for ( list< TopoDS_Edge >::iterator edge = orderedEdges.begin(); - edge != orderedEdges.end(); ++edge ) - { - if ( SMESHDS_SubMesh* smDS = meshDS->MeshElements( *edge )) - nbEdges.push_back ( smDS->NbElements() ); - else - nbEdges.push_back ( 0 ); - } - int nbQuads = sm->GetSubMeshDS()->NbElements(); - if ( nbEdges[0] * nbEdges[1] != nbQuads || - nbEdges[0] != nbEdges[2] || - nbEdges[1] != nbEdges[3] ) + meshedSubMesh.push_back( sm ); + if ( !myHelper->IsSameElemGeometry( sm->GetSubMeshDS(), SMDSGeom_QUADRANGLE ) || + !myHelper->IsStructured ( sm )) notQuadElemSubMesh.push_back( sm ); } } - // ---------------------------------------------------------------------- - // Analyse faces mesh and topology: choose the bottom submesh. - // If there are not quadrangle geom faces, they are top and bottom ones. - // Not quadrangle geom faces must be only on top and bottom. - // ---------------------------------------------------------------------- - - SMESH_subMesh * botSM = 0; - SMESH_subMesh * topSM = 0; - - int nbNotQuad = notQuadGeomSubMesh.size(); int nbNotQuadMeshed = notQuadElemSubMesh.size(); - bool hasNotQuad = ( nbNotQuad || nbNotQuadMeshed ); + int nbNotQuad = notQuadGeomSubMesh.size(); + bool hasNotQuad = ( nbNotQuad || nbNotQuadMeshed ); // detect bad cases - if ( nbNotQuad > 0 && nbNotQuad != 2 ) - return error(COMPERR_BAD_SHAPE, - TCom("More than 2 not quadrilateral faces: ") - < 2 ) - return error(COMPERR_BAD_INPUT_MESH, - TCom("More than 2 faces with not quadrangle elements: ") - < 2 || !thePrism.myBottom.IsNull() ) + { + // Issue 0020843 - one of side FACEs is quasi-quadrilateral (not 4 EDGEs). + // Remove from notQuadGeomSubMesh faces meshed with regular grid + int nbQuasiQuads = removeQuasiQuads( notQuadGeomSubMesh, myHelper, + TQuadrangleAlgo::instance(this,myHelper) ); + nbNotQuad -= nbQuasiQuads; + if ( nbNotQuad > 2 ) + return toSM( error(COMPERR_BAD_SHAPE, + TCom("More than 2 not quadrilateral faces: ") < 0 ) botSM = notQuadElemSubMesh.front(); else botSM = notQuadGeomSubMesh.front(); if ( nbNotQuadMeshed > 1 ) topSM = notQuadElemSubMesh.back(); else if ( nbNotQuad > 1 ) topSM = notQuadGeomSubMesh.back(); - } - // detect other bad cases - if ( nbNotQuad == 2 && nbNotQuadMeshed > 0 ) { - bool ok = false; - if ( nbNotQuadMeshed == 1 ) - ok = ( find( notQuadGeomSubMesh.begin(), - notQuadGeomSubMesh.end(), botSM ) != notQuadGeomSubMesh.end() ); - else - ok = ( notQuadGeomSubMesh == notQuadElemSubMesh ); - if ( !ok ) - return error(COMPERR_BAD_INPUT_MESH, "Side face meshed with not quadrangle elements"); + + if ( topSM == botSM ) { + if ( nbNotQuadMeshed > 1 ) topSM = notQuadElemSubMesh.front(); + else topSM = notQuadGeomSubMesh.front(); + } + + // detect mesh triangles on wall FACEs + if ( nbNotQuad == 2 && nbNotQuadMeshed > 0 ) { + bool ok = false; + if ( nbNotQuadMeshed == 1 ) + ok = ( find( notQuadGeomSubMesh.begin(), + notQuadGeomSubMesh.end(), botSM ) != notQuadGeomSubMesh.end() ); + else + ok = ( notQuadGeomSubMesh == notQuadElemSubMesh ); + if ( !ok ) + return toSM( error(COMPERR_BAD_INPUT_MESH, + "Side face meshed with not quadrangle elements")); + } } - myNotQuadOnTop = ( nbNotQuadMeshed > 1 ); - - // ---------------------------------------------------------- + thePrism.myNotQuadOnTop = ( nbNotQuadMeshed > 1 ); - if ( nbNotQuad == 0 ) // Standard block of 6 quadrangle faces ? + // use thePrism.myBottom + if ( !thePrism.myBottom.IsNull() ) { - // SMESH_Block will perform geometry analysis, we need just to find 2 - // connected vertices on top and bottom - - TopoDS_Vertex Vbot, Vtop; - if ( nbNotQuadMeshed > 0 ) // Look for vertices - { - TopTools_IndexedMapOfShape edgeMap; - TopExp::MapShapes( botSM->GetSubShape(), TopAbs_EDGE, edgeMap ); - // vertex 1 is any vertex of the bottom face - Vbot = TopExp::FirstVertex( TopoDS::Edge( edgeMap( 1 ))); - // vertex 2 is end vertex of edge sharing Vbot and not belonging to the bottom face - TopTools_ListIteratorOfListOfShape ancestIt = Mesh()->GetAncestors( Vbot ); - for ( ; Vtop.IsNull() && ancestIt.More(); ancestIt.Next() ) - { - const TopoDS_Shape & ancestor = ancestIt.Value(); - if ( ancestor.ShapeType() == TopAbs_EDGE && !edgeMap.FindIndex( ancestor )) - { - TopoDS_Vertex V1, V2; - TopExp::Vertices( TopoDS::Edge( ancestor ), V1, V2); - if ( Vbot.IsSame ( V1 )) Vtop = V2; - else if ( Vbot.IsSame ( V2 )) Vtop = V1; - // check that Vtop belongs to shape3D - TopExp_Explorer exp( shape3D, TopAbs_VERTEX ); - for ( ; exp.More(); exp.Next() ) - if ( Vtop.IsSame( exp.Current() )) - break; - if ( !exp.More() ) - Vtop.Nullify(); + if ( botSM ) { // <-- not quad geom or mesh on botSM + if ( ! botSM->GetSubShape().IsSame( thePrism.myBottom )) { + std::swap( botSM, topSM ); + if ( !botSM || ! botSM->GetSubShape().IsSame( thePrism.myBottom )) { + if ( !selectBottom ) + return toSM( error( COMPERR_BAD_INPUT_MESH, + "Incompatible non-structured sub-meshes")); + std::swap( botSM, topSM ); + thePrism.myBottom = TopoDS::Face( botSM->GetSubShape() ); } } } - // get shell from shape3D - TopoDS_Shell shell; - TopExp_Explorer exp( shape3D, TopAbs_SHELL ); - int nbShell = 0; - for ( ; exp.More(); exp.Next(), ++nbShell ) - shell = TopoDS::Shell( exp.Current() ); -// if ( nbShell != 1 ) -// RETURN_BAD_RESULT("There must be 1 shell in the block"); + else if ( !selectBottom ) { + botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); + } + } + if ( !botSM ) // find a proper bottom + { + bool savedSetErrorToSM = mySetErrorToSM; + mySetErrorToSM = false; // ingore errors in initPrism() - // Load geometry in SMESH_Block - if ( !SMESH_Block::FindBlockShapes( shell, Vbot, Vtop, myShapeIDMap )) { - if ( !hasNotQuad ) - return error(COMPERR_BAD_SHAPE, "Can't detect top and bottom of a prism"); + // search among meshed FACEs + list< SMESH_subMesh* >::iterator sm = meshedSubMesh.begin(); + for ( ; !botSM && sm != meshedSubMesh.end(); ++sm ) + { + thePrism.Clear(); + botSM = *sm; + thePrism.myBottom = TopoDS::Face( botSM->GetSubShape() ); + if ( !initPrism( thePrism, theShape3D, /*selectBottom=*/false )) + botSM = NULL; } - else { - if ( !botSM ) botSM = Mesh()->GetSubMeshContaining( myShapeIDMap( ID_BOT_FACE )); - if ( !topSM ) topSM = Mesh()->GetSubMeshContaining( myShapeIDMap( ID_TOP_FACE )); + // search among all FACEs + for ( TopExp_Explorer f( theShape3D, TopAbs_FACE ); !botSM && f.More(); f.Next() ) + { + int minNbFaces = 2 + myHelper->Count( f.Current(), TopAbs_EDGE, false); + if ( nbFaces < minNbFaces) continue; + thePrism.Clear(); + thePrism.myBottom = TopoDS::Face( f.Current() ); + botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); + if ( !initPrism( thePrism, theShape3D, /*selectBottom=*/false )) + botSM = NULL; } - - } // end Standard block of 6 quadrangle faces - // -------------------------------------------------------- - - // Here the top and bottom faces are found - if ( nbNotQuadMeshed == 2 ) // roughly check correspondence of horiz meshes - { -// SMESHDS_SubMesh* topSMDS = topSM->GetSubMeshDS(); -// SMESHDS_SubMesh* botSMDS = botSM->GetSubMeshDS(); -// if ( topSMDS->NbNodes() != botSMDS->NbNodes() || -// topSMDS->NbElements() != botSMDS->NbElements() ) -// RETURN_BAD_RESULT("Top mesh doesn't correspond to bottom one"); + mySetErrorToSM = savedSetErrorToSM; + return botSM ? true : toSM( error( COMPERR_BAD_SHAPE )); } - // --------------------------------------------------------- - // If there are not quadrangle geom faces, we emulate - // a block of 6 quadrangle faces. - // Load SMESH_Block with faces and edges geometry - // --------------------------------------------------------- - - // find vertex 000 - the one with smallest coordinates (for easy DEBUG :-) TopoDS_Vertex V000; double minVal = DBL_MAX, minX, val; @@ -992,64 +3091,136 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, } } + thePrism.myShape3D = theShape3D; + if ( thePrism.myBottom.IsNull() ) + thePrism.myBottom = TopoDS::Face( botSM->GetSubShape() ); + thePrism.myBottom.Orientation( myHelper->GetSubShapeOri( theShape3D, thePrism.myBottom )); + thePrism.myTop. Orientation( myHelper->GetSubShapeOri( theShape3D, thePrism.myTop )); + // Get ordered bottom edges - list< TopoDS_Edge > orderedEdges; - list< int > nbVertexInWires; - SMESH_Block::GetOrderedEdges( TopoDS::Face( botSM->GetSubShape().Reversed() ), - V000, orderedEdges, nbVertexInWires ); -// if ( nbVertexInWires.size() != 1 ) -// RETURN_BAD_RESULT("Wrong prism geometry"); - - // Get Wall faces corresponding to the ordered bottom edges - list< TopoDS_Face > wallFaces; - if ( !GetWallFaces( Mesh(), shape3D, botSM->GetSubShape(), orderedEdges, wallFaces)) - return error(COMPERR_BAD_SHAPE, "Can't find side faces"); + TopoDS_Face reverseBottom = // to have order of top EDGEs as in the top FACE + TopoDS::Face( thePrism.myBottom.Reversed() ); + SMESH_Block::GetOrderedEdges( reverseBottom, + thePrism.myBottomEdges, + thePrism.myNbEdgesInWires, V000 ); + + // Get Wall faces corresponding to the ordered bottom edges and the top FACE + if ( !getWallFaces( thePrism, nbFaces )) // it also sets thePrism.myTop + return false; //toSM( error(COMPERR_BAD_SHAPE, "Can't find side faces")); + + if ( topSM ) + { + if ( !thePrism.myTop.IsSame( topSM->GetSubShape() )) + return toSM( error + (notQuadGeomSubMesh.empty() ? COMPERR_BAD_INPUT_MESH : COMPERR_BAD_SHAPE, + "Non-quadrilateral faces are not opposite")); + + // check that the found top and bottom FACEs are opposite + list< TopoDS_Edge >::iterator edge = thePrism.myBottomEdges.begin(); + for ( ; edge != thePrism.myBottomEdges.end(); ++edge ) + if ( myHelper->IsSubShape( *edge, thePrism.myTop )) + return toSM( error + (notQuadGeomSubMesh.empty() ? COMPERR_BAD_INPUT_MESH : COMPERR_BAD_SHAPE, + "Non-quadrilateral faces are not opposite")); + } + + if ( thePrism.myBottomEdges.size() > thePrism.myWallQuads.size() ) + { + // composite bottom sides => set thePrism upside-down + thePrism.SetUpsideDown(); + } + + return true; +} + +//================================================================================ +/*! + * \brief Initialization. + * \param helper - helper loaded with mesh and 3D shape + * \param thePrism - a prism data + * \retval bool - false if a mesh or a shape are KO + */ +//================================================================================ + +bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, + const Prism_3D::TPrismTopo& thePrism) +{ + myHelper = helper; + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + SMESH_Mesh* mesh = myHelper->GetMesh(); + + if ( mySide ) { + delete mySide; mySide = 0; + } + vector< TSideFace* > sideFaces( NB_WALL_FACES, 0 ); + vector< pair< double, double> > params( NB_WALL_FACES ); + mySide = new TSideFace( *mesh, sideFaces, params ); + + + SMESH_Block::init(); + myShapeIDMap.Clear(); + myShapeIndex2ColumnMap.clear(); + + int wallFaceIds[ NB_WALL_FACES ] = { // to walk around a block + SMESH_Block::ID_Fx0z, SMESH_Block::ID_F1yz, + SMESH_Block::ID_Fx1z, SMESH_Block::ID_F0yz + }; + + myError = SMESH_ComputeError::New(); + + myNotQuadOnTop = thePrism.myNotQuadOnTop; // Find columns of wall nodes and calculate edges' lengths // -------------------------------------------------------- myParam2ColumnMaps.clear(); - myParam2ColumnMaps.resize( orderedEdges.size() ); // total nb edges + myParam2ColumnMaps.resize( thePrism.myBottomEdges.size() ); // total nb edges - int iE, nbEdges = nbVertexInWires.front(); // nb outer edges + size_t iE, nbEdges = thePrism.myNbEdgesInWires.front(); // nb outer edges vector< double > edgeLength( nbEdges ); - map< double, int > len2edgeMap; + multimap< double, int > len2edgeMap; - list< TopoDS_Edge >::iterator edgeIt = orderedEdges.begin(); - list< TopoDS_Face >::iterator faceIt = wallFaces.begin(); - for ( iE = 0; iE < nbEdges; ++edgeIt, ++faceIt ) - { - TParam2ColumnMap & faceColumns = myParam2ColumnMaps[ iE ]; - if ( !myHelper->LoadNodeColumns( faceColumns, *faceIt, *edgeIt, meshDS )) - return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ") - << "on a side face #" << MeshDS()->ShapeToIndex( *faceIt )); + // for each EDGE: either split into several parts, or join with several next EDGEs + vector nbSplitPerEdge( nbEdges, 0 ); + vector nbUnitePerEdge( nbEdges, 0 ); // -1 means "joined to a previous" - SHOWYXZ("\np1 F "<second.front() )); - SHOWYXZ("p2 F "<second.front() )); - SHOWYXZ("V First "<::const_iterator edgeIt = thePrism.myBottomEdges.begin(); + for ( iE = 0; iE < nbEdges; ++iE, ++edgeIt ) + { + TParam2ColumnMap & faceColumns = myParam2ColumnMaps[ iE ]; - if ( nbEdges < NB_WALL_FACES ) // fill map used to split faces + Prism_3D::TQuadList::const_iterator quad = thePrism.myWallQuads[ iE ].begin(); + for ( ; quad != thePrism.myWallQuads[ iE ].end(); ++quad ) { - SMESHDS_SubMesh* smDS = meshDS->MeshElements( *edgeIt); - if ( !smDS ) - return error(COMPERR_BAD_INPUT_MESH, TCom("Null submesh on the edge #") - << MeshDS()->ShapeToIndex( *edgeIt )); - // assure length uniqueness - edgeLength[ iE ] *= smDS->NbNodes() + edgeLength[ iE ] / ( 1000 + iE ); - len2edgeMap[ edgeLength[ iE ]] = iE; + const TopoDS_Edge& quadBot = (*quad)->side[ QUAD_BOTTOM_SIDE ].grid->Edge( 0 ); + if ( !myHelper->LoadNodeColumns( faceColumns, (*quad)->face, quadBot, meshDS )) + return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ") + << "on a side face #" << MeshDS()->ShapeToIndex( (*quad)->face )); } - ++iE; + SHOWYXZ("\np1 F " <second.front() )); + SHOWYXZ("p2 F " <second.front() )); + SHOWYXZ("V First "<LoadNodeColumns( faceColumns, *faceIt, *edgeIt, meshDS )) - return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ") - << "on a side face #" << MeshDS()->ShapeToIndex( *faceIt )); + + Prism_3D::TQuadList::const_iterator quad = thePrism.myWallQuads[ iE ].begin(); + for ( ; quad != thePrism.myWallQuads[ iE ].end(); ++quad ) + { + const TopoDS_Edge& quadBot = (*quad)->side[ QUAD_BOTTOM_SIDE ].grid->Edge( 0 ); + if ( !myHelper->LoadNodeColumns( faceColumns, (*quad)->face, quadBot, meshDS )) + return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ") + << "on a side face #" << MeshDS()->ShapeToIndex( (*quad)->face )); + } // edge columns int id = MeshDS()->ShapeToIndex( *edgeIt ); bool isForward = true; // meaningless for intenal wires @@ -1057,114 +3228,140 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, // columns for vertices // 1 const SMDS_MeshNode* n0 = faceColumns.begin()->second.front(); - id = n0->GetPosition()->GetShapeId(); + id = n0->getshapeId(); myShapeIndex2ColumnMap[ id ] = make_pair( & faceColumns, isForward ); // 2 const SMDS_MeshNode* n1 = faceColumns.rbegin()->second.front(); - id = n1->GetPosition()->GetShapeId(); + id = n1->getshapeId(); myShapeIndex2ColumnMap[ id ] = make_pair( & faceColumns, isForward ); -// SHOWYXZ("\np1 F "<second.front() )); -// SHOWYXZ("p2 F "<second.front() )); -// SHOWYXZ("V First "<second.front() )); + // SHOWYXZ("p2 F " <second.front() )); + // SHOWYXZ("V First "< iE2nbSplit; - if ( nbEdges != NB_WALL_FACES ) // define how to split + if ( nbSides != NB_WALL_FACES ) // define how to split { if ( len2edgeMap.size() != nbEdges ) RETURN_BAD_RESULT("Uniqueness of edge lengths not assured"); - map< double, int >::reverse_iterator maxLen_i = len2edgeMap.rbegin(); - map< double, int >::reverse_iterator midLen_i = ++len2edgeMap.rbegin(); + + multimap< double, int >::reverse_iterator maxLen_i = len2edgeMap.rbegin(); + multimap< double, int >::reverse_iterator midLen_i = ++len2edgeMap.rbegin(); + double maxLen = maxLen_i->first; double midLen = ( len2edgeMap.size() == 1 ) ? 0 : midLen_i->first; switch ( nbEdges ) { case 1: // 0-th edge is split into 4 parts - iE2nbSplit.insert( make_pair( 0, 4 )); break; + nbSplitPerEdge[ 0 ] = 4; + break; case 2: // either the longest edge is split into 3 parts, or both edges into halves if ( maxLen / 3 > midLen / 2 ) { - iE2nbSplit.insert( make_pair( maxLen_i->second, 3 )); + nbSplitPerEdge[ maxLen_i->second ] = 3; } else { - iE2nbSplit.insert( make_pair( maxLen_i->second, 2 )); - iE2nbSplit.insert( make_pair( midLen_i->second, 2 )); + nbSplitPerEdge[ maxLen_i->second ] = 2; + nbSplitPerEdge[ midLen_i->second ] = 2; } break; case 3: - // split longest into halves - iE2nbSplit.insert( make_pair( maxLen_i->second, 2 )); + if ( nbSides == 2 ) + // split longest into 3 parts + nbSplitPerEdge[ maxLen_i->second ] = 3; + else + // split longest into halves + nbSplitPerEdge[ maxLen_i->second ] = 2; } } - // Create TSideFace's - faceIt = wallFaces.begin(); - edgeIt = orderedEdges.begin(); - int iSide = 0; - for ( iE = 0; iE < nbEdges; ++edgeIt, ++faceIt ) - { - // split? - map< int, int >::iterator i_nb = iE2nbSplit.find( iE ); - if ( i_nb != iE2nbSplit.end() ) { - // split! - int nbSplit = i_nb->second; - vector< double > params; - splitParams( nbSplit, &myParam2ColumnMaps[ iE ], params ); - bool isForward = ( edgeIt->Orientation() == TopAbs_FORWARD ); - for ( int i = 0; i < nbSplit; ++i ) { - double f = ( isForward ? params[ i ] : params[ nbSplit - i-1 ]); - double l = ( isForward ? params[ i+1 ] : params[ nbSplit - i ]); - TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ], - *faceIt, *edgeIt, - &myParam2ColumnMaps[ iE ], f, l ); - mySide->SetComponent( iSide++, comp ); - } - } - else { - TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ], - *faceIt, *edgeIt, - &myParam2ColumnMaps[ iE ]); - mySide->SetComponent( iSide++, comp ); + } + else // **************************** Unite faces + { + int nbExraFaces = nbSides - 4; // nb of faces to fuse + for ( iE = 0; iE < nbEdges; ++iE ) + { + if ( nbUnitePerEdge[ iE ] < 0 ) + continue; + // look for already united faces + for ( int i = iE; i < iE + nbExraFaces; ++i ) + { + if ( nbUnitePerEdge[ i ] > 0 ) // a side including nbUnitePerEdge[i]+1 edge + nbExraFaces += nbUnitePerEdge[ i ]; + nbUnitePerEdge[ i ] = -1; } - ++iE; + nbUnitePerEdge[ iE ] = nbExraFaces; + break; } } - else { // **************************** Unite faces - // unite first faces - int nbExraFaces = nbEdges - 3; - int iSide = 0, iE; - double u0 = 0, sumLen = 0; - for ( iE = 0; iE < nbExraFaces; ++iE ) - sumLen += edgeLength[ iE ]; - - vector< TSideFace* > components( nbExraFaces ); - vector< pair< double, double> > params( nbExraFaces ); - faceIt = wallFaces.begin(); - edgeIt = orderedEdges.begin(); - for ( iE = 0; iE < nbExraFaces; ++edgeIt, ++faceIt ) + // Create TSideFace's + int iSide = 0; + list< TopoDS_Edge >::const_iterator botE = thePrism.myBottomEdges.begin(); + for ( iE = 0; iE < nbEdges; ++iE, ++botE ) + { + TFaceQuadStructPtr quad = thePrism.myWallQuads[ iE ].front(); + const int nbSplit = nbSplitPerEdge[ iE ]; + const int nbExraFaces = nbUnitePerEdge[ iE ] + 1; + if ( nbSplit > 0 ) // split { - components[ iE ] = new TSideFace( myHelper, wallFaceIds[ iSide ], - *faceIt, *edgeIt, - &myParam2ColumnMaps[ iE ]); - double u1 = u0 + edgeLength[ iE ] / sumLen; - params[ iE ] = make_pair( u0 , u1 ); - u0 = u1; - ++iE; + vector< double > params; + splitParams( nbSplit, &myParam2ColumnMaps[ iE ], params ); + const bool isForward = + StdMeshers_PrismAsBlock::IsForwardEdge( myHelper->GetMeshDS(), + myParam2ColumnMaps[iE], + *botE, SMESH_Block::ID_Fx0z ); + for ( int i = 0; i < nbSplit; ++i ) { + double f = ( isForward ? params[ i ] : params[ nbSplit - i-1 ]); + double l = ( isForward ? params[ i+1 ] : params[ nbSplit - i ]); + TSideFace* comp = new TSideFace( *mesh, wallFaceIds[ iSide ], + thePrism.myWallQuads[ iE ], *botE, + &myParam2ColumnMaps[ iE ], f, l ); + mySide->SetComponent( iSide++, comp ); + } } - mySide->SetComponent( iSide++, new TSideFace( components, params )); - - // fill the rest faces - for ( ; iE < nbEdges; ++faceIt, ++edgeIt ) + else if ( nbExraFaces > 1 ) // unite + { + double u0 = 0, sumLen = 0; + for ( int i = iE; i < iE + nbExraFaces; ++i ) + sumLen += edgeLength[ i ]; + + vector< TSideFace* > components( nbExraFaces ); + vector< pair< double, double> > params( nbExraFaces ); + bool endReached = false; + for ( int i = 0; i < nbExraFaces; ++i, ++botE, ++iE ) + { + if ( iE == nbEdges ) + { + endReached = true; + botE = thePrism.myBottomEdges.begin(); + iE = 0; + } + components[ i ] = new TSideFace( *mesh, wallFaceIds[ iSide ], + thePrism.myWallQuads[ iE ], *botE, + &myParam2ColumnMaps[ iE ]); + double u1 = u0 + edgeLength[ iE ] / sumLen; + params[ i ] = make_pair( u0 , u1 ); + u0 = u1; + } + TSideFace* comp = new TSideFace( *mesh, components, params ); + mySide->SetComponent( iSide++, comp ); + if ( endReached ) + break; + --iE; // for increment in an external loop on iE + --botE; + } + else if ( nbExraFaces < 0 ) // skip already united face { - TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ], - *faceIt, *edgeIt, + } + else // use as is + { + TSideFace* comp = new TSideFace( *mesh, wallFaceIds[ iSide ], + thePrism.myWallQuads[ iE ], *botE, &myParam2ColumnMaps[ iE ]); mySide->SetComponent( iSide++, comp ); - ++iE; } } @@ -1172,9 +3369,6 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, // Fill geometry fields of SMESH_Block // ------------------------------------ - TopoDS_Face botF = TopoDS::Face( botSM->GetSubShape() ); - TopoDS_Face topF = TopoDS::Face( topSM->GetSubShape() ); - vector< int > botEdgeIdVec; SMESH_Block::GetFaceEdgesIDs( ID_BOT_FACE, botEdgeIdVec ); @@ -1187,7 +3381,7 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, TSideFace * sideFace = mySide->GetComponent( iF ); if ( !sideFace ) RETURN_BAD_RESULT("NULL TSideFace"); - int fID = sideFace->FaceID(); + int fID = sideFace->FaceID(); // in-block ID // fill myShapeIDMap if ( sideFace->InsertSubShapes( myShapeIDMap ) != 8 && @@ -1231,23 +3425,26 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, // pcurves on horizontal faces for ( iE = 0; iE < NB_WALL_FACES; ++iE ) { if ( edgeIdVec[ BOTTOM_EDGE ] == botEdgeIdVec[ iE ] ) { - botPcurves[ iE ] = sideFace->HorizPCurve( false, botF ); - topPcurves[ iE ] = sideFace->HorizPCurve( true, topF ); + botPcurves[ iE ] = sideFace->HorizPCurve( false, thePrism.myBottom ); + topPcurves[ iE ] = sideFace->HorizPCurve( true, thePrism.myTop ); break; } } + //sideFace->dumpNodes( 4 ); // debug } // horizontal faces geometry { SMESH_Block::TFace& tFace = myFace[ ID_BOT_FACE - ID_FirstF ]; - tFace.Set( ID_BOT_FACE, new BRepAdaptor_Surface( botF ), botPcurves, isForward ); - SMESH_Block::Insert( botF, ID_BOT_FACE, myShapeIDMap ); + tFace.Set( ID_BOT_FACE, new BRepAdaptor_Surface( thePrism.myBottom ), botPcurves, isForward ); + SMESH_Block::Insert( thePrism.myBottom, ID_BOT_FACE, myShapeIDMap ); } { SMESH_Block::TFace& tFace = myFace[ ID_TOP_FACE - ID_FirstF ]; - tFace.Set( ID_TOP_FACE, new BRepAdaptor_Surface( topF ), topPcurves, isForward ); - SMESH_Block::Insert( topF, ID_TOP_FACE, myShapeIDMap ); + tFace.Set( ID_TOP_FACE, new BRepAdaptor_Surface( thePrism.myTop ), topPcurves, isForward ); + SMESH_Block::Insert( thePrism.myTop, ID_TOP_FACE, myShapeIDMap ); } + //faceGridToPythonDump( SMESH_Block::ID_Fxy0, 50 ); + //faceGridToPythonDump( SMESH_Block::ID_Fxy1 ); // Fill map ShapeIndex to TParam2ColumnMap // ---------------------------------------- @@ -1270,24 +3467,35 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, // columns for vertices const SMDS_MeshNode* n0 = cols->begin()->second.front(); - id = n0->GetPosition()->GetShapeId(); + id = n0->getshapeId(); myShapeIndex2ColumnMap[ id ] = make_pair( cols, isForward ); const SMDS_MeshNode* n1 = cols->rbegin()->second.front(); - id = n1->GetPosition()->GetShapeId(); + id = n1->getshapeId(); myShapeIndex2ColumnMap[ id ] = make_pair( cols, !isForward ); } } -// gp_XYZ testPar(0.25, 0.25, 0), testCoord; -// if ( !FacePoint( ID_BOT_FACE, testPar, testCoord )) -// RETURN_BAD_RESULT("TEST FacePoint() FAILED"); -// SHOWYXZ("IN TEST PARAM" , testPar); -// SHOWYXZ("OUT TEST CORD" , testCoord); -// if ( !ComputeParameters( testCoord, testPar , ID_BOT_FACE)) -// RETURN_BAD_RESULT("TEST ComputeParameters() FAILED"); -// SHOWYXZ("OUT TEST PARAM" , testPar); - +// #define SHOWYXZ(msg, xyz) { \ +// gp_Pnt p (xyz); \ +// cout << msg << " ("<< p.X() << "; " <GetPosition()->GetShapeId(); + int sID = node->getshapeId(); map >::const_iterator col_frw = myShapeIndex2ColumnMap.find( sID ); @@ -1312,7 +3520,93 @@ const TNodeColumn* StdMeshers_PrismAsBlock::GetNodeColumn(const SMDS_MeshNode* n if ( u_col->second[ 0 ] == node ) return & u_col->second; } - return 0; + return 0; +} + +//======================================================================= +//function : GetLayersTransformation +//purpose : Return transformations to get coordinates of nodes of each layer +// by nodes of the bottom. Layer is a set of nodes at a certain step +// from bottom to top. +// Transformation to get top node from bottom ones is computed +// only if the top FACE is not meshed. +//======================================================================= + +bool StdMeshers_PrismAsBlock::GetLayersTransformation(vector & trsf, + const Prism_3D::TPrismTopo& prism) const +{ + const bool itTopMeshed = !SubMesh( ID_BOT_FACE )->IsEmpty(); + const int zSize = VerticalSize(); + if ( zSize < 3 && !itTopMeshed ) return true; + trsf.resize( zSize - 1 ); + + // Select some node columns by which we will define coordinate system of layers + + vector< const TNodeColumn* > columns; + { + bool isReverse; + list< TopoDS_Edge >::const_iterator edgeIt = prism.myBottomEdges.begin(); + for ( int iE = 0; iE < prism.myNbEdgesInWires.front(); ++iE, ++edgeIt ) + { + if ( SMESH_Algo::isDegenerated( *edgeIt )) continue; + const TParam2ColumnMap* u2colMap = + GetParam2ColumnMap( MeshDS()->ShapeToIndex( *edgeIt ), isReverse ); + if ( !u2colMap ) return false; + double f = u2colMap->begin()->first, l = u2colMap->rbegin()->first; + //isReverse = ( edgeIt->Orientation() == TopAbs_REVERSED ); + //if ( isReverse ) swap ( f, l ); -- u2colMap takes orientation into account + const int nbCol = 5; + for ( int i = 0; i < nbCol; ++i ) + { + double u = f + i/double(nbCol) * ( l - f ); + const TNodeColumn* col = & getColumn( u2colMap, u )->second; + if ( columns.empty() || col != columns.back() ) + columns.push_back( col ); + } + } + } + + // Find tolerance to check transformations + + double tol2; + { + Bnd_B3d bndBox; + for ( int i = 0; i < columns.size(); ++i ) + bndBox.Add( gpXYZ( columns[i]->front() )); + tol2 = bndBox.SquareExtent() * 1e-5; + } + + // Compute transformations + + int xCol = -1; + gp_Trsf fromCsZ, toCs0; + gp_Ax3 cs0 = getLayerCoordSys(0, columns, xCol ); + //double dist0 = cs0.Location().Distance( gpXYZ( (*columns[0])[0])); + toCs0.SetTransformation( cs0 ); + for ( int z = 1; z < zSize; ++z ) + { + gp_Ax3 csZ = getLayerCoordSys(z, columns, xCol ); + //double distZ = csZ.Location().Distance( gpXYZ( (*columns[0])[z])); + fromCsZ.SetTransformation( csZ ); + fromCsZ.Invert(); + gp_Trsf& t = trsf[ z-1 ]; + t = fromCsZ * toCs0; + //t.SetScaleFactor( distZ/dist0 ); - it does not work properly, wrong base point + + // check a transformation + for ( int i = 0; i < columns.size(); ++i ) + { + gp_Pnt p0 = gpXYZ( (*columns[i])[0] ); + gp_Pnt pz = gpXYZ( (*columns[i])[z] ); + t.Transforms( p0.ChangeCoord() ); + if ( p0.SquareDistance( pz ) > tol2 ) + { + t = gp_Trsf(); + return ( z == zSize - 1 ); // OK if fails only botton->top trsf + } + } + } + return true; } //================================================================================ @@ -1322,7 +3616,7 @@ const TNodeColumn* StdMeshers_PrismAsBlock::GetNodeColumn(const SMDS_MeshNode* n * \param columnsMap - node columns map of side face * \param bottomEdge - the bootom edge * \param sideFaceID - side face in-block ID - * \retval bool - true if orientation coinside with in-block froward orientation + * \retval bool - true if orientation coinside with in-block forward orientation */ //================================================================================ @@ -1332,13 +3626,13 @@ bool StdMeshers_PrismAsBlock::IsForwardEdge(SMESHDS_Mesh* meshDS, const int sideFaceID) { bool isForward = false; - if ( TAssocTool::IsClosedEdge( bottomEdge )) + if ( SMESH_MesherHelper::IsClosedEdge( bottomEdge )) { isForward = ( bottomEdge.Orientation() == TopAbs_FORWARD ); } else { - const TNodeColumn& firstCol = columnsMap.begin()->second; + const TNodeColumn& firstCol = columnsMap.begin()->second; const SMDS_MeshNode* bottomNode = firstCol[0]; TopoDS_Shape firstVertex = SMESH_MesherHelper::GetSubShapeByNode( bottomNode, meshDS ); isForward = ( firstVertex.IsSame( TopExp::FirstVertex( bottomEdge, true ))); @@ -1349,94 +3643,143 @@ bool StdMeshers_PrismAsBlock::IsForwardEdge(SMESHDS_Mesh* meshDS, return isForward; } -//================================================================================ - /*! - * \brief Find wall faces by bottom edges - * \param mesh - the mesh - * \param mainShape - the prism - * \param bottomFace - the bottom face - * \param bottomEdges - edges bounding the bottom face - * \param wallFaces - faces list to fill in - */ -//================================================================================ +//======================================================================= +//function : faceGridToPythonDump +//purpose : Prints a script creating a normal grid on the prism side +//======================================================================= -bool StdMeshers_PrismAsBlock::GetWallFaces( SMESH_Mesh* mesh, - const TopoDS_Shape & mainShape, - const TopoDS_Shape & bottomFace, - const std::list< TopoDS_Edge >& bottomEdges, - std::list< TopoDS_Face >& wallFaces) +void StdMeshers_PrismAsBlock::faceGridToPythonDump(const SMESH_Block::TShapeID face, + const int nb) { - wallFaces.clear(); - - TopTools_IndexedMapOfShape faceMap; - TopExp::MapShapes( mainShape, TopAbs_FACE, faceMap ); - - list< TopoDS_Edge >::const_iterator edge = bottomEdges.begin(); - for ( ; edge != bottomEdges.end(); ++edge ) +#ifdef _DEBUG_ + gp_XYZ pOnF[6] = { gp_XYZ(0,0,0), gp_XYZ(0,0,1), + gp_XYZ(0,0,0), gp_XYZ(0,1,0), + gp_XYZ(0,0,0), gp_XYZ(1,0,0) }; + gp_XYZ p2; + cout << "mesh = smesh.Mesh( 'Face " << face << "')" << endl; + SMESH_Block::TFace& f = myFace[ face - ID_FirstF ]; + gp_XYZ params = pOnF[ face - ID_FirstF ]; + //const int nb = 10; // nb face rows + for ( int j = 0; j <= nb; ++j ) { - TopTools_ListIteratorOfListOfShape ancestIt = mesh->GetAncestors( *edge ); - for ( ; ancestIt.More(); ancestIt.Next() ) + params.SetCoord( f.GetVInd(), double( j )/ nb ); + for ( int i = 0; i <= nb; ++i ) { - const TopoDS_Shape& ancestor = ancestIt.Value(); - if ( ancestor.ShapeType() == TopAbs_FACE && // face - !bottomFace.IsSame( ancestor ) && // not bottom - faceMap.FindIndex( ancestor )) // belongs to the prism - { - wallFaces.push_back( TopoDS::Face( ancestor )); - break; - } + params.SetCoord( f.GetUInd(), double( i )/ nb ); + gp_XYZ p = f.Point( params ); + gp_XY uv = f.GetUV( params ); + cout << "mesh.AddNode( " << p.X() << ", " << p.Y() << ", " << p.Z() << " )" + << " # " << 1 + i + j * ( nb + 1 ) + << " ( " << i << ", " << j << " ) " + << " UV( " << uv.X() << ", " << uv.Y() << " )" << endl; + ShellPoint( params, p2 ); + double dist = ( p2 - p ).Modulus(); + if ( dist > 1e-4 ) + cout << "#### dist from ShellPoint " << dist + << " (" << p2.X() << ", " << p2.Y() << ", " << p2.Z() << " ) " << endl; } } - return ( wallFaces.size() == bottomEdges.size() ); + for ( int j = 0; j < nb; ++j ) + for ( int i = 0; i < nb; ++i ) + { + int n = 1 + i + j * ( nb + 1 ); + cout << "mesh.AddFace([ " + << n << ", " << n+1 << ", " + << n+nb+2 << ", " << n+nb+1 << "]) " << endl; + } + +#endif } //================================================================================ /*! * \brief Constructor * \param faceID - in-block ID - * \param face - geom face + * \param face - geom FACE + * \param baseEdge - EDGE proreply oriented in the bottom EDGE !!! * \param columnsMap - map of node columns * \param first - first normalized param * \param last - last normalized param */ //================================================================================ -StdMeshers_PrismAsBlock::TSideFace::TSideFace(SMESH_MesherHelper* helper, - const int faceID, - const TopoDS_Face& face, - const TopoDS_Edge& baseEdge, - TParam2ColumnMap* columnsMap, - const double first, - const double last): +StdMeshers_PrismAsBlock::TSideFace::TSideFace(SMESH_Mesh& mesh, + const int faceID, + const Prism_3D::TQuadList& quadList, + const TopoDS_Edge& baseEdge, + TParam2ColumnMap* columnsMap, + const double first, + const double last): myID( faceID ), myParamToColumnMap( columnsMap ), - myBaseEdge( baseEdge ), - myHelper( helper ) + myHelper( mesh ) { - mySurface.Initialize( face ); myParams.resize( 1 ); myParams[ 0 ] = make_pair( first, last ); - myIsForward = StdMeshers_PrismAsBlock::IsForwardEdge( myHelper->GetMeshDS(), - *myParamToColumnMap, - myBaseEdge, myID ); + mySurface = PSurface( new BRepAdaptor_Surface( quadList.front()->face )); + myBaseEdge = baseEdge; + myIsForward = StdMeshers_PrismAsBlock::IsForwardEdge( myHelper.GetMeshDS(), + *myParamToColumnMap, + myBaseEdge, myID ); + myHelper.SetSubShape( quadList.front()->face ); + + if ( quadList.size() > 1 ) // side is vertically composite + { + // fill myShapeID2Surf map to enable finding a right surface by any sub-shape ID + + SMESHDS_Mesh* meshDS = myHelper.GetMeshDS(); + + TopTools_IndexedDataMapOfShapeListOfShape subToFaces; + Prism_3D::TQuadList::const_iterator quad = quadList.begin(); + for ( ; quad != quadList.end(); ++quad ) + { + const TopoDS_Face& face = (*quad)->face; + TopExp::MapShapesAndAncestors( face, TopAbs_VERTEX, TopAbs_FACE, subToFaces ); + TopExp::MapShapesAndAncestors( face, TopAbs_EDGE, TopAbs_FACE, subToFaces ); + myShapeID2Surf.insert( make_pair( meshDS->ShapeToIndex( face ), + PSurface( new BRepAdaptor_Surface( face )))); + } + for ( int i = 1; i <= subToFaces.Extent(); ++i ) + { + const TopoDS_Shape& sub = subToFaces.FindKey( i ); + TopTools_ListOfShape& faces = subToFaces( i ); + int subID = meshDS->ShapeToIndex( sub ); + int faceID = meshDS->ShapeToIndex( faces.First() ); + myShapeID2Surf.insert ( make_pair( subID, myShapeID2Surf[ faceID ])); + } + } } //================================================================================ /*! - * \brief Constructor of complex side face + * \brief Constructor of a complex side face */ //================================================================================ StdMeshers_PrismAsBlock::TSideFace:: -TSideFace(const vector< TSideFace* >& components, +TSideFace(SMESH_Mesh& mesh, + const vector< TSideFace* >& components, const vector< pair< double, double> > & params) :myID( components[0] ? components[0]->myID : 0 ), myParamToColumnMap( 0 ), myParams( params ), myIsForward( true ), myComponents( components ), - myHelper( components[0] ? components[0]->myHelper : 0 ) -{} + myHelper( mesh ) +{ + if ( myID == ID_Fx1z || myID == ID_F0yz ) + { + // reverse components + std::reverse( myComponents.begin(), myComponents.end() ); + std::reverse( myParams.begin(), myParams.end() ); + for ( size_t i = 0; i < myParams.size(); ++i ) + { + const double f = myParams[i].first; + const double l = myParams[i].second; + myParams[i] = make_pair( 1. - l, 1. - f ); + } + } +} //================================================================================ /*! * \brief Copy constructor @@ -1444,17 +3787,17 @@ TSideFace(const vector< TSideFace* >& components, */ //================================================================================ -StdMeshers_PrismAsBlock::TSideFace::TSideFace( const TSideFace& other ) +StdMeshers_PrismAsBlock::TSideFace::TSideFace( const TSideFace& other ): + myID ( other.myID ), + myParamToColumnMap ( other.myParamToColumnMap ), + mySurface ( other.mySurface ), + myBaseEdge ( other.myBaseEdge ), + myShapeID2Surf ( other.myShapeID2Surf ), + myParams ( other.myParams ), + myIsForward ( other.myIsForward ), + myComponents ( other.myComponents.size() ), + myHelper ( *other.myHelper.GetMesh() ) { - myID = other.myID; - mySurface = other.mySurface; - myBaseEdge = other.myBaseEdge; - myParams = other.myParams; - myIsForward = other.myIsForward; - myHelper = other.myHelper; - myParamToColumnMap = other.myParamToColumnMap; - - myComponents.resize( other.myComponents.size()); for (int i = 0 ; i < myComponents.size(); ++i ) myComponents[ i ] = new TSideFace( *other.myComponents[ i ]); } @@ -1610,8 +3953,6 @@ double StdMeshers_PrismAsBlock::TSideFace::GetColumns(const double U, r = 0.5; } else { -// if ( !myIsForward ) -// std::swap( col1, col2 ); double uf = col1->first; double ul = col2->first; r = ( u - uf ) / ( ul - uf ); @@ -1619,6 +3960,52 @@ double StdMeshers_PrismAsBlock::TSideFace::GetColumns(const double U, return r; } +//================================================================================ +/*! + * \brief Return all nodes at a given height together with their normalized parameters + * \param [in] Z - the height of interest + * \param [out] nodes - map of parameter to node + */ +//================================================================================ + +void StdMeshers_PrismAsBlock:: +TSideFace::GetNodesAtZ(const int Z, + map& nodes ) const +{ + if ( !myComponents.empty() ) + { + double u0 = 0.; + for ( size_t i = 0; i < myComponents.size(); ++i ) + { + map nn; + myComponents[i]->GetNodesAtZ( Z, nn ); + map::iterator u2n = nn.begin(); + if ( !nodes.empty() && nodes.rbegin()->second == u2n->second ) + ++u2n; + const double uRange = myParams[i].second - myParams[i].first; + for ( ; u2n != nn.end(); ++u2n ) + nodes.insert( nodes.end(), make_pair( u0 + uRange * u2n->first, u2n->second )); + u0 += uRange; + } + } + else + { + double f = myParams[0].first, l = myParams[0].second; + if ( !myIsForward ) + std::swap( f, l ); + const double uRange = l - f; + if ( Abs( uRange ) < std::numeric_limits::min() ) + return; + TParam2ColumnIt u2col = getColumn( myParamToColumnMap, myParams[0].first + 1e-3 ); + for ( ; u2col != myParamToColumnMap->end(); ++u2col ) + if ( u2col->first > myParams[0].second + 1e-9 ) + break; + else + nodes.insert( nodes.end(), + make_pair( ( u2col->first - f ) / uRange, u2col->second[ Z ] )); + } +} + //================================================================================ /*! * \brief Return coordinates by normalized params @@ -1631,8 +4018,8 @@ double StdMeshers_PrismAsBlock::TSideFace::GetColumns(const double U, gp_Pnt StdMeshers_PrismAsBlock::TSideFace::Value(const Standard_Real U, const Standard_Real V) const { - double u; if ( !myComponents.empty() ) { + double u; TSideFace * comp = GetComponent(U,u); return comp->Value( u, V ); } @@ -1640,26 +4027,97 @@ gp_Pnt StdMeshers_PrismAsBlock::TSideFace::Value(const Standard_Real U, TParam2ColumnIt u_col1, u_col2; double vR, hR = GetColumns( U, u_col1, u_col2 ); - const SMDS_MeshNode* n1 = 0; - const SMDS_MeshNode* n2 = 0; - const SMDS_MeshNode* n3 = 0; - const SMDS_MeshNode* n4 = 0; - gp_XYZ pnt; + const SMDS_MeshNode* nn[4]; - vR = getRAndNodes( & u_col1->second, V, n1, n2 ); - vR = getRAndNodes( & u_col2->second, V, n3, n4 ); - - gp_XY uv1 = myHelper->GetNodeUV( mySurface.Face(), n1, n4); - gp_XY uv2 = myHelper->GetNodeUV( mySurface.Face(), n2, n3); + // BEGIN issue 0020680: Bad cell created by Radial prism in center of torus + // Workaround for a wrongly located point returned by mySurface.Value() for + // UV located near boundary of BSpline surface. + // To bypass the problem, we take point from 3D curve of EDGE. + // It solves pb of the bloc_fiss_new.py + const double tol = 1e-3; + if ( V < tol || V+tol >= 1. ) + { + nn[0] = V < tol ? u_col1->second.front() : u_col1->second.back(); + nn[2] = V < tol ? u_col2->second.front() : u_col2->second.back(); + TopoDS_Edge edge; + if ( V < tol ) + { + edge = myBaseEdge; + } + else + { + TopoDS_Shape s = myHelper.GetSubShapeByNode( nn[0], myHelper.GetMeshDS() ); + if ( s.ShapeType() != TopAbs_EDGE ) + s = myHelper.GetSubShapeByNode( nn[2], myHelper.GetMeshDS() ); + if ( !s.IsNull() && s.ShapeType() == TopAbs_EDGE ) + edge = TopoDS::Edge( s ); + } + if ( !edge.IsNull() ) + { + double u1 = myHelper.GetNodeU( edge, nn[0], nn[2] ); + double u3 = myHelper.GetNodeU( edge, nn[2], nn[0] ); + double u = u1 * ( 1 - hR ) + u3 * hR; + TopLoc_Location loc; double f,l; + Handle(Geom_Curve) curve = BRep_Tool::Curve( edge,loc,f,l ); + return curve->Value( u ).Transformed( loc ); + } + } + // END issue 0020680: Bad cell created by Radial prism in center of torus + + vR = getRAndNodes( & u_col1->second, V, nn[0], nn[1] ); + vR = getRAndNodes( & u_col2->second, V, nn[2], nn[3] ); + + if ( !myShapeID2Surf.empty() ) // side is vertically composite + { + // find a FACE on which the 4 nodes lie + TSideFace* me = (TSideFace*) this; + int notFaceID1 = 0, notFaceID2 = 0; + for ( int i = 0; i < 4; ++i ) + if ( nn[i]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) // node on FACE + { + me->mySurface = me->myShapeID2Surf[ nn[i]->getshapeId() ]; + notFaceID2 = 0; + break; + } + else if ( notFaceID1 == 0 ) // node on EDGE or VERTEX + { + me->mySurface = me->myShapeID2Surf[ nn[i]->getshapeId() ]; + notFaceID1 = nn[i]->getshapeId(); + } + else if ( notFaceID1 != nn[i]->getshapeId() ) // node on other EDGE or VERTEX + { + if ( mySurface != me->myShapeID2Surf[ nn[i]->getshapeId() ]) + notFaceID2 = nn[i]->getshapeId(); + } + if ( notFaceID2 ) // no nodes of FACE and nodes are on different FACEs + { + SMESHDS_Mesh* meshDS = myHelper.GetMeshDS(); + TopoDS_Shape face = myHelper.GetCommonAncestor( meshDS->IndexToShape( notFaceID1 ), + meshDS->IndexToShape( notFaceID2 ), + *myHelper.GetMesh(), + TopAbs_FACE ); + if ( face.IsNull() ) + throw SALOME_Exception("StdMeshers_PrismAsBlock::TSideFace::Value() face.IsNull()"); + int faceID = meshDS->ShapeToIndex( face ); + me->mySurface = me->myShapeID2Surf[ faceID ]; + if ( !mySurface ) + throw SALOME_Exception("StdMeshers_PrismAsBlock::TSideFace::Value() !mySurface"); + } + } + ((TSideFace*) this)->myHelper.SetSubShape( mySurface->Face() ); + + gp_XY uv1 = myHelper.GetNodeUV( mySurface->Face(), nn[0], nn[2]); + gp_XY uv2 = myHelper.GetNodeUV( mySurface->Face(), nn[1], nn[3]); gp_XY uv12 = uv1 * ( 1 - vR ) + uv2 * vR; - gp_XY uv3 = myHelper->GetNodeUV( mySurface.Face(), n3, n2); - gp_XY uv4 = myHelper->GetNodeUV( mySurface.Face(), n4, n1); + gp_XY uv3 = myHelper.GetNodeUV( mySurface->Face(), nn[2], nn[0]); + gp_XY uv4 = myHelper.GetNodeUV( mySurface->Face(), nn[3], nn[1]); gp_XY uv34 = uv3 * ( 1 - vR ) + uv4 * vR; gp_XY uv = uv12 * ( 1 - hR ) + uv34 * hR; - - return mySurface.Value( uv.X(), uv.Y() ); + + gp_Pnt p = mySurface->Value( uv.X(), uv.Y() ); + return p; } @@ -1682,7 +4140,7 @@ TopoDS_Edge StdMeshers_PrismAsBlock::TSideFace::GetEdge(const int iEdge) const } TopoDS_Shape edge; const SMDS_MeshNode* node = 0; - SMESHDS_Mesh * meshDS = myHelper->GetMesh()->GetMeshDS(); + SMESHDS_Mesh * meshDS = myHelper.GetMesh()->GetMeshDS(); TNodeColumn* column; switch ( iEdge ) { @@ -1690,7 +4148,7 @@ TopoDS_Edge StdMeshers_PrismAsBlock::TSideFace::GetEdge(const int iEdge) const case BOTTOM_EDGE: column = & (( ++myParamToColumnMap->begin())->second ); node = ( iEdge == TOP_EDGE ) ? column->back() : column->front(); - edge = myHelper->GetSubShapeByNode ( node, meshDS ); + edge = myHelper.GetSubShapeByNode ( node, meshDS ); if ( edge.ShapeType() == TopAbs_VERTEX ) { column = & ( myParamToColumnMap->begin()->second ); node = ( iEdge == TOP_EDGE ) ? column->back() : column->front(); @@ -1705,7 +4163,7 @@ TopoDS_Edge StdMeshers_PrismAsBlock::TSideFace::GetEdge(const int iEdge) const else column = & ( myParamToColumnMap->begin()->second ); if ( column->size() > 0 ) - edge = myHelper->GetSubShapeByNode( (*column)[ 1 ], meshDS ); + edge = myHelper.GetSubShapeByNode( (*column)[ 1 ], meshDS ); if ( edge.IsNull() || edge.ShapeType() == TopAbs_VERTEX ) node = column->front(); break; @@ -1717,28 +4175,21 @@ TopoDS_Edge StdMeshers_PrismAsBlock::TSideFace::GetEdge(const int iEdge) const // find edge by 2 vertices TopoDS_Shape V1 = edge; - TopoDS_Shape V2 = myHelper->GetSubShapeByNode( node, meshDS ); - if ( V2.ShapeType() == TopAbs_VERTEX && !V2.IsSame( V1 )) + TopoDS_Shape V2 = myHelper.GetSubShapeByNode( node, meshDS ); + if ( !V2.IsNull() && V2.ShapeType() == TopAbs_VERTEX && !V2.IsSame( V1 )) { - TopTools_ListIteratorOfListOfShape ancestIt = - myHelper->GetMesh()->GetAncestors( V1 ); - for ( ; ancestIt.More(); ancestIt.Next() ) - { - const TopoDS_Shape & ancestor = ancestIt.Value(); - if ( ancestor.ShapeType() == TopAbs_EDGE ) - for ( TopExp_Explorer e( ancestor, TopAbs_VERTEX ); e.More(); e.Next() ) - if ( V2.IsSame( e.Current() )) - return TopoDS::Edge( ancestor ); - } + TopoDS_Shape ancestor = myHelper.GetCommonAncestor( V1, V2, *myHelper.GetMesh(), TopAbs_EDGE); + if ( !ancestor.IsNull() ) + return TopoDS::Edge( ancestor ); } return TopoDS_Edge(); } //================================================================================ /*! - * \brief Fill block subshapes + * \brief Fill block sub-shapes * \param shapeMap - map to fill in - * \retval int - nb inserted subshapes + * \retval int - nb inserted sub-shapes */ //================================================================================ @@ -1767,8 +4218,8 @@ int StdMeshers_PrismAsBlock::TSideFace::InsertSubShapes(TBlockShapes& shapeMap) GetColumns(0, col1, col2 ); const SMDS_MeshNode* node0 = col1->second.front(); const SMDS_MeshNode* node1 = col1->second.back(); - TopoDS_Shape v0 = myHelper->GetSubShapeByNode( node0, myHelper->GetMeshDS()); - TopoDS_Shape v1 = myHelper->GetSubShapeByNode( node1, myHelper->GetMeshDS()); + TopoDS_Shape v0 = myHelper.GetSubShapeByNode( node0, myHelper.GetMeshDS()); + TopoDS_Shape v1 = myHelper.GetSubShapeByNode( node1, myHelper.GetMeshDS()); if ( v0.ShapeType() == TopAbs_VERTEX ) { nbInserted += SMESH_Block::Insert( v0, vertIdVec[ 0 ], shapeMap); } @@ -1781,8 +4232,8 @@ int StdMeshers_PrismAsBlock::TSideFace::InsertSubShapes(TBlockShapes& shapeMap) GetColumns(1, col1, col2 ); node0 = col2->second.front(); node1 = col2->second.back(); - v0 = myHelper->GetSubShapeByNode( node0, myHelper->GetMeshDS()); - v1 = myHelper->GetSubShapeByNode( node1, myHelper->GetMeshDS()); + v0 = myHelper.GetSubShapeByNode( node0, myHelper.GetMeshDS()); + v1 = myHelper.GetSubShapeByNode( node1, myHelper.GetMeshDS()); if ( v0.ShapeType() == TopAbs_VERTEX ) { nbInserted += SMESH_Block::Insert( v0, vertIdVec[ 0 ], shapeMap); } @@ -1837,6 +4288,28 @@ int StdMeshers_PrismAsBlock::TSideFace::InsertSubShapes(TBlockShapes& shapeMap) return nbInserted; } +//================================================================================ +/*! + * \brief Dump ids of nodes of sides + */ +//================================================================================ + +void StdMeshers_PrismAsBlock::TSideFace::dumpNodes(int nbNodes) const +{ +#ifdef _DEBUG_ + cout << endl << "NODES OF FACE "; SMESH_Block::DumpShapeID( myID, cout ) << endl; + THorizontalEdgeAdaptor* hSize0 = (THorizontalEdgeAdaptor*) HorizCurve(0); + cout << "Horiz side 0: "; hSize0->dumpNodes(nbNodes); cout << endl; + THorizontalEdgeAdaptor* hSize1 = (THorizontalEdgeAdaptor*) HorizCurve(1); + cout << "Horiz side 1: "; hSize1->dumpNodes(nbNodes); cout << endl; + TVerticalEdgeAdaptor* vSide0 = (TVerticalEdgeAdaptor*) VertiCurve(0); + cout << "Verti side 0: "; vSide0->dumpNodes(nbNodes); cout << endl; + TVerticalEdgeAdaptor* vSide1 = (TVerticalEdgeAdaptor*) VertiCurve(1); + cout << "Verti side 1: "; vSide1->dumpNodes(nbNodes); cout << endl; + delete hSize0; delete hSize1; delete vSide0; delete vSide1; +#endif +} + //================================================================================ /*! * \brief Creates TVerticalEdgeAdaptor @@ -1867,6 +4340,22 @@ gp_Pnt StdMeshers_PrismAsBlock::TVerticalEdgeAdaptor::Value(const Standard_Real return gpXYZ(n1) * ( 1 - r ) + gpXYZ(n2) * r; } +//================================================================================ +/*! + * \brief Dump ids of nodes + */ +//================================================================================ + +void StdMeshers_PrismAsBlock::TVerticalEdgeAdaptor::dumpNodes(int nbNodes) const +{ +#ifdef _DEBUG_ + for ( int i = 0; i < nbNodes && i < myNodeColumn->size(); ++i ) + cout << (*myNodeColumn)[i]->GetID() << " "; + if ( nbNodes < myNodeColumn->size() ) + cout << myNodeColumn->back()->GetID(); +#endif +} + //================================================================================ /*! * \brief Return coordinates for the given normalized parameter @@ -1880,6 +4369,125 @@ gp_Pnt StdMeshers_PrismAsBlock::THorizontalEdgeAdaptor::Value(const Standard_Rea return mySide->TSideFace::Value( U, myV ); } +//================================================================================ +/*! + * \brief Dump ids of first nodes and the last one + */ +//================================================================================ + +void StdMeshers_PrismAsBlock::THorizontalEdgeAdaptor::dumpNodes(int nbNodes) const +{ +#ifdef _DEBUG_ + // Not bedugged code. Last node is sometimes incorrect + const TSideFace* side = mySide; + double u = 0; + if ( mySide->IsComplex() ) + side = mySide->GetComponent(0,u); + + TParam2ColumnIt col, col2; + TParam2ColumnMap* u2cols = side->GetColumns(); + side->GetColumns( u , col, col2 ); + + int j, i = myV ? mySide->ColumnHeight()-1 : 0; + + const SMDS_MeshNode* n = 0; + const SMDS_MeshNode* lastN + = side->IsForward() ? u2cols->rbegin()->second[ i ] : u2cols->begin()->second[ i ]; + for ( j = 0; j < nbNodes && n != lastN; ++j ) + { + n = col->second[ i ]; + cout << n->GetID() << " "; + if ( side->IsForward() ) + ++col; + else + --col; + } + + // last node + u = 1; + if ( mySide->IsComplex() ) + side = mySide->GetComponent(1,u); + + side->GetColumns( u , col, col2 ); + if ( n != col->second[ i ] ) + cout << col->second[ i ]->GetID(); +#endif +} + +//================================================================================ +/*! + * \brief Costructor of TPCurveOnHorFaceAdaptor fills its map of + * normalized parameter to node UV on a horizontal face + * \param [in] sideFace - lateral prism side + * \param [in] isTop - is \a horFace top or bottom of the prism + * \param [in] horFace - top or bottom face of the prism + */ +//================================================================================ + +StdMeshers_PrismAsBlock:: +TPCurveOnHorFaceAdaptor::TPCurveOnHorFaceAdaptor( const TSideFace* sideFace, + const bool isTop, + const TopoDS_Face& horFace) +{ + if ( sideFace && !horFace.IsNull() ) + { + //cout << "\n\t FACE " << sideFace->FaceID() << endl; + const int Z = isTop ? sideFace->ColumnHeight() - 1 : 0; + map u2nodes; + sideFace->GetNodesAtZ( Z, u2nodes ); + if ( u2nodes.empty() ) + return; + + SMESH_MesherHelper helper( *sideFace->GetMesh() ); + helper.SetSubShape( horFace ); + + bool okUV; + gp_XY uv; + double f,l; + Handle(Geom2d_Curve) C2d; + int edgeID = -1; + const double tol = 10 * helper.MaxTolerance( horFace ); + const SMDS_MeshNode* prevNode = u2nodes.rbegin()->second; + + map::iterator u2n = u2nodes.begin(); + for ( ; u2n != u2nodes.end(); ++u2n ) + { + const SMDS_MeshNode* n = u2n->second; + okUV = false; + if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_EDGE ) + { + if ( n->getshapeId() != edgeID ) + { + C2d.Nullify(); + edgeID = n->getshapeId(); + TopoDS_Shape S = helper.GetSubShapeByNode( n, helper.GetMeshDS() ); + if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE ) + { + C2d = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), horFace, f,l ); + } + } + if ( !C2d.IsNull() ) + { + double u = static_cast< const SMDS_EdgePosition* >( n->GetPosition() )->GetUParameter(); + if ( f <= u && u <= l ) + { + uv = C2d->Value( u ).XY(); + okUV = helper.CheckNodeUV( horFace, n, uv, tol ); + } + } + } + if ( !okUV ) + uv = helper.GetNodeUV( horFace, n, prevNode, &okUV ); + + myUVmap.insert( myUVmap.end(), make_pair( u2n->first, uv )); + // cout << n->getshapeId() << " N " << n->GetID() + // << " \t" << uv.X() << ", " << uv.Y() << " \t" << u2n->first << endl; + + prevNode = n; + } + } +} + //================================================================================ /*! * \brief Return UV on pcurve for the given normalized parameter @@ -1890,9 +4498,372 @@ gp_Pnt StdMeshers_PrismAsBlock::THorizontalEdgeAdaptor::Value(const Standard_Rea gp_Pnt2d StdMeshers_PrismAsBlock::TPCurveOnHorFaceAdaptor::Value(const Standard_Real U) const { - TParam2ColumnIt u_col1, u_col2; - double r = mySide->GetColumns( U, u_col1, u_col2 ); - gp_XY uv1 = mySide->GetNodeUV( myFace, u_col1->second[ myZ ]); - gp_XY uv2 = mySide->GetNodeUV( myFace, u_col2->second[ myZ ]); - return uv1 * ( 1 - r ) + uv2 * r; + map< double, gp_XY >::const_iterator i1 = myUVmap.upper_bound( U ); + + if ( i1 == myUVmap.end() ) + return myUVmap.empty() ? gp_XY(0,0) : myUVmap.rbegin()->second; + + if ( i1 == myUVmap.begin() ) + return (*i1).second; + + map< double, gp_XY >::const_iterator i2 = i1--; + + double r = ( U - i1->first ) / ( i2->first - i1->first ); + return i1->second * ( 1 - r ) + i2->second * r; +} + +//================================================================================ +/*! + * \brief Projects internal nodes using transformation found by boundary nodes + */ +//================================================================================ + +bool StdMeshers_Sweeper::projectIntPoints(const vector< gp_XYZ >& fromBndPoints, + const vector< gp_XYZ >& toBndPoints, + const vector< gp_XYZ >& fromIntPoints, + vector< gp_XYZ >& toIntPoints, + NSProjUtils::TrsfFinder3D& trsf, + vector< gp_XYZ > * bndError) +{ + // find transformation + if ( trsf.IsIdentity() && !trsf.Solve( fromBndPoints, toBndPoints )) + return false; + + // compute internal points using the found trsf + for ( size_t iP = 0; iP < fromIntPoints.size(); ++iP ) + { + toIntPoints[ iP ] = trsf.Transform( fromIntPoints[ iP ]); + } + + // compute boundary error + if ( bndError ) + { + bndError->resize( fromBndPoints.size() ); + gp_XYZ fromTrsf; + for ( size_t iP = 0; iP < fromBndPoints.size(); ++iP ) + { + fromTrsf = trsf.Transform( fromBndPoints[ iP ] ); + (*bndError)[ iP ] = toBndPoints[ iP ] - fromTrsf; + } + } + return true; +} + +//================================================================================ +/*! + * \brief Add boundary error to ineternal points + */ +//================================================================================ + +void StdMeshers_Sweeper::applyBoundaryError(const vector< gp_XYZ >& bndPoints, + const vector< gp_XYZ >& bndError1, + const vector< gp_XYZ >& bndError2, + const double r, + vector< gp_XYZ >& intPoints, + vector< double >& int2BndDist) +{ + // fix each internal point + const double eps = 1e-100; + for ( size_t iP = 0; iP < intPoints.size(); ++iP ) + { + gp_XYZ & intPnt = intPoints[ iP ]; + + // compute distance from intPnt to each boundary node + double int2BndDistSum = 0; + for ( size_t iBnd = 0; iBnd < bndPoints.size(); ++iBnd ) + { + int2BndDist[ iBnd ] = 1 / (( intPnt - bndPoints[ iBnd ]).SquareModulus() + eps ); + int2BndDistSum += int2BndDist[ iBnd ]; + } + + // apply bndError + for ( size_t iBnd = 0; iBnd < bndPoints.size(); ++iBnd ) + { + intPnt += bndError1[ iBnd ] * ( 1 - r ) * int2BndDist[ iBnd ] / int2BndDistSum; + intPnt += bndError2[ iBnd ] * r * int2BndDist[ iBnd ] / int2BndDistSum; + } + } +} + +//================================================================================ +/*! + * \brief Creates internal nodes of the prism + */ +//================================================================================ + +bool StdMeshers_Sweeper::ComputeNodes( SMESH_MesherHelper& helper, + const double tol, + const bool allowHighBndError) +{ + const size_t zSize = myBndColumns[0]->size(); + const size_t zSrc = 0, zTgt = zSize-1; + if ( zSize < 3 ) return true; + + vector< vector< gp_XYZ > > intPntsOfLayer( zSize ); // node coodinates to compute + // set coordinates of src and tgt nodes + for ( size_t z = 0; z < intPntsOfLayer.size(); ++z ) + intPntsOfLayer[ z ].resize( myIntColumns.size() ); + for ( size_t iP = 0; iP < myIntColumns.size(); ++iP ) + { + intPntsOfLayer[ zSrc ][ iP ] = intPoint( iP, zSrc ); + intPntsOfLayer[ zTgt ][ iP ] = intPoint( iP, zTgt ); + } + + // compute coordinates of internal nodes by projecting (transfroming) src and tgt + // nodes towards the central layer + + vector< NSProjUtils::TrsfFinder3D > trsfOfLayer( zSize ); + vector< vector< gp_XYZ > > bndError( zSize ); + + // boundary points used to compute an affine transformation from a layer to a next one + vector< gp_XYZ > fromSrcBndPnts( myBndColumns.size() ), fromTgtBndPnts( myBndColumns.size() ); + vector< gp_XYZ > toSrcBndPnts ( myBndColumns.size() ), toTgtBndPnts ( myBndColumns.size() ); + for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) + { + fromSrcBndPnts[ iP ] = bndPoint( iP, zSrc ); + fromTgtBndPnts[ iP ] = bndPoint( iP, zTgt ); + } + + size_t zS = zSrc + 1; + size_t zT = zTgt - 1; + for ( ; zS < zT; ++zS, --zT ) // vertical loop on layers + { + for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) + { + toSrcBndPnts[ iP ] = bndPoint( iP, zS ); + toTgtBndPnts[ iP ] = bndPoint( iP, zT ); + } + if (! projectIntPoints( fromSrcBndPnts, toSrcBndPnts, + intPntsOfLayer[ zS-1 ], intPntsOfLayer[ zS ], + trsfOfLayer [ zS-1 ], & bndError[ zS-1 ])) + return false; + if (! projectIntPoints( fromTgtBndPnts, toTgtBndPnts, + intPntsOfLayer[ zT+1 ], intPntsOfLayer[ zT ], + trsfOfLayer [ zT+1 ], & bndError[ zT+1 ])) + return false; + + // if ( zT == zTgt - 1 ) + // { + // for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) + // { + // gp_XYZ fromTrsf = trsfOfLayer [ zT+1].Transform( fromTgtBndPnts[ iP ] ); + // cout << "mesh.AddNode( " + // << fromTrsf.X() << ", " + // << fromTrsf.Y() << ", " + // << fromTrsf.Z() << ") " << endl; + // } + // for ( size_t iP = 0; iP < myIntColumns.size(); ++iP ) + // cout << "mesh.AddNode( " + // << intPntsOfLayer[ zT ][ iP ].X() << ", " + // << intPntsOfLayer[ zT ][ iP ].Y() << ", " + // << intPntsOfLayer[ zT ][ iP ].Z() << ") " << endl; + // } + + fromTgtBndPnts.swap( toTgtBndPnts ); + fromSrcBndPnts.swap( toSrcBndPnts ); + } + + // Compute two projections of internal points to the central layer + // in order to evaluate an error of internal points + + bool centerIntErrorIsSmall; + vector< gp_XYZ > centerSrcIntPnts( myIntColumns.size() ); + vector< gp_XYZ > centerTgtIntPnts( myIntColumns.size() ); + + for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) + { + toSrcBndPnts[ iP ] = bndPoint( iP, zS ); + toTgtBndPnts[ iP ] = bndPoint( iP, zT ); + } + if (! projectIntPoints( fromSrcBndPnts, toSrcBndPnts, + intPntsOfLayer[ zS-1 ], centerSrcIntPnts, + trsfOfLayer [ zS-1 ], & bndError[ zS-1 ])) + return false; + if (! projectIntPoints( fromTgtBndPnts, toTgtBndPnts, + intPntsOfLayer[ zT+1 ], centerTgtIntPnts, + trsfOfLayer [ zT+1 ], & bndError[ zT+1 ])) + return false; + + // evaluate an error of internal points on the central layer + centerIntErrorIsSmall = true; + if ( zS == zT ) // odd zSize + { + for ( size_t iP = 0; ( iP < myIntColumns.size() && centerIntErrorIsSmall ); ++iP ) + centerIntErrorIsSmall = + (centerSrcIntPnts[ iP ] - centerTgtIntPnts[ iP ]).SquareModulus() < tol*tol; + } + else // even zSize + { + for ( size_t iP = 0; ( iP < myIntColumns.size() && centerIntErrorIsSmall ); ++iP ) + centerIntErrorIsSmall = + (intPntsOfLayer[ zS-1 ][ iP ] - centerTgtIntPnts[ iP ]).SquareModulus() < tol*tol; + } + + // Evaluate an error of boundary points + + bool bndErrorIsSmall = true; + for ( size_t iP = 0; ( iP < myBndColumns.size() && bndErrorIsSmall ); ++iP ) + { + double sumError = 0; + for ( size_t z = 1; z < zS; ++z ) // loop on layers + sumError += ( bndError[ z-1 ][ iP ].Modulus() + + bndError[ zSize-z ][ iP ].Modulus() ); + + bndErrorIsSmall = ( sumError < tol ); + } + + if ( !bndErrorIsSmall && !allowHighBndError ) + return false; + + // compute final points on the central layer + std::vector< double > int2BndDist( myBndColumns.size() ); // work array of applyBoundaryError() + double r = zS / ( zSize - 1.); + if ( zS == zT ) + { + for ( size_t iP = 0; iP < myIntColumns.size(); ++iP ) + { + intPntsOfLayer[ zS ][ iP ] = + ( 1 - r ) * centerSrcIntPnts[ iP ] + r * centerTgtIntPnts[ iP ]; + } + if ( !bndErrorIsSmall ) + { + applyBoundaryError( toSrcBndPnts, bndError[ zS-1 ], bndError[ zS+1 ], r, + intPntsOfLayer[ zS ], int2BndDist ); + } + } + else + { + for ( size_t iP = 0; iP < myIntColumns.size(); ++iP ) + { + intPntsOfLayer[ zS ][ iP ] = + r * intPntsOfLayer[ zS ][ iP ] + ( 1 - r ) * centerSrcIntPnts[ iP ]; + intPntsOfLayer[ zT ][ iP ] = + r * intPntsOfLayer[ zT ][ iP ] + ( 1 - r ) * centerTgtIntPnts[ iP ]; + } + if ( !bndErrorIsSmall ) + { + applyBoundaryError( toSrcBndPnts, bndError[ zS-1 ], bndError[ zS+1 ], r, + intPntsOfLayer[ zS ], int2BndDist ); + applyBoundaryError( toTgtBndPnts, bndError[ zT+1 ], bndError[ zT-1 ], r, + intPntsOfLayer[ zT ], int2BndDist ); + } + } + + //centerIntErrorIsSmall = true; + //bndErrorIsSmall = true; + if ( !centerIntErrorIsSmall ) + { + // Compensate the central error; continue adding projection + // by going from central layer to the source and target ones + + vector< gp_XYZ >& fromSrcIntPnts = centerSrcIntPnts; + vector< gp_XYZ >& fromTgtIntPnts = centerTgtIntPnts; + vector< gp_XYZ > toSrcIntPnts( myIntColumns.size() ); + vector< gp_XYZ > toTgtIntPnts( myIntColumns.size() ); + vector< gp_XYZ > srcBndError( myBndColumns.size() ); + vector< gp_XYZ > tgtBndError( myBndColumns.size() ); + + fromTgtBndPnts.swap( toTgtBndPnts ); + fromSrcBndPnts.swap( toSrcBndPnts ); + + for ( ++zS, --zT; zS < zTgt; ++zS, --zT ) // vertical loop on layers + { + // invert transformation + if ( !trsfOfLayer[ zS+1 ].Invert() ) + trsfOfLayer[ zS+1 ] = NSProjUtils::TrsfFinder3D(); // to recompute + if ( !trsfOfLayer[ zT-1 ].Invert() ) + trsfOfLayer[ zT-1 ] = NSProjUtils::TrsfFinder3D(); + + // project internal nodes and compute bnd error + for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) + { + toSrcBndPnts[ iP ] = bndPoint( iP, zS ); + toTgtBndPnts[ iP ] = bndPoint( iP, zT ); + } + projectIntPoints( fromSrcBndPnts, toSrcBndPnts, + fromSrcIntPnts, toSrcIntPnts, + trsfOfLayer[ zS+1 ], & srcBndError ); + projectIntPoints( fromTgtBndPnts, toTgtBndPnts, + fromTgtIntPnts, toTgtIntPnts, + trsfOfLayer[ zT-1 ], & tgtBndError ); + + // if ( zS == zTgt - 1 ) + // { + // cout << "mesh2 = smesh.Mesh()" << endl; + // for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) + // { + // gp_XYZ fromTrsf = trsfOfLayer [ zS+1].Transform( fromSrcBndPnts[ iP ] ); + // cout << "mesh2.AddNode( " + // << fromTrsf.X() << ", " + // << fromTrsf.Y() << ", " + // << fromTrsf.Z() << ") " << endl; + // } + // for ( size_t iP = 0; iP < myIntColumns.size(); ++iP ) + // cout << "mesh2.AddNode( " + // << toSrcIntPnts[ iP ].X() << ", " + // << toSrcIntPnts[ iP ].Y() << ", " + // << toSrcIntPnts[ iP ].Z() << ") " << endl; + // } + + // sum up 2 projections + r = zS / ( zSize - 1.); + vector< gp_XYZ >& zSIntPnts = intPntsOfLayer[ zS ]; + vector< gp_XYZ >& zTIntPnts = intPntsOfLayer[ zT ]; + for ( size_t iP = 0; iP < myIntColumns.size(); ++iP ) + { + zSIntPnts[ iP ] = r * zSIntPnts[ iP ] + ( 1 - r ) * toSrcIntPnts[ iP ]; + zTIntPnts[ iP ] = r * zTIntPnts[ iP ] + ( 1 - r ) * toTgtIntPnts[ iP ]; + } + + // compensate bnd error + if ( !bndErrorIsSmall ) + { + applyBoundaryError( toSrcBndPnts, srcBndError, bndError[ zS+1 ], r, + intPntsOfLayer[ zS ], int2BndDist ); + applyBoundaryError( toTgtBndPnts, tgtBndError, bndError[ zT-1 ], r, + intPntsOfLayer[ zT ], int2BndDist ); + } + + fromSrcBndPnts.swap( toSrcBndPnts ); + fromSrcIntPnts.swap( toSrcIntPnts ); + fromTgtBndPnts.swap( toTgtBndPnts ); + fromTgtIntPnts.swap( toTgtIntPnts ); + } + } // if ( !centerIntErrorIsSmall ) + + else if ( !bndErrorIsSmall ) + { + zS = zSrc + 1; + zT = zTgt - 1; + for ( ; zS < zT; ++zS, --zT ) // vertical loop on layers + { + for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) + { + toSrcBndPnts[ iP ] = bndPoint( iP, zS ); + toTgtBndPnts[ iP ] = bndPoint( iP, zT ); + } + // compensate bnd error + applyBoundaryError( toSrcBndPnts, bndError[ zS-1 ], bndError[ zS-1 ], 0.5, + intPntsOfLayer[ zS ], int2BndDist ); + applyBoundaryError( toTgtBndPnts, bndError[ zT+1 ], bndError[ zT+1 ], 0.5, + intPntsOfLayer[ zT ], int2BndDist ); + } + } + + // cout << "centerIntErrorIsSmall = " << centerIntErrorIsSmall<< endl; + // cout << "bndErrorIsSmall = " << bndErrorIsSmall<< endl; + + // Create nodes + for ( size_t iP = 0; iP < myIntColumns.size(); ++iP ) + { + vector< const SMDS_MeshNode* > & nodeCol = *myIntColumns[ iP ]; + for ( size_t z = zSrc + 1; z < zTgt; ++z ) // vertical loop on layers + { + const gp_XYZ & xyz = intPntsOfLayer[ z ][ iP ]; + if ( !( nodeCol[ z ] = helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() ))) + return false; + } + } + + return true; } diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionSource1D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionSource1D.cpp index 803e72a08d7a..7fe47bd1476b 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionSource1D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionSource1D.cpp @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : idl implementation based on 'SMESH' unit's classes // File : StdMeshers_ProjectionSource1D.cxx // Author : Edward AGAPOV // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_ProjectionSource1D.cxx,v 1.2.2.1 2008/11/27 13:03:50 abd Exp $ // #include "StdMeshers_ProjectionSource1D.hxx" @@ -73,13 +73,13 @@ StdMeshers_ProjectionSource1D::~StdMeshers_ProjectionSource1D() //============================================================================= void StdMeshers_ProjectionSource1D::SetSourceEdge(const TopoDS_Shape& edge) - throw ( SMESH_Exception ) + throw ( SALOME_Exception ) { if ( edge.IsNull() ) - throw SMESH_Exception(LOCALIZED("Null edge is not allowed")); + throw SALOME_Exception(LOCALIZED("Null edge is not allowed")); if ( edge.ShapeType() != TopAbs_EDGE && edge.ShapeType() != TopAbs_COMPOUND ) - throw SMESH_Exception(LOCALIZED("Wrong shape type")); + throw SALOME_Exception(LOCALIZED("Wrong shape type")); if ( !_sourceEdge.IsSame( edge ) ) { @@ -98,15 +98,15 @@ void StdMeshers_ProjectionSource1D::SetSourceEdge(const TopoDS_Shape& edge) void StdMeshers_ProjectionSource1D::SetVertexAssociation(const TopoDS_Shape& sourceVertex, const TopoDS_Shape& targetVertex) - throw ( SMESH_Exception ) + throw ( SALOME_Exception ) { if ( sourceVertex.IsNull() != targetVertex.IsNull() ) - throw SMESH_Exception(LOCALIZED("Two or none vertices must be provided")); + throw SALOME_Exception(LOCALIZED("Two or none vertices must be provided")); if ( !sourceVertex.IsNull() ) { if ( sourceVertex.ShapeType() != TopAbs_VERTEX || targetVertex.ShapeType() != TopAbs_VERTEX ) - throw SMESH_Exception(LOCALIZED("Wrong shape type")); + throw SALOME_Exception(LOCALIZED("Wrong shape type")); } if ( !_sourceVertex.IsSame( sourceVertex ) || @@ -242,3 +242,4 @@ bool StdMeshers_ProjectionSource1D::SetParametersByDefaults(const TDefaults& /* { return false; } + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionSource2D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionSource2D.cpp index c285c623ba90..05b80199de16 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionSource2D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionSource2D.cpp @@ -1,33 +1,35 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : idl implementation based on 'SMESH' unit's classes // File : StdMeshers_ProjectionSource2D.cxx // Author : Edward AGAPOV // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_ProjectionSource2D.cxx,v 1.2.2.1 2008/11/27 13:03:50 abd Exp $ // #include "StdMeshers_ProjectionSource2D.hxx" #include "SMESH_Mesh.hxx" +#include "SMESH_MesherHelper.hxx" +#include "StdMeshers_ProjectionUtils.hxx" #include "utilities.h" @@ -72,13 +74,13 @@ StdMeshers_ProjectionSource2D::~StdMeshers_ProjectionSource2D() //============================================================================= void StdMeshers_ProjectionSource2D::SetSourceFace(const TopoDS_Shape& Face) - throw ( SMESH_Exception ) + throw ( SALOME_Exception ) { if ( Face.IsNull() ) - throw SMESH_Exception(LOCALIZED("Null Face is not allowed")); + throw SALOME_Exception(LOCALIZED("Null Face is not allowed")); if ( Face.ShapeType() != TopAbs_FACE && Face.ShapeType() != TopAbs_COMPOUND ) - throw SMESH_Exception(LOCALIZED("Wrong shape type")); + throw SALOME_Exception(LOCALIZED("Wrong shape type")); if ( !_sourceFace.IsSame( Face ) ) { @@ -100,20 +102,30 @@ void StdMeshers_ProjectionSource2D::SetVertexAssociation(const TopoDS_Shape& sou const TopoDS_Shape& sourceVertex2, const TopoDS_Shape& targetVertex1, const TopoDS_Shape& targetVertex2) - throw ( SMESH_Exception ) + throw ( SALOME_Exception ) { if ( sourceVertex1.IsNull() != targetVertex1.IsNull() || - sourceVertex2.IsNull() != targetVertex2.IsNull() || - sourceVertex1.IsNull() != targetVertex2.IsNull() ) - throw SMESH_Exception(LOCALIZED("Two or none pairs of vertices must be provided")); + sourceVertex2.IsNull() != targetVertex2.IsNull() ) + throw SALOME_Exception(LOCALIZED("Vertices must be provided in couples")); - if ( !sourceVertex1.IsNull() ) { + if ( sourceVertex1.IsNull() != sourceVertex2.IsNull() ) + { + // possibly there is only 1 vertex in the face + if ( !_sourceFace.IsNull() && + SMESH_MesherHelper::Count( _sourceFace, TopAbs_VERTEX, /*ignoreSame=*/true) != 1 ) + throw SALOME_Exception(LOCALIZED("Two or none pairs of vertices must be provided")); + } + + if ( !sourceVertex1.IsNull() ) if ( sourceVertex1.ShapeType() != TopAbs_VERTEX || - sourceVertex2.ShapeType() != TopAbs_VERTEX || - targetVertex1.ShapeType() != TopAbs_VERTEX || + targetVertex1.ShapeType() != TopAbs_VERTEX ) + throw SALOME_Exception(LOCALIZED("Wrong shape type")); + + if ( !sourceVertex2.IsNull() ) + if ( sourceVertex2.ShapeType() != TopAbs_VERTEX || targetVertex2.ShapeType() != TopAbs_VERTEX ) - throw SMESH_Exception(LOCALIZED("Wrong shape type")); - } + throw SALOME_Exception(LOCALIZED("Wrong shape type")); + if ( !_sourceVertex1.IsSame( sourceVertex1 ) || !_sourceVertex2.IsSame( sourceVertex2 ) || @@ -137,9 +149,10 @@ void StdMeshers_ProjectionSource2D::SetVertexAssociation(const TopoDS_Shape& sou void StdMeshers_ProjectionSource2D::SetSourceMesh(SMESH_Mesh* mesh) { - if ( _sourceMesh != mesh ) + if ( _sourceMesh != mesh ) { _sourceMesh = mesh; NotifySubMeshesHypothesisModification(); + } } //============================================================================= @@ -161,14 +174,14 @@ TopoDS_Shape StdMeshers_ProjectionSource2D::GetSourceFace() const //============================================================================= TopoDS_Vertex StdMeshers_ProjectionSource2D::GetSourceVertex(int i) const - throw ( SMESH_Exception ) + throw ( SALOME_Exception ) { if ( i == 1 ) return _sourceVertex1; else if ( i == 2 ) return _sourceVertex2; else - throw SMESH_Exception(LOCALIZED("Wrong vertex index")); + throw SALOME_Exception(LOCALIZED("Wrong vertex index")); } //============================================================================= @@ -179,14 +192,14 @@ TopoDS_Vertex StdMeshers_ProjectionSource2D::GetSourceVertex(int i) const //============================================================================= TopoDS_Vertex StdMeshers_ProjectionSource2D::GetTargetVertex(int i) const - throw ( SMESH_Exception ) + throw ( SALOME_Exception ) { if ( i == 1 ) return _targetVertex1; else if ( i == 2 ) return _targetVertex2; else - throw SMESH_Exception(LOCALIZED("Wrong vertex index")); + throw SALOME_Exception(LOCALIZED("Wrong vertex index")); } //============================================================================= @@ -309,3 +322,4 @@ bool StdMeshers_ProjectionSource2D::SetParametersByDefaults(const TDefaults& /* { return false; } + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionSource3D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionSource3D.cpp index 14f9a6d4c863..c6446dc972ee 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionSource3D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionSource3D.cpp @@ -1,29 +1,29 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : idl implementation based on 'SMESH' unit's classes // File : StdMeshers_ProjectionSource3D.cxx // Author : Edward AGAPOV // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_ProjectionSource3D.cxx,v 1.2.2.1 2008/11/27 13:03:49 abd Exp $ // #include "StdMeshers_ProjectionSource3D.hxx" @@ -71,13 +71,13 @@ StdMeshers_ProjectionSource3D::~StdMeshers_ProjectionSource3D() //============================================================================= void StdMeshers_ProjectionSource3D::SetSource3DShape(const TopoDS_Shape& Shape) - throw ( SMESH_Exception ) + throw ( SALOME_Exception ) { if ( Shape.IsNull() ) - throw SMESH_Exception(LOCALIZED("Null Shape is not allowed")); + throw SALOME_Exception(LOCALIZED("Null Shape is not allowed")); if ( SMESH_Gen::GetShapeDim( Shape ) != 3 ) - throw SMESH_Exception(LOCALIZED("Wrong shape type")); + throw SALOME_Exception(LOCALIZED("Wrong shape type")); if ( !_sourceShape.IsSame( Shape ) ) { @@ -99,19 +99,19 @@ void StdMeshers_ProjectionSource3D::SetVertexAssociation(const TopoDS_Shape& sou const TopoDS_Shape& sourceVertex2, const TopoDS_Shape& targetVertex1, const TopoDS_Shape& targetVertex2) - throw ( SMESH_Exception ) + throw ( SALOME_Exception ) { if ( sourceVertex1.IsNull() != targetVertex1.IsNull() || sourceVertex2.IsNull() != targetVertex2.IsNull() || sourceVertex1.IsNull() != targetVertex2.IsNull() ) - throw SMESH_Exception(LOCALIZED("Two or none pairs of vertices must be provided")); + throw SALOME_Exception(LOCALIZED("Two or none pairs of vertices must be provided")); if ( !sourceVertex1.IsNull() ) { if ( sourceVertex1.ShapeType() != TopAbs_VERTEX || sourceVertex2.ShapeType() != TopAbs_VERTEX || targetVertex1.ShapeType() != TopAbs_VERTEX || targetVertex2.ShapeType() != TopAbs_VERTEX ) - throw SMESH_Exception(LOCALIZED("Wrong shape type")); + throw SALOME_Exception(LOCALIZED("Wrong shape type")); } if ( !_sourceVertex1.IsSame( sourceVertex1 ) || @@ -136,9 +136,10 @@ void StdMeshers_ProjectionSource3D::SetVertexAssociation(const TopoDS_Shape& sou void StdMeshers_ProjectionSource3D::SetSourceMesh(SMESH_Mesh* mesh) { - if ( _sourceMesh != mesh ) + if ( _sourceMesh != mesh ) { _sourceMesh = mesh; NotifySubMeshesHypothesisModification(); + } } //============================================================================= @@ -160,14 +161,14 @@ TopoDS_Shape StdMeshers_ProjectionSource3D::GetSource3DShape() const //============================================================================= TopoDS_Vertex StdMeshers_ProjectionSource3D::GetSourceVertex(int i) const - throw ( SMESH_Exception ) + throw ( SALOME_Exception ) { if ( i == 1 ) return _sourceVertex1; else if ( i == 2 ) return _sourceVertex2; else - throw SMESH_Exception(LOCALIZED("Wrong vertex index")); + throw SALOME_Exception(LOCALIZED("Wrong vertex index")); } //============================================================================= @@ -178,14 +179,14 @@ TopoDS_Vertex StdMeshers_ProjectionSource3D::GetSourceVertex(int i) const //============================================================================= TopoDS_Vertex StdMeshers_ProjectionSource3D::GetTargetVertex(int i) const - throw ( SMESH_Exception ) + throw ( SALOME_Exception ) { if ( i == 1 ) return _targetVertex1; else if ( i == 2 ) return _targetVertex2; else - throw SMESH_Exception(LOCALIZED("Wrong vertex index")); + throw SALOME_Exception(LOCALIZED("Wrong vertex index")); } @@ -309,3 +310,4 @@ bool StdMeshers_ProjectionSource3D::SetParametersByDefaults(const TDefaults& /* { return false; } + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionUtils.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionUtils.cpp index c7ca13380f1c..a2f1047fee30 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionUtils.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ProjectionUtils.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : idl implementation based on 'SMESH' unit's calsses // File : StdMeshers_ProjectionUtils.cxx // Created : Fri Oct 27 10:24:28 2006 @@ -30,28 +31,35 @@ #include "StdMeshers_ProjectionSource2D.hxx" #include "StdMeshers_ProjectionSource3D.hxx" +#include "SMDS_EdgePosition.hxx" #include "SMESH_Algo.hxx" #include "SMESH_Block.hxx" #include "SMESH_Gen.hxx" +#include "SMESH_HypoFilter.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_IndexedDataMapOfShapeIndexedMapOfShape.hxx" #include "SMESH_Mesh.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_subMesh.hxx" #include "SMESH_subMeshEventListener.hxx" -#include "SMDS_EdgePosition.hxx" +#include "SMESH_MeshAlgos.hxx" #include "utilities.h" +#include #include #include #include #include #include +#include +#include #include #include #include #include +#include +#include +#include #include #include #include @@ -60,20 +68,24 @@ #include #include #include -#include -#include +#include + +#include +#include using namespace std; #define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; } -#define SHOW_VERTEX(v,msg) // { \ -// if ( v.IsNull() ) cout << msg << " NULL SHAPE" << endl; \ -// else if (v.ShapeType() == TopAbs_VERTEX) {\ -// gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( v ));\ -// cout << msg << (v).TShape().operator->()<<" ( " <()<ShapeToIndex(S), theMeshDS[1]->ShapeToIndex(S) ); + return long(S.TShape().operator->()); + } + //================================================================================ /*! * \brief Write shape for debug purposes */ //================================================================================ - bool _StoreBadShape(const TopoDS_Shape& shape) + bool storeShapeForDebug(const TopoDS_Shape& shape) { #ifdef _DEBUG_ const char* type[] ={"COMPOUND","COMPSOLID","SOLID","SHELL","FACE","WIRE","EDGE","VERTEX"}; @@ -113,31 +133,24 @@ namespace { */ //================================================================================ - void Reverse( list< TopoDS_Edge > & edges, const int nbEdges ) + void reverseEdges( list< TopoDS_Edge > & edges, const int nbEdges, const int firstEdge=0) { SHOW_LIST("BEFORE REVERSE", edges); list< TopoDS_Edge >::iterator eIt = edges.begin(); - if ( edges.size() == nbEdges ) + std::advance( eIt, firstEdge ); + list< TopoDS_Edge >::iterator eBackIt = eIt; + for ( int i = 0; i < nbEdges; ++i, ++eBackIt ) + eBackIt->Reverse(); // reverse edge + // reverse list + --eBackIt; + while ( eIt != eBackIt ) { - edges.reverse(); - } - else // reverse only the given nb of edges - { - // look for the last edge to be reversed - list< TopoDS_Edge >::iterator eBackIt = edges.begin(); - for ( int i = 1; i < nbEdges; ++i ) - ++eBackIt; - // reverse - while ( eIt != eBackIt ) { - std::swap( *eIt, *eBackIt ); - SHOW_LIST("# AFTER SWAP", edges) + std::swap( *eIt, *eBackIt ); + SHOW_LIST("# AFTER SWAP", edges) if ( (++eIt) != eBackIt ) --eBackIt; - } } - for ( eIt = edges.begin(); eIt != edges.end(); ++eIt ) - eIt->Reverse(); SHOW_LIST("ATFER REVERSE", edges) } @@ -150,7 +163,7 @@ namespace { */ //================================================================================ - bool IsPropagationPossible( SMESH_Mesh* theMesh1, SMESH_Mesh* theMesh2 ) + bool isPropagationPossible( SMESH_Mesh* theMesh1, SMESH_Mesh* theMesh2 ) { if ( theMesh1 != theMesh2 ) { TopoDS_Shape mainShape1 = theMesh1->GetMeshDS()->ShapeToMesh(); @@ -172,24 +185,61 @@ namespace { */ //================================================================================ - bool FixAssocByPropagation( const int nbEdges, + bool fixAssocByPropagation( const int nbEdges, list< TopoDS_Edge > & edges1, list< TopoDS_Edge > & edges2, SMESH_Mesh* theMesh1, SMESH_Mesh* theMesh2) { - if ( nbEdges == 2 && IsPropagationPossible( theMesh1, theMesh2 ) ) + if ( nbEdges == 2 && isPropagationPossible( theMesh1, theMesh2 ) ) { list< TopoDS_Edge >::iterator eIt2 = ++edges2.begin(); // 2nd edge of the 2nd face TopoDS_Edge edge2 = HERE::GetPropagationEdge( theMesh1, *eIt2, edges1.front() ).second; if ( !edge2.IsNull() ) { // propagation found for the second edge - Reverse( edges2, nbEdges ); + reverseEdges( edges2, nbEdges ); return true; } } return false; } + //================================================================================ + /*! + * \brief Associate faces having one edge in the outer wire. + * No check is done if there is really only one outer edge + */ + //================================================================================ + + bool assocFewEdgesFaces( const TopoDS_Face& face1, + SMESH_Mesh* mesh1, + const TopoDS_Face& face2, + SMESH_Mesh* mesh2, + HERE::TShapeShapeMap & theMap) + { + TopoDS_Vertex v1 = TopoDS::Vertex( HERE::OuterShape( face1, TopAbs_VERTEX )); + TopoDS_Vertex v2 = TopoDS::Vertex( HERE::OuterShape( face2, TopAbs_VERTEX )); + TopoDS_Vertex VV1[2] = { v1, v1 }; + TopoDS_Vertex VV2[2] = { v2, v2 }; + list< TopoDS_Edge > edges1, edges2; + if ( int nbE = HERE::FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2 )) + { + HERE::InsertAssociation( face1, face2, theMap ); + fixAssocByPropagation( nbE, edges1, edges2, mesh1, mesh2 ); + list< TopoDS_Edge >::iterator eIt1 = edges1.begin(); + list< TopoDS_Edge >::iterator eIt2 = edges2.begin(); + for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 ) + { + HERE::InsertAssociation( *eIt1, *eIt2, theMap ); + v1 = SMESH_MesherHelper::IthVertex( 0, *eIt1 ); + v2 = SMESH_MesherHelper::IthVertex( 0, *eIt2 ); + HERE::InsertAssociation( v1, v2, theMap ); + } + theMap.SetAssocType( HERE::TShapeShapeMap::FEW_EF ); + return true; + } + return false; + } + //================================================================================ /*! * \brief Look for a group containing a target shape and similar to a source group @@ -200,20 +250,19 @@ namespace { */ //================================================================================ - TopoDS_Shape FindGroupContaining(const TopoDS_Shape& tgtShape, + TopoDS_Shape findGroupContaining(const TopoDS_Shape& tgtShape, const SMESH_Mesh* tgtMesh1, const TopoDS_Shape& srcGroup) { list subMeshes = tgtMesh1->GetGroupSubMeshesContaining(tgtShape); list::iterator sm = subMeshes.begin(); int type, last = TopAbs_SHAPE; - StdMeshers_ProjectionUtils util; for ( ; sm != subMeshes.end(); ++sm ) { const TopoDS_Shape & group = (*sm)->GetSubShape(); // check if group is similar to srcGroup for ( type = srcGroup.ShapeType(); type < last; ++type) - if ( util.Count( srcGroup, (TopAbs_ShapeEnum)type, 0) != - util.Count( group, (TopAbs_ShapeEnum)type, 0)) + if ( SMESH_MesherHelper::Count( srcGroup, (TopAbs_ShapeEnum)type, 0) != + SMESH_MesherHelper::Count( group, (TopAbs_ShapeEnum)type, 0)) break; if ( type == last ) return group; @@ -227,7 +276,7 @@ namespace { */ //================================================================================ - bool AssocGroupsByPropagation(const TopoDS_Shape& theGroup1, + bool assocGroupsByPropagation(const TopoDS_Shape& theGroup1, const TopoDS_Shape& theGroup2, SMESH_Mesh& theMesh, HERE::TShapeShapeMap& theMap) @@ -277,9 +326,9 @@ namespace { // get edges of the face TopoDS_Edge edgeGr1, edgeGr2, verticEdge2; list< TopoDS_Edge > edges; list< int > nbEdgesInWire; - SMESH_Block::GetOrderedEdges( face, v1, edges, nbEdgesInWire); + SMESH_Block::GetOrderedEdges( face, edges, nbEdgesInWire, v1); if ( nbEdgesInWire.front() != 4 ) - return _StoreBadShape( face ); + return storeShapeForDebug( face ); list< TopoDS_Edge >::iterator edge = edges.begin(); if ( verticEdge.IsSame( *edge )) { edgeGr2 = *(++edge); @@ -300,11 +349,7 @@ namespace { if ( gr1It.Value().ShapeType() == TopAbs_FACE ) { // find a boundary edge of group1 to start from - TopoDS_Shape bndEdge; - TopExp_Explorer edgeExp1( theGroup1, TopAbs_EDGE ); - for ( ; bndEdge.IsNull() && edgeExp1.More(); edgeExp1.Next()) - if ( HERE::IsBoundaryEdge( TopoDS::Edge( edgeExp1.Current()), theGroup1, theMesh )) - bndEdge = edgeExp1.Current(); + TopoDS_Shape bndEdge = HERE::GetBoundaryEdge( theGroup1, theMesh ); if ( bndEdge.IsNull() ) return false; @@ -334,7 +379,7 @@ namespace { ancestIt.Initialize( theMesh.GetAncestors( edge2 ) ); for ( ; ancestIt.More() && face2.IsNull(); ancestIt.Next() ) { if ( ancestIt.Value().ShapeType() == TopAbs_FACE && - !theMap.IsBound( ancestIt.Value() ) && + !theMap.IsBound( ancestIt.Value(), /*is2nd=*/true ) && subshapes2.Contains( ancestIt.Value() )) face2 = ancestIt.Value(); } @@ -345,21 +390,98 @@ namespace { } } } + theMap.SetAssocType( HERE::TShapeShapeMap::PROPAGATION ); return true; } + //================================================================================ + /*! + * \brief Return true if uv position of the vIndex-th vertex of edge on face is close + * enough to given uv + */ + //================================================================================ + + bool sameVertexUV( const TopoDS_Edge& edge, + const TopoDS_Face& face, + const int& vIndex, + const gp_Pnt2d& uv, + const double& tol2d ) + { + TopoDS_Vertex VV[2]; + TopExp::Vertices( edge, VV[0], VV[1], true); + gp_Pnt2d v1UV = BRep_Tool::Parameters( VV[vIndex], face); + double dist2d = v1UV.Distance( uv ); + return dist2d < tol2d; + } + + //================================================================================ + /*! + * \brief Returns an EDGE suitable for search of initial vertex association + */ + //================================================================================ + + bool getOuterEdges( const TopoDS_Shape shape, + SMESH_Mesh& mesh, + std::list< TopoDS_Edge >& allBndEdges ) + { + if ( shape.ShapeType() == TopAbs_COMPOUND ) + { + TopoDS_Iterator it( shape ); + if ( it.More() && it.Value().ShapeType() == TopAbs_FACE ) // group of FACEs + { + // look for a boundary EDGE of a group + StdMeshers_ProjectionUtils::GetBoundaryEdge( shape, mesh, &allBndEdges ); + if ( !allBndEdges.empty() ) + return true; + } + } + SMESH_MesherHelper helper( mesh ); + helper.SetSubShape( shape ); + + TopExp_Explorer expF( shape, TopAbs_FACE ), expE; + if ( expF.More() ) { + for ( ; expF.More(); expF.Next() ) { + TopoDS_Shape wire = + StdMeshers_ProjectionUtils::OuterShape( TopoDS::Face( expF.Current() ), TopAbs_WIRE ); + for ( expE.Init( wire, TopAbs_EDGE ); expE.More(); expE.Next() ) + if ( ! helper.IsClosedEdge( TopoDS::Edge( expE.Current() ))) + { + if ( helper.IsSeamShape( expE.Current() )) + allBndEdges.push_back( TopoDS::Edge( expE.Current() )); + else + allBndEdges.push_front( TopoDS::Edge( expE.Current() )); + } + } + } + else if ( shape.ShapeType() != TopAbs_EDGE) { // no faces + for ( expE.Init( shape, TopAbs_EDGE ); expE.More(); expE.Next() ) + if ( ! helper.IsClosedEdge( TopoDS::Edge( expE.Current() ))) + { + if ( helper.IsSeamShape( expE.Current() )) + allBndEdges.push_back( TopoDS::Edge( expE.Current() )); + else + allBndEdges.push_front( TopoDS::Edge( expE.Current() )); + } + } + else if ( shape.ShapeType() == TopAbs_EDGE ) { + if ( ! helper.IsClosedEdge( TopoDS::Edge( shape ))) + allBndEdges.push_back( TopoDS::Edge( shape )); + } + return !allBndEdges.empty(); + } + } // namespace //======================================================================= -/*! - * \brief Looks for association of all subshapes of two shapes - * \param theShape1 - shape 1 - * \param theMesh1 - mesh built on shape 1 - * \param theShape2 - shape 2 - * \param theMesh2 - mesh built on shape 2 - * \param theAssociation - association map to be filled that may - * contain association of one or two pairs of vertices - * \retval bool - true if association found +/* + * Looks for association of all sub-shapes of two shapes + * \param theShape1 - target shape + * \param theMesh1 - mesh built on shape 1 + * \param theShape2 - source shape + * \param theMesh2 - mesh built on shape 2 + * \param theAssociation - association map to be filled that may + * contain association of one or two pairs of vertices + * \retval bool - true if association found */ //======================================================================= @@ -369,16 +491,40 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the SMESH_Mesh* theMesh2, TShapeShapeMap & theMap) { - if ( theShape1.ShapeType() != theShape2.ShapeType() ) { - // is it the case of a group member -> another group? (PAL16202, 16203) + // Structure of this long function is following + // 1) Group -> Group projection: theShape1 is a group member, + // theShape2 is another group. We find the group theShape1 is in and recall self. + // 2) Accosiate same shapes with different location (partners). + // 3) If vertex association is given, perform association according to shape type: + // switch ( ShapeType ) { + // case TopAbs_EDGE: + // case ...: + // } + // 4) else try to accosiate in different ways: + // a) accosiate shapes by propagation and other simple cases + // switch ( ShapeType ) { + // case TopAbs_EDGE: + // case ...: + // } + // b) find association of a couple of vertices and recall self. + // + + theMeshDS[0] = theMesh1->GetMeshDS(); // debug + theMeshDS[1] = theMesh2->GetMeshDS(); + + // ================================================================================= + // 1) Is it the case of associating a group member -> another group? (PAL16202, 16203) + // ================================================================================= + if ( theShape1.ShapeType() != theShape2.ShapeType() ) + { TopoDS_Shape group1, group2; if ( theShape1.ShapeType() == TopAbs_COMPOUND ) { group1 = theShape1; - group2 = FindGroupContaining( theShape2, theMesh2, group1 ); + group2 = findGroupContaining( theShape2, theMesh2, group1 ); } else if ( theShape2.ShapeType() == TopAbs_COMPOUND ) { group2 = theShape2; - group1 = FindGroupContaining( theShape1, theMesh1, group2 ); + group1 = findGroupContaining( theShape1, theMesh1, group2 ); } if ( group1.IsNull() || group2.IsNull() ) RETURN_BAD_RESULT("Different shape types"); @@ -386,28 +532,58 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the return FindSubShapeAssociation(group1, theMesh1, group2, theMesh2, theMap ); } - bool bidirect = ( !theShape1.IsSame( theShape2 )); + // ============ + // 2) Is partner? + // ============ + bool partner = theShape1.IsPartner( theShape2 ); + TopTools_DataMapIteratorOfDataMapOfShapeShape vvIt( theMap._map1to2 ); + for ( ; partner && vvIt.More(); vvIt.Next() ) + partner = vvIt.Key().IsPartner( vvIt.Value() ); + + if ( partner ) // Same shape with different location + { + // recursively associate all sub-shapes of theShape1 and theShape2 + typedef list< pair< TopoDS_Shape, TopoDS_Shape > > TShapePairsList; + TShapePairsList shapesQueue( 1, make_pair( theShape1, theShape2 )); + TShapePairsList::iterator s1_s2 = shapesQueue.begin(); + for ( ; s1_s2 != shapesQueue.end(); ++s1_s2 ) + { + if ( theMap.IsBound( s1_s2->first )) // avoid re-binding for a seam edge + continue; // to avoid this: Forward seam -> Reversed seam + InsertAssociation( s1_s2->first, s1_s2->second, theMap ); + TopoDS_Iterator s1It( s1_s2->first), s2It( s1_s2->second ); + for ( ; s1It.More(); s1It.Next(), s2It.Next() ) + shapesQueue.push_back( make_pair( s1It.Value(), s2It.Value() )); + } + theMap.SetAssocType( TShapeShapeMap::PARTNER ); + return true; + } + if ( !theMap.IsEmpty() ) { //====================================================================== - // HAS initial vertex association + // 3) HAS initial vertex association //====================================================================== + bool isVCloseness = ( theMap._assocType == TShapeShapeMap::CLOSE_VERTEX ); + theMap.SetAssocType( TShapeShapeMap::INIT_VERTEX ); switch ( theShape1.ShapeType() ) { // ---------------------------------------------------------------------- case TopAbs_EDGE: { // TopAbs_EDGE // ---------------------------------------------------------------------- - if ( theMap.Extent() != 2 ) + if ( theMap.Extent() != 1 ) RETURN_BAD_RESULT("Wrong map extent " << theMap.Extent() ); TopoDS_Edge edge1 = TopoDS::Edge( theShape1 ); TopoDS_Edge edge2 = TopoDS::Edge( theShape2 ); + if ( edge1.Orientation() >= TopAbs_INTERNAL ) edge1.Orientation( TopAbs_FORWARD ); + if ( edge2.Orientation() >= TopAbs_INTERNAL ) edge2.Orientation( TopAbs_FORWARD ); TopoDS_Vertex VV1[2], VV2[2]; TopExp::Vertices( edge1, VV1[0], VV1[1] ); TopExp::Vertices( edge2, VV2[0], VV2[1] ); int i1 = 0, i2 = 0; if ( theMap.IsBound( VV1[ i1 ] )) i1 = 1; if ( theMap.IsBound( VV2[ i2 ] )) i2 = 1; - InsertAssociation( VV1[ i1 ], VV2[ i2 ], theMap, bidirect); - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + InsertAssociation( VV1[ i1 ], VV2[ i2 ], theMap ); + InsertAssociation( theShape1, theShape2, theMap ); return true; } // ---------------------------------------------------------------------- @@ -415,6 +591,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the // ---------------------------------------------------------------------- TopoDS_Face face1 = TopoDS::Face( theShape1 ); TopoDS_Face face2 = TopoDS::Face( theShape2 ); + if ( face1.Orientation() >= TopAbs_INTERNAL ) face1.Orientation( TopAbs_FORWARD ); + if ( face2.Orientation() >= TopAbs_INTERNAL ) face2.Orientation( TopAbs_FORWARD ); TopoDS_Vertex VV1[2], VV2[2]; // find a not closed edge of face1 both vertices of which are associated @@ -436,20 +614,20 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } } list< TopoDS_Edge > edges1, edges2; - int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2 ); + int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2, isVCloseness ); if ( !nbE ) RETURN_BAD_RESULT("FindFaceAssociation() failed"); - FixAssocByPropagation( nbE, edges1, edges2, theMesh1, theMesh2 ); + fixAssocByPropagation( nbE, edges1, edges2, theMesh1, theMesh2 ); list< TopoDS_Edge >::iterator eIt1 = edges1.begin(); list< TopoDS_Edge >::iterator eIt2 = edges2.begin(); for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 ) { - InsertAssociation( *eIt1, *eIt2, theMap, bidirect); + InsertAssociation( *eIt1, *eIt2, theMap ); VV1[0] = TopExp::FirstVertex( *eIt1, true ); VV2[0] = TopExp::FirstVertex( *eIt2, true ); - InsertAssociation( VV1[0], VV2[0], theMap, bidirect); + InsertAssociation( VV1[0], VV2[0], theMap ); } - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + InsertAssociation( theShape1, theShape2, theMap ); return true; } // ---------------------------------------------------------------------- @@ -462,6 +640,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopExp_Explorer exp ( theShape1, TopAbs_EDGE ); for ( ; VV2[ 1 ].IsNull() && exp.More(); exp.Next() ) { edge1 = TopoDS::Edge( exp.Current() ); + if ( edge1.Orientation() >= TopAbs_INTERNAL ) edge1.Orientation( TopAbs_FORWARD ); TopExp::Vertices( edge1 , VV1[0], VV1[1] ); if ( theMap.IsBound( VV1[0] )) { VV2[ 0 ] = TopoDS::Vertex( theMap( VV1[0] )); @@ -476,7 +655,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the if ( edge2.IsNull() ) RETURN_BAD_RESULT("GetEdgeByVertices() failed"); - // build map of edge to faces if shapes are not subshapes of main ones + // build map of edge to faces if shapes are not sub-shapes of main ones bool isSubOfMain = false; if ( SMESHDS_SubMesh * sm = theMesh1->GetMeshDS()->MeshElements( theShape1 )) isSubOfMain = !sm->IsComplexSubmesh(); @@ -499,19 +678,21 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopoDS_Shape F1, F2; // get a face sharing edge1 (F1) - TopoDS_Shape FF2[2]; TopTools_ListIteratorOfListOfShape ancestIt1( edgeToFace1.FindFromKey( edge1 )); for ( ; F1.IsNull() && ancestIt1.More(); ancestIt1.Next() ) if ( ancestIt1.Value().ShapeType() == TopAbs_FACE ) - F1 = ancestIt1.Value().Oriented( TopAbs_FORWARD ); + F1 = ancestIt1.Value().Oriented //( TopAbs_FORWARD ); + ( SMESH_MesherHelper::GetSubShapeOri( theShape1, ancestIt1.Value() )); if ( F1.IsNull() ) RETURN_BAD_RESULT(" Face1 not found"); // get 2 faces sharing edge2 (one of them is F2) + TopoDS_Shape FF2[2]; TopTools_ListIteratorOfListOfShape ancestIt2( edgeToFace2.FindFromKey( edge2 )); for ( int i = 0; FF2[1].IsNull() && ancestIt2.More(); ancestIt2.Next() ) if ( ancestIt2.Value().ShapeType() == TopAbs_FACE ) - FF2[ i++ ] = ancestIt2.Value().Oriented( TopAbs_FORWARD ); + FF2[ i++ ] = ancestIt2.Value().Oriented // ( TopAbs_FORWARD ); + ( SMESH_MesherHelper::GetSubShapeOri( theShape2, ancestIt2.Value() )); // get oriented edge1 and edge2 from F1 and FF2[0] for ( exp.Init( F1, TopAbs_EDGE ); exp.More(); exp.Next() ) @@ -529,7 +710,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopExp::Vertices( edge1, VV1[0], VV1[1], true ); TopExp::Vertices( edge2, VV2[0], VV2[1], true ); F2 = FF2[ 0 ]; // (F2 !) - if ( !VV1[ 0 ].IsSame( theMap( VV2[ 0 ]))) { + if ( !VV1[ 0 ].IsSame( theMap( VV2[ 0 ], /*is2=*/true))) { edge2.Reverse(); if ( FF2[ 1 ].IsNull() ) F2.Reverse(); @@ -537,9 +718,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the F2 = FF2[ 1 ]; } - TopTools_MapOfShape boundEdges; - - // association of face subshapes and neighbour faces + // association of face sub-shapes and neighbour faces list< pair < TopoDS_Face, TopoDS_Edge > > FE1, FE2; list< pair < TopoDS_Face, TopoDS_Edge > >::iterator fe1, fe2; FE1.push_back( make_pair( TopoDS::Face( F1 ), edge1 )); @@ -554,39 +733,39 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopExp::Vertices( edge1, VV1[0], VV1[1], true ); TopExp::Vertices( edge2, VV2[0], VV2[1], true ); list< TopoDS_Edge > edges1, edges2; - int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2 ); + int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2, isVCloseness ); if ( !nbE ) RETURN_BAD_RESULT("FindFaceAssociation() failed"); - InsertAssociation( face1, face2, theMap, bidirect); // assoc faces + InsertAssociation( face1, face2, theMap ); // assoc faces MESSAGE("Assoc FACE " << theMesh1->GetMeshDS()->ShapeToIndex( face1 )<< " to " << theMesh2->GetMeshDS()->ShapeToIndex( face2 )); if ( nbE == 2 && (edge1.IsSame( edges1.front())) != (edge2.IsSame( edges2.front()))) { - Reverse( edges2, nbE ); + reverseEdges( edges2, nbE ); } list< TopoDS_Edge >::iterator eIt1 = edges1.begin(); list< TopoDS_Edge >::iterator eIt2 = edges2.begin(); for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 ) { - if ( !boundEdges.Add( *eIt1 )) continue; // already associated - InsertAssociation( *eIt1, *eIt2, theMap, bidirect); // assoc edges - MESSAGE("Assoc edge " << theMesh1->GetMeshDS()->ShapeToIndex( *eIt1 )<< - " to " << theMesh2->GetMeshDS()->ShapeToIndex( *eIt2 )); + if ( !InsertAssociation( *eIt1, *eIt2, theMap )) // assoc edges + continue; // already associated VV1[0] = TopExp::FirstVertex( *eIt1, true ); VV2[0] = TopExp::FirstVertex( *eIt2, true ); - InsertAssociation( VV1[0], VV2[0], theMap, bidirect); // assoc vertices - MESSAGE("Assoc vertex " << theMesh1->GetMeshDS()->ShapeToIndex( VV1[0] )<< - " to " << theMesh2->GetMeshDS()->ShapeToIndex( VV2[0] )); + InsertAssociation( VV1[0], VV2[0], theMap ); // assoc vertices // add adjacent faces to process TopoDS_Face nextFace1 = GetNextFace( edgeToFace1, *eIt1, face1 ); TopoDS_Face nextFace2 = GetNextFace( edgeToFace2, *eIt2, face2 ); if ( !nextFace1.IsNull() && !nextFace2.IsNull() ) { + if ( SMESH_MesherHelper::GetSubShapeOri( nextFace1, *eIt1 ) == eIt1->Orientation() ) + nextFace1.Reverse(); + if ( SMESH_MesherHelper::GetSubShapeOri( nextFace2, *eIt2 ) == eIt2->Orientation() ) + nextFace2.Reverse(); FE1.push_back( make_pair( nextFace1, *eIt1 )); FE2.push_back( make_pair( nextFace2, *eIt2 )); } } } - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + InsertAssociation( theShape1, theShape2, theMap ); return true; } // ---------------------------------------------------------------------- @@ -595,7 +774,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the // Maybe groups contain only one member TopoDS_Iterator it1( theShape1 ), it2( theShape2 ); TopAbs_ShapeEnum memberType = it1.Value().ShapeType(); - int nbMembers = Count( theShape1, memberType, true ); + int nbMembers = SMESH_MesherHelper::Count( theShape1, memberType, true ); if ( nbMembers == 0 ) return true; if ( nbMembers == 1 ) { return FindSubShapeAssociation( it1.Value(), theMesh1, it2.Value(), theMesh2, theMap ); @@ -625,7 +804,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the if ( !initAssocOK ) { // for shell association there must be an edge with both vertices bound TopoDS_Vertex v1, v2; - TopExp::Vertices( TopoDS::Edge( it1.Value()), v1, v2 ); + TopExp::Vertices( TopoDS::Edge( it1.Value().Oriented(TopAbs_FORWARD)), v1, v2 ); initAssocOK = ( theMap.IsBound( v1 ) && theMap.IsBound( v2 )); } } @@ -644,7 +823,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the if ( groupEdges[ is2ndGroup ].Contains( f.Current() )) if ( ++nbGroupEdges > 1 ) break; - bool add = (nbGroupEdges > 1 || Count( face, TopAbs_EDGE, true ) == 1 ); + bool add = (nbGroupEdges > 1 || + SMESH_MesherHelper::Count( face, TopAbs_EDGE, true ) == 1 ); if ( !add ) { add = true; for ( TopExp_Explorer v( face, TopAbs_VERTEX ); add && v.More(); v.Next()) @@ -661,8 +841,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } // Associate shells // - int nbFaces1 = Count( shell1, TopAbs_FACE, 0 ); - int nbFaces2 = Count( shell2, TopAbs_FACE, 0 ); + int nbFaces1 = SMESH_MesherHelper:: Count( shell1, TopAbs_FACE, 0 ); + int nbFaces2 = SMESH_MesherHelper:: Count( shell2, TopAbs_FACE, 0 ); if ( nbFaces1 != nbFaces2 ) RETURN_BAD_RESULT("Different nb of faces found for shells"); if ( nbFaces1 > 0 ) { @@ -708,7 +888,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TShapeShapeMap tmpMap; ok = FindSubShapeAssociation( comp[0], theMesh1, comp[1], theMesh2, tmpMap ); if ( ok ) { - TopTools_DataMapIteratorOfDataMapOfShapeShape mapIt( tmpMap ); + TopTools_DataMapIteratorOfDataMapOfShapeShape mapIt( tmpMap._map1to2 ); for ( ; mapIt.More(); mapIt.Next() ) theMap.Bind( mapIt.Key(), mapIt.Value()); } @@ -767,13 +947,13 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopoDS_Edge e1 = TopoDS::Edge( edges1.First() ); v2e[0].UnBind( V[0] ); v2e[1].UnBind( V[1] ); - InsertAssociation( e0, e1, theMap, bidirect ); + InsertAssociation( e0, e1, theMap ); MESSAGE("Assoc edge " << theMesh1->GetMeshDS()->ShapeToIndex( e0 )<< " to " << theMesh2->GetMeshDS()->ShapeToIndex( e1 )); V[0] = GetNextVertex( e0, V[0] ); V[1] = GetNextVertex( e1, V[1] ); if ( !V[0].IsNull() ) { - InsertAssociation( V[0], V[1], theMap, bidirect ); + InsertAssociation( V[0], V[1], theMap ); MESSAGE("Assoc vertex " << theMesh1->GetMeshDS()->ShapeToIndex( V[0] )<< " to " << theMesh2->GetMeshDS()->ShapeToIndex( V[1] )); } @@ -799,9 +979,9 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } else { v1n = v1e1; e1b = edges1.First(); e1n = edges1.Last(); } - InsertAssociation( e0b, e1b, theMap, bidirect ); - InsertAssociation( e0n, e1n, theMap, bidirect ); - InsertAssociation( v0n, v1n, theMap, bidirect ); + InsertAssociation( e0b, e1b, theMap ); + InsertAssociation( e0n, e1n, theMap ); + InsertAssociation( v0n, v1n, theMap ); MESSAGE("Assoc edge " << theMesh1->GetMeshDS()->ShapeToIndex( e0b )<< " to " << theMesh2->GetMeshDS()->ShapeToIndex( e1b )); MESSAGE("Assoc edge " << theMesh1->GetMeshDS()->ShapeToIndex( e0n )<< @@ -828,7 +1008,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } // end case of available initial vertex association //====================================================================== - // NO INITIAL VERTEX ASSOCIATION + // 4) NO INITIAL VERTEX ASSOCIATION //====================================================================== switch ( theShape1.ShapeType() ) { @@ -837,7 +1017,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the // ---------------------------------------------------------------------- TopoDS_Edge edge1 = TopoDS::Edge( theShape1 ); TopoDS_Edge edge2 = TopoDS::Edge( theShape2 ); - if ( IsPropagationPossible( theMesh1, theMesh2 )) + if ( isPropagationPossible( theMesh1, theMesh2 )) { TopoDS_Edge prpEdge = GetPropagationEdge( theMesh1, edge2, edge1 ).second; if ( !prpEdge.IsNull() ) @@ -845,24 +1025,26 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopoDS_Vertex VV1[2], VV2[2]; TopExp::Vertices( edge1, VV1[0], VV1[1], true ); TopExp::Vertices( prpEdge, VV2[0], VV2[1], true ); - InsertAssociation( VV1[ 0 ], VV2[ 0 ], theMap, bidirect); - InsertAssociation( VV1[ 1 ], VV2[ 1 ], theMap, bidirect); + InsertAssociation( VV1[ 0 ], VV2[ 0 ], theMap ); + InsertAssociation( VV1[ 1 ], VV2[ 1 ], theMap ); if ( VV1[0].IsSame( VV1[1] ) || // one of edges is closed VV2[0].IsSame( VV2[1] ) ) { - InsertAssociation( edge1, prpEdge, theMap, bidirect); // insert with a proper orientation + InsertAssociation( edge1, prpEdge, theMap ); // insert with a proper orientation } - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + InsertAssociation( theShape1, theShape2, theMap ); + theMap.SetAssocType( TShapeShapeMap::PROPAGATION ); return true; // done } } - if ( IsClosedEdge( edge1 ) && IsClosedEdge( edge2 )) + if ( SMESH_MesherHelper::IsClosedEdge( edge1 ) && + SMESH_MesherHelper::IsClosedEdge( edge2 )) { // TODO: find out a proper orientation (is it possible?) - InsertAssociation( edge1, edge2, theMap, bidirect); // insert with a proper orientation + InsertAssociation( edge1, edge2, theMap ); // insert with a proper orientation InsertAssociation( TopExp::FirstVertex(edge1), TopExp::FirstVertex(edge2), - theMap, bidirect); - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + theMap ); + InsertAssociation( theShape1, theShape2, theMap ); return true; // done } break; // try by vertex closeness @@ -870,50 +1052,64 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the case TopAbs_FACE: { // ---------------------------------------------------------------------- - if ( IsPropagationPossible( theMesh1, theMesh2 )) // try by propagation in one mesh + if ( isPropagationPossible( theMesh1, theMesh2 )) // try by propagation in one mesh { TopoDS_Face face1 = TopoDS::Face(theShape1); TopoDS_Face face2 = TopoDS::Face(theShape2); + if ( face1.Orientation() >= TopAbs_INTERNAL ) face1.Orientation( TopAbs_FORWARD ); + if ( face2.Orientation() >= TopAbs_INTERNAL ) face2.Orientation( TopAbs_FORWARD ); TopoDS_Edge edge1, edge2; // get outer edge of theShape1 - edge1 = TopoDS::Edge( OuterShape( face1, TopAbs_EDGE )); - // find out if any edge of face2 is a propagation edge of outer edge1 - map propag_edges; // use map to find the closest propagation edge - for ( TopExp_Explorer exp( face2, TopAbs_EDGE ); exp.More(); exp.Next() ) { - edge2 = TopoDS::Edge( exp.Current() ); - pair step_edge = GetPropagationEdge( theMesh1, edge2, edge1 ); - if ( !step_edge.second.IsNull() ) { // propagation found - propag_edges.insert( step_edge ); + TopoDS_Shape wire = OuterShape( face1, TopAbs_WIRE ); + //edge1 = TopoDS::Edge( OuterShape( face1, TopAbs_EDGE )); + // use map to find the closest propagation edge + map > propag_edges; + for ( TopoDS_Iterator edgeIt( wire ); edgeIt.More(); edgeIt.Next() ) + { + edge1 = TopoDS::Edge( edgeIt.Value() ); + // find out if any edge of face2 is a propagation edge of outer edge1 + for ( TopExp_Explorer exp( face2, TopAbs_EDGE ); exp.More(); exp.Next() ) { + edge2 = TopoDS::Edge( exp.Current() ); + pair step_edge = GetPropagationEdge( theMesh1, edge2, edge1 ); + if ( !step_edge.second.IsNull() ) { // propagation found + propag_edges.insert( make_pair( step_edge.first, + ( make_pair( edge1, step_edge.second )))); + if ( step_edge.first == 1 ) break; // most close found + } } + if ( !propag_edges.empty() && propag_edges.begin()->first == 1 ) break; } if ( !propag_edges.empty() ) // propagation found { - edge2 = propag_edges.begin()->second; + edge1 = propag_edges.begin()->second.first; + edge2 = propag_edges.begin()->second.second; TopoDS_Vertex VV1[2], VV2[2]; TopExp::Vertices( edge1, VV1[0], VV1[1], true ); TopExp::Vertices( edge2, VV2[0], VV2[1], true ); list< TopoDS_Edge > edges1, edges2; int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2 ); if ( !nbE ) RETURN_BAD_RESULT("FindFaceAssociation() failed"); - if ( nbE == 2 ) // only 2 edges + // take care of proper association of propagated edges + bool same1 = edge1.IsSame( edges1.front() ); + bool same2 = edge2.IsSame( edges2.front() ); + if ( same1 != same2 ) { - // take care of proper association of propagated edges - bool same1 = edge1.IsSame( edges1.front() ); - bool same2 = edge2.IsSame( edges2.front() ); - if ( same1 != same2 ) - Reverse(edges2, nbE); + reverseEdges(edges2, nbE); + if ( nbE != 2 ) // 2 degen edges of 4 (issue 0021144) + edges2.splice( edges2.end(), edges2, edges2.begin()); } // store association list< TopoDS_Edge >::iterator eIt1 = edges1.begin(); list< TopoDS_Edge >::iterator eIt2 = edges2.begin(); for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 ) { - InsertAssociation( *eIt1, *eIt2, theMap, bidirect); + InsertAssociation( *eIt1, *eIt2, theMap ); VV1[0] = TopExp::FirstVertex( *eIt1, true ); VV2[0] = TopExp::FirstVertex( *eIt2, true ); - InsertAssociation( VV1[0], VV2[0], theMap, bidirect); + InsertAssociation( VV1[0], VV2[0], theMap ); } - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + InsertAssociation( theShape1, theShape2, theMap ); + theMap.SetAssocType( TShapeShapeMap::PROPAGATION ); return true; } } @@ -921,21 +1117,14 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } case TopAbs_COMPOUND: { // ---------------------------------------------------------------------- - if ( IsPropagationPossible( theMesh1, theMesh2 )) { + if ( isPropagationPossible( theMesh1, theMesh2 )) { // try to accosiate all using propagation - if ( AssocGroupsByPropagation( theShape1, theShape2, *theMesh1, theMap )) + if ( assocGroupsByPropagation( theShape1, theShape2, *theMesh1, theMap )) return true; - // find a boundary edge for theShape1 - TopoDS_Edge E; - for(TopExp_Explorer exp(theShape1, TopAbs_EDGE); exp.More(); exp.Next() ) { - E = TopoDS::Edge( exp.Current() ); - if ( IsBoundaryEdge( E, theShape1, *theMesh1 )) - break; - else - E.Nullify(); - } + // find a boundary edge of theShape1 + TopoDS_Edge E = GetBoundaryEdge( theShape1, *theMesh1 ); if ( E.IsNull() ) break; // try by vertex closeness @@ -983,9 +1172,13 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } } if ( !VV1[1].IsNull() ) { - InsertAssociation( VV1[0], VV2[0], theMap, bidirect); - InsertAssociation( VV1[1], VV2[1], theMap, bidirect); - return FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap); + InsertAssociation( VV1[0], VV2[0], theMap ); + InsertAssociation( VV1[1], VV2[1], theMap ); + TShapeShapeMap::EAssocType asType = theMap._assocType; + theMap.SetAssocType( TShapeShapeMap::PROPAGATION ); + if ( FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap )) + return true; + theMap._assocType = asType; } } break; // try by vertex closeness @@ -993,32 +1186,70 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the default:; } - // Find association by closeness of vertices - // ------------------------------------------ + // 4.b) Find association by closeness of vertices + // ---------------------------------------------- TopTools_IndexedMapOfShape vMap1, vMap2; TopExp::MapShapes( theShape1, TopAbs_VERTEX, vMap1 ); TopExp::MapShapes( theShape2, TopAbs_VERTEX, vMap2 ); + TopoDS_Vertex VV1[2], VV2[2]; if ( vMap1.Extent() != vMap2.Extent() ) - RETURN_BAD_RESULT("Different nb of vertices"); + { + if ( SMESH_MesherHelper:: Count( theShape1, TopAbs_EDGE, /*ignoreSame=*/false ) != + SMESH_MesherHelper:: Count( theShape2, TopAbs_EDGE, /*ignoreSame=*/false )) + RETURN_BAD_RESULT("Different nb of vertices"); + } - if ( vMap1.Extent() == 1 ) { - InsertAssociation( vMap1(1), vMap2(1), theMap, bidirect); + if ( vMap1.Extent() == 1 || vMap2.Extent() == 1 ) { + InsertAssociation( vMap1(1), vMap2(1), theMap ); if ( theShape1.ShapeType() == TopAbs_EDGE ) { - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + if ( vMap1.Extent() == 2 ) + InsertAssociation( vMap1(2), vMap2(1), theMap ); + else if ( vMap2.Extent() == 2 ) + InsertAssociation( vMap2(2), vMap1(1), theMap ); + InsertAssociation( theShape1, theShape2, theMap ); return true; } return FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap); } + // Try to associate by common vertices of an edge + for ( int i = 1; i <= vMap1.Extent(); ++i ) + { + const TopoDS_Shape& v1 = vMap1(i); + if ( vMap2.Contains( v1 )) + { + // find an egde sharing v1 and sharing at the same time another common vertex + PShapeIteratorPtr edgeIt = SMESH_MesherHelper::GetAncestors( v1, *theMesh1, TopAbs_EDGE); + bool edgeFound = false; + while ( edgeIt->more() && !edgeFound ) + { + TopoDS_Edge edge = TopoDS::Edge( edgeIt->next()->Oriented(TopAbs_FORWARD)); + TopExp::Vertices(edge, VV1[0], VV1[1]); + if ( !VV1[0].IsSame( VV1[1] )) + edgeFound = ( vMap2.Contains( VV1[ v1.IsSame(VV1[0]) ? 1:0])); + } + if ( edgeFound ) + { + InsertAssociation( VV1[0], VV1[0], theMap ); + InsertAssociation( VV1[1], VV1[1], theMap ); + TShapeShapeMap::EAssocType asType = theMap._assocType; + theMap.SetAssocType( TShapeShapeMap::COMMON_VERTEX ); + if ( FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap )) + return true; + theMap._assocType = asType; + } + } + } + // Find transformation to make the shapes be of similar size at same location Bnd_Box box[2]; - for ( int i = 1; i <= vMap1.Extent(); ++i ) { + for ( int i = 1; i <= vMap1.Extent(); ++i ) box[ 0 ].Add( BRep_Tool::Pnt ( TopoDS::Vertex( vMap1( i )))); + for ( int i = 1; i <= vMap2.Extent(); ++i ) box[ 1 ].Add( BRep_Tool::Pnt ( TopoDS::Vertex( vMap2( i )))); - } gp_Pnt gc[2]; // box center double x0,y0,z0, x1,y1,z1; @@ -1033,59 +1264,84 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the // Find 2 closest vertices - TopoDS_Vertex VV1[2], VV2[2]; // get 2 linked vertices of shape 1 not belonging to an inner wire of a face - TopoDS_Shape edge = theShape1; - TopExp_Explorer expF( theShape1, TopAbs_FACE ), expE; - if ( expF.More() ) { - for ( ; expF.More(); expF.Next() ) { - edge.Nullify(); - TopoDS_Shape wire = OuterShape( TopoDS::Face( expF.Current() ), TopAbs_WIRE ); - for ( expE.Init( wire, TopAbs_EDGE ); edge.IsNull() && expE.More(); expE.Next() ) - if ( !IsClosedEdge( TopoDS::Edge( expE.Current() ))) - edge = expE.Current(); - if ( !edge.IsNull() ) - break; - } - } else if (edge.ShapeType() != TopAbs_EDGE) { // no faces - edge.Nullify(); - for ( expE.Init( theShape1, TopAbs_EDGE ); edge.IsNull() && expE.More(); expE.Next() ) - if ( !IsClosedEdge( TopoDS::Edge( expE.Current() ))) - edge = expE.Current(); + std::list< TopoDS_Edge > allBndEdges1; + if ( !getOuterEdges( theShape1, *theMesh1, allBndEdges1 )) + { + if ( theShape1.ShapeType() != TopAbs_FACE ) + RETURN_BAD_RESULT("Edge not found"); + return assocFewEdgesFaces( TopoDS::Face( theShape1 ), theMesh1, + TopoDS::Face( theShape2 ), theMesh2, theMap ); } - if ( edge.IsNull() || edge.ShapeType() != TopAbs_EDGE ) - RETURN_BAD_RESULT("Edge not found"); - - TopExp::Vertices( TopoDS::Edge( edge ), VV1[0], VV1[1]); - if ( VV1[0].IsSame( VV1[1] )) - RETURN_BAD_RESULT("Only closed edges"); - - // find vertices closest to 2 linked vertices of shape 1 - for ( int i1 = 0; i1 < 2; ++i1 ) + std::list< TopoDS_Edge >::iterator edge1 = allBndEdges1.begin(); + double minDist = std::numeric_limits::max(); + for ( int nbChecked=0; edge1 != allBndEdges1.end() && nbChecked++ < 10; ++edge1 ) { - double dist2 = DBL_MAX; - gp_Pnt p1 = BRep_Tool::Pnt( VV1[ i1 ]); - p1.Translate( vec01 ); - p1.Scale( gc[1], scale ); - for ( int i2 = 1; i2 <= vMap2.Extent(); ++i2 ) + TopoDS_Vertex edge1VV[2]; + TopExp::Vertices( TopoDS::Edge( edge1->Oriented(TopAbs_FORWARD)), edge1VV[0], edge1VV[1]); + if ( edge1VV[0].IsSame( edge1VV[1] )) + continue;//RETURN_BAD_RESULT("Only closed edges"); + + // find vertices closest to 2 linked vertices of shape 1 + double dist2[2] = { 1e+100, 1e+100 }; + TopoDS_Vertex edge2VV[2]; + for ( int i1 = 0; i1 < 2; ++i1 ) { - TopoDS_Vertex V2 = TopoDS::Vertex( vMap2( i2 )); - gp_Pnt p2 = BRep_Tool::Pnt ( V2 ); - double d2 = p1.SquareDistance( p2 ); - if ( d2 < dist2 && !V2.IsSame( VV2[ 0 ])) { - VV2[ i1 ] = V2; dist2 = d2; + gp_Pnt p1 = BRep_Tool::Pnt( edge1VV[ i1 ]); + p1.Scale( gc[0], scale ); + p1.Translate( vec01 ); + if ( !i1 ) { + // select a closest vertex among all ones in vMap2 + for ( int i2 = 1; i2 <= vMap2.Extent(); ++i2 ) + { + TopoDS_Vertex V2 = TopoDS::Vertex( vMap2( i2 )); + gp_Pnt p2 = BRep_Tool::Pnt ( V2 ); + double d2 = p1.SquareDistance( p2 ); + if ( d2 < dist2[ 0 ] && d2 < minDist ) { + edge2VV[ 0 ] = V2; + dist2 [ 0 ] = d2; + } + } + } + else if ( !edge2VV[0].IsNull() ) { + // select a closest vertex among ends of edges meeting at edge2VV[0] + PShapeIteratorPtr edgeIt = SMESH_MesherHelper::GetAncestors( edge2VV[0], + *theMesh2, TopAbs_EDGE); + while ( const TopoDS_Shape* edge2 = edgeIt->next() ) + for ( TopoDS_Iterator itV2( *edge2 ); itV2.More(); itV2.Next() ) + { + if ( itV2.Value().IsSame( edge2VV[ 0 ])) continue; + if ( !vMap2.Contains( itV2.Value() )) continue; + TopoDS_Vertex V2 = TopoDS::Vertex( itV2.Value() ); + gp_Pnt p2 = BRep_Tool::Pnt ( V2 ); + double d2 = p1.SquareDistance( p2 ); + if ( d2 < dist2[1] && d2 < minDist ) { + edge2VV[ 1 ] = V2; + dist2 [ 1 ] = d2; + } + } } } + if ( dist2[0] + dist2[1] < minDist ) { + VV1[0] = edge1VV[0]; + VV1[1] = edge1VV[1]; + VV2[0] = edge2VV[0]; + VV2[1] = edge2VV[1]; + minDist = dist2[0] + dist2[1]; + if ( minDist < 1e-10 ) + break; + } } + theMap.SetAssocType( TShapeShapeMap::CLOSE_VERTEX ); - InsertAssociation( VV1[ 0 ], VV2[ 0 ], theMap, bidirect); - InsertAssociation( VV1[ 1 ], VV2[ 1 ], theMap, bidirect); + InsertAssociation( VV1[ 0 ], VV2[ 0 ], theMap ); + InsertAssociation( VV1[ 1 ], VV2[ 1 ], theMap ); MESSAGE("Initial assoc VERT " << theMesh1->GetMeshDS()->ShapeToIndex( VV1[ 0 ] )<< " to " << theMesh2->GetMeshDS()->ShapeToIndex( VV2[ 0 ] )<< "\nand VERT " << theMesh1->GetMeshDS()->ShapeToIndex( VV1[ 1 ] )<< " to " << theMesh2->GetMeshDS()->ShapeToIndex( VV2[ 1 ] )); if ( theShape1.ShapeType() == TopAbs_EDGE ) { - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + InsertAssociation( theShape1, theShape2, theMap ); return true; } @@ -1093,80 +1349,319 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } //================================================================================ -/*! - * \brief Find association of edges of faces - * \param face1 - face 1 - * \param VV1 - vertices of face 1 - * \param face2 - face 2 - * \param VV2 - vertices of face 2 associated with ones of face 1 - * \param edges1 - out list of edges of face 1 - * \param edges2 - out list of edges of face 2 - * \retval int - nb of edges in an outer wire in a success case, else zero +/* + * Find association of edges of faces + * \param face1 - face 1 + * \param VV1 - vertices of face 1 + * \param face2 - face 2 + * \param VV2 - vertices of face 2 associated with ones of face 1 + * \param edges1 - out list of edges of face 1 + * \param edges2 - out list of edges of face 2 + * \param isClosenessAssoc - is association starting by VERTEX closeness + * \retval int - nb of edges in an outer wire in a success case, else zero */ //================================================================================ -int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, - TopoDS_Vertex VV1[2], - const TopoDS_Face& face2, - TopoDS_Vertex VV2[2], +int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, + TopoDS_Vertex VV1[2], + const TopoDS_Face& face2, + TopoDS_Vertex VV2[2], list< TopoDS_Edge > & edges1, - list< TopoDS_Edge > & edges2) + list< TopoDS_Edge > & edges2, + const bool isClosenessAssoc) { - edges1.clear(); - edges2.clear(); - - list< int > nbVInW1, nbVInW2; - if ( SMESH_Block::GetOrderedEdges( face1, VV1[0], edges1, nbVInW1) != - SMESH_Block::GetOrderedEdges( face2, VV2[0], edges2, nbVInW2) ) - RETURN_BAD_RESULT("Different number of wires in faces "); - - if ( nbVInW1.front() != nbVInW2.front() ) - RETURN_BAD_RESULT("Different number of edges in faces: " << - nbVInW1.front() << " != " << nbVInW2.front()); - - // Define if we need to reverse one of wires to make edges in lists match each other - - bool reverse = false; - - list< TopoDS_Edge >::iterator eBackIt; - if ( !VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) { - reverse = true; - eBackIt = --edges1.end(); - // check if the second vertex belongs to the first or last edge in the wire - if ( !VV1[1].IsSame( TopExp::FirstVertex( *eBackIt, true ))) { - bool KO = true; // belongs to none - if ( nbVInW1.size() > 1 ) { // several wires - eBackIt = edges1.begin(); - for ( int i = 1; i < nbVInW1.front(); ++i ) ++eBackIt; - KO = !VV1[1].IsSame( TopExp::FirstVertex( *eBackIt, true )); + bool OK = false; + list< int > nbEInW1, nbEInW2; + list< TopoDS_Edge >::iterator edgeIt; + int i_ok_wire_algo = -1; + for ( int outer_wire_algo = 0; outer_wire_algo < 2 && !OK; ++outer_wire_algo ) + { + edges1.clear(); + edges2.clear(); + + if ( SMESH_Block::GetOrderedEdges( face1, edges1, nbEInW1, VV1[0], outer_wire_algo) != + SMESH_Block::GetOrderedEdges( face2, edges2, nbEInW2, VV2[0], outer_wire_algo) ) + CONT_BAD_RESULT("Different number of wires in faces "); + + if ( nbEInW1 != nbEInW2 && outer_wire_algo == 0 && + ( std::accumulate( nbEInW1.begin(), nbEInW1.end(), 0) != + std::accumulate( nbEInW2.begin(), nbEInW2.end(), 0))) + RETURN_BAD_RESULT("Different number of edges in faces"); + + if ( nbEInW1.front() != nbEInW2.front() ) + CONT_BAD_RESULT("Different number of edges in the outer wire: " << + nbEInW1.front() << " != " << nbEInW2.front()); + + i_ok_wire_algo = outer_wire_algo; + + // Define if we need to reverse one of wires to make edges in lists match each other + + bool reverse = false; + const bool severalWires = ( nbEInW1.size() > 1 ); + + if ( !VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) + { + reverse = true; + // check if the second vertex belongs to the first or last edge in the wire + edgeIt = --edges1.end(); // pointer to the last edge in the outer wire + if ( severalWires ) { + edgeIt = edges1.begin(); + std::advance( edgeIt, nbEInW1.front()-1 ); + } + if ( TopExp::FirstVertex( *edgeIt ).IsSame( TopExp::LastVertex( *edgeIt )) && + SMESH_Algo::isDegenerated( *edgeIt )) { + --edgeIt; // skip a degenerated edge (test 3D_mesh_Projection_00/A3) + } + if ( !VV1[1].IsSame( TopExp::FirstVertex( *edgeIt, true ))) { + CONT_BAD_RESULT("GetOrderedEdges() failed"); + } + } + if ( !VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true ))) + { + reverse = !reverse; + // check if the second vertex belongs to the first or last edge in the wire + edgeIt = --edges2.end(); // pointer to the last edge in the outer wire + if ( severalWires ) { + edgeIt = edges2.begin(); + std::advance( edgeIt, nbEInW2.front()-1 ); + } + if ( TopExp::FirstVertex( *edgeIt ).IsSame( TopExp::LastVertex( *edgeIt )) && + SMESH_Algo::isDegenerated( *edgeIt )) { + --edgeIt; // skip a degenerated edge + } + if ( !VV2[1].IsSame( TopExp::FirstVertex( *edgeIt, true ))) { + CONT_BAD_RESULT("GetOrderedEdges() failed"); + } + } + if ( reverse ) + { + reverseEdges( edges2 , nbEInW2.front()); + + if ( SMESH_Algo::isDegenerated( edges2.front() )) + { + // move a degenerated edge to the back of the outer wire + edgeIt = edges2.end(); + if ( severalWires ) { + edgeIt = edges2.begin(); + std::advance( edgeIt, nbEInW2.front() ); + } + edges2.splice( edgeIt, edges2, edges2.begin() ); + } + if (( VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) != + ( VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true )))) + CONT_BAD_RESULT("GetOrderedEdges() failed"); + } + OK = true; + + } // loop algos getting an outer wire + + if ( OK && nbEInW1.front() > 4 ) // care of a case where faces are closed (23032) + { + // check if the first edges are seam ones + list< TopoDS_Edge >::iterator revSeam1, revSeam2; + revSeam1 = std::find( ++edges1.begin(), edges1.end(), edges1.front().Reversed()); + revSeam2 = edges2.end(); + if ( revSeam1 != edges1.end() ) + revSeam2 = std::find( ++edges2.begin(), edges2.end(), edges2.front().Reversed()); + if ( revSeam2 != edges2.end() ) // two seams detected + { + bool reverse = + std::distance( edges1.begin(), revSeam1 ) != std::distance( edges2.begin(), revSeam2 ); + if ( !reverse && isClosenessAssoc ) + { + // compare orientations of a non-seam edges using 3D closeness; + // look for a non-seam edges + list< TopoDS_Edge >::iterator edge1 = ++edges1.begin(); + list< TopoDS_Edge >::iterator edge2 = ++edges2.begin(); + for ( ; edge1 != edges1.end(); ++edge1, ++edge2 ) + { + if (( edge1 == revSeam1 ) || + ( SMESH_Algo::isDegenerated( *edge1 )) || + ( std::find( ++edges1.begin(), edges1.end(), edge1->Reversed()) != edges1.end() )) + continue; + gp_Pnt p1 = BRep_Tool::Pnt( VV1[0] ); + gp_Pnt p2 = BRep_Tool::Pnt( VV2[0] ); + gp_Vec vec2to1( p2, p1 ); + + gp_Pnt pp1[2], pp2[2]; + const double r = 0.2345; + double f,l; + Handle(Geom_Curve) C = BRep_Tool::Curve( *edge1, f,l ); + pp1[0] = C->Value( f * r + l * ( 1. - r )); + pp1[1] = C->Value( l * r + f * ( 1. - r )); + if ( edge1->Orientation() == TopAbs_REVERSED ) + std::swap( pp1[0], pp1[1] ); + C = BRep_Tool::Curve( *edge2, f,l ); + if ( C.IsNull() ) return 0; + pp2[0] = C->Value( f * r + l * ( 1. - r )).Translated( vec2to1 ); + pp2[1] = C->Value( l * r + f * ( 1. - r )).Translated( vec2to1 ); + if ( edge2->Orientation() == TopAbs_REVERSED ) + std::swap( pp2[0], pp2[1] ); + + double dist00 = pp1[0].SquareDistance( pp2[0] ); + double dist01 = pp1[0].SquareDistance( pp2[1] ); + reverse = ( dist00 > dist01 ); + break; + } + } + if ( reverse ) // make a seam counterpart be the first + { + list< TopoDS_Edge >::iterator outWireEnd = edges2.begin(); + std::advance( outWireEnd, nbEInW2.front() ); + edges2.splice( outWireEnd, edges2, edges2.begin(), ++revSeam2 ); + reverseEdges( edges2 , nbEInW2.front()); } - if ( KO ) - RETURN_BAD_RESULT("GetOrderedEdges() failed"); } } - eBackIt = --edges2.end(); - if ( !VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true ))) { - reverse = !reverse; - // check if the second vertex belongs to the first or last edge in the wire - if ( !VV2[1].IsSame( TopExp::FirstVertex( *eBackIt, true ))) { - bool KO = true; // belongs to none - if ( nbVInW2.size() > 1 ) { // several wires - eBackIt = edges2.begin(); - for ( int i = 1; i < nbVInW2.front(); ++i ) ++eBackIt; - KO = !VV2[1].IsSame( TopExp::FirstVertex( *eBackIt, true )); + + // Try to orient all (if !OK) or only internal wires (issue 0020996) by UV similarity + + if (( !OK || nbEInW1.size() > 1 ) && i_ok_wire_algo > -1 ) + { + // Check that Vec(VV1[0],VV1[1]) in 2D on face1 is the same + // as Vec(VV2[0],VV2[1]) on face2 + double vTol = BRep_Tool::Tolerance( VV1[0] ); + BRepAdaptor_Surface surface1( face1, true ); + BRepAdaptor_Surface surface2( face2, true ); + // TODO: use TrsfFinder2D to superpose the faces + gp_Pnt2d v0f1UV( surface1.FirstUParameter(), surface1.FirstVParameter() ); + gp_Pnt2d v0f2UV( surface2.FirstUParameter(), surface2.FirstVParameter() ); + gp_Pnt2d v1f1UV( surface1.LastUParameter(), surface1.LastVParameter() ); + gp_Pnt2d v1f2UV( surface2.LastUParameter(), surface2.LastVParameter() ); + double vTolUV = + surface1.UResolution( vTol ) + surface1.VResolution( vTol ); // let's be tolerant + // VV1[0] = TopExp::FirstVertex( edges1.front(), true ); // ori is important if face is closed + // VV1[1] = TopExp::LastVertex ( edges1.front(), true ); + // VV2[0] = TopExp::FirstVertex( edges2.front(), true ); + // VV2[1] = TopExp::LastVertex ( edges2.front(), true ); + // gp_Pnt2d v0f1UV = BRep_Tool::Parameters( VV1[0], face1 ); + // gp_Pnt2d v0f2UV = BRep_Tool::Parameters( VV2[0], face2 ); + // gp_Pnt2d v1f1UV = BRep_Tool::Parameters( VV1[1], face1 ); + // gp_Pnt2d v1f2UV = BRep_Tool::Parameters( VV2[1], face2 ); + gp_Vec2d v01f1Vec( v0f1UV, v1f1UV ); + gp_Vec2d v01f2Vec( v0f2UV, v1f2UV ); + if ( Abs( v01f1Vec.X()-v01f2Vec.X()) < vTolUV && + Abs( v01f1Vec.Y()-v01f2Vec.Y()) < vTolUV ) + { + if ( !OK /*i_ok_wire_algo != 1*/ ) + { + edges1.clear(); + edges2.clear(); + SMESH_Block::GetOrderedEdges( face1, edges1, nbEInW1, VV1[0], i_ok_wire_algo); + SMESH_Block::GetOrderedEdges( face2, edges2, nbEInW2, VV2[0], i_ok_wire_algo); + } + gp_XY dUV = v0f2UV.XY() - v0f1UV.XY(); // UV shift between 2 faces + // + // skip edges of the outer wire (if the outer wire is OK) + list< int >::iterator nbE2, nbE1 = nbEInW1.begin(); + list< TopoDS_Edge >::iterator edge2Beg, edge1Beg = edges1.begin(); + if ( OK ) std::advance( edge1Beg, *nbE1++ ); + list< TopoDS_Edge >::iterator edge2End, edge1End; + // + // find corresponding wires of face2 + for ( int iW1 = OK; nbE1 != nbEInW1.end(); ++nbE1, ++iW1 ) // loop on wires of face1 + { + // reach an end of edges of a current wire1 + edge1End = edge1Beg; + std::advance( edge1End, *nbE1 ); + // UV on face1 to find on face2 + TopoDS_Vertex v01 = SMESH_MesherHelper::IthVertex(0,*edge1Beg); + TopoDS_Vertex v11 = SMESH_MesherHelper::IthVertex(1,*edge1Beg); + v0f1UV = BRep_Tool::Parameters( v01, face1 ); + v1f1UV = BRep_Tool::Parameters( v11, face1 ); + v0f1UV.ChangeCoord() += dUV; + v1f1UV.ChangeCoord() += dUV; + // + // look through wires of face2 + edge2Beg = edges2.begin(); + nbE2 = nbEInW2.begin(); + if ( OK ) std::advance( edge2Beg, *nbE2++ ); + for ( int iW2 = OK; nbE2 != nbEInW2.end(); ++nbE2, ++iW2 ) // loop on wires of face2 + { + // reach an end of edges of a current wire2 + edge2End = edge2Beg; + std::advance( edge2End, *nbE2 ); + if ( *nbE1 == *nbE2 && iW2 >= iW1 ) + { + // rotate edge2 untill coincidence with edge1 in 2D + int i = *nbE2; + bool sameUV = false; + while ( !( sameUV = sameVertexUV( *edge2Beg, face2, 0, v0f1UV, vTolUV )) && --i > 0 ) + // move edge2Beg to place before edge2End + edges2.splice( edge2End, edges2, edge2Beg++ ); + + if ( sameUV ) + { + if ( iW1 == 0 ) OK = true; // OK is for the first wire + + // reverse edges2 if needed + if ( SMESH_MesherHelper::IsClosedEdge( *edge1Beg )) + { + // Commented (so far?) as it's not checked if orientation must be same or reversed + // double f,l; + // Handle(Geom2d_Curve) c1 = BRep_Tool::CurveOnSurface( *edge1Beg, face1,f,l ); + // if ( edge1Beg->Orientation() == TopAbs_REVERSED ) + // std::swap( f,l ); + // gp_Pnt2d uv1 = dUV + c1->Value( f * 0.8 + l * 0.2 ).XY(); + + // Handle(Geom2d_Curve) c2 = BRep_Tool::CurveOnSurface( *edge2Beg, face2,f,l ); + // if ( edge2Beg->Orientation() == TopAbs_REVERSED ) + // std::swap( f,l ); + // gp_Pnt2d uv2 = c2->Value( f * 0.8 + l * 0.2 ); + // gp_Pnt2d uv3 = c2->Value( l * 0.8 + f * 0.2 ); + + // if ( uv1.SquareDistance( uv2 ) > uv1.SquareDistance( uv3 )) + // edge2Beg->Reverse(); + } + else + { + if ( !sameVertexUV( *edge2Beg, face2, 1, v1f1UV, vTolUV )) + reverseEdges( edges2 , *nbE2, std::distance( edges2.begin(),edge2Beg )); + } + + // put wire2 at a right place within edges2 + if ( iW1 != iW2 ) { + list< TopoDS_Edge >::iterator place2 = edges2.begin(); + std::advance( place2, std::distance( edges1.begin(), edge1Beg )); + edges2.splice( place2, edges2, edge2Beg, edge2End ); + // move nbE2 as well + list< int >::iterator placeNbE2 = nbEInW2.begin(); + std::advance( placeNbE2, iW1 ); + nbEInW2.splice( placeNbE2, nbEInW2, nbE2 ); + } + break; + } + } + // prepare to the next wire loop + edge2Beg = edge2End; + } + edge1Beg = edge1End; } - if ( KO ) - RETURN_BAD_RESULT("GetOrderedEdges() failed"); } } - if ( reverse ) + + const int nbEdges = nbEInW1.front(); + if ( OK && nbEdges == 2 ) { - Reverse( edges2 , nbVInW2.front()); - if (( VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) != - ( VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true )))) - RETURN_BAD_RESULT("GetOrderedEdges() failed"); + // if wires include 2 edges, it's impossible to associate them using + // topological information only. Try to use length of edges for association. + double l1[2], l2[2]; + edgeIt = edges1.begin(); + l1[0] = SMESH_Algo::EdgeLength( *edgeIt++ ); + l1[1] = SMESH_Algo::EdgeLength( *edgeIt++ ); + if ( Abs( l1[0] - l1[1] ) > 0.1 * Max( l1[0], l1[1] ) ) + { + edgeIt = edges2.begin(); + l2[0] = SMESH_Algo::EdgeLength( *edgeIt++ ); + l2[1] = SMESH_Algo::EdgeLength( *edgeIt++ ); + if (( l1[0] < l1[1] ) != ( l2[0] < l2[1] )) + { + reverseEdges( edges2, nbEdges ); + } + } } - return nbVInW2.front(); + + return OK ? nbEInW1.front() : 0; } //======================================================================= @@ -1175,108 +1670,66 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, //======================================================================= void StdMeshers_ProjectionUtils::InitVertexAssociation( const SMESH_Hypothesis* theHyp, - TShapeShapeMap & theAssociationMap, - const TopoDS_Shape& theTargetShape) + TShapeShapeMap & theAssociationMap) { string hypName = theHyp->GetName(); if ( hypName == "ProjectionSource1D" ) { const StdMeshers_ProjectionSource1D * hyp = static_cast( theHyp ); if ( hyp->HasVertexAssociation() ) - InsertAssociation( hyp->GetSourceVertex(),hyp->GetTargetVertex(),theAssociationMap); + InsertAssociation( hyp->GetTargetVertex(),hyp->GetSourceVertex(),theAssociationMap ); } else if ( hypName == "ProjectionSource2D" ) { const StdMeshers_ProjectionSource2D * hyp = static_cast( theHyp ); if ( hyp->HasVertexAssociation() ) { - InsertAssociation( hyp->GetSourceVertex(1),hyp->GetTargetVertex(1),theAssociationMap); - InsertAssociation( hyp->GetSourceVertex(2),hyp->GetTargetVertex(2),theAssociationMap); + InsertAssociation( hyp->GetTargetVertex(1),hyp->GetSourceVertex(1),theAssociationMap); + InsertAssociation( hyp->GetTargetVertex(2),hyp->GetSourceVertex(2),theAssociationMap); } } else if ( hypName == "ProjectionSource3D" ) { const StdMeshers_ProjectionSource3D * hyp = static_cast( theHyp ); if ( hyp->HasVertexAssociation() ) { - InsertAssociation( hyp->GetSourceVertex(1),hyp->GetTargetVertex(1),theAssociationMap); - InsertAssociation( hyp->GetSourceVertex(2),hyp->GetTargetVertex(2),theAssociationMap); + InsertAssociation( hyp->GetTargetVertex(1),hyp->GetSourceVertex(1),theAssociationMap); + InsertAssociation( hyp->GetTargetVertex(2),hyp->GetSourceVertex(2),theAssociationMap); } } } //======================================================================= -/*! - * \brief Inserts association theShape1 <-> theShape2 to TShapeShapeMap - * \param theShape1 - shape 1 - * \param theShape2 - shape 2 - * \param theAssociationMap - association map - * \retval bool - true if there was no association for these shapes before +/* + * Inserts association theShape1 <-> theShape2 to TShapeShapeMap + * \param theShape1 - target shape + * \param theShape2 - source shape + * \param theAssociationMap - association map + * \retval bool - true if there was no association for these shapes before */ //======================================================================= -bool StdMeshers_ProjectionUtils::InsertAssociation( const TopoDS_Shape& theShape1, - const TopoDS_Shape& theShape2, - TShapeShapeMap & theAssociationMap, - const bool theBidirectional) +bool StdMeshers_ProjectionUtils::InsertAssociation( const TopoDS_Shape& theShape1, // tgt + const TopoDS_Shape& theShape2, // src + TShapeShapeMap & theAssociationMap) { if ( !theShape1.IsNull() && !theShape2.IsNull() ) { - SHOW_VERTEX(theShape1,"Assoc "); - SHOW_VERTEX(theShape2," to "); + SHOW_SHAPE(theShape1,"Assoc "); + SHOW_SHAPE(theShape2," to "); bool isNew = ( theAssociationMap.Bind( theShape1, theShape2 )); - if ( theBidirectional ) - theAssociationMap.Bind( theShape2, theShape1 ); return isNew; } else { - throw SMESH_Exception("StdMeshers_ProjectionUtils: attempt to associate NULL shape"); + throw SALOME_Exception("StdMeshers_ProjectionUtils: attempt to associate NULL shape"); } return false; } //======================================================================= -//function : IsSubShape -//purpose : -//======================================================================= - -bool StdMeshers_ProjectionUtils::IsSubShape( const TopoDS_Shape& shape, - SMESH_Mesh* aMesh ) -{ - if ( shape.IsNull() || !aMesh ) - return false; - return - aMesh->GetMeshDS()->ShapeToIndex( shape ) || - // PAL16202 - (shape.ShapeType() == TopAbs_COMPOUND && aMesh->GetMeshDS()->IsGroupOfSubShapes( shape )); -} - -//======================================================================= -//function : IsSubShape -//purpose : -//======================================================================= - -bool StdMeshers_ProjectionUtils::IsSubShape( const TopoDS_Shape& shape, - const TopoDS_Shape& mainShape ) -{ - if ( !shape.IsNull() && !mainShape.IsNull() ) - { - for ( TopExp_Explorer exp( mainShape, shape.ShapeType()); - exp.More(); - exp.Next() ) - if ( shape.IsSame( exp.Current() )) - return true; - } - SCRUTE((shape.IsNull())); - SCRUTE((mainShape.IsNull())); - return false; -} - - -//======================================================================= -/*! - * \brief Finds an edge by its vertices in a main shape of the mesh - * \param aMesh - the mesh - * \param V1 - vertex 1 - * \param V2 - vertex 2 - * \retval TopoDS_Edge - found edge +/* + * Finds an edge by its vertices in a main shape of the mesh + * \param aMesh - the mesh + * \param V1 - vertex 1 + * \param V2 - vertex 2 + * \retval TopoDS_Edge - found edge */ //======================================================================= @@ -1299,12 +1752,12 @@ TopoDS_Edge StdMeshers_ProjectionUtils::GetEdgeByVertices( SMESH_Mesh* } //================================================================================ -/*! - * \brief Return another face sharing an edge - * \param edgeToFaces - data map of descendants to ancestors - * \param edge - edge - * \param face - face - * \retval TopoDS_Face - found face +/* + * Return another face sharing an edge + * \param edgeToFaces - data map of descendants to ancestors + * \param edge - edge + * \param face - face + * \retval TopoDS_Face - found face */ //================================================================================ @@ -1325,8 +1778,8 @@ TopoDS_Face StdMeshers_ProjectionUtils::GetNextFace( const TAncestorMap& edgeToF } //================================================================================ -/*! - * \brief Return other vertex of an edge +/* + * Return other vertex of an edge */ //================================================================================ @@ -1341,82 +1794,90 @@ TopoDS_Vertex StdMeshers_ProjectionUtils::GetNextVertex(const TopoDS_Edge& edg } //================================================================================ -/*! - * \brief Return a propagation edge - * \param aMesh - mesh - * \param theEdge - edge to find by propagation - * \param fromEdge - start edge for propagation - * \retval pair - propagation step and found edge +/* + * Return a propagation edge + * \param aMesh - mesh + * \param anEdge - edge to find by propagation + * \param fromEdge - start edge for propagation + * \param chain - return, if !NULL, a propagation chain passed till + * anEdge; if anEdge.IsNull() then a full propagation chain is returned; + * fromEdge is the 1st in the chain + * \retval pair - propagation step and found edge */ //================================================================================ pair -StdMeshers_ProjectionUtils::GetPropagationEdge( SMESH_Mesh* aMesh, - const TopoDS_Edge& theEdge, - const TopoDS_Edge& fromEdge) +StdMeshers_ProjectionUtils::GetPropagationEdge( SMESH_Mesh* aMesh, + const TopoDS_Edge& anEdge, + const TopoDS_Edge& fromEdge, + TopTools_IndexedMapOfShape* chain) { - SMESH_IndexedMapOfShape aChain; + TopTools_IndexedMapOfShape locChain; + TopTools_IndexedMapOfShape& aChain = chain ? *chain : locChain; int step = 0; + //TopTools_IndexedMapOfShape checkedWires; + BRepTools_WireExplorer aWE; + TopoDS_Shape fourEdges[4]; + // List of edges, added to chain on the previous cycle pass TopTools_ListOfShape listPrevEdges; - listPrevEdges.Append(fromEdge); + listPrevEdges.Append( fromEdge ); + aChain.Add( fromEdge ); // Collect all edges pass by pass - while (listPrevEdges.Extent() > 0) { + while (listPrevEdges.Extent() > 0) + { step++; // List of edges, added to chain on this cycle pass TopTools_ListOfShape listCurEdges; // Find the next portion of edges TopTools_ListIteratorOfListOfShape itE (listPrevEdges); - for (; itE.More(); itE.Next()) { - TopoDS_Shape anE = itE.Value(); + for (; itE.More(); itE.Next()) + { + const TopoDS_Shape& anE = itE.Value(); // Iterate on faces, having edge TopTools_ListIteratorOfListOfShape itA (aMesh->GetAncestors(anE)); - for (; itA.More(); itA.Next()) { - TopoDS_Shape aW = itA.Value(); + for (; itA.More(); itA.Next()) + { + const TopoDS_Shape& aW = itA.Value(); // There are objects of different type among the ancestors of edge - if (aW.ShapeType() == TopAbs_WIRE) { - TopoDS_Shape anOppE; - - BRepTools_WireExplorer aWE (TopoDS::Wire(aW)); - Standard_Integer nb = 1, found = 0; - TopTools_Array1OfShape anEdges (1,4); - for (; aWE.More(); aWE.Next(), nb++) { - if (nb > 4) { - found = 0; + if ( aW.ShapeType() == TopAbs_WIRE /*&& checkedWires.Add( aW )*/) + { + Standard_Integer nb = 0, found = -1; + for ( aWE.Init( TopoDS::Wire( aW )); aWE.More(); aWE.Next() ) { + if (nb+1 > 4) { + found = -1; break; } - anEdges(nb) = aWE.Current(); - if (anEdges(nb).IsSame(anE)) found = nb; + fourEdges[ nb ] = aWE.Current(); + if ( aWE.Current().IsSame( anE )) found = nb; + nb++; } - - if (nb == 5 && found > 0) { + if (nb == 4 && found >= 0) { // Quadrangle face found, get an opposite edge - Standard_Integer opp = found + 2; - if (opp > 4) opp -= 4; - anOppE = anEdges(opp); + TopoDS_Shape& anOppE = fourEdges[( found + 2 ) % 4 ]; // add anOppE to aChain if ... - if (!aChain.Contains(anOppE)) { // ... anOppE is not in aChain + int prevChainSize = aChain.Extent(); + if ( aChain.Add(anOppE) > prevChainSize ) { // ... anOppE is not in aChain // Add found edge to the chain oriented so that to // have it co-directed with a forward MainEdge TopAbs_Orientation ori = anE.Orientation(); - if ( anEdges(opp).Orientation() == anEdges(found).Orientation() ) + if ( anOppE.Orientation() == fourEdges[found].Orientation() ) ori = TopAbs::Reverse( ori ); anOppE.Orientation( ori ); - if ( anOppE.IsSame( theEdge )) + if ( anOppE.IsSame( anEdge )) return make_pair( step, TopoDS::Edge( anOppE )); - aChain.Add(anOppE); listCurEdges.Append(anOppE); } - } // if (nb == 5 && found > 0) + } // if (nb == 4 && found >= 0) } // if (aF.ShapeType() == TopAbs_WIRE) - } // for (; itF.More(); itF.Next()) - } // for (; itE.More(); itE.Next()) + } // loop on ancestors of anE + } // loop on listPrevEdges listPrevEdges = listCurEdges; } // while (listPrevEdges.Extent() > 0) @@ -1425,16 +1886,16 @@ StdMeshers_ProjectionUtils::GetPropagationEdge( SMESH_Mesh* aMesh, } //================================================================================ - /*! - * \brief Find corresponding nodes on two faces - * \param face1 - the first face - * \param mesh1 - mesh containing elements on the first face - * \param face2 - the second face - * \param mesh2 - mesh containing elements on the second face - * \param assocMap - map associating subshapes of the faces - * \param node1To2Map - map containing found matching nodes - * \retval bool - is a success - */ +/* + * Find corresponding nodes on two faces + * \param face1 - the first face + * \param mesh1 - mesh containing elements on the first face + * \param face2 - the second face + * \param mesh2 - mesh containing elements on the second face + * \param assocMap - map associating sub-shapes of the faces + * \param node1To2Map - map containing found matching nodes + * \retval bool - is a success + */ //================================================================================ bool StdMeshers_ProjectionUtils:: @@ -1447,7 +1908,7 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, { SMESHDS_Mesh* meshDS1 = mesh1->GetMeshDS(); SMESHDS_Mesh* meshDS2 = mesh2->GetMeshDS(); - + SMESH_MesherHelper helper1( *mesh1 ); SMESH_MesherHelper helper2( *mesh2 ); @@ -1482,12 +1943,13 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, TopoDS_Edge e2 = TopoDS::Edge( eE.Current() ); eE.Next(); // edge 1 - if ( !assocMap.IsBound( e2 )) - RETURN_BAD_RESULT("Association not found for edge " << meshDS2->ShapeToIndex( e2 )); - TopoDS_Edge e1 = TopoDS::Edge( assocMap( e2 )); - if ( !IsSubShape( e1, face1 )) + if ( !assocMap.IsBound( e2, /*is2nd=*/true )) + continue; + //RETURN_BAD_RESULT("Association not found for edge " << meshDS2->ShapeToIndex( e2 )); + TopoDS_Edge e1 = TopoDS::Edge( assocMap( e2, /*is2nd=*/true )); + if ( !helper1.IsSubShape( e1, face1 )) RETURN_BAD_RESULT("Wrong association, edge " << meshDS1->ShapeToIndex( e1 ) << - " isn't a subshape of face " << meshDS1->ShapeToIndex( face1 )); + " isn't a sub-shape of face " << meshDS1->ShapeToIndex( face1 )); // check that there are nodes on edges SMESHDS_SubMesh * eSM1 = meshDS1->MeshElements( e1 ); SMESHDS_SubMesh * eSM2 = meshDS2->MeshElements( e2 ); @@ -1526,9 +1988,13 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, // get 2 matching vertices TopoDS_Vertex V2 = TopExp::FirstVertex( TopoDS::Edge( edge2 )); - if ( !assocMap.IsBound( V2 )) - RETURN_BAD_RESULT("Association not found for vertex " << meshDS2->ShapeToIndex( V2 )); - TopoDS_Vertex V1 = TopoDS::Vertex( assocMap( V2 )); + if ( !assocMap.IsBound( V2, /*is2nd=*/true )) + { + V2 = TopExp::LastVertex( TopoDS::Edge( edge2 )); + if ( !assocMap.IsBound( V2, /*is2nd=*/true )) + RETURN_BAD_RESULT("Association not found for vertex " << meshDS2->ShapeToIndex( V2 )); + } + TopoDS_Vertex V1 = TopoDS::Vertex( assocMap( V2, /*is2nd=*/true )); // nodes on vertices const SMDS_MeshNode* vNode1 = SMESH_Algo::VertexNode( V1, meshDS1 ); @@ -1543,7 +2009,7 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, if ( hasNodesOnEdge ) { int nbNodeToGet = 1; - if ( IsClosedEdge( edge1 ) || IsClosedEdge( edge2 ) ) + if ( helper1.IsClosedEdge( edge1 ) || helper2.IsClosedEdge( edge2 ) ) nbNodeToGet = 2; for ( int is2 = 0; is2 < 2; ++is2 ) { @@ -1577,9 +2043,9 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, { // get 2 other matching vertices V2 = TopExp::LastVertex( TopoDS::Edge( edge2 )); - if ( !assocMap.IsBound( V2 )) + if ( !assocMap.IsBound( V2, /*is2nd=*/true )) RETURN_BAD_RESULT("Association not found for vertex " << meshDS2->ShapeToIndex( V2 )); - V1 = TopoDS::Vertex( assocMap( V2 )); + V1 = TopoDS::Vertex( assocMap( V2, /*is2nd=*/true )); // nodes on vertices eNode1[0] = SMESH_Algo::VertexNode( V1, meshDS1 ); @@ -1590,97 +2056,109 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, // 2. face sets - set Elems1, Elems2; - for ( int is2 = 0; is2 < 2; ++is2 ) + int assocRes; + for ( int iAttempt = 0; iAttempt < 2; ++iAttempt ) { - set & elems = is2 ? Elems2 : Elems1; - SMESHDS_SubMesh* sm = is2 ? SM2 : SM1; - SMESH_MesherHelper* helper = is2 ? &helper2 : &helper1; - const TopoDS_Face & face = is2 ? face2 : face1; - SMDS_ElemIteratorPtr eIt = sm->GetElements(); - - if ( !helper->IsRealSeam( is2 ? edge2 : edge1 )) - { - while ( eIt->more() ) elems.insert( eIt->next() ); - } - else + set Elems1, Elems2; + for ( int is2 = 0; is2 < 2; ++is2 ) { - // the only suitable edge is seam, i.e. it is a sphere. - // FindMatchingNodes() will not know which way to go from any edge. - // So we ignore all faces having nodes on edges or vertices except - // one of faces sharing current start nodes - - // find a face to keep - const SMDS_MeshElement* faceToKeep = 0; - const SMDS_MeshNode* vNode = is2 ? vNode2 : vNode1; - const SMDS_MeshNode* eNode = is2 ? eNode2[0] : eNode1[0]; - TIDSortedElemSet inSet, notInSet; - - const SMDS_MeshElement* f1 = - SMESH_MeshEditor::FindFaceInSet( vNode, eNode, inSet, notInSet ); - if ( !f1 ) RETURN_BAD_RESULT("The first face on seam not found"); - notInSet.insert( f1 ); - - const SMDS_MeshElement* f2 = - SMESH_MeshEditor::FindFaceInSet( vNode, eNode, inSet, notInSet ); - if ( !f2 ) RETURN_BAD_RESULT("The second face on seam not found"); - - // select a face with less UV of vNode - const SMDS_MeshNode* notSeamNode[2] = {0, 0}; - for ( int iF = 0; iF < 2; ++iF ) { - const SMDS_MeshElement* f = ( iF ? f2 : f1 ); - for ( int i = 0; !notSeamNode[ iF ] && i < f->NbNodes(); ++i ) { - const SMDS_MeshNode* node = f->GetNode( i ); - if ( !helper->IsSeamShape( node->GetPosition()->GetShapeId() )) - notSeamNode[ iF ] = node; - } + set & elems = is2 ? Elems2 : Elems1; + SMESHDS_SubMesh* sm = is2 ? SM2 : SM1; + SMESH_MesherHelper* helper = is2 ? &helper2 : &helper1; + const TopoDS_Face & face = is2 ? face2 : face1; + SMDS_ElemIteratorPtr eIt = sm->GetElements(); + + if ( !helper->IsRealSeam( is2 ? edge2 : edge1 )) + { + while ( eIt->more() ) elems.insert( elems.end(), eIt->next() ); } - gp_Pnt2d uv1 = helper->GetNodeUV( face, vNode, notSeamNode[0] ); - gp_Pnt2d uv2 = helper->GetNodeUV( face, vNode, notSeamNode[1] ); - if ( uv1.X() + uv1.Y() > uv2.X() + uv2.Y() ) - faceToKeep = f2; else - faceToKeep = f1; - - // fill elem set - elems.insert( faceToKeep ); - while ( eIt->more() ) { - const SMDS_MeshElement* f = eIt->next(); - int nbNodes = f->NbNodes(); - if ( f->IsQuadratic() ) - nbNodes /= 2; - bool onBnd = false; - for ( int i = 0; !onBnd && i < nbNodes; ++i ) { - const SMDS_MeshNode* node = f->GetNode( i ); - onBnd = ( node->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE); + { + // the only suitable edge is seam, i.e. it is a sphere. + // FindMatchingNodes() will not know which way to go from any edge. + // So we ignore all faces having nodes on edges or vertices except + // one of faces sharing current start nodes + + // find a face to keep + const SMDS_MeshElement* faceToKeep = 0; + const SMDS_MeshNode* vNode = is2 ? vNode2 : vNode1; + const SMDS_MeshNode* eNode = is2 ? eNode2[0] : eNode1[0]; + TIDSortedElemSet inSet, notInSet; + + const SMDS_MeshElement* f1 = + SMESH_MeshAlgos::FindFaceInSet( vNode, eNode, inSet, notInSet ); + if ( !f1 ) RETURN_BAD_RESULT("The first face on seam not found"); + notInSet.insert( f1 ); + + const SMDS_MeshElement* f2 = + SMESH_MeshAlgos::FindFaceInSet( vNode, eNode, inSet, notInSet ); + if ( !f2 ) RETURN_BAD_RESULT("The second face on seam not found"); + + // select a face with less UV of vNode + const SMDS_MeshNode* notSeamNode[2] = {0, 0}; + for ( int iF = 0; iF < 2; ++iF ) { + const SMDS_MeshElement* f = ( iF ? f2 : f1 ); + for ( int i = 0; !notSeamNode[ iF ] && i < f->NbNodes(); ++i ) { + const SMDS_MeshNode* node = f->GetNode( i ); + if ( !helper->IsSeamShape( node->getshapeId() )) + notSeamNode[ iF ] = node; + } } - if ( !onBnd ) - elems.insert( f ); - } - // add also faces adjacent to faceToKeep - int nbNodes = faceToKeep->NbNodes(); - if ( faceToKeep->IsQuadratic() ) nbNodes /= 2; - notInSet.insert( f1 ); - notInSet.insert( f2 ); - for ( int i = 0; i < nbNodes; ++i ) { - const SMDS_MeshNode* n1 = faceToKeep->GetNode( i ); - const SMDS_MeshNode* n2 = faceToKeep->GetNode( i+1 % nbNodes ); - f1 = SMESH_MeshEditor::FindFaceInSet( n1, n2, inSet, notInSet ); - if ( f1 ) - elems.insert( f1 ); - } - } // case on a sphere - } // loop on 2 faces - - // int quadFactor = (*Elems1.begin())->IsQuadratic() ? 2 : 1; + gp_Pnt2d uv1 = helper->GetNodeUV( face, vNode, notSeamNode[0] ); + gp_Pnt2d uv2 = helper->GetNodeUV( face, vNode, notSeamNode[1] ); + if ( uv1.X() + uv1.Y() > uv2.X() + uv2.Y() ) + faceToKeep = f2; + else + faceToKeep = f1; + + // fill elem set + elems.insert( faceToKeep ); + while ( eIt->more() ) { + const SMDS_MeshElement* f = eIt->next(); + int nbNodes = f->NbNodes(); + if ( f->IsQuadratic() ) + nbNodes /= 2; + bool onBnd = false; + for ( int i = 0; !onBnd && i < nbNodes; ++i ) { + const SMDS_MeshNode* node = f->GetNode( i ); + onBnd = ( node->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE); + } + if ( !onBnd ) + elems.insert( f ); + } + // add also faces adjacent to faceToKeep + int nbNodes = faceToKeep->NbNodes(); + if ( faceToKeep->IsQuadratic() ) nbNodes /= 2; + notInSet.insert( f1 ); + notInSet.insert( f2 ); + for ( int i = 0; i < nbNodes; ++i ) { + const SMDS_MeshNode* n1 = faceToKeep->GetNode( i ); + const SMDS_MeshNode* n2 = faceToKeep->GetNode(( i+1 ) % nbNodes ); + f1 = SMESH_MeshAlgos::FindFaceInSet( n1, n2, inSet, notInSet ); + if ( f1 ) + elems.insert( f1 ); + } + } // case on a sphere + } // loop on 2 faces + + node1To2Map.clear(); + assocRes = SMESH_MeshEditor::FindMatchingNodes( Elems1, Elems2, + vNode1, vNode2, + eNode1[0], eNode2[0], + node1To2Map); + if (( assocRes != SMESH_MeshEditor::SEW_OK ) && + ( eNode1[1] || eNode2[1] )) // there is another node to try (on a closed EDGE) + { + node1To2Map.clear(); + if ( eNode1[1] ) std::swap( eNode1[0], eNode1[1] ); + else std::swap( eNode2[0], eNode2[1] ); + continue; // one more attempt + } - node1To2Map.clear(); - int res = SMESH_MeshEditor::FindMatchingNodes( Elems1, Elems2, - vNode1, vNode2, - eNode1[0], eNode2[0], - node1To2Map); - if ( res != SMESH_MeshEditor::SEW_OK ) - RETURN_BAD_RESULT("FindMatchingNodes() result " << res ); + break; + } + if ( assocRes != SMESH_MeshEditor::SEW_OK ) + RETURN_BAD_RESULT("FindMatchingNodes() result " << assocRes ); // On a sphere, add matching nodes on the edge @@ -1699,7 +2177,7 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, while ( nIt->more() ) { const SMDS_MeshNode* node = nIt->next(); const SMDS_EdgePosition* pos = - static_cast(node->GetPosition().get()); + static_cast(node->GetPosition()); pos2nodes.insert( make_pair( pos->GetUParameter(), node )); } if ( pos2nodes.size() != edgeSM->NbNodes() ) @@ -1731,9 +2209,9 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, // associate matching nodes on the last vertices V2 = TopExp::LastVertex( TopoDS::Edge( edge2 )); - if ( !assocMap.IsBound( V2 )) + if ( !assocMap.IsBound( V2, /*is2nd=*/true )) RETURN_BAD_RESULT("Association not found for vertex " << meshDS2->ShapeToIndex( V2 )); - V1 = TopoDS::Vertex( assocMap( V2 )); + V1 = TopoDS::Vertex( assocMap( V2, /*is2nd=*/true )); vNode1 = SMESH_Algo::VertexNode( V1, meshDS1 ); vNode2 = SMESH_Algo::VertexNode( V2, meshDS2 ); if ( !vNode1 ) RETURN_BAD_RESULT("No node on vertex #" << meshDS1->ShapeToIndex( V1 )); @@ -1741,38 +2219,25 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, node1To2Map.insert( make_pair( vNode1, vNode2 )); } -// don't know why this condition is usually true :( -// if ( node1To2Map.size() * quadFactor < SM1->NbNodes() ) -// MESSAGE("FindMatchingNodes() found too few node pairs starting from nodes (" -// << vNode1->GetID() << " - " << eNode1[0]->GetID() << ") (" -// << vNode2->GetID() << " - " << eNode2[0]->GetID() << "):" -// << node1To2Map.size() * quadFactor << " < " << SM1->NbNodes()); - + // don't know why this condition is usually true :( + // if ( node1To2Map.size() * quadFactor < SM1->NbNodes() ) + // MESSAGE("FindMatchingNodes() found too few node pairs starting from nodes (" + // << vNode1->GetID() << " - " << eNode1[0]->GetID() << ") (" + // << vNode2->GetID() << " - " << eNode2[0]->GetID() << "):" + // << node1To2Map.size() * quadFactor << " < " << SM1->NbNodes()); + return true; } //================================================================================ -/*! - * \brief Check if the first and last vertices of an edge are the same - * \param anEdge - the edge to check - * \retval bool - true if same +/* + * Return any sub-shape of a face belonging to the outer wire + * \param face - the face + * \param type - type of sub-shape to return + * \retval TopoDS_Shape - the found sub-shape */ //================================================================================ -bool StdMeshers_ProjectionUtils::IsClosedEdge( const TopoDS_Edge& anEdge ) -{ - return TopExp::FirstVertex( anEdge ).IsSame( TopExp::LastVertex( anEdge )); -} - -//================================================================================ - /*! - * \brief Return any subshape of a face belonging to the outer wire - * \param face - the face - * \param type - type of subshape to return - * \retval TopoDS_Shape - the found subshape - */ -//================================================================================ - TopoDS_Shape StdMeshers_ProjectionUtils::OuterShape( const TopoDS_Face& face, TopAbs_ShapeEnum type) { @@ -1783,12 +2248,12 @@ TopoDS_Shape StdMeshers_ProjectionUtils::OuterShape( const TopoDS_Face& face, } //================================================================================ - /*! - * \brief Check that submesh is computed and try to compute it if is not - * \param sm - submesh to compute - * \param iterationNb - int used to stop infinite recursive call - * \retval bool - true if computed - */ +/* + * Check that sub-mesh is computed and try to compute it if is not + * \param sm - sub-mesh to compute + * \param iterationNb - int used to stop infinite recursive call + * \retval bool - true if computed + */ //================================================================================ bool StdMeshers_ProjectionUtils::MakeComputed(SMESH_subMesh * sm, const int iterationNb) @@ -1800,30 +2265,65 @@ bool StdMeshers_ProjectionUtils::MakeComputed(SMESH_subMesh * sm, const int iter if ( sm->IsMeshComputed() ) return true; - SMESH_Mesh* mesh = sm->GetFather(); - SMESH_Gen* gen = mesh->GetGen(); - SMESH_Algo* algo = gen->GetAlgo( *mesh, sm->GetSubShape() ); + SMESH_Mesh* mesh = sm->GetFather(); + SMESH_Gen* gen = mesh->GetGen(); + SMESH_Algo* algo = sm->GetAlgo(); + TopoDS_Shape shape = sm->GetSubShape(); if ( !algo ) { - if ( sm->GetSubShape().ShapeType() != TopAbs_COMPOUND ) - RETURN_BAD_RESULT("No algo assigned to submesh " << sm->GetId()); - // group - bool computed = true; - for ( TopoDS_Iterator grMember( sm->GetSubShape() ); grMember.More(); grMember.Next()) - if ( SMESH_subMesh* grSub = mesh->GetSubMesh( grMember.Value() )) - if ( !MakeComputed( grSub, iterationNb + 1 )) - computed = false; - return computed; + if ( shape.ShapeType() != TopAbs_COMPOUND ) + { + // No algo assigned to a non-compound sub-mesh. + // Try to find an all-dimensional algo of an upper dimension + int dim = gen->GetShapeDim( shape ); + for ( ++dim; ( dim <= 3 && !algo ); ++dim ) + { + SMESH_HypoFilter hypoFilter( SMESH_HypoFilter::IsAlgo() ); + hypoFilter.And( SMESH_HypoFilter::HasDim( dim )); + list hyps; + list< TopoDS_Shape > assignedTo; + int nbAlgos = + mesh->GetHypotheses( shape, hypoFilter, hyps, true, &assignedTo ); + if ( nbAlgos > 1 ) // concurrent algos + { + vector smList; // where an algo is assigned + list< TopoDS_Shape >::iterator shapeIt = assignedTo.begin(); + for ( ; shapeIt != assignedTo.end(); ++shapeIt ) + smList.push_back( mesh->GetSubMesh( *shapeIt )); + + mesh->SortByMeshOrder( smList ); + algo = smList.front()->GetAlgo(); + shape = smList.front()->GetSubShape(); + } + else if ( nbAlgos == 1 ) + { + algo = (SMESH_Algo*) hyps.front(); + shape = assignedTo.front(); + } + } + if ( !algo ) + return false; + } + else + { + // group + bool computed = true; + for ( TopoDS_Iterator grMember( shape ); grMember.More(); grMember.Next()) + if ( SMESH_subMesh* grSub = mesh->GetSubMesh( grMember.Value() )) + if ( !MakeComputed( grSub, iterationNb + 1 )) + computed = false; + return computed; + } } string algoType = algo->GetName(); if ( algoType.substr(0, 11) != "Projection_") - return gen->Compute( *mesh, sm->GetSubShape() ); + return gen->Compute( *mesh, shape, /*shapeOnly=*/true ); // try to compute source mesh const list & hyps = - algo->GetUsedHypothesis( *mesh, sm->GetSubShape() ); + algo->GetUsedHypothesis( *mesh, shape ); TopoDS_Shape srcShape; SMESH_Mesh* srcMesh = 0; @@ -1850,77 +2350,96 @@ bool StdMeshers_ProjectionUtils::MakeComputed(SMESH_subMesh * sm, const int iter } } if ( srcShape.IsNull() ) // no projection source defined - return gen->Compute( *mesh, sm->GetSubShape() ); + return gen->Compute( *mesh, shape, /*shapeOnly=*/true ); - if ( srcShape.IsSame( sm->GetSubShape() )) + if ( srcShape.IsSame( shape )) RETURN_BAD_RESULT("Projection from self"); if ( !srcMesh ) srcMesh = mesh; - if ( MakeComputed( srcMesh->GetSubMesh( srcShape ), iterationNb + 1 )) - return gen->Compute( *mesh, sm->GetSubShape() ); + if ( MakeComputed( srcMesh->GetSubMesh( srcShape ), iterationNb + 1 ) && + gen->Compute( *mesh, shape, /*shapeOnly=*/true )) + return sm->IsMeshComputed(); return false; } + //================================================================================ -/*! - * \brief Count nb of subshapes - * \param shape - the shape - * \param type - the type of subshapes to count - * \retval int - the calculated number +/* + * Returns an error message to show in case if MakeComputed( sm ) fails. */ //================================================================================ -int StdMeshers_ProjectionUtils::Count(const TopoDS_Shape& shape, - const TopAbs_ShapeEnum type, - const bool ignoreSame) +std::string StdMeshers_ProjectionUtils::SourceNotComputedError( SMESH_subMesh * sm, + SMESH_Algo* projAlgo ) { - if ( ignoreSame ) { - TopTools_IndexedMapOfShape map; - TopExp::MapShapes( shape, type, map ); - return map.Extent(); - } - else { - int nb = 0; - for ( TopExp_Explorer exp( shape, type ); exp.More(); exp.Next() ) - ++nb; - return nb; + const char usualMessage [] = "Source mesh not computed"; + if ( !projAlgo ) + return usualMessage; + if ( !sm || sm->GetAlgoState() != SMESH_subMesh::NO_ALGO ) + return usualMessage; // algo is OK, anything else is KO. + + // Try to find a type of all-dimentional algorithm that would compute the + // given sub-mesh if it could be launched before projection + const TopoDS_Shape shape = sm->GetSubShape(); + const int shapeDim = SMESH_Gen::GetShapeDim( shape ); + + for ( int dimIncrement = 1; shapeDim + dimIncrement < 4; ++dimIncrement ) + { + SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() ); + filter.And( filter.HasDim( shapeDim + dimIncrement )); + + SMESH_Algo* algo = (SMESH_Algo*) sm->GetFather()->GetHypothesis( shape, filter, true ); + if ( algo && !algo->NeedDiscreteBoundary() ) + return SMESH_Comment("\"") + << algo->GetFeatures()._label << "\"" + << " can't be used to compute the source mesh for \"" + << projAlgo->GetFeatures()._label << "\" in this case"; } + return usualMessage; } //================================================================================ -/*! - * \brief Return true if edge is a boundary of edgeContainer +/* + * Return a boundary EDGE (or all boundary EDGEs) of edgeContainer */ //================================================================================ -bool StdMeshers_ProjectionUtils::IsBoundaryEdge(const TopoDS_Edge& edge, - const TopoDS_Shape& edgeContainer, - SMESH_Mesh& mesh) +TopoDS_Edge +StdMeshers_ProjectionUtils::GetBoundaryEdge(const TopoDS_Shape& edgeContainer, + const SMESH_Mesh& mesh, + std::list< TopoDS_Edge >* allBndEdges) { TopTools_IndexedMapOfShape facesOfEdgeContainer, facesNearEdge; TopExp::MapShapes( edgeContainer, TopAbs_FACE, facesOfEdgeContainer ); - const TopTools_ListOfShape& EAncestors = mesh.GetAncestors(edge); - TopTools_ListIteratorOfListOfShape itea(EAncestors); - for(; itea.More(); itea.Next()) { - if( itea.Value().ShapeType() == TopAbs_FACE && - facesOfEdgeContainer.Contains( itea.Value() )) + if ( !facesOfEdgeContainer.IsEmpty() ) + for ( TopExp_Explorer exp(edgeContainer, TopAbs_EDGE); exp.More(); exp.Next() ) { - facesNearEdge.Add( itea.Value() ); - if ( facesNearEdge.Extent() > 1 ) - return false; + const TopoDS_Edge& edge = TopoDS::Edge( exp.Current() ); + facesNearEdge.Clear(); + PShapeIteratorPtr faceIt = SMESH_MesherHelper::GetAncestors( edge, mesh, TopAbs_FACE ); + while ( const TopoDS_Shape* face = faceIt->next() ) + if ( facesOfEdgeContainer.Contains( *face )) + if ( facesNearEdge.Add( *face ) && facesNearEdge.Extent() > 1 ) + break; + if ( facesNearEdge.Extent() == 1 ) { + if ( allBndEdges ) + allBndEdges->push_back( edge ); + else + return edge; + } } - } - return ( facesNearEdge.Extent() == 1 ); + + return TopoDS_Edge(); } -namespace { +namespace { // Definition of event listeners - SMESH_subMeshEventListener* GetSrcSubMeshListener(); + SMESH_subMeshEventListener* getSrcSubMeshListener(); //================================================================================ /*! @@ -1931,8 +2450,8 @@ namespace { struct HypModifWaiter: SMESH_subMeshEventListener { - HypModifWaiter():SMESH_subMeshEventListener(0){} // won't be deleted by submesh - + HypModifWaiter():SMESH_subMeshEventListener(false,// won't be deleted by submesh + "StdMeshers_ProjectionUtils::HypModifWaiter") {} void ProcessEvent(const int event, const int eventType, SMESH_subMesh* subMesh, EventListenerData*, const SMESH_Hypothesis*) { @@ -1940,11 +2459,9 @@ namespace { eventType == SMESH_subMesh::ALGO_EVENT) { // delete current source listener - subMesh->DeleteEventListener( GetSrcSubMeshListener() ); + subMesh->DeleteEventListener( getSrcSubMeshListener() ); // let algo set a new one - SMESH_Gen* gen = subMesh->GetFather()->GetGen(); - if ( SMESH_Algo* algo = gen->GetAlgo( *subMesh->GetFather(), - subMesh->GetSubShape() )) + if ( SMESH_Algo* algo = subMesh->GetAlgo() ) algo->SetEventListener( subMesh ); } } @@ -1955,7 +2472,7 @@ namespace { */ //================================================================================ - SMESH_subMeshEventListener* GetHypModifWaiter() { + SMESH_subMeshEventListener* getHypModifWaiter() { static HypModifWaiter aHypModifWaiter; return &aHypModifWaiter; } @@ -1965,18 +2482,19 @@ namespace { */ //================================================================================ - SMESH_subMeshEventListener* GetSrcSubMeshListener() { - static SMESH_subMeshEventListener srcListener(0); // won't be deleted by submesh + SMESH_subMeshEventListener* getSrcSubMeshListener() { + static SMESH_subMeshEventListener srcListener(false, // won't be deleted by submesh + "StdMeshers_ProjectionUtils::SrcSubMeshListener"); return &srcListener; } } //================================================================================ -/*! - * \brief Set event listeners to submesh with projection algo - * \param subMesh - submesh with projection algo - * \param srcShape - source shape - * \param srcMesh - source mesh +/* + * Set event listeners to submesh with projection algo + * \param subMesh - submesh with projection algo + * \param srcShape - source shape + * \param srcMesh - source mesh */ //================================================================================ @@ -1984,9 +2502,9 @@ void StdMeshers_ProjectionUtils::SetEventListener(SMESH_subMesh* subMesh, TopoDS_Shape srcShape, SMESH_Mesh* srcMesh) { - // Set listener that resets an event listener on source submesh when - // "ProjectionSource*D" hypothesis is modified - subMesh->SetEventListener( GetHypModifWaiter(),0,subMesh); + // Set the listener that resets an event listener on source submesh when + // "ProjectionSource*D" hypothesis is modified since source shape can be changed + subMesh->SetEventListener( getHypModifWaiter(),0,subMesh); // Set an event listener to submesh of the source shape if ( !srcShape.IsNull() ) @@ -2000,26 +2518,267 @@ void StdMeshers_ProjectionUtils::SetEventListener(SMESH_subMesh* subMesh, if ( srcShapeSM->GetSubMeshDS() && srcShapeSM->GetSubMeshDS()->IsComplexSubmesh() ) { // source shape is a group - TopExp_Explorer it(srcShapeSM->GetSubShape(), // explore the group into subshapes... + TopExp_Explorer it(srcShapeSM->GetSubShape(), // explore the group into sub-shapes... subMesh->GetSubShape().ShapeType()); // ...of target shape type for (; it.More(); it.Next()) { SMESH_subMesh* srcSM = srcMesh->GetSubMesh( it.Current() ); - SMESH_subMeshEventListenerData* data = - srcSM->GetEventListenerData(GetSrcSubMeshListener()); - if ( data ) - data->mySubMeshes.push_back( subMesh ); - else - data = SMESH_subMeshEventListenerData::MakeData( subMesh ); - subMesh->SetEventListener ( GetSrcSubMeshListener(), data, srcSM ); + if ( srcSM != subMesh ) + { + SMESH_subMeshEventListenerData* data = + srcSM->GetEventListenerData(getSrcSubMeshListener()); + if ( data ) + data->mySubMeshes.push_back( subMesh ); + else + data = SMESH_subMeshEventListenerData::MakeData( subMesh ); + subMesh->SetEventListener ( getSrcSubMeshListener(), data, srcSM ); + } } } else { - subMesh->SetEventListener( GetSrcSubMeshListener(), - SMESH_subMeshEventListenerData::MakeData( subMesh ), - srcShapeSM ); + if ( SMESH_subMeshEventListenerData* data = + srcShapeSM->GetEventListenerData( getSrcSubMeshListener() )) + { + bool alreadyIn = + (std::find( data->mySubMeshes.begin(), + data->mySubMeshes.end(), subMesh ) != data->mySubMeshes.end() ); + if ( !alreadyIn ) + data->mySubMeshes.push_back( subMesh ); + } + else + { + subMesh->SetEventListener( getSrcSubMeshListener(), + SMESH_subMeshEventListenerData::MakeData( subMesh ), + srcShapeSM ); + } + } + } + } +} + +namespace StdMeshers_ProjectionUtils +{ + + //================================================================================ + /*! + * \brief Computes transformation beween two sets of 2D points using + * a least square approximation + * + * See "Surface Mesh Projection For Hexahedral Mesh Generation By Sweeping" + * by X.Roca, J.Sarrate, A.Huerta. (2.2) + */ + //================================================================================ + + bool TrsfFinder2D::Solve( const vector< gp_XY >& srcPnts, + const vector< gp_XY >& tgtPnts ) + { + // find gravity centers + gp_XY srcGC( 0,0 ), tgtGC( 0,0 ); + for ( size_t i = 0; i < srcPnts.size(); ++i ) + { + srcGC += srcPnts[i]; + tgtGC += tgtPnts[i]; + } + srcGC /= srcPnts.size(); + tgtGC /= tgtPnts.size(); + + // find trsf + + math_Matrix mat (1,4,1,4, 0.); + math_Vector vec (1,4, 0.); + + // cout << "m1 = smesh.Mesh('src')" << endl + // << "m2 = smesh.Mesh('tgt')" << endl; + double xx = 0, xy = 0, yy = 0; + for ( size_t i = 0; i < srcPnts.size(); ++i ) + { + gp_XY srcUV = srcPnts[i] - srcGC; + gp_XY tgtUV = tgtPnts[i] - tgtGC; + xx += srcUV.X() * srcUV.X(); + yy += srcUV.Y() * srcUV.Y(); + xy += srcUV.X() * srcUV.Y(); + vec( 1 ) += srcUV.X() * tgtUV.X(); + vec( 2 ) += srcUV.Y() * tgtUV.X(); + vec( 3 ) += srcUV.X() * tgtUV.Y(); + vec( 4 ) += srcUV.Y() * tgtUV.Y(); + // cout << "m1.AddNode( " << srcUV.X() << ", " << srcUV.Y() << ", 0 )" << endl + // << "m2.AddNode( " << tgtUV.X() << ", " << tgtUV.Y() << ", 0 )" << endl; + } + mat( 1,1 ) = mat( 3,3 ) = xx; + mat( 2,2 ) = mat( 4,4 ) = yy; + mat( 1,2 ) = mat( 2,1 ) = mat( 3,4 ) = mat( 4,3 ) = xy; + + math_Gauss solver( mat ); + if ( !solver.IsDone() ) + return false; + solver.Solve( vec ); + if ( vec.Norm2() < gp::Resolution() ) + return false; + // cout << vec( 1 ) << "\t " << vec( 2 ) << endl + // << vec( 3 ) << "\t " << vec( 4 ) << endl; + + _trsf.SetTranslationPart( tgtGC ); + _srcOrig = srcGC; + + gp_Mat2d& M = const_cast< gp_Mat2d& >( _trsf.VectorialPart()); + M( 1,1 ) = vec( 1 ); + M( 2,1 ) = vec( 2 ); // | 1 3 | -- is it correct ???????? + M( 1,2 ) = vec( 3 ); // | 2 4 | + M( 2,2 ) = vec( 4 ); + + return true; + } + + //================================================================================ + /*! + * \brief Transforms a 2D points using a found transformation + */ + //================================================================================ + + gp_XY TrsfFinder2D::Transform( const gp_Pnt2d& srcUV ) const + { + gp_XY uv = srcUV.XY() - _srcOrig ; + _trsf.Transforms( uv ); + return uv; + } + + //================================================================================ + /*! + * \brief Computes transformation beween two sets of 3D points using + * a least square approximation + * + * See "Surface Mesh Projection For Hexahedral Mesh Generation By Sweeping" + * by X.Roca, J.Sarrate, A.Huerta. (2.4) + */ + //================================================================================ + + bool TrsfFinder3D::Solve( const vector< gp_XYZ > & srcPnts, + const vector< gp_XYZ > & tgtPnts ) + { + // find gravity center + gp_XYZ srcGC( 0,0,0 ), tgtGC( 0,0,0 ); + for ( size_t i = 0; i < srcPnts.size(); ++i ) + { + srcGC += srcPnts[i]; + tgtGC += tgtPnts[i]; + } + srcGC /= srcPnts.size(); + tgtGC /= tgtPnts.size(); + + gp_XYZ srcOrig = 2 * srcGC - tgtGC; + gp_XYZ tgtOrig = srcGC; + + // find trsf + + math_Matrix mat (1,9,1,9, 0.); + math_Vector vec (1,9, 0.); + + double xx = 0, yy = 0, zz = 0; + double xy = 0, xz = 0, yz = 0; + for ( size_t i = 0; i < srcPnts.size(); ++i ) + { + gp_XYZ src = srcPnts[i] - srcOrig; + gp_XYZ tgt = tgtPnts[i] - tgtOrig; + xx += src.X() * src.X(); + yy += src.Y() * src.Y(); + zz += src.Z() * src.Z(); + xy += src.X() * src.Y(); + xz += src.X() * src.Z(); + yz += src.Y() * src.Z(); + vec( 1 ) += src.X() * tgt.X(); + vec( 2 ) += src.Y() * tgt.X(); + vec( 3 ) += src.Z() * tgt.X(); + vec( 4 ) += src.X() * tgt.Y(); + vec( 5 ) += src.Y() * tgt.Y(); + vec( 6 ) += src.Z() * tgt.Y(); + vec( 7 ) += src.X() * tgt.Z(); + vec( 8 ) += src.Y() * tgt.Z(); + vec( 9 ) += src.Z() * tgt.Z(); + } + mat( 1,1 ) = mat( 4,4 ) = mat( 7,7 ) = xx; + mat( 2,2 ) = mat( 5,5 ) = mat( 8,8 ) = yy; + mat( 3,3 ) = mat( 6,6 ) = mat( 9,9 ) = zz; + mat( 1,2 ) = mat( 2,1 ) = mat( 4,5 ) = mat( 5,4 ) = mat( 7,8 ) = mat( 8,7 ) = xy; + mat( 1,3 ) = mat( 3,1 ) = mat( 4,6 ) = mat( 6,4 ) = mat( 7,9 ) = mat( 9,7 ) = xz; + mat( 2,3 ) = mat( 3,2 ) = mat( 5,6 ) = mat( 6,5 ) = mat( 8,9 ) = mat( 9,8 ) = yz; + + math_Gauss solver( mat ); + if ( !solver.IsDone() ) + return false; + solver.Solve( vec ); + if ( vec.Norm2() < gp::Resolution() ) + return false; + // cout << endl + // << vec( 1 ) << "\t " << vec( 2 ) << "\t " << vec( 3 ) << endl + // << vec( 4 ) << "\t " << vec( 5 ) << "\t " << vec( 6 ) << endl + // << vec( 7 ) << "\t " << vec( 8 ) << "\t " << vec( 9 ) << endl; + + _srcOrig = srcOrig; + _trsf.SetTranslationPart( tgtOrig ); + + gp_Mat& M = const_cast< gp_Mat& >( _trsf.VectorialPart() ); + M.SetRows( gp_XYZ( vec( 1 ), vec( 2 ), vec( 3 )), + gp_XYZ( vec( 4 ), vec( 5 ), vec( 6 )), + gp_XYZ( vec( 7 ), vec( 8 ), vec( 9 ))); + return true; + } + + //================================================================================ + /*! + * \brief Transforms a 3D point using a found transformation + */ + //================================================================================ + + gp_XYZ TrsfFinder3D::Transform( const gp_Pnt& srcP ) const + { + gp_XYZ p = srcP.XYZ() - _srcOrig; + _trsf.Transforms( p ); + return p; + } + + //================================================================================ + /*! + * \brief Transforms a 3D vector using a found transformation + */ + //================================================================================ + + gp_XYZ TrsfFinder3D::TransformVec( const gp_Vec& v ) const + { + return v.XYZ().Multiplied( _trsf.VectorialPart() ); + } + //================================================================================ + /*! + * \brief Inversion + */ + //================================================================================ + + bool TrsfFinder3D::Invert() + { + if (( _trsf.Form() == gp_Translation ) && + ( _srcOrig.X() != 0 || _srcOrig.Y() != 0 || _srcOrig.Z() != 0 )) + { + // seems to be defined via Solve() + gp_XYZ newSrcOrig = _trsf.TranslationPart(); + gp_Mat& M = const_cast< gp_Mat& >( _trsf.VectorialPart() ); + const double D = M.Determinant(); + if ( D < 1e-3 * ( newSrcOrig - _srcOrig ).Modulus() ) + { +#ifdef _DEBUG_ + cerr << "TrsfFinder3D::Invert()" + << "D " << M.Determinant() << " IsSingular " << M.IsSingular() << endl; +#endif + return false; } + gp_Mat Minv = M.Inverted(); + _trsf.SetTranslationPart( _srcOrig ); + _srcOrig = newSrcOrig; + M = Minv; } + else + { + _trsf.Invert(); + } + return true; } } diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_1D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_1D.cpp index 4fd7c5d8dc9c..efeacb0e2c3d 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_1D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_1D.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Projection_1D.cxx // Module : SMESH @@ -56,7 +57,8 @@ using namespace std; #define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; } -typedef StdMeshers_ProjectionUtils TAssocTool; +//typedef StdMeshers_ProjectionUtils TAssocTool; +namespace TAssocTool = StdMeshers_ProjectionUtils; //======================================================================= //function : StdMeshers_Projection_1D @@ -67,7 +69,7 @@ StdMeshers_Projection_1D::StdMeshers_Projection_1D(int hypId, int studyId, SMESH :SMESH_1D_Algo(hypId, studyId, gen) { _name = "Projection_1D"; - _shapeType = (1 << TopAbs_EDGE); // 1 bit per shape type + _shapeType = (1 << TopAbs_EDGE); // 1 bit per shape type _compatibleHypothesis.push_back("ProjectionSource1D"); _sourceHypo = 0; @@ -128,25 +130,25 @@ bool StdMeshers_Projection_1D::CheckHypothesis(SMESH_Mesh& if ( _sourceHypo->HasVertexAssociation() ) { // source and target vertices - if ( !TAssocTool::IsSubShape( _sourceHypo->GetSourceVertex(), srcMesh ) || - !TAssocTool::IsSubShape( _sourceHypo->GetTargetVertex(), tgtMesh ) || - !TAssocTool::IsSubShape( _sourceHypo->GetSourceVertex(), - _sourceHypo->GetSourceEdge() )) + if ( !SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceVertex(), srcMesh ) || + !SMESH_MesherHelper::IsSubShape( _sourceHypo->GetTargetVertex(), tgtMesh ) || + !SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceVertex(), + _sourceHypo->GetSourceEdge() )) { aStatus = HYP_BAD_PARAMETER; - SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetSourceVertex(), srcMesh ))); - SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetTargetVertex(), tgtMesh ))); - SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetSourceVertex(), - _sourceHypo->GetSourceEdge() ))); + SCRUTE((SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceVertex(), srcMesh ))); + SCRUTE((SMESH_MesherHelper::IsSubShape( _sourceHypo->GetTargetVertex(), tgtMesh ))); + SCRUTE((SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceVertex(), + _sourceHypo->GetSourceEdge() ))); } // PAL16202 - else + else { - bool isSub = TAssocTool::IsSubShape( _sourceHypo->GetTargetVertex(), aShape ); + bool isSub = SMESH_MesherHelper::IsSubShape( _sourceHypo->GetTargetVertex(), aShape ); if ( !_sourceHypo->IsCompoundSource() ) { if ( !isSub ) { aStatus = HYP_BAD_PARAMETER; - SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetTargetVertex(), aShape))); + SCRUTE((SMESH_MesherHelper::IsSubShape( _sourceHypo->GetTargetVertex(), aShape))); } } else if ( isSub ) { @@ -159,7 +161,7 @@ bool StdMeshers_Projection_1D::CheckHypothesis(SMESH_Mesh& { const TopoDS_Shape& ancestor = ancestIt.Value(); if ( ancestor.ShapeType() == TopAbs_EDGE && - TAssocTool::IsSubShape( ancestor, _sourceHypo->GetSourceEdge() )) + SMESH_MesherHelper::IsSubShape( ancestor, _sourceHypo->GetSourceEdge() )) { if ( sharingEdge.IsNull() || ancestor.IsSame( sharingEdge )) sharingEdge = ancestor; @@ -175,11 +177,11 @@ bool StdMeshers_Projection_1D::CheckHypothesis(SMESH_Mesh& } } // check source edge - if ( !TAssocTool::IsSubShape( _sourceHypo->GetSourceEdge(), srcMesh ) || + if ( !SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceEdge(), srcMesh ) || ( srcMesh == tgtMesh && aShape == _sourceHypo->GetSourceEdge() )) { aStatus = HYP_BAD_PARAMETER; - SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetSourceEdge(), srcMesh ))); + SCRUTE((SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceEdge(), srcMesh ))); SCRUTE((srcMesh == tgtMesh)); SCRUTE(( aShape == _sourceHypo->GetSourceEdge() )); } @@ -209,14 +211,14 @@ bool StdMeshers_Projection_1D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& SMESHDS_Mesh * meshDS = theMesh.GetMeshDS(); // --------------------------- - // Make subshapes association + // Make sub-shapes association // --------------------------- TopoDS_Edge srcEdge, tgtEdge = TopoDS::Edge( theShape.Oriented(TopAbs_FORWARD)); TopoDS_Shape srcShape = _sourceHypo->GetSourceEdge().Oriented(TopAbs_FORWARD); TAssocTool::TShapeShapeMap shape2ShapeMap; - TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap, tgtEdge ); + TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap ); if ( !TAssocTool::FindSubShapeAssociation( tgtEdge, tgtMesh, srcShape, srcMesh, shape2ShapeMap) || !shape2ShapeMap.IsBound( tgtEdge )) @@ -237,14 +239,18 @@ bool StdMeshers_Projection_1D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( srcEdge ); //SMESH_subMesh* tgtSubMesh = tgtMesh->GetSubMesh( tgtEdge ); + string srcMeshError; if ( tgtMesh == srcMesh ) { if ( !TAssocTool::MakeComputed( srcSubMesh )) - return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed"); + srcMeshError = TAssocTool::SourceNotComputedError( srcSubMesh, this ); } else { if ( !srcSubMesh->IsMeshComputed() ) - return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed"); + srcMeshError = TAssocTool::SourceNotComputedError(); } + if ( !srcMeshError.empty() ) + return error(COMPERR_BAD_INPUT_MESH, srcMeshError ); + // ----------------------------------------------- // Find out nodes distribution on the source edge // ----------------------------------------------- @@ -372,6 +378,97 @@ bool StdMeshers_Projection_1D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& return true; } + +//======================================================================= +//function : Evaluate +//purpose : +//======================================================================= + +bool StdMeshers_Projection_1D::Evaluate(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + MapShapeNbElems& aResMap) +{ + if ( !_sourceHypo ) + return false; + + SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh(); + SMESH_Mesh * tgtMesh = & theMesh; + if ( !srcMesh ) + srcMesh = tgtMesh; + + //SMESHDS_Mesh * meshDS = theMesh.GetMeshDS(); + + // --------------------------- + // Make sub-shapes association + // --------------------------- + + TopoDS_Edge srcEdge, tgtEdge = TopoDS::Edge( theShape.Oriented(TopAbs_FORWARD)); + TopoDS_Shape srcShape = _sourceHypo->GetSourceEdge().Oriented(TopAbs_FORWARD); + + TAssocTool::TShapeShapeMap shape2ShapeMap; + TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap ); + if ( !TAssocTool::FindSubShapeAssociation( tgtEdge, tgtMesh, srcShape, srcMesh, + shape2ShapeMap) || + !shape2ShapeMap.IsBound( tgtEdge )) + return error("Vertices association failed" ); + + srcEdge = TopoDS::Edge( shape2ShapeMap( tgtEdge ).Oriented(TopAbs_FORWARD)); +// cout << " srcEdge #" << srcMesh->GetMeshDS()->ShapeToIndex( srcEdge ) +// << " tgtEdge #" << tgtMesh->GetMeshDS()->ShapeToIndex( tgtEdge ) << endl; + + TopoDS_Vertex tgtV[2], srcV[2]; + TopExp::Vertices( tgtEdge, tgtV[0], tgtV[1] ); + TopExp::Vertices( srcEdge, srcV[0], srcV[1] ); + + // ---------------------------------------------- + // Assure that mesh on a source edge is computed + // ---------------------------------------------- + + SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( srcEdge ); + //SMESH_subMesh* tgtSubMesh = tgtMesh->GetSubMesh( tgtEdge ); + + if ( tgtMesh == srcMesh ) { + if ( !TAssocTool::MakeComputed( srcSubMesh )) + return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed"); + } + else { + if ( !srcSubMesh->IsMeshComputed() ) + return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed"); + } + // ----------------------------------------------- + // Find out nodes distribution on the source edge + // ----------------------------------------------- + + //double srcLength = EdgeLength( srcEdge ); + //double tgtLength = EdgeLength( tgtEdge ); + + vector< double > params; // sorted parameters of nodes on the source edge + if ( !SMESH_Algo::GetNodeParamOnEdge( srcMesh->GetMeshDS(), srcEdge, params )) + return error(COMPERR_BAD_INPUT_MESH,"Bad node parameters on the source edge"); + + int nbNodes = params.size(); + + std::vector aVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; iGetSubMeshDS()->GetElements(); + if ( elemIt->more() ) + quadratic = elemIt->next()->IsQuadratic(); + if(quadratic) + aVec[SMDSEntity_Quad_Edge] = (nbNodes-1)/2; + else + aVec[SMDSEntity_Edge] = nbNodes - 1; + + SMESH_subMesh * sm = theMesh.GetSubMesh(theShape); + aResMap.insert(std::make_pair(sm,aVec)); + + return true; +} + + //============================================================================= /*! * \brief Sets a default event listener to submesh of the source edge diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_1D2D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_1D2D.cpp new file mode 100644 index 000000000000..125412c9f9a6 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_1D2D.cpp @@ -0,0 +1,301 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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_Projection_1D2D.cxx +// Module : SMESH +// Author : Edward AGAPOV (eap) +// +#include "StdMeshers_Projection_1D2D.hxx" + +#include "SMESH_Gen.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_subMeshEventListener.hxx" +#include "StdMeshers_FaceSide.hxx" +#include "StdMeshers_ProjectionSource2D.hxx" +#include "StdMeshers_ProjectionUtils.hxx" + +#include +#include + +using namespace std; + +namespace +{ + // -------------------------------------------------------------------------------- + /*! + * \brief an event listener updating submehses of EDGEs according to + * events on the target FACE submesh + */ + struct EventProparatorToEdges : public SMESH_subMeshEventListener + { + EventProparatorToEdges(): SMESH_subMeshEventListener(/*isDeletable=*/false, + "Projection_1D2D::EventProparatorToEdges") + {} + static EventProparatorToEdges* Instance() { static EventProparatorToEdges E; return &E; } + + static void Set(SMESH_subMesh* faceSubMesh) + { + SMESH_subMeshEventListenerData* edgeSubMeshes = + new SMESH_subMeshEventListenerData(/*isDeletable=*/true); + SMESH_Mesh* mesh = faceSubMesh->GetFather(); + TopExp_Explorer eExp( faceSubMesh->GetSubShape(), TopAbs_EDGE ); + for ( ; eExp.More(); eExp.Next() ) + edgeSubMeshes->mySubMeshes.push_back( mesh->GetSubMesh( eExp.Current() )); + + // set a listener + faceSubMesh->SetEventListener( Instance(), edgeSubMeshes, faceSubMesh ); + } + }; + // -------------------------------------------------------------------------------- + /*! + * \brief Structure used to temporary remove EventProparatorToEdges from faceSubMesh + * in order to prevent propagation of CLEAN event from FACE to EDGEs during + * StdMeshers_Projection_1D2D::Compute(). The CLEAN event is emmited by Pattern mapper + * and causes removal of faces generated on adjacent FACEs. + */ + struct UnsetterOfEventProparatorToEdges + { + SMESH_subMesh* _faceSubMesh; + UnsetterOfEventProparatorToEdges( SMESH_subMesh* faceSubMesh ):_faceSubMesh(faceSubMesh) + { + faceSubMesh->DeleteEventListener( EventProparatorToEdges::Instance() ); + } + ~UnsetterOfEventProparatorToEdges() + { + EventProparatorToEdges::Set(_faceSubMesh); + } + }; +} + +//======================================================================= +//function : StdMeshers_Projection_1D2D +//purpose : +//======================================================================= + +StdMeshers_Projection_1D2D::StdMeshers_Projection_1D2D(int hypId, int studyId, SMESH_Gen* gen) + :StdMeshers_Projection_2D(hypId, studyId, gen) +{ + _name = "Projection_1D2D"; + _requireDiscreteBoundary = false; + _supportSubmeshes = true; +} + +//======================================================================= +//function : Compute +//purpose : +//======================================================================= + +bool StdMeshers_Projection_1D2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape) +{ + UnsetterOfEventProparatorToEdges eventBarrier( theMesh.GetSubMesh( theShape )); + + // 1) Project faces + + if ( !StdMeshers_Projection_2D::Compute(theMesh, theShape)) + return false; + + // 2) Create segments + + SMESHDS_Mesh * meshDS = theMesh.GetMeshDS(); + + SMESHDS_SubMesh * faceSubMesh = meshDS->MeshElements( theShape ); + if ( !faceSubMesh || faceSubMesh->NbElements() == 0 ) return false; + _quadraticMesh = faceSubMesh->GetElements()->next()->IsQuadratic(); + + SMESH_MesherHelper helper( theMesh ); + helper.SetSubShape( theShape ); + + if ( _quadraticMesh ) + { + // 2a) Move some medium nodes from FACE to EDGES. They are on FACE because + // EDGEs are discreteized later than FACE, in this case. + + SMESH_MesherHelper posFixer( theMesh ); + posFixer.ToFixNodeParameters( true ); + SMDS_ElemIteratorPtr fIt = faceSubMesh->GetElements(); + vector< const SMDS_MeshNode* > nodes; + double dummyU, tol = 1e-7; + while ( fIt->more() ) // loop on mesh faces created by StdMeshers_Projection_2D + { + const SMDS_MeshElement* f = fIt->next(); + //if ( !f->IsQuadratic() ) continue; + nodes.assign( SMDS_MeshElement::iterator( f->interlacedNodesElemIterator() ), + SMDS_MeshElement::iterator() ); + nodes.push_back( nodes[0] ); + for ( size_t i = 2; i < nodes.size(); i += 2 ) + { + pair idType = helper.GetMediumPos( nodes[i], nodes[i-2] ); + if ( idType.second == TopAbs_EDGE && + idType.first != nodes[i-1]->getshapeId() ) + { + faceSubMesh->RemoveNode( nodes[i-1], /*isDeleted=*/false ); + meshDS->SetNodeOnEdge( (SMDS_MeshNode*) nodes[i-1], idType.first ); + posFixer.SetSubShape( idType.first ); + posFixer.CheckNodeU( TopoDS::Edge( posFixer.GetSubShape() ), + nodes[i-1], dummyU=0., tol, /*force=*/true ); + } + } + } + } + TopoDS_Face F = TopoDS::Face( theShape ); + TError err; + TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, theMesh, + /*ignoreMediumNodes=*/false, err); + if ( err && !err->IsOK() ) + return error( err ); + + for ( size_t iWire = 0; iWire < wires.size(); ++iWire ) + { + vector nodes = wires[ iWire ]->GetOrderedNodes(); + if ( nodes.empty() ) + return error("Wrong nodes on a wire"); + + // check that all nodes are shared by faces generated on F + for ( size_t i = 0; i < nodes.size(); ++i ) + { + SMDS_ElemIteratorPtr fIt = nodes[i]->GetInverseElementIterator(SMDSAbs_Face); + bool faceFound = false; + while ( !faceFound && fIt->more() ) + faceFound = ( helper.GetSubShapeID() == fIt->next()->getshapeId() ); + if ( !faceFound ) + return error("The existing 1D mesh mismatches the generated 2D mesh"); + } + + const bool checkExisting = ( wires[ iWire ]->NbSegments() || helper.HasSeam() ); + + if ( _quadraticMesh ) + { + for ( size_t i = 2; i < nodes.size(); i += 2 ) + { + if ( checkExisting && meshDS->FindEdge( nodes[i-2], nodes[i], nodes[i-1])) + continue; + SMDS_MeshElement* e = meshDS->AddEdge( nodes[i-2], nodes[i], nodes[i-1] ); + meshDS->SetMeshElementOnShape( e, nodes[i-1]->getshapeId() ); + } + } + else + { + int edgeID = meshDS->ShapeToIndex( wires[ iWire ]->Edge(0) ); + for ( size_t i = 1; i < nodes.size(); ++i ) + { + if ( checkExisting && meshDS->FindEdge( nodes[i-1], nodes[i])) + continue; + SMDS_MeshElement* e = meshDS->AddEdge( nodes[i-1], nodes[i] ); + if ( nodes[i-1]->getshapeId() != edgeID && + nodes[i ]->getshapeId() != edgeID ) + { + edgeID = helper.GetMediumPos( nodes[i-1], nodes[i] ).first; + if ( edgeID < 1 ) edgeID = helper.GetSubShapeID(); + } + meshDS->SetMeshElementOnShape( e, edgeID ); + } + } + } + + return true; +} + +//======================================================================= +//function : Evaluate +//purpose : +//======================================================================= + +bool StdMeshers_Projection_1D2D::Evaluate(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + MapShapeNbElems& aResMap) +{ + if ( !StdMeshers_Projection_2D::Evaluate(theMesh,theShape,aResMap)) + return false; + + TopoDS_Shape srcFace = _sourceHypo->GetSourceFace(); + SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh(); + if ( !srcMesh ) srcMesh = & theMesh; + SMESH_subMesh* srcFaceSM = srcMesh->GetSubMesh( srcFace ); + + namespace SPU = StdMeshers_ProjectionUtils; + SPU::TShapeShapeMap shape2ShapeMap; + SPU::InitVertexAssociation( _sourceHypo, shape2ShapeMap ); + if ( !SPU::FindSubShapeAssociation( theShape, &theMesh, srcFace, srcMesh, shape2ShapeMap)) + return error(COMPERR_BAD_SHAPE,"Topology of source and target faces seems different" ); + + MapShapeNbElems srcResMap; + if ( !srcFaceSM->IsMeshComputed() ) + _gen->Evaluate( *srcMesh, srcFace, srcResMap); + + SMESH_subMeshIteratorPtr smIt = srcFaceSM->getDependsOnIterator(/*includeSelf=*/false, + /*complexShapeFirst=*/true); + while ( smIt->more() ) + { + SMESH_subMesh* srcSM = smIt->next(); + TopAbs_ShapeEnum shapeType = srcSM->GetSubShape().ShapeType(); + if ( shapeType == TopAbs_EDGE ) + { + std::vector aVec; + SMESHDS_SubMesh* srcSubMeshDS = srcSM->GetSubMeshDS(); + if ( srcSubMeshDS && srcSubMeshDS->NbElements() ) + { + aVec.resize(SMDSEntity_Last, 0); + SMDS_ElemIteratorPtr eIt = srcSubMeshDS->GetElements(); + _quadraticMesh = ( eIt->more() && eIt->next()->IsQuadratic() ); + + aVec[SMDSEntity_Node] = srcSubMeshDS->NbNodes(); + aVec[_quadraticMesh ? SMDSEntity_Quad_Edge : SMDSEntity_Edge] = srcSubMeshDS->NbElements(); + } + else + { + if ( srcResMap.empty() ) + if ( !_gen->Evaluate( *srcMesh, srcSM->GetSubShape(), srcResMap )) + return error(COMPERR_BAD_INPUT_MESH,"Source mesh not evaluatable"); + aVec = srcResMap[ srcSM ]; + if ( aVec.empty() ) + return error(COMPERR_BAD_INPUT_MESH,"Source mesh is wrongly evaluated"); + } + TopoDS_Shape tgtEdge = shape2ShapeMap( srcSM->GetSubShape(), /*isSrc=*/true ); + SMESH_subMesh* tgtSM = theMesh.GetSubMesh( tgtEdge ); + aResMap.insert(std::make_pair(tgtSM,aVec)); + } + if ( shapeType == TopAbs_VERTEX ) break; + } + + return true; +} + +//======================================================================= +//function : SetEventListener +//purpose : Sets a default event listener to submesh of the source face. +// faceSubMesh - submesh where algo is set +// After being set, event listener is notified on each event of a submesh. +// This method is called when a submesh gets HYP_OK algo_state. +// Arranges that CLEAN event is translated from source submesh to +// the faceSubMesh submesh. +//======================================================================= + +void StdMeshers_Projection_1D2D::SetEventListener(SMESH_subMesh* faceSubMesh) +{ + // set a listener of events on a source submesh + StdMeshers_Projection_2D::SetEventListener(faceSubMesh); + + // set a listener to the target FACE submesh in order to update submehses + // of EDGEs according to events on the target FACE submesh + EventProparatorToEdges::Set( faceSubMesh ); +} + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_2D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_2D.cpp index 3457197f5baf..87572c18f404 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_2D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_2D.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Projection_2D.cxx // Module : SMESH @@ -29,34 +30,46 @@ #include "StdMeshers_ProjectionSource2D.hxx" #include "StdMeshers_ProjectionUtils.hxx" +#include "StdMeshers_FaceSide.hxx" +#include "SMDS_EdgePosition.hxx" +#include "SMDS_FacePosition.hxx" #include "SMESHDS_Hypothesis.hxx" #include "SMESHDS_SubMesh.hxx" #include "SMESH_Block.hxx" +#include "SMESH_Comment.hxx" #include "SMESH_Gen.hxx" #include "SMESH_Mesh.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_Pattern.hxx" #include "SMESH_subMesh.hxx" #include "SMESH_subMeshEventListener.hxx" -#include "SMESH_Comment.hxx" -#include "SMDS_EdgePosition.hxx" #include "utilities.h" +#include #include #include +#include +#include #include #include +#include #include +#include #include +#include +#include +#include +#include using namespace std; #define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; } -typedef StdMeshers_ProjectionUtils TAssocTool; +namespace TAssocTool = StdMeshers_ProjectionUtils; +//typedef StdMeshers_ProjectionUtils TAssocTool; //======================================================================= //function : StdMeshers_Projection_2D @@ -67,8 +80,6 @@ StdMeshers_Projection_2D::StdMeshers_Projection_2D(int hypId, int studyId, SMESH :SMESH_2D_Algo(hypId, studyId, gen) { _name = "Projection_2D"; - _shapeType = (1 << TopAbs_FACE); // 1 bit per shape type - _compatibleHypothesis.push_back("ProjectionSource2D"); _sourceHypo = 0; } @@ -130,40 +141,44 @@ bool StdMeshers_Projection_2D::CheckHypothesis(SMESH_Mesh& TopoDS_Shape edge = TAssocTool::GetEdgeByVertices ( srcMesh, _sourceHypo->GetSourceVertex(1), _sourceHypo->GetSourceVertex(2) ); if ( edge.IsNull() || - !TAssocTool::IsSubShape( edge, srcMesh ) || - !TAssocTool::IsSubShape( edge, _sourceHypo->GetSourceFace() )) + !SMESH_MesherHelper::IsSubShape( edge, srcMesh ) || + !SMESH_MesherHelper::IsSubShape( edge, _sourceHypo->GetSourceFace() )) { theStatus = HYP_BAD_PARAMETER; + error("Invalid source vertices"); SCRUTE((edge.IsNull())); - SCRUTE((TAssocTool::IsSubShape( edge, srcMesh ))); - SCRUTE((TAssocTool::IsSubShape( edge, _sourceHypo->GetSourceFace() ))); + SCRUTE((SMESH_MesherHelper::IsSubShape( edge, srcMesh ))); + SCRUTE((SMESH_MesherHelper::IsSubShape( edge, _sourceHypo->GetSourceFace() ))); } else { // target vertices edge = TAssocTool::GetEdgeByVertices ( tgtMesh, _sourceHypo->GetTargetVertex(1), _sourceHypo->GetTargetVertex(2) ); - if ( edge.IsNull() || !TAssocTool::IsSubShape( edge, tgtMesh )) + if ( edge.IsNull() || !SMESH_MesherHelper::IsSubShape( edge, tgtMesh )) { theStatus = HYP_BAD_PARAMETER; + error("Invalid target vertices"); SCRUTE((edge.IsNull())); - SCRUTE((TAssocTool::IsSubShape( edge, tgtMesh ))); + SCRUTE((SMESH_MesherHelper::IsSubShape( edge, tgtMesh ))); } // PAL16203 else if ( !_sourceHypo->IsCompoundSource() && - !TAssocTool::IsSubShape( edge, theShape )) + !SMESH_MesherHelper::IsSubShape( edge, theShape )) { theStatus = HYP_BAD_PARAMETER; - SCRUTE((TAssocTool::IsSubShape( edge, theShape ))); + error("Invalid target vertices"); + SCRUTE((SMESH_MesherHelper::IsSubShape( edge, theShape ))); } } } // check a source face - if ( !TAssocTool::IsSubShape( _sourceHypo->GetSourceFace(), srcMesh ) || + if ( !SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceFace(), srcMesh ) || ( srcMesh == tgtMesh && theShape == _sourceHypo->GetSourceFace() )) { theStatus = HYP_BAD_PARAMETER; - SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetSourceFace(), srcMesh ))); + error("Invalid source face"); + SCRUTE((SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceFace(), srcMesh ))); SCRUTE((srcMesh == tgtMesh)); SCRUTE(( theShape == _sourceHypo->GetSourceFace() )); } @@ -177,12 +192,11 @@ bool StdMeshers_Projection_2D::CheckHypothesis(SMESH_Mesh& namespace { - //================================================================================ /*! * \brief define if a node is new or old - * \param node - node to check - * \retval bool - true if the node existed before Compute() is called + * \param node - node to check + * \retval bool - true if the node existed before Compute() is called */ //================================================================================ @@ -190,9 +204,17 @@ namespace { { // old nodes are shared by edges and new ones are shared // only by faces created by mapper - SMDS_ElemIteratorPtr invEdge = node->GetInverseElementIterator(SMDSAbs_Edge); - bool isOld = invEdge->more(); - return isOld; + //if ( is1DComputed ) + { + bool isOld = node->NbInverseElements(SMDSAbs_Edge) > 0; + return isOld; + } + // else + // { + // SMDS_ElemIteratorPtr invFace = node->GetInverseElementIterator(SMDSAbs_Face); + // bool isNew = invFace->more(); + // return !isNew; + // } } //================================================================================ @@ -211,7 +233,7 @@ namespace { void Release() { sm = 0; } // mesh will not be removed static void Clean( SMESH_subMesh* sm, bool withSub=true ) { - if ( !sm ) return; + if ( !sm || !sm->GetSubMeshDS() ) return; // PAL16567, 18920. Remove face nodes as well // switch ( sm->GetSubShape().ShapeType() ) { // case TopAbs_VERTEX: @@ -238,7 +260,7 @@ namespace { /*! * \brief find new nodes belonging to one free border of mesh on face * \param sm - submesh on edge or vertex containg nodes to choose from - * \param face - the face bound the submesh + * \param face - the face bound by the submesh * \param u2nodes - map to fill with nodes * \param seamNodes - set of found nodes * \retval bool - is a success @@ -280,43 +302,45 @@ namespace { if ( !smV1->IsMeshComputed() || !smV2->IsMeshComputed() ) RETURN_BAD_RESULT("Empty vertex submeshes"); - // Look for a new node on V1 - nIt = smV1->GetSubMeshDS()->GetNodes(); const SMDS_MeshNode* nV1 = 0; - while ( nIt->more() && !nV1 ) { - const SMDS_MeshNode* node = nIt->next(); - if ( !isOldNode( node ) ) nV1 = node; - } - if ( !nV1 ) - RETURN_BAD_RESULT("No new node found on V1"); - - // Find a new node connected to nV1 and belonging to edge submesh; const SMDS_MeshNode* nE = 0; - SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); - SMDS_ElemIteratorPtr vElems = nV1->GetInverseElementIterator(SMDSAbs_Face); - while ( vElems->more() && !nE ) { - const SMDS_MeshElement* elem = vElems->next(); - int nbNodes = elem->NbNodes(); - if ( elem->IsQuadratic() ) - nbNodes /= 2; - int iV1 = elem->GetNodeIndex( nV1 ); - // try next after nV1 - int iE = SMESH_MesherHelper::WrapIndex( iV1 + 1, nbNodes ); - if ( smDS->Contains( elem->GetNode( iE ) )) - nE = elem->GetNode( iE ); - if ( !nE ) { - // try node before nV1 - iE = SMESH_MesherHelper::WrapIndex( iV1 - 1, nbNodes ); - if ( smDS->Contains( elem->GetNode( iE ))) + + // Look for nV1 - a new node on V1 + nIt = smV1->GetSubMeshDS()->GetNodes(); + while ( nIt->more() && !nE ) { + const SMDS_MeshNode* node = nIt->next(); + if ( isOldNode( node ) ) continue; + nV1 = node; + + // Find nE - a new node connected to nV1 and belonging to edge submesh; + SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); + SMDS_ElemIteratorPtr vElems = nV1->GetInverseElementIterator(SMDSAbs_Face); + while ( vElems->more() && !nE ) { + const SMDS_MeshElement* elem = vElems->next(); + int nbNodes = elem->NbNodes(); + if ( elem->IsQuadratic() ) + nbNodes /= 2; + int iV1 = elem->GetNodeIndex( nV1 ); + // try next after nV1 + int iE = SMESH_MesherHelper::WrapIndex( iV1 + 1, nbNodes ); + if ( smDS->Contains( elem->GetNode( iE ) )) nE = elem->GetNode( iE ); - } - if ( nE && elem->IsQuadratic() ) { // find medium node between nV1 and nE - if ( Abs( iV1 - iE ) == 1 ) - nE = elem->GetNode( Min ( iV1, iE ) + nbNodes ); - else - nE = elem->GetNode( elem->NbNodes() - 1 ); + if ( !nE ) { + // try node before nV1 + iE = SMESH_MesherHelper::WrapIndex( iV1 - 1, nbNodes ); + if ( smDS->Contains( elem->GetNode( iE ))) + nE = elem->GetNode( iE ); + } + if ( nE && elem->IsQuadratic() ) { // find medium node between nV1 and nE + if ( Abs( iV1 - iE ) == 1 ) + nE = elem->GetNode( Min ( iV1, iE ) + nbNodes ); + else + nE = elem->GetNode( elem->NbNodes() - 1 ); + } } } + if ( !nV1 ) + RETURN_BAD_RESULT("No new node found on V1"); if ( !nE ) RETURN_BAD_RESULT("new node on edge not found"); @@ -339,7 +363,7 @@ namespace { RETURN_BAD_RESULT("Bad node position type: node " << node->GetID() << " pos type " << node->GetPosition()->GetTypeOfPosition()); const SMDS_EdgePosition* pos = - static_cast(node->GetPosition().get()); + static_cast(node->GetPosition()); u2nodes.insert( make_pair( pos->GetUParameter(), node )); seamNodes.insert( node ); } @@ -354,15 +378,789 @@ namespace { } // bool getBoundaryNodes() + //================================================================================ + /*! + * \brief Check if two consecutive EDGEs are connected in 2D + * \param [in] E1 - a well oriented non-seam EDGE + * \param [in] E2 - a possibly well oriented seam EDGE + * \param [in] F - a FACE + * \return bool - result + */ + //================================================================================ + + bool are2dConnected( const TopoDS_Edge & E1, + const TopoDS_Edge & E2, + const TopoDS_Face & F ) + { + double f,l; + Handle(Geom2d_Curve) c1 = BRep_Tool::CurveOnSurface( E1, F, f, l ); + gp_Pnt2d uvFirst1 = c1->Value( f ); + gp_Pnt2d uvLast1 = c1->Value( l ); + + Handle(Geom2d_Curve) c2 = BRep_Tool::CurveOnSurface( E2, F, f, l ); + gp_Pnt2d uvFirst2 = c2->Value( E2.Orientation() == TopAbs_REVERSED ? l : f ); + double tol2 = Max( Precision::PConfusion() * Precision::PConfusion(), + 1e-5 * uvLast1.SquareDistance( uvFirst1 )); + + return (( uvFirst2.SquareDistance( uvFirst1 ) < tol2 ) || + ( uvFirst2.SquareDistance( uvLast1 ) < tol2 )); + } + + //================================================================================ + /*! + * \brief Compose TSideVector for both FACEs keeping matching order of EDGEs + * and fill src2tgtNodes map + */ + //================================================================================ + + TError getWires(const TopoDS_Face& tgtFace, + const TopoDS_Face& srcFace, + SMESH_Mesh * tgtMesh, + SMESH_Mesh * srcMesh, + const TAssocTool::TShapeShapeMap& shape2ShapeMap, + TSideVector& srcWires, + TSideVector& tgtWires, + TAssocTool::TNodeNodeMap& src2tgtNodes, + bool& is1DComputed) + { + SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS(); + SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS(); + + src2tgtNodes.clear(); + + // get ordered src EDGEs + TError err; + srcWires = StdMeshers_FaceSide::GetFaceWires( srcFace, *srcMesh,/*skipMediumNodes=*/0, err); + if ( err && !err->IsOK() || srcWires.empty() ) + return err; + + SMESH_MesherHelper srcHelper( *srcMesh ); + srcHelper.SetSubShape( srcFace ); + + // make corresponding sequence of tgt EDGEs + tgtWires.resize( srcWires.size() ); + for ( size_t iW = 0; iW < srcWires.size(); ++iW ) + { + StdMeshers_FaceSidePtr srcWire = srcWires[iW]; + + list< TopoDS_Edge > tgtEdges; + TopTools_IndexedMapOfShape edgeMap; // to detect seam edges + for ( int iE = 0; iE < srcWire->NbEdges(); ++iE ) + { + TopoDS_Edge srcE = srcWire->Edge( iE ); + TopoDS_Edge tgtE = TopoDS::Edge( shape2ShapeMap( srcE, /*isSrc=*/true)); + TopoDS_Shape srcEbis = shape2ShapeMap( tgtE, /*isSrc=*/false ); + if ( srcE.Orientation() != srcEbis.Orientation() ) + tgtE.Reverse(); + // reverse a seam edge encountered for the second time + const int index = edgeMap.Add( tgtE ); + if ( index < edgeMap.Extent() ) // E is a seam + { + // check which of edges to reverse, E or one already being in tgtEdges + if ( are2dConnected( tgtEdges.back(), tgtE, tgtFace )) + { + list< TopoDS_Edge >::iterator eIt = tgtEdges.begin(); + std::advance( eIt, index-1 ); + if ( are2dConnected( tgtEdges.back(), *eIt, tgtFace )) + eIt->Reverse(); + } + else + { + tgtE.Reverse(); + } + } + if ( srcWire->NbEdges() == 1 && tgtMesh == srcMesh ) // circle + { + // try to verify ori by propagation + pair nE = + StdMeshers_ProjectionUtils::GetPropagationEdge( srcMesh, tgtE, srcE ); + if ( !nE.second.IsNull() ) + tgtE = nE.second; + } + tgtEdges.push_back( tgtE ); + } + + tgtWires[ iW ].reset( new StdMeshers_FaceSide( tgtFace, tgtEdges, tgtMesh, + /*theIsForward = */ true, + /*theIgnoreMediumNodes = */false)); + StdMeshers_FaceSidePtr tgtWire = tgtWires[ iW ]; + + // Fill map of src to tgt nodes with nodes on edges + + for ( int iE = 0; iE < srcWire->NbEdges(); ++iE ) + { + if ( srcMesh->GetSubMesh( srcWire->Edge(iE) )->IsEmpty() || + tgtMesh->GetSubMesh( tgtWire->Edge(iE) )->IsEmpty() ) + { + // add nodes on VERTEXes for a case of not meshes EDGEs + const SMDS_MeshNode* srcN = srcWire->VertexNode( iE ); + const SMDS_MeshNode* tgtN = tgtWire->VertexNode( iE ); + if ( srcN && tgtN ) + src2tgtNodes.insert( make_pair( srcN, tgtN )); + } + else + { + const bool skipMedium = true, isFwd = true; + StdMeshers_FaceSide srcEdge( srcFace, srcWire->Edge(iE), srcMesh, isFwd, skipMedium); + StdMeshers_FaceSide tgtEdge( tgtFace, tgtWire->Edge(iE), tgtMesh, isFwd, skipMedium); + + vector< const SMDS_MeshNode* > srcNodes = srcEdge.GetOrderedNodes(); + vector< const SMDS_MeshNode* > tgtNodes = tgtEdge.GetOrderedNodes(); + + if (( srcNodes.size() != tgtNodes.size() ) && tgtNodes.size() > 0 ) + return SMESH_ComputeError::New( COMPERR_BAD_INPUT_MESH, + "Different number of nodes on edges"); + if ( !tgtNodes.empty() ) + { + vector< const SMDS_MeshNode* >::iterator tn = tgtNodes.begin(); + //if ( srcWire->Edge(iE).Orientation() == tgtWire->Edge(iE).Orientation() ) + { + vector< const SMDS_MeshNode* >::iterator sn = srcNodes.begin(); + for ( ; tn != tgtNodes.end(); ++tn, ++sn) + src2tgtNodes.insert( make_pair( *sn, *tn )); + } + // else + // { + // vector< const SMDS_MeshNode* >::reverse_iterator sn = srcNodes.rbegin(); + // for ( ; tn != tgtNodes.end(); ++tn, ++sn) + // src2tgtNodes.insert( make_pair( *sn, *tn )); + // } + is1DComputed = true; + } + } + } // loop on EDGEs of a WIRE + + } // loop on WIREs + + return TError(); + } + + //================================================================================ + /*! + * \brief Preform projection in case if tgtFace.IsPartner( srcFace ) and in case + * if projection by 3D transformation is possible + */ + //================================================================================ + + bool projectPartner(const TopoDS_Face& tgtFace, + const TopoDS_Face& srcFace, + const TSideVector& tgtWires, + const TSideVector& srcWires, + const TAssocTool::TShapeShapeMap& shape2ShapeMap, + TAssocTool::TNodeNodeMap& src2tgtNodes, + const bool is1DComputed) + { + SMESH_Mesh * tgtMesh = tgtWires[0]->GetMesh(); + SMESH_Mesh * srcMesh = srcWires[0]->GetMesh(); + SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS(); + SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS(); + SMESH_MesherHelper helper( *tgtMesh ); + + const double tol = 1.e-7 * srcMeshDS->getMaxDim(); + + // transformation to get location of target nodes from source ones + StdMeshers_ProjectionUtils::TrsfFinder3D trsf; + bool trsfIsOK = false; + if ( tgtFace.IsPartner( srcFace )) + { + gp_GTrsf srcTrsf = srcFace.Location().Transformation(); + gp_GTrsf tgtTrsf = tgtFace.Location().Transformation(); + gp_GTrsf t = srcTrsf.Inverted().Multiplied( tgtTrsf ); + trsf.Set( t ); + // check + gp_Pnt srcP = BRep_Tool::Pnt( srcWires[0]->FirstVertex() ); + gp_Pnt tgtP = BRep_Tool::Pnt( tgtWires[0]->FirstVertex() ); + trsfIsOK = ( tgtP.Distance( trsf.Transform( srcP )) < tol ); + if ( !trsfIsOK ) + { + trsf.Set( tgtTrsf.Inverted().Multiplied( srcTrsf )); + trsfIsOK = ( tgtP.Distance( trsf.Transform( srcP )) < tol ); + } + } + if ( !trsfIsOK ) + { + // Try to find the 3D transformation + + const int totNbSeg = 50; + vector< gp_XYZ > srcPnts, tgtPnts; + srcPnts.reserve( totNbSeg ); + tgtPnts.reserve( totNbSeg ); + gp_XYZ srcBC( 0,0,0 ), tgtBC( 0,0,0 ); + for ( size_t iW = 0; iW < srcWires.size(); ++iW ) + { + const double minSegLen = srcWires[iW]->Length() / totNbSeg; + for ( int iE = 0; iE < srcWires[iW]->NbEdges(); ++iE ) + { + int nbSeg = Max( 1, int( srcWires[iW]->EdgeLength( iE ) / minSegLen )); + double srcU = srcWires[iW]->FirstParameter( iE ); + double tgtU = tgtWires[iW]->FirstParameter( iE ); + double srcDu = ( srcWires[iW]->LastParameter( iE )- srcU ) / nbSeg; + double tgtDu = ( tgtWires[iW]->LastParameter( iE )- tgtU ) / nbSeg; + for ( size_t i = 0; i < nbSeg; ++i ) + { + srcPnts.push_back( srcWires[iW]->Value3d( srcU ).XYZ() ); + tgtPnts.push_back( tgtWires[iW]->Value3d( tgtU ).XYZ() ); + srcU += srcDu; + tgtU += tgtDu; + srcBC += srcPnts.back(); + tgtBC += tgtPnts.back(); + } + } + } + if ( !trsf.Solve( srcPnts, tgtPnts )) + return false; + + // check trsf + + const int nbTestPnt = 20; + const size_t iStep = Max( 1, int( srcPnts.size() / nbTestPnt )); + // check boundary + gp_Pnt trsfTgt = trsf.Transform( srcBC / srcPnts.size() ); + trsfIsOK = ( trsfTgt.SquareDistance( tgtBC / tgtPnts.size() ) < tol*tol ); + for ( size_t i = 0; ( i < srcPnts.size() && trsfIsOK ); i += iStep ) + { + gp_Pnt trsfTgt = trsf.Transform( srcPnts[i] ); + trsfIsOK = ( trsfTgt.SquareDistance( tgtPnts[i] ) < tol*tol ); + } + // check an in-FACE point + if ( trsfIsOK ) + { + BRepAdaptor_Surface srcSurf( srcFace ); + gp_Pnt srcP = + srcSurf.Value( 0.321 * ( srcSurf.FirstUParameter() + srcSurf.LastUParameter() ), + 0.123 * ( srcSurf.FirstVParameter() + srcSurf.LastVParameter() )); + gp_Pnt tgtTrsfP = trsf.Transform( srcP ); + TopLoc_Location loc; + GeomAPI_ProjectPointOnSurf& proj = helper.GetProjector( tgtFace, loc, 0.1*tol ); + if ( !loc.IsIdentity() ) + tgtTrsfP.Transform( loc.Transformation().Inverted() ); + proj.Perform( tgtTrsfP ); + trsfIsOK = ( proj.IsDone() && + proj.NbPoints() > 0 && + proj.LowerDistance() < tol ); + } + if ( !trsfIsOK ) + return false; + } + + // Make new faces + + // prepare the helper to adding quadratic elements if necessary + //helper.SetSubShape( tgtFace ); + helper.IsQuadraticSubMesh( tgtFace ); + + SMESHDS_SubMesh* srcSubDS = srcMeshDS->MeshElements( srcFace ); + if ( !is1DComputed && srcSubDS->NbElements() ) + helper.SetIsQuadratic( srcSubDS->GetElements()->next()->IsQuadratic() ); + + SMESH_MesherHelper srcHelper( *srcMesh ); + srcHelper.SetSubShape( srcFace ); + + const SMDS_MeshNode* nullNode = 0; + TAssocTool::TNodeNodeMap::iterator srcN_tgtN; + + // indices of nodes to create properly oriented faces + bool isReverse = ( !trsf.IsIdentity() ); + int tri1 = 1, tri2 = 2, quad1 = 1, quad3 = 3; + if ( isReverse ) + std::swap( tri1, tri2 ), std::swap( quad1, quad3 ); + + SMDS_ElemIteratorPtr elemIt = srcSubDS->GetElements(); + vector< const SMDS_MeshNode* > tgtNodes; + while ( elemIt->more() ) // loop on all mesh faces on srcFace + { + const SMDS_MeshElement* elem = elemIt->next(); + const int nbN = elem->NbCornerNodes(); + tgtNodes.resize( nbN ); + helper.SetElementsOnShape( false ); + for ( int i = 0; i < nbN; ++i ) // loop on nodes of the source element + { + const SMDS_MeshNode* srcNode = elem->GetNode(i); + srcN_tgtN = src2tgtNodes.insert( make_pair( srcNode, nullNode )).first; + if ( srcN_tgtN->second == nullNode ) + { + // create a new node + gp_Pnt tgtP = trsf.Transform( SMESH_TNodeXYZ( srcNode )); + SMDS_MeshNode* n = helper.AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() ); + srcN_tgtN->second = n; + switch ( srcNode->GetPosition()->GetTypeOfPosition() ) + { + case SMDS_TOP_FACE: + { + gp_Pnt2d srcUV = srcHelper.GetNodeUV( srcFace, srcNode ); + tgtMeshDS->SetNodeOnFace( n, helper.GetSubShapeID(), srcUV.X(), srcUV.Y() ); + break; + } + case SMDS_TOP_EDGE: + { + const TopoDS_Shape & srcE = srcMeshDS->IndexToShape( srcNode->getshapeId() ); + const TopoDS_Shape & tgtE = shape2ShapeMap( srcE, /*isSrc=*/true ); + double srcU = srcHelper.GetNodeU( TopoDS::Edge( srcE ), srcNode ); + tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtE ), srcU ); + break; + } + case SMDS_TOP_VERTEX: + { + const TopoDS_Shape & srcV = srcMeshDS->IndexToShape( srcNode->getshapeId() ); + const TopoDS_Shape & tgtV = shape2ShapeMap( srcV, /*isSrc=*/true ); + tgtMeshDS->SetNodeOnVertex( n, TopoDS::Vertex( tgtV )); + break; + } + default:; + } + } + tgtNodes[i] = srcN_tgtN->second; + } + // create a new face + helper.SetElementsOnShape( true ); + switch ( nbN ) + { + case 3: helper.AddFace(tgtNodes[0], tgtNodes[tri1], tgtNodes[tri2]); break; + case 4: helper.AddFace(tgtNodes[0], tgtNodes[quad1], tgtNodes[2], tgtNodes[quad3]); break; + default: + if ( isReverse ) std::reverse( tgtNodes.begin(), tgtNodes.end() ); + helper.AddPolygonalFace( tgtNodes ); + } + } + + // check node positions + + if ( !tgtFace.IsPartner( srcFace ) ) + { + SMESH_MesherHelper edgeHelper( *tgtMesh ); + edgeHelper.ToFixNodeParameters( true ); + helper.ToFixNodeParameters( true ); + + int nbOkPos = 0; + bool toCheck = true; + const double tol2d = 1e-12; + srcN_tgtN = src2tgtNodes.begin(); + for ( ; srcN_tgtN != src2tgtNodes.end(); ++srcN_tgtN ) + { + const SMDS_MeshNode* n = srcN_tgtN->second; + switch ( n->GetPosition()->GetTypeOfPosition() ) + { + case SMDS_TOP_FACE: + { + if ( nbOkPos > 10 ) break; + gp_XY uv = helper.GetNodeUV( tgtFace, n ), uvBis = uv; + if (( helper.CheckNodeUV( tgtFace, n, uv, tol )) && + (( uv - uvBis ).SquareModulus() < tol2d )) + ++nbOkPos; + else + nbOkPos = -((int) src2tgtNodes.size() ); + break; + } + case SMDS_TOP_EDGE: + { + const TopoDS_Edge & tgtE = TopoDS::Edge( tgtMeshDS->IndexToShape( n->getshapeId() )); + edgeHelper.SetSubShape( tgtE ); + edgeHelper.GetNodeU( tgtE, n, 0, &toCheck ); + break; + } + default:; + } + } + } + + return true; + + } // bool projectPartner() + + //================================================================================ + /*! + * \brief Preform projection in case if the faces are similar in 2D space + */ + //================================================================================ + + bool projectBy2DSimilarity(const TopoDS_Face& tgtFace, + const TopoDS_Face& srcFace, + const TSideVector& tgtWires, + const TSideVector& srcWires, + const TAssocTool::TShapeShapeMap& shape2ShapeMap, + TAssocTool::TNodeNodeMap& src2tgtNodes, + const bool is1DComputed) + { + SMESH_Mesh * tgtMesh = tgtWires[0]->GetMesh(); + SMESH_Mesh * srcMesh = srcWires[0]->GetMesh(); + + // WARNING: we can have problems if the FACE is symmetrical in 2D, + // then the projection can be mirrored relating to what is expected + + // 1) Find 2D transformation + + StdMeshers_ProjectionUtils::TrsfFinder2D trsf; + { + // get 2 pairs of corresponding UVs + gp_Pnt2d srcP0 = srcWires[0]->Value2d(0.0); + gp_Pnt2d srcP1 = srcWires[0]->Value2d(0.333); + gp_Pnt2d tgtP0 = tgtWires[0]->Value2d(0.0); + gp_Pnt2d tgtP1 = tgtWires[0]->Value2d(0.333); + + // make transformation + gp_Trsf2d fromTgtCS, toSrcCS; // from/to global CS + gp_Ax2d srcCS( srcP0, gp_Vec2d( srcP0, srcP1 )); + gp_Ax2d tgtCS( tgtP0, gp_Vec2d( tgtP0, tgtP1 )); + toSrcCS .SetTransformation( srcCS ); + fromTgtCS.SetTransformation( tgtCS ); + fromTgtCS.Invert(); + trsf.Set( fromTgtCS * toSrcCS ); + + // check transformation + bool trsfIsOK = true; + const double tol = 1e-5 * gp_Vec2d( srcP0, srcP1 ).Magnitude(); + for ( double u = 0.12; ( u < 1. && trsfIsOK ); u += 0.1 ) + { + gp_Pnt2d srcUV = srcWires[0]->Value2d( u ); + gp_Pnt2d tgtUV = tgtWires[0]->Value2d( u ); + gp_Pnt2d tgtUV2 = trsf.Transform( srcUV ); + trsfIsOK = ( tgtUV.Distance( tgtUV2 ) < tol ); + } + + // Find trsf using a least-square approximation + if ( !trsfIsOK ) + { + // find trsf + const int totNbSeg = 50; + vector< gp_XY > srcPnts, tgtPnts; + srcPnts.resize( totNbSeg ); + tgtPnts.resize( totNbSeg ); + for ( size_t iW = 0; iW < srcWires.size(); ++iW ) + { + const double minSegLen = srcWires[iW]->Length() / totNbSeg; + for ( int iE = 0; iE < srcWires[iW]->NbEdges(); ++iE ) + { + int nbSeg = Max( 1, int( srcWires[iW]->EdgeLength( iE ) / minSegLen )); + double srcU = srcWires[iW]->FirstParameter( iE ); + double tgtU = tgtWires[iW]->FirstParameter( iE ); + double srcDu = ( srcWires[iW]->LastParameter( iE )- srcU ) / nbSeg; + double tgtDu = ( tgtWires[iW]->LastParameter( iE )- tgtU ) / nbSeg; + for ( size_t i = 0; i < nbSeg; ++i, srcU += srcDu, tgtU += tgtDu ) + { + srcPnts.push_back( srcWires[iW]->Value2d( srcU ).XY() ); + tgtPnts.push_back( tgtWires[iW]->Value2d( tgtU ).XY() ); + } + } + } + if ( !trsf.Solve( srcPnts, tgtPnts )) + return false; + + // check trsf + + trsfIsOK = true; + const int nbTestPnt = 10; + const size_t iStep = Max( 1, int( srcPnts.size() / nbTestPnt )); + for ( size_t i = 0; ( i < srcPnts.size() && trsfIsOK ); i += iStep ) + { + gp_Pnt2d trsfTgt = trsf.Transform( srcPnts[i] ); + trsfIsOK = ( trsfTgt.Distance( tgtPnts[i] ) < tol ); + } + if ( !trsfIsOK ) + return false; + } + } // "Find transformation" block + + // 2) Projection + + SMESHDS_SubMesh* srcSubDS = srcMesh->GetMeshDS()->MeshElements( srcFace ); + + SMESH_MesherHelper helper( *tgtMesh ); + helper.SetSubShape( tgtFace ); + if ( is1DComputed ) + helper.IsQuadraticSubMesh( tgtFace ); + else + helper.SetIsQuadratic( srcSubDS->GetElements()->next()->IsQuadratic() ); + helper.SetElementsOnShape( true ); + Handle(Geom_Surface) tgtSurface = BRep_Tool::Surface( tgtFace ); + SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS(); + + SMESH_MesherHelper srcHelper( *srcMesh ); + srcHelper.SetSubShape( srcFace ); + + const SMDS_MeshNode* nullNode = 0; + TAssocTool::TNodeNodeMap::iterator srcN_tgtN; + + SMDS_ElemIteratorPtr elemIt = srcSubDS->GetElements(); + vector< const SMDS_MeshNode* > tgtNodes; + bool uvOK; + while ( elemIt->more() ) // loop on all mesh faces on srcFace + { + const SMDS_MeshElement* elem = elemIt->next(); + const int nbN = elem->NbCornerNodes(); + tgtNodes.resize( nbN ); + for ( int i = 0; i < nbN; ++i ) // loop on nodes of the source element + { + const SMDS_MeshNode* srcNode = elem->GetNode(i); + srcN_tgtN = src2tgtNodes.insert( make_pair( srcNode, nullNode )).first; + if ( srcN_tgtN->second == nullNode ) + { + // create a new node + gp_Pnt2d srcUV = srcHelper.GetNodeUV( srcFace, srcNode, + elem->GetNode( helper.WrapIndex(i+1,nbN)), &uvOK); + gp_Pnt2d tgtUV = trsf.Transform( srcUV ); + gp_Pnt tgtP = tgtSurface->Value( tgtUV.X(), tgtUV.Y() ); + SMDS_MeshNode* n = tgtMeshDS->AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() ); + switch ( srcNode->GetPosition()->GetTypeOfPosition() ) + { + case SMDS_TOP_FACE: { + tgtMeshDS->SetNodeOnFace( n, helper.GetSubShapeID(), tgtUV.X(), tgtUV.Y() ); + break; + } + case SMDS_TOP_EDGE: { + TopoDS_Shape srcEdge = srcHelper.GetSubShapeByNode( srcNode, srcHelper.GetMeshDS() ); + TopoDS_Edge tgtEdge = TopoDS::Edge( shape2ShapeMap( srcEdge, /*isSrc=*/true )); + double U = Precision::Infinite(); + helper.CheckNodeU( tgtEdge, n, U, Precision::PConfusion()); + tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtEdge ), U ); + break; + } + case SMDS_TOP_VERTEX: { + TopoDS_Shape srcV = srcHelper.GetSubShapeByNode( srcNode, srcHelper.GetMeshDS() ); + TopoDS_Shape tgtV = shape2ShapeMap( srcV, /*isSrc=*/true ); + tgtMeshDS->SetNodeOnVertex( n, TopoDS::Vertex( tgtV )); + break; + } + } + srcN_tgtN->second = n; + } + tgtNodes[i] = srcN_tgtN->second; + } + // create a new face (with reversed orientation) + switch ( nbN ) + { + case 3: helper.AddFace(tgtNodes[0], tgtNodes[2], tgtNodes[1]); break; + case 4: helper.AddFace(tgtNodes[0], tgtNodes[3], tgtNodes[2], tgtNodes[1]); break; + } + } // loop on all mesh faces on srcFace + + return true; + } + + //================================================================================ + /*! + * \brief Preform projection in case of quadrilateral faces + */ + //================================================================================ + + bool projectQuads(const TopoDS_Face& tgtFace, + const TopoDS_Face& srcFace, + const TSideVector& tgtWires, + const TSideVector& srcWires, + const TAssocTool::TShapeShapeMap& shape2ShapeMap, + TAssocTool::TNodeNodeMap& src2tgtNodes, + const bool is1DComputed) + { + SMESH_Mesh * tgtMesh = tgtWires[0]->GetMesh(); + SMESH_Mesh * srcMesh = srcWires[0]->GetMesh(); + SMESHDS_Mesh * tgtMeshDS = tgtMesh->GetMeshDS(); + SMESHDS_Mesh * srcMeshDS = srcMesh->GetMeshDS(); + + if ( srcWires[0]->NbEdges() != 4 ) + return false; + if ( !is1DComputed ) + return false; + for ( int iE = 0; iE < 4; ++iE ) + { + SMESHDS_SubMesh* sm = srcMeshDS->MeshElements( srcWires[0]->Edge( iE )); + if ( !sm ) return false; + if ( sm->NbNodes() + sm->NbElements() == 0 ) return false; + } + if ( BRepAdaptor_Surface( tgtFace ).GetType() != GeomAbs_Plane ) + return false; + // if ( BRepAdaptor_Surface( tgtFace ).GetType() == GeomAbs_Plane && + // BRepAdaptor_Surface( srcFace ).GetType() == GeomAbs_Plane ) + // return false; // too easy + + // load EDGEs to SMESH_Block + + SMESH_Block block; + TopTools_IndexedMapOfOrientedShape blockSubShapes; + { + const TopoDS_Solid& box = srcMesh->PseudoShape(); + TopoDS_Shell shell = TopoDS::Shell( TopExp_Explorer( box, TopAbs_SHELL ).Current() ); + TopoDS_Vertex v; + block.LoadBlockShapes( shell, v, v, blockSubShapes ); // fill all since operator[] is missing + } + const SMESH_Block::TShapeID srcFaceBID = SMESH_Block::ID_Fxy0; + const SMESH_Block::TShapeID tgtFaceBID = SMESH_Block::ID_Fxy1; + vector< int > edgeBID; + block.GetFaceEdgesIDs( srcFaceBID, edgeBID ); // u0, u1, 0v, 1v + blockSubShapes.Substitute( edgeBID[0], srcWires[0]->Edge(0) ); + blockSubShapes.Substitute( edgeBID[1], srcWires[0]->Edge(2) ); + blockSubShapes.Substitute( edgeBID[2], srcWires[0]->Edge(3) ); + blockSubShapes.Substitute( edgeBID[3], srcWires[0]->Edge(1) ); + block.GetFaceEdgesIDs( tgtFaceBID, edgeBID ); // u0, u1, 0v, 1v + blockSubShapes.Substitute( edgeBID[0], tgtWires[0]->Edge(0) ); + blockSubShapes.Substitute( edgeBID[1], tgtWires[0]->Edge(2) ); + blockSubShapes.Substitute( edgeBID[2], tgtWires[0]->Edge(3) ); + blockSubShapes.Substitute( edgeBID[3], tgtWires[0]->Edge(1) ); + block.LoadFace( srcFace, srcFaceBID, blockSubShapes ); + block.LoadFace( tgtFace, tgtFaceBID, blockSubShapes ); + + // remember connectivity of new faces in terms of ( node-or-XY ) + + typedef std::pair< const SMDS_MeshNode*, gp_XYZ > TNodeOrXY; // node-or-XY + typedef std::vector< TNodeOrXY* > TFaceConn; // face connectivity + std::vector< TFaceConn > newFacesVec; // connectivity of all faces + std::map< const SMDS_MeshNode*, TNodeOrXY > srcNode2tgtNXY; // src node -> node-or-XY + + TAssocTool::TNodeNodeMap::iterator srcN_tgtN; + std::map< const SMDS_MeshNode*, TNodeOrXY >::iterator srcN_tgtNXY; + std::pair< std::map< const SMDS_MeshNode*, TNodeOrXY >::iterator, bool > n2n_isNew; + TNodeOrXY nullNXY( (SMDS_MeshNode*)NULL, gp_XYZ(0,0,0) ); + + SMESHDS_SubMesh* srcSubDS = srcMeshDS->MeshElements( srcFace ); + newFacesVec.resize( srcSubDS->NbElements() ); + int iFaceSrc = 0; + + SMDS_ElemIteratorPtr elemIt = srcSubDS->GetElements(); + while ( elemIt->more() ) // loop on all mesh faces on srcFace + { + const SMDS_MeshElement* elem = elemIt->next(); + TFaceConn& tgtNodes = newFacesVec[ iFaceSrc++ ]; + + const int nbN = elem->NbCornerNodes(); + tgtNodes.resize( nbN ); + for ( int i = 0; i < nbN; ++i ) // loop on nodes of the source element + { + const SMDS_MeshNode* srcNode = elem->GetNode(i); + n2n_isNew = srcNode2tgtNXY.insert( make_pair( srcNode, nullNXY )); + TNodeOrXY & tgtNodeOrXY = n2n_isNew.first->second; + if ( n2n_isNew.second ) // new src node encounters + { + srcN_tgtN = src2tgtNodes.find( srcNode ); + if ( srcN_tgtN != src2tgtNodes.end() ) + { + tgtNodeOrXY.first = srcN_tgtN->second; // tgt node exists + } + else + { + // find XY of src node withing the quadrilateral srcFace + if ( !block.ComputeParameters( SMESH_TNodeXYZ( srcNode ), + tgtNodeOrXY.second, srcFaceBID )) + return false; + } + } + tgtNodes[ i ] = & tgtNodeOrXY; + } + } + + // as all XY are computed, create tgt nodes and faces + + SMESH_MesherHelper helper( *tgtMesh ); + helper.SetSubShape( tgtFace ); + if ( is1DComputed ) + helper.IsQuadraticSubMesh( tgtFace ); + else + helper.SetIsQuadratic( srcSubDS->GetElements()->next()->IsQuadratic() ); + helper.SetElementsOnShape( true ); + Handle(Geom_Surface) tgtSurface = BRep_Tool::Surface( tgtFace ); + + SMESH_MesherHelper srcHelper( *srcMesh ); + srcHelper.SetSubShape( srcFace ); + + vector< const SMDS_MeshNode* > tgtNodes; + gp_XY uv; + + for ( size_t iFaceTgt = 0; iFaceTgt < newFacesVec.size(); ++iFaceTgt ) + { + TFaceConn& tgtConn = newFacesVec[ iFaceTgt ]; + tgtNodes.resize( tgtConn.size() ); + for ( size_t iN = 0; iN < tgtConn.size(); ++iN ) + { + const SMDS_MeshNode* & tgtN = tgtConn[ iN ]->first; + if ( !tgtN ) // create a node + { + if ( !block.FaceUV( tgtFaceBID, tgtConn[iN]->second, uv )) + return false; + gp_Pnt p = tgtSurface->Value( uv.X(), uv.Y() ); + tgtN = helper.AddNode( p.X(), p.Y(), p.Z(), uv.X(), uv.Y() ); + } + tgtNodes[ tgtNodes.size() - iN - 1] = tgtN; // reversed orientation + } + switch ( tgtNodes.size() ) + { + case 3: helper.AddFace(tgtNodes[0], tgtNodes[1], tgtNodes[2]); break; + case 4: helper.AddFace(tgtNodes[0], tgtNodes[1], tgtNodes[2], tgtNodes[3]); break; + default: + if ( tgtNodes.size() > 4 ) + helper.AddPolygonalFace( tgtNodes ); + } + } + return true; + + } // bool projectQuads(...) + + //================================================================================ + /*! + * \brief Fix bad faces by smoothing + */ + //================================================================================ + + bool fixDistortedFaces( SMESH_MesherHelper& helper, + TSideVector& tgtWires ) + { + SMESH_subMesh* faceSM = helper.GetMesh()->GetSubMesh( helper.GetSubShape() ); + + if ( helper.IsDistorted2D( faceSM, /*checkUV=*/false )) + { + SMESH_MeshEditor editor( helper.GetMesh() ); + SMESHDS_SubMesh* smDS = faceSM->GetSubMeshDS(); + const TopoDS_Face& F = TopoDS::Face( faceSM->GetSubShape() ); + + TIDSortedElemSet faces; + SMDS_ElemIteratorPtr faceIt = smDS->GetElements(); + for ( faceIt = smDS->GetElements(); faceIt->more(); ) + faces.insert( faces.end(), faceIt->next() ); + + // choose smoothing algo + //SMESH_MeshEditor:: SmoothMethod algo = SMESH_MeshEditor::CENTROIDAL; + bool isConcaveBoundary = false; + for ( size_t iW = 0; iW < tgtWires.size() && !isConcaveBoundary; ++iW ) + { + TopoDS_Edge prevEdge = tgtWires[iW]->Edge( tgtWires[iW]->NbEdges() - 1 ); + for ( int iE = 0; iE < tgtWires[iW]->NbEdges() && !isConcaveBoundary; ++iE ) + { + double angle = helper.GetAngle( prevEdge, tgtWires[iW]->Edge( iE ), + F, tgtWires[iW]->FirstVertex( iE )); + isConcaveBoundary = ( angle < -5. * M_PI / 180. ); + + prevEdge = tgtWires[iW]->Edge( iE ); + } + } + SMESH_MeshEditor:: SmoothMethod algo = + isConcaveBoundary ? SMESH_MeshEditor::CENTROIDAL : SMESH_MeshEditor::LAPLACIAN; + + // smooth in 2D or 3D? + TopLoc_Location loc; + Handle(Geom_Surface) surface = BRep_Tool::Surface( F, loc ); + bool isPlanar = GeomLib_IsPlanarSurface( surface ).IsPlanar(); + + // smoothing + set fixedNodes; + editor.Smooth( faces, fixedNodes, algo, /*nbIterations=*/ 10, + /*theTgtAspectRatio=*/1.0, /*the2D=*/!isPlanar); + + helper.ToFixNodeParameters( true ); + + return !helper.IsDistorted2D( faceSM, /*checkUV=*/true ); + } + return true; + } + } // namespace + //======================================================================= //function : Compute -//purpose : +//purpose : //======================================================================= bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape) { + _src2tgtNodes.clear(); + + MESSAGE("Projection_2D Compute"); if ( !_sourceHypo ) return false; @@ -372,23 +1170,51 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& srcMesh = tgtMesh; SMESHDS_Mesh * meshDS = theMesh.GetMeshDS(); + SMESH_MesherHelper helper( theMesh ); // --------------------------- - // Make subshapes association + // Make sub-shapes association // --------------------------- - TopoDS_Face tgtFace = TopoDS::Face( theShape.Oriented(TopAbs_FORWARD)); + TopoDS_Face tgtFace = TopoDS::Face( theShape.Oriented(TopAbs_FORWARD)); TopoDS_Shape srcShape = _sourceHypo->GetSourceFace().Oriented(TopAbs_FORWARD); TAssocTool::TShapeShapeMap shape2ShapeMap; - TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap, tgtFace ); + TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap ); if ( !TAssocTool::FindSubShapeAssociation( tgtFace, tgtMesh, srcShape, srcMesh, shape2ShapeMap) || !shape2ShapeMap.IsBound( tgtFace )) + { + if ( srcShape.ShapeType() == TopAbs_FACE ) + { + int nbE1 = helper.Count( tgtFace, TopAbs_EDGE, /*ignoreSame=*/true ); + int nbE2 = helper.Count( srcShape, TopAbs_EDGE, /*ignoreSame=*/true ); + if ( nbE1 != nbE2 ) + return error(COMPERR_BAD_SHAPE, + SMESH_Comment("Different number of edges in source and target faces: ") + << nbE2 << " and " << nbE1 ); + } return error(COMPERR_BAD_SHAPE,"Topology of source and target faces seems different" ); - + } TopoDS_Face srcFace = TopoDS::Face( shape2ShapeMap( tgtFace ).Oriented(TopAbs_FORWARD)); + // orient faces + // if ( srcMesh == tgtMesh ) + // { + // TopoDS_Shape solid = + // helper.GetCommonAncestor( srcFace, tgtFace, *tgtMesh, TopAbs_SOLID ); + // if ( !solid.IsNull() ) + // { + // srcFace.Orientation( helper.GetSubShapeOri( solid, srcFace )); + // tgtFace.Orientation( helper.GetSubShapeOri( solid, tgtFace )); + // } + // else if ( helper.NbAncestors( srcFace, *tgtMesh, TopAbs_SOLID ) == 1 && + // helper.NbAncestors( tgtFace, *tgtMesh, TopAbs_SOLID ) == 1 ) + // { + // srcFace.Orientation( helper.GetSubShapeOri( tgtMesh->GetShapeToMesh(), srcFace )); + // tgtFace.Orientation( helper.GetSubShapeOri( tgtMesh->GetShapeToMesh(), tgtFace )); + // } + // } // ---------------------------------------------- // Assure that mesh on a source Face is computed // ---------------------------------------------- @@ -396,208 +1222,407 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( srcFace ); SMESH_subMesh* tgtSubMesh = tgtMesh->GetSubMesh( tgtFace ); + string srcMeshError; if ( tgtMesh == srcMesh ) { if ( !TAssocTool::MakeComputed( srcSubMesh )) - return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed"); + srcMeshError = TAssocTool::SourceNotComputedError( srcSubMesh, this ); } else { if ( !srcSubMesh->IsMeshComputed() ) - return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed"); + srcMeshError = TAssocTool::SourceNotComputedError(); } + if ( !srcMeshError.empty() ) + return error(COMPERR_BAD_INPUT_MESH, srcMeshError ); - // -------------------- - // Prepare to mapping - // -------------------- + // =========== + // Projection + // =========== - SMESH_MesherHelper helper( theMesh ); - helper.SetSubShape( tgtFace ); + // get ordered src and tgt EDGEs + TSideVector srcWires, tgtWires; + bool is1DComputed = false; // if any tgt EDGE is meshed + TError err = getWires( tgtFace, srcFace, tgtMesh, srcMesh, + shape2ShapeMap, srcWires, tgtWires, _src2tgtNodes, is1DComputed ); + if ( err && !err->IsOK() ) + return error( err ); - // Check if node projection to a face is needed - Bnd_B2d uvBox; - SMDS_ElemIteratorPtr faceIt = srcSubMesh->GetSubMeshDS()->GetElements(); - int nbFaceNodes = 0; - for ( ; nbFaceNodes < 3 && faceIt->more(); ) { - const SMDS_MeshElement* face = faceIt->next(); - SMDS_ElemIteratorPtr nodeIt = face->nodesIterator(); - while ( nodeIt->more() ) { - const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) { - nbFaceNodes++; - uvBox.Add( helper.GetNodeUV( srcFace, node )); - } - } - } - const bool toProjectNodes = - ( nbFaceNodes > 0 && ( uvBox.IsVoid() || uvBox.SquareExtent() < DBL_MIN )); - - // Load pattern from the source face - SMESH_Pattern mapper; - mapper.Load( srcMesh, srcFace, toProjectNodes ); - if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) - return error(COMPERR_BAD_INPUT_MESH,"Can't load mesh pattern from the source face"); - - // Find the first target vertex corresponding to first vertex of the - // and flag needed to call mapper.Apply() - - TopoDS_Vertex srcV1 = TopoDS::Vertex( mapper.GetSubShape( 1 )); - if ( srcV1.IsNull() ) - RETURN_BAD_RESULT("Mesh is not bound to the face"); - if ( !shape2ShapeMap.IsBound( srcV1 )) - RETURN_BAD_RESULT("Not associated vertices, srcV1 " << srcV1.TShape().operator->() ); - TopoDS_Vertex tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1 )); - - if ( !TAssocTool::IsSubShape( srcV1, srcFace )) - RETURN_BAD_RESULT("Wrong srcV1 " << srcV1.TShape().operator->()); - if ( !TAssocTool::IsSubShape( tgtV1, tgtFace )) - RETURN_BAD_RESULT("Wrong tgtV1 " << tgtV1.TShape().operator->()); - - // try to find out orientation by order of edges - bool reverse = false; - list< TopoDS_Edge > tgtEdges, srcEdges; - list< int > nbEdgesInWires; - SMESH_Block::GetOrderedEdges( tgtFace, tgtV1, tgtEdges, nbEdgesInWires); - SMESH_Block::GetOrderedEdges( srcFace, srcV1, srcEdges, nbEdgesInWires); - if ( nbEdgesInWires.front() > 1 ) // possible to find out + bool projDone = false; + + if ( !projDone ) { - TopoDS_Edge srcE1 = srcEdges.front(), tgtE1 = tgtEdges.front(); - TopoDS_Shape srcE1bis = shape2ShapeMap( tgtE1 ); - reverse = ( ! srcE1.IsSame( srcE1bis )); + // try to project from the same face with different location + projDone = projectPartner( tgtFace, srcFace, tgtWires, srcWires, + shape2ShapeMap, _src2tgtNodes, is1DComputed ); } - else if ( nbEdgesInWires.front() == 1 ) + if ( !projDone ) { - // TODO::Compare orientation of curves in a sole edge - //RETURN_BAD_RESULT("Not implemented case"); + // projection in case if the faces are similar in 2D space + projDone = projectBy2DSimilarity( tgtFace, srcFace, tgtWires, srcWires, + shape2ShapeMap, _src2tgtNodes, is1DComputed); } - else + if ( !projDone ) { - RETURN_BAD_RESULT("Bad result from SMESH_Block::GetOrderedEdges()"); + // projection in case of quadrilateral faces + // projDone = projectQuads( tgtFace, srcFace, tgtWires, srcWires, + // shape2ShapeMap, _src2tgtNodes, is1DComputed); } - // -------------------- - // Perform 2D mapping - // -------------------- + helper.SetSubShape( tgtFace ); - // Compute mesh on a target face + // it will remove mesh built on edges and vertices in failure case + MeshCleaner cleaner( tgtSubMesh ); - mapper.Apply( tgtFace, tgtV1, reverse ); - if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) - return error("Can't apply source mesh pattern to the face"); + if ( !projDone ) + { + _src2tgtNodes.clear(); + // -------------------- + // Prepare to mapping + // -------------------- + + // Check if node projection to a face is needed + Bnd_B2d uvBox; + SMDS_ElemIteratorPtr faceIt = srcSubMesh->GetSubMeshDS()->GetElements(); + set< const SMDS_MeshNode* > faceNodes; + for ( ; faceNodes.size() < 3 && faceIt->more(); ) { + const SMDS_MeshElement* face = faceIt->next(); + SMDS_ElemIteratorPtr nodeIt = face->nodesIterator(); + while ( nodeIt->more() ) { + const SMDS_MeshNode* node = static_cast( nodeIt->next() ); + if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE && + faceNodes.insert( node ).second ) + uvBox.Add( helper.GetNodeUV( srcFace, node )); + } + } + bool toProjectNodes = false; + if ( faceNodes.size() == 1 ) + toProjectNodes = ( uvBox.IsVoid() || uvBox.CornerMin().IsEqual( gp_XY(0,0), 1e-12 )); + else if ( faceNodes.size() > 1 ) + toProjectNodes = ( uvBox.IsVoid() || uvBox.SquareExtent() < DBL_MIN ); - // Create the mesh + // Find the corresponding source and target vertex + // and flag needed to call mapper.Apply() - const bool toCreatePolygons = false, toCreatePolyedrs = false; - mapper.MakeMesh( tgtMesh, toCreatePolygons, toCreatePolyedrs ); - if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) - return error("Can't make mesh by source mesh pattern"); + TopoDS_Vertex srcV1, tgtV1; + bool reverse = false; - // it will remove mesh built by pattern mapper on edges and vertices - // in failure case - MeshCleaner cleaner( tgtSubMesh ); + TopExp_Explorer vSrcExp( srcFace, TopAbs_VERTEX ); + srcV1 = TopoDS::Vertex( vSrcExp.Current() ); + tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1, /*isSrc=*/true )); - // ------------------------------------------------------------------------- - // mapper doesn't take care of nodes already existing on edges and vertices, - // so we must merge nodes created by it with existing ones - // ------------------------------------------------------------------------- + list< TopoDS_Edge > tgtEdges, srcEdges; + list< int > nbEdgesInWires; + SMESH_Block::GetOrderedEdges( tgtFace, tgtEdges, nbEdgesInWires, tgtV1 ); + SMESH_Block::GetOrderedEdges( srcFace, srcEdges, nbEdgesInWires, srcV1 ); - SMESH_MeshEditor editor( tgtMesh ); - SMESH_MeshEditor::TListOfListOfNodes groupsOfNodes; + if ( nbEdgesInWires.front() > 1 ) // possible to find out orientation + { + TopoDS_Edge srcE1 = srcEdges.front(), tgtE1 = tgtEdges.front(); + TopoDS_Shape srcE1bis = shape2ShapeMap( tgtE1 ); + reverse = ( ! srcE1.IsSame( srcE1bis )); + if ( reverse && + //_sourceHypo->HasVertexAssociation() && + nbEdgesInWires.front() > 2 && + helper.IsRealSeam( tgtEdges.front() )) + { + // projection to a face with seam EDGE; pb is that GetOrderedEdges() + // always puts a seam EDGE first (if possible) and as a result + // we can't use only theReverse flag to correctly associate source + // and target faces in the mapper. Thus we select srcV1 so that + // GetOrderedEdges() to return EDGEs in a needed order + TopoDS_Face tgtFaceBis = tgtFace; + TopTools_MapOfShape checkedVMap( tgtEdges.size() ); + checkedVMap.Add ( srcV1 ); + for ( vSrcExp.Next(); vSrcExp.More(); ) + { + tgtFaceBis.Reverse(); + tgtEdges.clear(); + SMESH_Block::GetOrderedEdges( tgtFaceBis, tgtEdges, nbEdgesInWires, tgtV1 ); + bool ok = true; + list< TopoDS_Edge >::iterator edgeS = srcEdges.begin(), edgeT = tgtEdges.begin(); + for ( ; edgeS != srcEdges.end() && ok ; ++edgeS, ++edgeT ) + ok = edgeT->IsSame( shape2ShapeMap( *edgeS, /*isSrc=*/true )); + if ( ok ) + break; // FOUND! + + reverse = !reverse; + if ( reverse ) + { + vSrcExp.Next(); + while ( vSrcExp.More() && !checkedVMap.Add( vSrcExp.Current() )) + vSrcExp.Next(); + } + else + { + srcV1 = TopoDS::Vertex( vSrcExp.Current() ); + tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1, /*isSrc=*/true )); + srcEdges.clear(); + SMESH_Block::GetOrderedEdges( srcFace, srcEdges, nbEdgesInWires, srcV1 ); + } + } + } + // for the case: project to a closed face from a non-closed face w/o vertex assoc; + // avoid projecting to a seam from two EDGEs with different nb nodes on them + // ( test mesh_Projection_2D_01/B1 ) + if ( !_sourceHypo->HasVertexAssociation() && + nbEdgesInWires.front() > 2 && + helper.IsRealSeam( tgtEdges.front() )) + { + TopoDS_Shape srcEdge1 = shape2ShapeMap( tgtEdges.front() ); + list< TopoDS_Edge >::iterator srcEdge2 = + std::find( srcEdges.begin(), srcEdges.end(), srcEdge1); + list< TopoDS_Edge >::iterator srcEdge3 = + std::find( srcEdges.begin(), srcEdges.end(), srcEdge1.Reversed()); + if ( srcEdge2 == srcEdges.end() || srcEdge3 == srcEdges.end() ) // srcEdge1 is not a seam + { + // find srcEdge2 which also will be projected to tgtEdges.front() + for ( srcEdge2 = srcEdges.begin(); srcEdge2 != srcEdges.end(); ++srcEdge2 ) + if ( !srcEdge1.IsSame( *srcEdge2 ) && + tgtEdges.front().IsSame( shape2ShapeMap( *srcEdge2, /*isSrc=*/true ))) + break; + // compare nb nodes on srcEdge1 and srcEdge2 + if ( srcEdge2 != srcEdges.end() ) + { + int nbN1 = 0, nbN2 = 0; + if ( SMESHDS_SubMesh* sm = srcMesh->GetMeshDS()->MeshElements( srcEdge1 )) + nbN1 = sm->NbNodes(); + if ( SMESHDS_SubMesh* sm = srcMesh->GetMeshDS()->MeshElements( *srcEdge2 )) + nbN2 = sm->NbNodes(); + if ( nbN1 != nbN2 ) + srcV1 = helper.IthVertex( 1, srcEdges.front() ); + } + } + } + } + else if ( nbEdgesInWires.front() == 1 ) + { + // TODO::Compare orientation of curves in a sole edge + //RETURN_BAD_RESULT("Not implemented case"); + } + else + { + RETURN_BAD_RESULT("Bad result from SMESH_Block::GetOrderedEdges()"); + } - // Make groups of nodes to merge + // Load pattern from the source face + SMESH_Pattern mapper; + mapper.Load( srcMesh, srcFace, toProjectNodes, srcV1 ); + if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) + return error(COMPERR_BAD_INPUT_MESH,"Can't load mesh pattern from the source face"); - // loop on edge and vertex submeshes of a target face - SMESH_subMeshIteratorPtr smIt = tgtSubMesh->getDependsOnIterator(false,false); - while ( smIt->more() ) - { - SMESH_subMesh* sm = smIt->next(); - SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); + // -------------------- + // Perform 2D mapping + // -------------------- + + // Compute mesh on a target face + + mapper.Apply( tgtFace, tgtV1, reverse ); + if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) { + // std::ofstream file("/tmp/Pattern.smp" ); + // mapper.Save( file ); + return error("Can't apply source mesh pattern to the face"); + } + + // Create the mesh - // Sort new and old nodes of a submesh separately + const bool toCreatePolygons = false, toCreatePolyedrs = false; + mapper.MakeMesh( tgtMesh, toCreatePolygons, toCreatePolyedrs ); + if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) + return error("Can't make mesh by source mesh pattern"); - bool isSeam = helper.IsRealSeam( sm->GetId() ); + // ------------------------------------------------------------------------- + // mapper doesn't take care of nodes already existing on edges and vertices, + // so we must merge nodes created by it with existing ones + // ------------------------------------------------------------------------- - enum { NEW_NODES = 0, OLD_NODES }; - map< double, const SMDS_MeshNode* > u2nodesMaps[2], u2nodesOnSeam; - map< double, const SMDS_MeshNode* >::iterator u_oldNode, u_newNode, u_newOnSeam, newEnd; - set< const SMDS_MeshNode* > seamNodes; + SMESH_MeshEditor::TListOfListOfNodes groupsOfNodes; - // mapper puts on a seam edge nodes from 2 edges - if ( isSeam && ! getBoundaryNodes ( sm, tgtFace, u2nodesOnSeam, seamNodes )) - RETURN_BAD_RESULT("getBoundaryNodes() failed"); + // Make groups of nodes to merge - SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); - while ( nIt->more() ) + // loop on EDGE and VERTEX sub-meshes of a target FACE + SMESH_subMeshIteratorPtr smIt = tgtSubMesh->getDependsOnIterator(/*includeSelf=*/false, + /*complexShapeFirst=*/false); + while ( smIt->more() ) { - const SMDS_MeshNode* node = nIt->next(); - bool isOld = isOldNode( node ); + SMESH_subMesh* sm = smIt->next(); + SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); + if ( !smDS || smDS->NbNodes() == 0 ) + continue; + //if ( !is1DComputed && sm->GetSubShape().ShapeType() == TopAbs_EDGE ) + // break; - if ( !isOld && isSeam ) { // new node on a seam edge - if ( seamNodes.find( node ) != seamNodes.end()) - continue; // node is already in the map + if ( helper.IsDegenShape( sm->GetId() ) ) // to merge all nodes on degenerated + { + if ( sm->GetSubShape().ShapeType() == TopAbs_EDGE ) + { + groupsOfNodes.push_back( list< const SMDS_MeshNode* >() ); + SMESH_subMeshIteratorPtr smDegenIt + = sm->getDependsOnIterator(/*includeSelf=*/true,/*complexShapeFirst=*/false); + while ( smDegenIt->more() ) + if (( smDS = smDegenIt->next()->GetSubMeshDS() )) + { + SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); + while ( nIt->more() ) + groupsOfNodes.back().push_back( nIt->next() ); + } + } + continue; // do not treat sm of degen VERTEX } - // sort nodes on edges by their position - map< double, const SMDS_MeshNode* > & pos2nodes = u2nodesMaps[isOld ? OLD_NODES : NEW_NODES]; - switch ( node->GetPosition()->GetTypeOfPosition() ) + // Sort new and old nodes of a submesh separately + + bool isSeam = helper.IsRealSeam( sm->GetId() ); + + enum { NEW_NODES = 0, OLD_NODES }; + map< double, const SMDS_MeshNode* > u2nodesMaps[2], u2nodesOnSeam; + map< double, const SMDS_MeshNode* >::iterator u_oldNode, u_newNode, u_newOnSeam, newEnd; + set< const SMDS_MeshNode* > seamNodes; + + // mapper changed, no more "mapper puts on a seam edge nodes from 2 edges" + if ( isSeam && ! getBoundaryNodes ( sm, tgtFace, u2nodesOnSeam, seamNodes )) + ;//RETURN_BAD_RESULT("getBoundaryNodes() failed"); + + SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); + while ( nIt->more() ) { - case SMDS_TOP_VERTEX: { - pos2nodes.insert( make_pair( 0, node )); - break; - } - case SMDS_TOP_EDGE: { - const SMDS_EdgePosition* pos = - static_cast(node->GetPosition().get()); - pos2nodes.insert( make_pair( pos->GetUParameter(), node )); - break; + const SMDS_MeshNode* node = nIt->next(); + bool isOld = isOldNode( node ); + + if ( !isOld && isSeam ) { // new node on a seam edge + if ( seamNodes.count( node ) ) + continue; // node is already in the map + } + + // sort nodes on edges by their position + map< double, const SMDS_MeshNode* > & pos2nodes = u2nodesMaps[isOld ? OLD_NODES : NEW_NODES]; + switch ( node->GetPosition()->GetTypeOfPosition() ) + { + case SMDS_TOP_VERTEX: { + if ( !is1DComputed && !pos2nodes.empty() ) + u2nodesMaps[isOld ? NEW_NODES : OLD_NODES].insert( make_pair( 0, node )); + else + pos2nodes.insert( make_pair( 0, node )); + break; + } + case SMDS_TOP_EDGE: { + const SMDS_EdgePosition* pos = + static_cast(node->GetPosition()); + pos2nodes.insert( make_pair( pos->GetUParameter(), node )); + break; + } + default: + RETURN_BAD_RESULT("Wrong node position type: "<< + node->GetPosition()->GetTypeOfPosition()); + } } - default: - RETURN_BAD_RESULT("Wrong node position type: "<< - node->GetPosition()->GetTypeOfPosition()); + const bool mergeNewToOld = + ( u2nodesMaps[ NEW_NODES ].size() == u2nodesMaps[ OLD_NODES ].size() ); + const bool mergeSeamToNew = + ( u2nodesMaps[ NEW_NODES ].size() == u2nodesOnSeam.size() ); + + if ( !mergeNewToOld ) + if ( u2nodesMaps[ NEW_NODES ].size() > 0 && + u2nodesMaps[ OLD_NODES ].size() > 0 ) + { + u_oldNode = u2nodesMaps[ OLD_NODES ].begin(); + newEnd = u2nodesMaps[ OLD_NODES ].end(); + for ( ; u_oldNode != newEnd; ++u_oldNode ) + SMESH_Algo::addBadInputElement( u_oldNode->second ); + return error( COMPERR_BAD_INPUT_MESH, + SMESH_Comment( "Existing mesh mismatches the projected 2D mesh on " ) + << ( sm->GetSubShape().ShapeType() == TopAbs_EDGE ? "edge" : "vertex" ) + << " #" << sm->GetId() ); + } + if ( isSeam && !mergeSeamToNew ) { + const TopoDS_Shape& seam = sm->GetSubShape(); + if ( u2nodesMaps[ NEW_NODES ].size() > 0 && + u2nodesOnSeam.size() > 0 && + seam.ShapeType() == TopAbs_EDGE ) + { + int nbE1 = helper.Count( tgtFace, TopAbs_EDGE, /*ignoreSame=*/true ); + int nbE2 = helper.Count( srcFace, TopAbs_EDGE, /*ignoreSame=*/true ); + if ( nbE1 != nbE2 ) // 2 EDGEs are mapped to a seam EDGE + { + // find the 2 EDGEs of srcFace + TopTools_DataMapIteratorOfDataMapOfShapeShape src2tgtIt( shape2ShapeMap._map2to1 ); + for ( ; src2tgtIt.More(); src2tgtIt.Next() ) + if ( seam.IsSame( src2tgtIt.Value() )) + SMESH_Algo::addBadInputElements + ( srcMesh->GetMeshDS()->MeshElements( src2tgtIt.Key() )); + return error( COMPERR_BAD_INPUT_MESH, + "Different number of nodes on two edges projected to a seam edge" ); + } + } } - } - if ( u2nodesMaps[ NEW_NODES ].size() != u2nodesMaps[ OLD_NODES ].size() ) + + // Make groups of nodes to merge + + u_oldNode = u2nodesMaps[ OLD_NODES ].begin(); + u_newNode = u2nodesMaps[ NEW_NODES ].begin(); + newEnd = u2nodesMaps[ NEW_NODES ].end(); + u_newOnSeam = u2nodesOnSeam.begin(); + if ( mergeNewToOld ) + for ( ; u_newNode != newEnd; ++u_newNode, ++u_oldNode ) + { + groupsOfNodes.push_back( list< const SMDS_MeshNode* >() ); + groupsOfNodes.back().push_back( u_oldNode->second ); + groupsOfNodes.back().push_back( u_newNode->second ); + if ( mergeSeamToNew ) + groupsOfNodes.back().push_back( (u_newOnSeam++)->second ); + } + else if ( mergeSeamToNew ) + for ( ; u_newNode != newEnd; ++u_newNode, ++u_newOnSeam ) + { + groupsOfNodes.push_back( list< const SMDS_MeshNode* >() ); + groupsOfNodes.back().push_back( u_newNode->second ); + groupsOfNodes.back().push_back( u_newOnSeam->second ); + } + + } // loop on EDGE and VERTEX submeshes of a target FACE + + // Merge + + SMESH_MeshEditor editor( tgtMesh ); + int nbFaceBeforeMerge = tgtSubMesh->GetSubMeshDS()->NbElements(); + editor.MergeNodes( groupsOfNodes ); + int nbFaceAtferMerge = tgtSubMesh->GetSubMeshDS()->NbElements(); + if ( nbFaceBeforeMerge != nbFaceAtferMerge && !helper.HasDegeneratedEdges() ) + return error(COMPERR_BAD_INPUT_MESH, "Probably invalid node parameters on geom faces"); + + // ---------------------------------------------------------------- + // The mapper can't create quadratic elements, so convert if needed + // ---------------------------------------------------------------- + + faceIt = srcSubMesh->GetSubMeshDS()->GetElements(); + bool srcIsQuad = faceIt->next()->IsQuadratic(); + faceIt = tgtSubMesh->GetSubMeshDS()->GetElements(); + bool tgtIsQuad = faceIt->next()->IsQuadratic(); + if ( srcIsQuad && !tgtIsQuad ) { - if ( u2nodesMaps[ NEW_NODES ].size() == 0 && - sm->GetSubShape().ShapeType() == TopAbs_EDGE && - helper.IsDegenShape( sm->GetId() ) ) - // NPAL15894 (tt88bis.py) - project mesh built by NETGEN_1d_2D that - // does not make segments/nodes on degenerated edges - continue; + TIDSortedElemSet tgtFaces; + faceIt = tgtSubMesh->GetSubMeshDS()->GetElements(); + while ( faceIt->more() ) + tgtFaces.insert( tgtFaces.end(), faceIt->next() ); - RETURN_BAD_RESULT("Different nb of old and new nodes on shape #"<< sm->GetId() <<" "<< - u2nodesMaps[ OLD_NODES ].size() << " != " << - u2nodesMaps[ NEW_NODES ].size()); + editor.ConvertToQuadratic(/*theForce3d=*/false, tgtFaces, false); } - if ( isSeam && u2nodesMaps[ OLD_NODES ].size() != u2nodesOnSeam.size() ) { - RETURN_BAD_RESULT("Different nb of old and seam nodes " << - u2nodesMaps[ OLD_NODES ].size() << " != " << u2nodesOnSeam.size()); - } - // Make groups of nodes to merge - u_oldNode = u2nodesMaps[ OLD_NODES ].begin(); - u_newNode = u2nodesMaps[ NEW_NODES ].begin(); - newEnd = u2nodesMaps[ NEW_NODES ].end(); - u_newOnSeam = u2nodesOnSeam.begin(); - for ( ; u_newNode != newEnd; ++u_newNode, ++u_oldNode ) { - groupsOfNodes.push_back( list< const SMDS_MeshNode* >() ); - groupsOfNodes.back().push_back( u_oldNode->second ); - groupsOfNodes.back().push_back( u_newNode->second ); - if ( isSeam ) - groupsOfNodes.back().push_back( (u_newOnSeam++)->second ); - } - } - // Merge + } // end of projection using Pattern mapping + - int nbFaceBeforeMerge = tgtSubMesh->GetSubMeshDS()->NbElements(); - editor.MergeNodes( groupsOfNodes ); - int nbFaceAtferMerge = tgtSubMesh->GetSubMeshDS()->NbElements(); - if ( nbFaceBeforeMerge != nbFaceAtferMerge ) - return error(COMPERR_BAD_INPUT_MESH, "Probably invalid node parameters on geom faces"); + if ( !projDone || is1DComputed ) + // ---------------------------------------------------------------- + // The mapper can create distorted faces by placing nodes out of the FACE + // boundary, also bad face can be created if EDGEs already discretized + // --> fix bad faces by smoothing + // ---------------------------------------------------------------- + if ( !fixDistortedFaces( helper, tgtWires )) + return error("Invalid mesh generated"); // --------------------------- // Check elements orientation // --------------------------- - TopoDS_Face face = tgtFace; + TopoDS_Face face = TopoDS::Face( theShape ); if ( !theMesh.IsMainShape( tgtFace )) { // find the main shape @@ -627,8 +1652,9 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& } } // Fix orientation - if ( SMESH_Algo::IsReversedSubMesh( face, meshDS )) + if ( helper.IsReversedSubMesh( face )) { + SMESH_MeshEditor editor( tgtMesh ); SMDS_ElemIteratorPtr eIt = meshDS->MeshElements( face )->GetElements(); while ( eIt->more() ) { const SMDS_MeshElement* e = eIt->next(); @@ -637,11 +1663,79 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& } } - cleaner.Release(); // do not remove mesh + cleaner.Release(); // not to remove mesh return true; } + +//======================================================================= +//function : Evaluate +//purpose : +//======================================================================= + +bool StdMeshers_Projection_2D::Evaluate(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + MapShapeNbElems& aResMap) +{ + if ( !_sourceHypo ) + return false; + + SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh(); + SMESH_Mesh * tgtMesh = & theMesh; + if ( !srcMesh ) + srcMesh = tgtMesh; + + // --------------------------- + // Make sub-shapes association + // --------------------------- + + TopoDS_Face tgtFace = TopoDS::Face( theShape.Oriented(TopAbs_FORWARD)); + TopoDS_Shape srcShape = _sourceHypo->GetSourceFace().Oriented(TopAbs_FORWARD); + + TAssocTool::TShapeShapeMap shape2ShapeMap; + TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap ); + if ( !TAssocTool::FindSubShapeAssociation( tgtFace, tgtMesh, srcShape, srcMesh, + shape2ShapeMap) || + !shape2ShapeMap.IsBound( tgtFace )) + return error(COMPERR_BAD_SHAPE,"Topology of source and target faces seems different" ); + + TopoDS_Face srcFace = TopoDS::Face( shape2ShapeMap( tgtFace ).Oriented(TopAbs_FORWARD)); + + // ------------------------------------------------------- + // Assure that mesh on a source Face is computed/evaluated + // ------------------------------------------------------- + + std::vector aVec; + + SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( srcFace ); + if ( srcSubMesh->IsMeshComputed() ) + { + aVec.resize( SMDSEntity_Last, 0 ); + aVec[SMDSEntity_Node] = srcSubMesh->GetSubMeshDS()->NbNodes(); + + SMDS_ElemIteratorPtr elemIt = srcSubMesh->GetSubMeshDS()->GetElements(); + while ( elemIt->more() ) + aVec[ elemIt->next()->GetEntityType() ]++; + } + else + { + MapShapeNbElems tmpResMap; + MapShapeNbElems& srcResMap = (srcMesh == tgtMesh) ? aResMap : tmpResMap; + if ( !_gen->Evaluate( *srcMesh, srcShape, srcResMap )) + return error(COMPERR_BAD_INPUT_MESH,"Source mesh not evaluatable"); + aVec = srcResMap[ srcSubMesh ]; + if ( aVec.empty() ) + return error(COMPERR_BAD_INPUT_MESH,"Source mesh is wrongly evaluated"); + } + + SMESH_subMesh * sm = theMesh.GetSubMesh(theShape); + aResMap.insert(std::make_pair(sm,aVec)); + + return true; +} + + //============================================================================= /*! * \brief Sets a default event listener to submesh of the source face diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_3D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_3D.cpp index 86d6d65d3d5e..1dc3ace8d998 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_3D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Projection_3D.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Projection_3D.cxx // Module : SMESH @@ -56,7 +57,7 @@ // cout << msg << " ("<< p.X() << "; " <GetSourceVertex(1), _sourceHypo->GetSourceVertex(2) ); if ( edge.IsNull() || - !TAssocTool::IsSubShape( edge, srcMesh ) || - !TAssocTool::IsSubShape( edge, _sourceHypo->GetSource3DShape() )) + !SMESH_MesherHelper::IsSubShape( edge, srcMesh ) || + !SMESH_MesherHelper::IsSubShape( edge, _sourceHypo->GetSource3DShape() )) { SCRUTE((edge.IsNull())); - SCRUTE((TAssocTool::IsSubShape( edge, srcMesh ))); - SCRUTE((TAssocTool::IsSubShape( edge, _sourceHypo->GetSource3DShape() ))); + SCRUTE((SMESH_MesherHelper::IsSubShape( edge, srcMesh ))); + SCRUTE((SMESH_MesherHelper::IsSubShape( edge, _sourceHypo->GetSource3DShape() ))); aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER; } else @@ -155,21 +156,21 @@ bool StdMeshers_Projection_3D::CheckHypothesis(SMESH_Mesh& edge = TAssocTool::GetEdgeByVertices ( tgtMesh, _sourceHypo->GetTargetVertex(1), _sourceHypo->GetTargetVertex(2) ); if ( edge.IsNull() || - !TAssocTool::IsSubShape( edge, tgtMesh ) || - !TAssocTool::IsSubShape( edge, aShape )) + !SMESH_MesherHelper::IsSubShape( edge, tgtMesh ) || + !SMESH_MesherHelper::IsSubShape( edge, aShape )) { SCRUTE((edge.IsNull())); - SCRUTE((TAssocTool::IsSubShape( edge, tgtMesh ))); - SCRUTE((TAssocTool::IsSubShape( edge, aShape ))); + SCRUTE((SMESH_MesherHelper::IsSubShape( edge, tgtMesh ))); + SCRUTE((SMESH_MesherHelper::IsSubShape( edge, aShape ))); aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER; } } } // check a source shape - if ( !TAssocTool::IsSubShape( _sourceHypo->GetSource3DShape(), srcMesh ) || + if ( !SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSource3DShape(), srcMesh ) || ( srcMesh == tgtMesh && aShape == _sourceHypo->GetSource3DShape())) { - SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetSource3DShape(), srcMesh))); + SCRUTE((SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSource3DShape(), srcMesh))); SCRUTE((srcMesh == tgtMesh)); SCRUTE((aShape == _sourceHypo->GetSource3DShape())); aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER; @@ -218,13 +219,13 @@ bool StdMeshers_Projection_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aS SMESH_Comment("Target shape must have 1 shell but not ") << nbShell); // Check that shapes are blocks - if ( TAssocTool::Count( tgtShell, TopAbs_FACE , 1 ) != 6 || - TAssocTool::Count( tgtShell, TopAbs_EDGE , 1 ) != 12 || - TAssocTool::Count( tgtShell, TopAbs_WIRE , 1 ) != 6 ) + if ( SMESH_MesherHelper::Count( tgtShell, TopAbs_FACE , 1 ) != 6 || + SMESH_MesherHelper::Count( tgtShell, TopAbs_EDGE , 1 ) != 12 || + SMESH_MesherHelper::Count( tgtShell, TopAbs_WIRE , 1 ) != 6 ) return error(COMPERR_BAD_SHAPE, "Target shape is not a block"); - if ( TAssocTool::Count( srcShell, TopAbs_FACE , 1 ) != 6 || - TAssocTool::Count( srcShell, TopAbs_EDGE , 1 ) != 12 || - TAssocTool::Count( srcShell, TopAbs_WIRE , 1 ) != 6 ) + if ( SMESH_MesherHelper::Count( srcShell, TopAbs_FACE , 1 ) != 6 || + SMESH_MesherHelper::Count( srcShell, TopAbs_EDGE , 1 ) != 12 || + SMESH_MesherHelper::Count( srcShell, TopAbs_WIRE , 1 ) != 6 ) return error(COMPERR_BAD_SHAPE, "Source shape is not a block"); // Assure that mesh on a source shape is computed @@ -232,13 +233,14 @@ bool StdMeshers_Projection_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aS SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( _sourceHypo->GetSource3DShape() ); //SMESH_subMesh* tgtSubMesh = tgtMesh->GetSubMesh( aShape ); - if ( tgtMesh == srcMesh && !aShape.IsSame( _sourceHypo->GetSource3DShape() )) { + string srcMeshError; + if ( tgtMesh == srcMesh && !aShape.IsSame( _sourceHypo->GetSource3DShape() )) { if ( !TAssocTool::MakeComputed( srcSubMesh )) - return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed"); + srcMeshError = TAssocTool::SourceNotComputedError( srcSubMesh, this ); } else { if ( !srcSubMesh->IsMeshComputed() ) - return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed"); + srcMeshError = TAssocTool::SourceNotComputedError(); } // Find 2 pairs of corresponding vertices @@ -263,12 +265,12 @@ bool StdMeshers_Projection_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aS TopExp::Vertices( TopoDS::Edge( exp.Current() ), tgtV000, tgtV100 ); if ( !shape2ShapeMap.IsBound( tgtV000 ) || !shape2ShapeMap.IsBound( tgtV100 )) - return error("Association of subshapes failed" ); + return error("Association of sub-shapes failed" ); srcV000 = TopoDS::Vertex( shape2ShapeMap( tgtV000 )); srcV100 = TopoDS::Vertex( shape2ShapeMap( tgtV100 )); - if ( !TAssocTool::IsSubShape( srcV000, srcShell ) || - !TAssocTool::IsSubShape( srcV100, srcShell )) - return error("Incorrect association of subshapes" ); + if ( !SMESH_MesherHelper::IsSubShape( srcV000, srcShell ) || + !SMESH_MesherHelper::IsSubShape( srcV100, srcShell )) + return error("Incorrect association of sub-shapes" ); } // Load 2 SMESH_Block's with src and tgt shells @@ -276,41 +278,41 @@ bool StdMeshers_Projection_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aS SMESH_Block srcBlock, tgtBlock; TopTools_IndexedMapOfOrientedShape scrShapes, tgtShapes; if ( !tgtBlock.LoadBlockShapes( tgtShell, tgtV000, tgtV100, tgtShapes )) - return error(COMPERR_BAD_SHAPE, "Can't detect block subshapes. Not a block?"); + return error(COMPERR_BAD_SHAPE, "Can't detect block sub-shapes. Not a block?"); if ( !srcBlock.LoadBlockShapes( srcShell, srcV000, srcV100, scrShapes )) - return error(COMPERR_BAD_SHAPE, "Can't detect block subshapes. Not a block?"); + return error(COMPERR_BAD_SHAPE, "Can't detect block sub-shapes. Not a block?"); // Find matching nodes of src and tgt shells TNodeNodeMap src2tgtNodeMap; for ( int fId = SMESH_Block::ID_FirstF; fId < SMESH_Block::ID_Shell; ++fId ) { - // Corresponding subshapes + // Corresponding sub-shapes TopoDS_Face srcFace = TopoDS::Face( scrShapes( fId )); TopoDS_Face tgtFace = TopoDS::Face( tgtShapes( fId )); - if ( _sourceHypo->HasVertexAssociation() ) { // associate face subshapes + if ( _sourceHypo->HasVertexAssociation() ) { // associate face sub-shapes shape2ShapeMap.Clear(); vector< int > edgeIdVec; SMESH_Block::GetFaceEdgesIDs( fId, edgeIdVec ); for ( int i = 0; i < edgeIdVec.size(); ++i ) { int eID = edgeIdVec[ i ]; - shape2ShapeMap.Bind( tgtShapes( eID ), scrShapes( eID )); + shape2ShapeMap.Bind( scrShapes( eID ), tgtShapes( eID )); if ( i < 2 ) { vector< int > vertexIdVec; SMESH_Block::GetEdgeVertexIDs( eID, vertexIdVec ); - shape2ShapeMap.Bind( tgtShapes( vertexIdVec[0] ), scrShapes( vertexIdVec[0] )); - shape2ShapeMap.Bind( tgtShapes( vertexIdVec[1] ), scrShapes( vertexIdVec[1] )); + shape2ShapeMap.Bind( scrShapes( vertexIdVec[0]), tgtShapes( vertexIdVec[0]) ); + shape2ShapeMap.Bind( scrShapes( vertexIdVec[1]), tgtShapes( vertexIdVec[1]) ); } } } // Find matching nodes of tgt and src faces - TNodeNodeMap faceMatchingNodes; + TAssocTool::TNodeNodeMap faceMatchingNodes; if ( ! TAssocTool::FindMatchingNodesOnFaces( srcFace, srcMesh, tgtFace, tgtMesh, shape2ShapeMap, faceMatchingNodes )) - return error(COMPERR_BAD_INPUT_MESH,SMESH_Comment("Mesh on faces #") - << srcMeshDS->ShapeToIndex( srcFace ) << " and " - << tgtMeshDS->ShapeToIndex( tgtFace ) << " seems different" ); + return error(COMPERR_BAD_INPUT_MESH,SMESH_Comment("Mesh on faces #") + << srcMeshDS->ShapeToIndex( srcFace ) << " and " + << tgtMeshDS->ShapeToIndex( tgtFace ) << " seems different" ); // put found matching nodes of 2 faces to the global map src2tgtNodeMap.insert( faceMatchingNodes.begin(), faceMatchingNodes.end() ); @@ -406,11 +408,13 @@ bool StdMeshers_Projection_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aS nodes[6], nodes[7], id, force3d); break; default: // polyhedron - const SMDS_PolyhedralVolumeOfNodes * poly = - dynamic_cast( srcVol ); + const SMDS_VtkVolume * poly = + dynamic_cast( srcVol ); if ( !poly ) RETURN_BAD_RESULT("Unexpected volume type"); - tgtVol = tgtMeshDS->AddPolyhedralVolume( nodes, poly->GetQuanities() ); + if ( !poly->IsPoly()) + RETURN_BAD_RESULT("Unexpected volume type"); + tgtVol = tgtMeshDS->AddPolyhedralVolume( nodes, poly->GetQuantities() ); } if ( tgtVol ) { tgtMeshDS->SetMeshElementOnShape( tgtVol, helper.GetSubShapeID() ); @@ -420,6 +424,104 @@ bool StdMeshers_Projection_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aS return true; } + +//======================================================================= +//function : Evaluate +//purpose : +//======================================================================= + +bool StdMeshers_Projection_3D::Evaluate(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + MapShapeNbElems& aResMap) +{ + if ( !_sourceHypo ) + return false; + + SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh(); + SMESH_Mesh * tgtMesh = & aMesh; + if ( !srcMesh ) + srcMesh = tgtMesh; + + // get shell from shape3D + TopoDS_Shell srcShell, tgtShell; + TopExp_Explorer exp( _sourceHypo->GetSource3DShape(), TopAbs_SHELL ); + int nbShell; + for ( nbShell = 0; exp.More(); exp.Next(), ++nbShell ) + srcShell = TopoDS::Shell( exp.Current() ); + if ( nbShell != 1 ) + return error(COMPERR_BAD_SHAPE, + SMESH_Comment("Source shape must have 1 shell but not ") << nbShell); + + exp.Init( aShape, TopAbs_SHELL ); + for ( nbShell = 0; exp.More(); exp.Next(), ++nbShell ) + tgtShell = TopoDS::Shell( exp.Current() ); + if ( nbShell != 1 ) + return error(COMPERR_BAD_SHAPE, + SMESH_Comment("Target shape must have 1 shell but not ") << nbShell); + + // Check that shapes are blocks + if ( SMESH_MesherHelper::Count( tgtShell, TopAbs_FACE , 1 ) != 6 || + SMESH_MesherHelper::Count( tgtShell, TopAbs_EDGE , 1 ) != 12 || + SMESH_MesherHelper::Count( tgtShell, TopAbs_WIRE , 1 ) != 6 ) + return error(COMPERR_BAD_SHAPE, "Target shape is not a block"); + if ( SMESH_MesherHelper::Count( srcShell, TopAbs_FACE , 1 ) != 6 || + SMESH_MesherHelper::Count( srcShell, TopAbs_EDGE , 1 ) != 12 || + SMESH_MesherHelper::Count( srcShell, TopAbs_WIRE , 1 ) != 6 ) + return error(COMPERR_BAD_SHAPE, "Source shape is not a block"); + + // Assure that mesh on a source shape is computed + + SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( _sourceHypo->GetSource3DShape() ); + + if ( !srcSubMesh->IsMeshComputed() ) + return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed"); + + + std::vector aVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; iGetSubMeshDS()->NbNodes(); + + //bool quadratic = false; + SMDS_ElemIteratorPtr elemIt = srcSubMesh->GetSubMeshDS()->GetElements(); + while ( elemIt->more() ) { + const SMDS_MeshElement* E = elemIt->next(); + if( E->NbNodes()==4 ) { + aVec[SMDSEntity_Tetra]++; + } + else if( E->NbNodes()==5 ) { + aVec[SMDSEntity_Pyramid]++; + } + else if( E->NbNodes()==6 ) { + aVec[SMDSEntity_Penta]++; + } + else if( E->NbNodes()==8 ) { + aVec[SMDSEntity_Hexa]++; + } + else if( E->NbNodes()==10 && E->IsQuadratic() ) { + aVec[SMDSEntity_Quad_Tetra]++; + } + else if( E->NbNodes()==13 && E->IsQuadratic() ) { + aVec[SMDSEntity_Quad_Pyramid]++; + } + else if( E->NbNodes()==15 && E->IsQuadratic() ) { + aVec[SMDSEntity_Quad_Penta]++; + } + else if( E->NbNodes()==20 && E->IsQuadratic() ) { + aVec[SMDSEntity_Quad_Hexa]++; + } + else { + aVec[SMDSEntity_Polyhedra]++; + } + } + + SMESH_subMesh * sm = aMesh.GetSubMesh(aShape); + aResMap.insert(std::make_pair(sm,aVec)); + + return true; +} + + //============================================================================= /*! * \brief Sets a default event listener to submesh of the source shape @@ -439,3 +541,39 @@ void StdMeshers_Projection_3D::SetEventListener(SMESH_subMesh* subMesh) _sourceHypo->GetSourceMesh() ); } +//================================================================================ +/*! + * \brief Return true if the algorithm can mesh this shape + * \param [in] aShape - shape to check + * \param [in] toCheckAll - if true, this check returns OK if all shapes are OK, + * else, returns OK if at least one shape is OK + */ +//================================================================================ + +bool StdMeshers_Projection_3D::IsApplicable(const TopoDS_Shape & aShape, bool toCheckAll) +{ + TopExp_Explorer exp0( aShape, TopAbs_SOLID ); + if ( !exp0.More() ) return false; + + TopTools_IndexedMapOfOrientedShape blockShapes; + TopoDS_Vertex v; + TopoDS_Shell shell; + for ( ; exp0.More(); exp0.Next() ) + { + int nbFoundShells = 0; + TopExp_Explorer exp1( exp0.Current(), TopAbs_SHELL ); + for ( ; exp1.More(); exp1.Next(), ++nbFoundShells ) + { + shell = TopoDS::Shell( exp1.Current() ); + if ( nbFoundShells == 2 ) break; + } + if ( nbFoundShells != 1 ) { + if ( toCheckAll ) return false; + continue; + } + bool isBlock = SMESH_Block::FindBlockShapes( shell, v, v, blockShapes ); + if ( toCheckAll && !isBlock ) return false; + if ( !toCheckAll && isBlock ) return true; + } + return toCheckAll; +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Propagation.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Propagation.cpp index c6b9b015fb50..5a6c9ade0841 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Propagation.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Propagation.cpp @@ -1,34 +1,36 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Propagation.cxx // Module : SMESH - +// #include "StdMeshers_Propagation.hxx" #include "utilities.h" #include "SMDS_SetIterator.hxx" #include "SMESH_Algo.hxx" +#include "SMESH_Gen.hxx" #include "SMESH_HypoFilter.hxx" #include "SMESH_Mesh.hxx" #include "SMESH_subMesh.hxx" @@ -39,7 +41,7 @@ #include #define DBGMSG(txt) \ -// cout << txt << endl; + // cout << txt << endl; using namespace std; @@ -62,7 +64,8 @@ namespace { /*! * \brief Return an edge from which hypotheses are propagated from */ - static TopoDS_Edge GetSource(SMESH_subMesh * submesh); + static TopoDS_Edge GetSource(SMESH_subMesh * submesh, + bool& isPropagOfDistribution); /*! * \brief Does it's main job */ @@ -88,25 +91,40 @@ StdMeshers_Propagation::StdMeshers_Propagation (int hypId, int studyId, SMESH_Ge _name = GetName(); _param_algo_dim = -1; // 1D auxiliary } +StdMeshers_PropagOfDistribution::StdMeshers_PropagOfDistribution (int hypId, + int studyId, + SMESH_Gen * gen) + : StdMeshers_Propagation(hypId, studyId, gen) { _name = GetName(); } StdMeshers_Propagation::~StdMeshers_Propagation() {} string StdMeshers_Propagation::GetName () { return "Propagation"; } +string StdMeshers_PropagOfDistribution::GetName () { return "PropagOfDistribution"; } ostream & StdMeshers_Propagation::SaveTo (ostream & save) { return save; } istream & StdMeshers_Propagation::LoadFrom (istream & load) { return load; } -ostream & operator << (ostream & save, StdMeshers_Propagation & hyp) { return hyp.SaveTo(save); } -istream & operator >> (istream & load, StdMeshers_Propagation & hyp) { return hyp.LoadFrom(load); } bool StdMeshers_Propagation::SetParametersByMesh(const SMESH_Mesh*, const TopoDS_Shape& ) { return false; } bool StdMeshers_Propagation::SetParametersByDefaults(const TDefaults&,const SMESH_Mesh*) { return false; } void StdMeshers_Propagation::SetPropagationMgr(SMESH_subMesh* subMesh) { PropagationMgr::Set( subMesh ); } /*! - * \brief Return an edge from which hypotheses are propagated from + * \brief Return an edge from which hypotheses are propagated */ -TopoDS_Edge StdMeshers_Propagation::GetPropagationSource(SMESH_Mesh& theMesh, - const TopoDS_Shape& theEdge) +TopoDS_Edge StdMeshers_Propagation::GetPropagationSource(SMESH_Mesh& theMesh, + const TopoDS_Shape& theEdge, + bool& isPropagOfDistribution) { - return PropagationMgr::GetSource(theMesh.GetSubMeshContaining( theEdge )); + return PropagationMgr::GetSource( theMesh.GetSubMeshContaining( theEdge ), + isPropagOfDistribution); +} +const SMESH_HypoFilter& StdMeshers_Propagation::GetFilter() +{ + static SMESH_HypoFilter propagHypFilter; + if ( propagHypFilter.IsEmpty() ) + { + propagHypFilter. + Init( SMESH_HypoFilter::HasName( StdMeshers_Propagation::GetName ())). + Or ( SMESH_HypoFilter::HasName( StdMeshers_PropagOfDistribution::GetName ())); + } + return propagHypFilter; } - //============================================================================= //============================================================================= // PROPAGATION MANAGEMENT @@ -124,11 +142,13 @@ namespace { struct PropagationMgrData : public EventListenerData { bool myForward; //!< true if a curve of edge in chain is codirected with one of source edge + bool myIsPropagOfDistribution; //!< type of Propagation hyp PropagationMgrData( SubMeshState state=WAIT_PROPAG_HYP ): EventListenerData(true) { - myType = state; myForward = true; + myType = state; myForward = true; myIsPropagOfDistribution = false; } void Init() { myType = WAIT_PROPAG_HYP; mySubMeshes.clear(); myForward = true; + myIsPropagOfDistribution = false; } SubMeshState State() const { return (SubMeshState) myType; @@ -199,25 +219,27 @@ namespace { /*! * \brief Returns a local 1D hypothesis used for theEdge */ - const SMESH_Hypothesis* getLocal1DHyp (SMESH_Mesh& theMesh, - const TopoDS_Shape& theEdge) + const SMESH_Hypothesis* getLocal1DHyp (SMESH_subMesh* theSubMesh, + //const TopoDS_Shape& theEdge, + TopoDS_Shape* theSssignedTo=0) { static SMESH_HypoFilter hypo; hypo.Init( hypo.HasDim( 1 )). AndNot ( hypo.IsAlgo() ). - AndNot ( hypo.IsAssignedTo( theMesh.GetMeshDS()->ShapeToMesh() )); - return theMesh.GetHypothesis( theEdge, hypo, true ); + AndNot ( hypo.HasName( StdMeshers_Propagation::GetName() )). + AndNot ( hypo.HasName( StdMeshers_PropagOfDistribution::GetName() )). + AndNot ( hypo.IsAssignedTo( theSubMesh->GetFather()->GetShapeToMesh() )); + + return theSubMesh->GetFather()->GetHypothesis( theSubMesh, hypo, true, theSssignedTo ); } //============================================================================= /*! * \brief Returns a propagation hypothesis assigned to theEdge */ - const SMESH_Hypothesis* getProagationHyp (SMESH_Mesh& theMesh, - const TopoDS_Shape& theEdge) + const SMESH_Hypothesis* getProagationHyp (SMESH_subMesh* theSubMesh) { - static SMESH_HypoFilter propagHypFilter - ( SMESH_HypoFilter::HasName( StdMeshers_Propagation::GetName ())); - return theMesh.GetHypothesis( theEdge, propagHypFilter, true ); + return theSubMesh->GetFather()->GetHypothesis + ( theSubMesh, StdMeshers_Propagation::GetFilter(), true ); } //================================================================================ /*! @@ -243,9 +265,17 @@ namespace { SMESH_Mesh* mesh = theMainSubMesh->GetFather(); + TopoDS_Shape shapeOfHyp1D; // shape to which an hyp being propagated is assigned + const SMESH_Hypothesis* hyp1D = getLocal1DHyp( theMainSubMesh, &shapeOfHyp1D ); + SMESH_HypoFilter moreLocalCheck( SMESH_HypoFilter::IsMoreLocalThan( shapeOfHyp1D, *mesh )); + PropagationMgrData* chainData = getData( theMainSubMesh ); chainData->SetState( HAS_PROPAG_HYP ); + if ( const SMESH_Hypothesis * propagHyp = getProagationHyp( theMainSubMesh )) + chainData->myIsPropagOfDistribution = + ( StdMeshers_PropagOfDistribution::GetName() == propagHyp->GetName() ); + // Edge submeshes, to which the 1D hypothesis will be propagated from theMainEdge list & chain = chainData->mySubMeshes; chain.clear(); @@ -254,6 +284,8 @@ namespace { TopTools_MapOfShape checkedShapes; checkedShapes.Add( theMainEdge ); + vector edges; + list::iterator smIt = chain.begin(); for ( ; smIt != chain.end(); ++smIt ) { @@ -266,13 +298,12 @@ namespace { for (; itA.More(); itA.Next()) { // there are objects of different type among the ancestors of edge - if ( itA.Value().ShapeType() != TopAbs_WIRE || !checkedShapes.Add( itA.Value() )) + if ( itA.Value().ShapeType() != TopAbs_WIRE /*|| !checkedShapes.Add( itA.Value() )*/) continue; // Get ordered edges and find index of anE in a sequence + edges.clear(); BRepTools_WireExplorer aWE (TopoDS::Wire(itA.Value())); - vector edges; - edges.reserve(4); int edgeIndex = 0; for (; aWE.More(); aWE.Next()) { TopoDS_Edge edge = aWE.Current(); @@ -288,8 +319,7 @@ namespace { continue; // too few edges } else if ( edges.size() == 4 ) { - int oppIndex = edgeIndex + 2; - if ( oppIndex > 3 ) oppIndex -= 4; + int oppIndex = ( edgeIndex + 2 ) % 4; anOppE = edges[ oppIndex ]; } else { @@ -337,7 +367,8 @@ namespace { if ( oppData->State() == WAIT_PROPAG_HYP ) // ... anOppE is not in any chain { oppData->SetSource( theMainSubMesh ); - if ( !getLocal1DHyp( *mesh, anOppE )) // ... no 1d hyp on anOppE + if ( ! (hyp1D = getLocal1DHyp( oppSM, &shapeOfHyp1D )) || //...no 1d hyp on anOppE + ! (moreLocalCheck.IsOk( hyp1D, shapeOfHyp1D ))) // ... or hyp1D is "more global" { oppData->myForward = data->myForward; if ( edges[ edgeIndex ].Orientation() == anOppE.Orientation() ) @@ -346,6 +377,10 @@ namespace { oppSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); oppData->SetState( IN_CHAIN ); DBGMSG( "set IN_CHAIN on " << oppSM->GetId() ); + if ( oppSM->GetAlgoState() != SMESH_subMesh::HYP_OK ) + // make oppSM check algo state + if ( SMESH_Algo* algo = oppSM->GetAlgo() ) + oppSM->AlgoStateEngine(SMESH_subMesh::ADD_FATHER_ALGO, algo); } else { oppData->SetState( LAST_IN_CHAIN ); @@ -444,7 +479,8 @@ namespace { //================================================================================ PropagationMgr::PropagationMgr() - : SMESH_subMeshEventListener( false ) // won't be deleted by submesh + : SMESH_subMeshEventListener( false, // won't be deleted by submesh + "StdMeshers_Propagation::PropagationMgr") {} //================================================================================ /*! @@ -454,18 +490,23 @@ namespace { void PropagationMgr::Set(SMESH_subMesh * submesh) { + if ( findData( submesh )) return; DBGMSG( "PropagationMgr::Set() on " << submesh->GetId() ); - EventListenerData* data = new PropagationMgrData(); + PropagationMgrData* data = new PropagationMgrData(); submesh->SetEventListener( getListener(), data, submesh ); const SMESH_Hypothesis * propagHyp = - getProagationHyp( *submesh->GetFather(), submesh->GetSubShape() ); + getProagationHyp( submesh ); if ( propagHyp ) + { + data->myIsPropagOfDistribution = + ( StdMeshers_PropagOfDistribution::GetName() == propagHyp->GetName() ); getListener()->ProcessEvent( SMESH_subMesh::ADD_HYP, SMESH_subMesh::ALGO_EVENT, submesh, data, propagHyp); + } } //================================================================================ /*! @@ -473,7 +514,8 @@ namespace { */ //================================================================================ - TopoDS_Edge PropagationMgr::GetSource(SMESH_subMesh * submesh) + TopoDS_Edge PropagationMgr::GetSource(SMESH_subMesh * submesh, + bool& isPropagOfDistribution) { if ( PropagationMgrData* data = findData( submesh )) { if ( data->State() == IN_CHAIN ) { @@ -482,6 +524,9 @@ namespace { TopoDS_Shape edge = sm->GetSubShape(); edge = edge.Oriented( data->myForward ? TopAbs_FORWARD : TopAbs_REVERSED ); DBGMSG( " GetSource() = edge " << sm->GetId() << " REV = " << (!data->myForward)); + isPropagOfDistribution = false; + if ( PropagationMgrData* data = findData( sm )) + isPropagOfDistribution = data->myIsPropagOfDistribution; if ( edge.ShapeType() == TopAbs_EDGE ) return TopoDS::Edge( edge ); } @@ -495,9 +540,9 @@ namespace { */ //================================================================================ - void PropagationMgr::ProcessEvent(const int event, - const int eventType, - SMESH_subMesh* subMesh, + void PropagationMgr::ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* subMesh, SMESH_subMeshEventListenerData* listenerData, const SMESH_Hypothesis* hyp) { @@ -509,18 +554,18 @@ namespace { return; DBGMSG( "PropagationMgr::ProcessEvent() on " << subMesh->GetId() ); - bool isPropagHyp = ( StdMeshers_Propagation::GetName() == hyp->GetName() ); + bool isPropagHyp = ( StdMeshers_Propagation::GetName() == hyp->GetName() || + StdMeshers_PropagOfDistribution::GetName() == hyp->GetName() ); PropagationMgrData* data = static_cast( listenerData ); switch ( data->State() ) { case WAIT_PROPAG_HYP: { // propagation hyp or local 1D hyp is missing // -------------------------------------------------------- - bool hasPropagHyp = ( isPropagHyp || - getProagationHyp( *subMesh->GetFather(), subMesh->GetSubShape()) ); + bool hasPropagHyp = ( isPropagHyp || getProagationHyp( subMesh )); if ( !hasPropagHyp ) return; - bool hasLocal1DHyp = getLocal1DHyp( *subMesh->GetFather(), subMesh->GetSubShape()); + bool hasLocal1DHyp = getLocal1DHyp( subMesh ); if ( !hasLocal1DHyp ) return; if ( event == SMESH_subMesh::ADD_HYP || @@ -537,7 +582,7 @@ namespace { switch ( event ) { case SMESH_subMesh::REMOVE_HYP: case SMESH_subMesh::REMOVE_FATHER_HYP: // remove propagation hyp - if ( isPropagHyp && !getProagationHyp( *subMesh->GetFather(), subMesh->GetSubShape()) ) + if ( isPropagHyp && !getProagationHyp( subMesh )) { DBGMSG( "REMOVE_HYP propagation from HAS_PROPAG_HYP " << subMesh->GetId() ); // clear propagation chain diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadFromMedialAxis_1D2D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadFromMedialAxis_1D2D.cpp new file mode 100644 index 000000000000..a9b924724f4a --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadFromMedialAxis_1D2D.cpp @@ -0,0 +1,2098 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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_QuadFromMedialAxis_1D2D.cxx +// Created : Wed Jun 3 17:33:45 2015 +// Author : Edward AGAPOV (eap) + +#include "StdMeshers_QuadFromMedialAxis_1D2D.hxx" + +#include "SMESH_Block.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_MAT2d.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MeshEditor.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_ProxyMesh.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_subMeshEventListener.hxx" +#include "StdMeshers_FaceSide.hxx" +#include "StdMeshers_LayerDistribution.hxx" +#include "StdMeshers_NumberOfLayers.hxx" +#include "StdMeshers_Regular_1D.hxx" +#include "StdMeshers_ViscousLayers2D.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +//================================================================================ +/*! + * \brief 1D algo + */ +class StdMeshers_QuadFromMedialAxis_1D2D::Algo1D : public StdMeshers_Regular_1D +{ +public: + Algo1D(int studyId, SMESH_Gen* gen): + StdMeshers_Regular_1D( gen->GetANewId(), studyId, gen ) + { + } + void SetSegmentLength( double len ) + { + SMESH_Algo::_usedHypList.clear(); + _value[ BEG_LENGTH_IND ] = len; + _value[ PRECISION_IND ] = 1e-7; + _hypType = LOCAL_LENGTH; + } + void SetRadialDistribution( const SMESHDS_Hypothesis* hyp ) + { + SMESH_Algo::_usedHypList.clear(); + if ( !hyp ) + return; + + if ( const StdMeshers_NumberOfLayers* nl = + dynamic_cast< const StdMeshers_NumberOfLayers* >( hyp )) + { + _ivalue[ NB_SEGMENTS_IND ] = nl->GetNumberOfLayers(); + _ivalue[ DISTR_TYPE_IND ] = 0; + _hypType = NB_SEGMENTS; + } + if ( const StdMeshers_LayerDistribution* ld = + dynamic_cast< const StdMeshers_LayerDistribution* >( hyp )) + { + if ( SMESH_Hypothesis* h = ld->GetLayerDistribution() ) + { + SMESH_Algo::_usedHypList.clear(); + SMESH_Algo::_usedHypList.push_back( h ); + } + } + } + void ComputeDistribution(SMESH_MesherHelper& theHelper, + const gp_Pnt& thePnt1, + const gp_Pnt& thePnt2, + list< double >& theParams) + { + SMESH_Mesh& mesh = *theHelper.GetMesh(); + TopoDS_Edge edge = BRepBuilderAPI_MakeEdge( thePnt1, thePnt2 ); + + SMESH_Hypothesis::Hypothesis_Status aStatus; + CheckHypothesis( mesh, edge, aStatus ); + + theParams.clear(); + BRepAdaptor_Curve C3D(edge); + double f = C3D.FirstParameter(), l = C3D.LastParameter(), len = thePnt1.Distance( thePnt2 ); + if ( !StdMeshers_Regular_1D::computeInternalParameters( mesh, C3D, len, f, l, theParams, false)) + { + for ( size_t i = 1; i < 15; ++i ) + theParams.push_back( i/15 ); + } + else + { + for (list::iterator itU = theParams.begin(); itU != theParams.end(); ++itU ) + *itU /= len; + } + } + virtual const list & + GetUsedHypothesis(SMESH_Mesh &, const TopoDS_Shape &, const bool) + { + return SMESH_Algo::_usedHypList; + } + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus) + { + if ( !SMESH_Algo::_usedHypList.empty() ) + return StdMeshers_Regular_1D::CheckHypothesis( aMesh, aShape, aStatus ); + return true; + } +}; + +//================================================================================ +/*! + * \brief Constructor sets algo features + */ +//================================================================================ + +StdMeshers_QuadFromMedialAxis_1D2D::StdMeshers_QuadFromMedialAxis_1D2D(int hypId, + int studyId, + SMESH_Gen* gen) + : StdMeshers_Quadrangle_2D(hypId, studyId, gen), + _regular1D( 0 ) +{ + _name = "QuadFromMedialAxis_1D2D"; + _shapeType = (1 << TopAbs_FACE); + _onlyUnaryInput = true; // FACE by FACE so far + _requireDiscreteBoundary = false; // make 1D by myself + _supportSubmeshes = true; // make 1D by myself + _neededLowerHyps[ 1 ] = true; // suppress warning on hiding a global 1D algo + _neededLowerHyps[ 2 ] = true; // suppress warning on hiding a global 2D algo + _compatibleHypothesis.clear(); + _compatibleHypothesis.push_back("ViscousLayers2D"); + _compatibleHypothesis.push_back("LayerDistribution2D"); + _compatibleHypothesis.push_back("NumberOfLayers2D"); +} + +//================================================================================ +/*! + * \brief Destructor + */ +//================================================================================ + +StdMeshers_QuadFromMedialAxis_1D2D::~StdMeshers_QuadFromMedialAxis_1D2D() +{ + delete _regular1D; + _regular1D = 0; +} + +//================================================================================ +/*! + * \brief Check if needed hypotheses are present + */ +//================================================================================ + +bool StdMeshers_QuadFromMedialAxis_1D2D::CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + Hypothesis_Status& aStatus) +{ + aStatus = HYP_OK; + + // get one main optional hypothesis + const list & hyps = GetUsedHypothesis(aMesh, aShape); + _hyp2D = hyps.empty() ? 0 : hyps.front(); + + return true; // does not require hypothesis +} + +namespace +{ + typedef map< const SMDS_MeshNode*, list< const SMDS_MeshNode* > > TMergeMap; + + //================================================================================ + /*! + * \brief Sinuous face + */ + struct SinuousFace + { + FaceQuadStruct::Ptr _quad; + vector< TopoDS_Edge > _edges; + vector< TopoDS_Edge > _sinuSide[2], _shortSide[2]; + vector< TopoDS_Edge > _sinuEdges; + vector< Handle(Geom_Curve) > _sinuCurves; + int _nbWires; + list< int > _nbEdgesInWire; + TMergeMap _nodesToMerge; + + SinuousFace( const TopoDS_Face& f ): _quad( new FaceQuadStruct ) + { + list< TopoDS_Edge > edges; + _nbWires = SMESH_Block::GetOrderedEdges (f, edges, _nbEdgesInWire); + _edges.assign( edges.begin(), edges.end() ); + + _quad->side.resize( 4 ); + _quad->face = f; + } + const TopoDS_Face& Face() const { return _quad->face; } + bool IsRing() const { return _shortSide[0].empty() && !_sinuSide[0].empty(); } + }; + + //================================================================================ + /*! + * \brief Temporary mesh + */ + struct TmpMesh : public SMESH_Mesh + { + TmpMesh() + { + _myMeshDS = new SMESHDS_Mesh(/*id=*/0, /*isEmbeddedMode=*/true); + } + }; + + //================================================================================ + /*! + * \brief Event listener which removes mesh from EDGEs when 2D hyps change + */ + struct EdgeCleaner : public SMESH_subMeshEventListener + { + int _prevAlgoEvent; + EdgeCleaner(): + SMESH_subMeshEventListener( /*isDeletable=*/true, + "StdMeshers_QuadFromMedialAxis_1D2D::EdgeCleaner") + { + _prevAlgoEvent = -1; + } + virtual void ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* faceSubMesh, + SMESH_subMeshEventListenerData* data, + const SMESH_Hypothesis* hyp) + { + if ( eventType == SMESH_subMesh::ALGO_EVENT ) + { + _prevAlgoEvent = event; + return; + } + // SMESH_subMesh::COMPUTE_EVENT + if ( _prevAlgoEvent == SMESH_subMesh::REMOVE_HYP || + _prevAlgoEvent == SMESH_subMesh::REMOVE_ALGO || + _prevAlgoEvent == SMESH_subMesh::MODIF_HYP ) + { + SMESH_subMeshIteratorPtr smIt = faceSubMesh->getDependsOnIterator(/*includeSelf=*/false); + while ( smIt->more() ) + smIt->next()->ComputeStateEngine( SMESH_subMesh::CLEAN ); + } + _prevAlgoEvent = -1; + } + }; + + //================================================================================ + /*! + * \brief Return a member of a std::pair + */ + //================================================================================ + + template< typename T > + T& get( std::pair< T, T >& thePair, bool is2nd ) + { + return is2nd ? thePair.second : thePair.first; + } + + //================================================================================ + /*! + * \brief Select two EDGEs from a map, either mapped to least values or to max values + */ + //================================================================================ + + // template< class TVal2EdgesMap > + // void getTwo( bool least, + // TVal2EdgesMap& map, + // vector& twoEdges, + // vector& otherEdges) + // { + // twoEdges.clear(); + // otherEdges.clear(); + // if ( least ) + // { + // TVal2EdgesMap::iterator i = map.begin(); + // twoEdges.push_back( i->second ); + // twoEdges.push_back( ++i->second ); + // for ( ; i != map.end(); ++i ) + // otherEdges.push_back( i->second ); + // } + // else + // { + // TVal2EdgesMap::reverse_iterator i = map.rbegin(); + // twoEdges.push_back( i->second ); + // twoEdges.push_back( ++i->second ); + // for ( ; i != map.rend(); ++i ) + // otherEdges.push_back( i->second ); + // } + // TopoDS_Vertex v; + // if ( TopExp::CommonVertex( twoEdges[0], twoEdges[1], v )) + // { + // twoEdges.clear(); // two EDGEs must not be connected + // otherEdges.clear(); + // } + // } + + //================================================================================ + /*! + * \brief Finds out a minimal segment length given EDGEs will be divided into. + * This length is further used to discretize the Medial Axis + */ + //================================================================================ + + double getMinSegLen(SMESH_MesherHelper& theHelper, + const vector& theEdges) + { + TmpMesh tmpMesh; + SMESH_Mesh* mesh = theHelper.GetMesh(); + + vector< SMESH_Algo* > algos( theEdges.size() ); + for ( size_t i = 0; i < theEdges.size(); ++i ) + { + SMESH_subMesh* sm = mesh->GetSubMesh( theEdges[i] ); + algos[i] = sm->GetAlgo(); + } + + int nbSegDflt = mesh->GetGen() ? mesh->GetGen()->GetDefaultNbSegments() : 15; + double minSegLen = Precision::Infinite(); + + for ( size_t i = 0; i < theEdges.size(); ++i ) + { + SMESH_subMesh* sm = mesh->GetSubMesh( theEdges[i] ); + if ( SMESH_Algo::IsStraight( theEdges[i], /*degenResult=*/true )) + continue; + // get algo + size_t iOpp = ( theEdges.size() == 4 ? (i+2)%4 : i ); + SMESH_Algo* algo = sm->GetAlgo(); + if ( !algo ) algo = algos[ iOpp ]; + // get hypo + SMESH_Hypothesis::Hypothesis_Status status = SMESH_Hypothesis::HYP_MISSING; + if ( algo ) + { + if ( !algo->CheckHypothesis( *mesh, theEdges[i], status )) + algo->CheckHypothesis( *mesh, theEdges[iOpp], status ); + } + // compute + if ( status != SMESH_Hypothesis::HYP_OK ) + { + minSegLen = Min( minSegLen, SMESH_Algo::EdgeLength( theEdges[i] ) / nbSegDflt ); + } + else + { + tmpMesh.Clear(); + tmpMesh.ShapeToMesh( TopoDS_Shape()); + tmpMesh.ShapeToMesh( theEdges[i] ); + try { + if ( !mesh->GetGen() ) continue; // tmp mesh + mesh->GetGen()->Compute( tmpMesh, theEdges[i], true, true ); // make nodes on VERTEXes + if ( !algo->Compute( tmpMesh, theEdges[i] )) + continue; + } + catch (...) { + continue; + } + SMDS_EdgeIteratorPtr segIt = tmpMesh.GetMeshDS()->edgesIterator(); + while ( segIt->more() ) + { + const SMDS_MeshElement* seg = segIt->next(); + double len = SMESH_TNodeXYZ( seg->GetNode(0) ).Distance( seg->GetNode(1) ); + minSegLen = Min( minSegLen, len ); + } + } + } + if ( Precision::IsInfinite( minSegLen )) + minSegLen = mesh->GetShapeDiagonalSize() / nbSegDflt; + + return minSegLen; + } + + //================================================================================ + /*! + * \brief Returns EDGEs located between two VERTEXes at which given MA branches end + * \param [in] br1 - one MA branch + * \param [in] br2 - one more MA branch + * \param [in] allEdges - all EDGEs of a FACE + * \param [out] shortEdges - the found EDGEs + * \return bool - is OK or not + */ + //================================================================================ + + bool getConnectedEdges( const SMESH_MAT2d::Branch* br1, + const SMESH_MAT2d::Branch* br2, + const vector& allEdges, + vector& shortEdges) + { + vector< size_t > edgeIDs[4]; + br1->getGeomEdges( edgeIDs[0], edgeIDs[1] ); + br2->getGeomEdges( edgeIDs[2], edgeIDs[3] ); + + // EDGEs returned by a Branch form a connected chain with a VERTEX where + // the Branch ends at the chain middle. One of end EDGEs of the chain is common + // with either end EDGE of the chain of the other Branch, or the chains are connected + // at a common VERTEX; + + // Get indices of end EDGEs of the branches + bool vAtStart1 = ( br1->getEnd(0)->_type == SMESH_MAT2d::BE_ON_VERTEX ); + bool vAtStart2 = ( br2->getEnd(0)->_type == SMESH_MAT2d::BE_ON_VERTEX ); + size_t iEnd[4] = { + vAtStart1 ? edgeIDs[0].back() : edgeIDs[0][0], + vAtStart1 ? edgeIDs[1].back() : edgeIDs[1][0], + vAtStart2 ? edgeIDs[2].back() : edgeIDs[2][0], + vAtStart2 ? edgeIDs[3].back() : edgeIDs[3][0] + }; + + set< size_t > connectedIDs; + TopoDS_Vertex vCommon; + // look for the same EDGEs + for ( int i = 0; i < 2; ++i ) + for ( int j = 2; j < 4; ++j ) + if ( iEnd[i] == iEnd[j] ) + { + connectedIDs.insert( edgeIDs[i].begin(), edgeIDs[i].end() ); + connectedIDs.insert( edgeIDs[j].begin(), edgeIDs[j].end() ); + i = j = 4; + } + if ( connectedIDs.empty() ) + // look for connected EDGEs + for ( int i = 0; i < 2; ++i ) + for ( int j = 2; j < 4; ++j ) + if ( TopExp::CommonVertex( allEdges[ iEnd[i]], allEdges[ iEnd[j]], vCommon )) + { + connectedIDs.insert( edgeIDs[i].begin(), edgeIDs[i].end() ); + connectedIDs.insert( edgeIDs[j].begin(), edgeIDs[j].end() ); + i = j = 4; + } + if ( connectedIDs.empty() || // nothing + allEdges.size() - connectedIDs.size() < 2 ) // too many + return false; + + // set shortEdges in the order as in allEdges + if ( connectedIDs.count( 0 ) && + connectedIDs.count( allEdges.size()-1 )) + { + size_t iE = allEdges.size()-1; + while ( connectedIDs.count( iE-1 )) + --iE; + for ( size_t i = 0; i < connectedIDs.size(); ++i ) + { + shortEdges.push_back( allEdges[ iE ]); + iE = ( iE + 1 ) % allEdges.size(); + } + } + else + { + set< size_t >::iterator i = connectedIDs.begin(); + for ( ; i != connectedIDs.end(); ++i ) + shortEdges.push_back( allEdges[ *i ]); + } + return true; + } + + //================================================================================ + /*! + * \brief Find EDGEs to discretize using projection from MA + * \param [in,out] theSinuFace - the FACE to be meshed + * \return bool - OK or not + * + * It separates all EDGEs into four sides of a quadrangle connected in the order: + * theSinuEdges[0], theShortEdges[0], theSinuEdges[1], theShortEdges[1] + */ + //================================================================================ + + bool getSinuousEdges( SMESH_MesherHelper& theHelper, + SinuousFace& theSinuFace) + { + vector * theSinuEdges = & theSinuFace._sinuSide [0]; + vector * theShortEdges = & theSinuFace._shortSide[0]; + theSinuEdges[0].clear(); + theSinuEdges[1].clear(); + theShortEdges[0].clear(); + theShortEdges[1].clear(); + + vector & allEdges = theSinuFace._edges; + const size_t nbEdges = allEdges.size(); + if ( nbEdges < 4 && theSinuFace._nbWires == 1 ) + return false; + + if ( theSinuFace._nbWires == 2 ) // ring + { + size_t nbOutEdges = theSinuFace._nbEdgesInWire.front(); + theSinuEdges[0].assign ( allEdges.begin(), allEdges.begin() + nbOutEdges ); + theSinuEdges[1].assign ( allEdges.begin() + nbOutEdges, allEdges.end() ); + theSinuFace._sinuEdges = allEdges; + return true; + } + if ( theSinuFace._nbWires > 2 ) + return false; + + // create MedialAxis to find short edges by analyzing MA branches + double minSegLen = getMinSegLen( theHelper, allEdges ); + SMESH_MAT2d::MedialAxis ma( theSinuFace.Face(), allEdges, minSegLen * 3 ); + + // in an initial request case, theFace represents a part of a river with almost parallel banks + // so there should be two branch points + using SMESH_MAT2d::BranchEnd; + using SMESH_MAT2d::Branch; + const vector< const BranchEnd* >& braPoints = ma.getBranchPoints(); + if ( braPoints.size() < 2 ) + return false; + TopTools_MapOfShape shortMap; + size_t nbBranchPoints = 0; + for ( size_t i = 0; i < braPoints.size(); ++i ) + { + vector< const Branch* > vertBranches; // branches with an end on VERTEX + for ( size_t ib = 0; ib < braPoints[i]->_branches.size(); ++ib ) + { + const Branch* branch = braPoints[i]->_branches[ ib ]; + if ( branch->hasEndOfType( SMESH_MAT2d::BE_ON_VERTEX )) + vertBranches.push_back( branch ); + } + if ( vertBranches.size() != 2 || braPoints[i]->_branches.size() != 3) + continue; + + // get common EDGEs of two branches + if ( !getConnectedEdges( vertBranches[0], vertBranches[1], + allEdges, theShortEdges[ nbBranchPoints > 0 ] )) + return false; + + for ( size_t iS = 0; iS < theShortEdges[ nbBranchPoints ].size(); ++iS ) + shortMap.Add( theShortEdges[ nbBranchPoints ][ iS ]); + + ++nbBranchPoints; + } + + if ( nbBranchPoints != 2 ) + return false; + + // add to theSinuEdges all edges that are not theShortEdges + vector< vector > sinuEdges(1); + TopoDS_Vertex vCommon; + for ( size_t i = 0; i < allEdges.size(); ++i ) + { + if ( !shortMap.Contains( allEdges[i] )) + { + if ( !sinuEdges.back().empty() ) + if ( !TopExp::CommonVertex( sinuEdges.back().back(), allEdges[ i ], vCommon )) + sinuEdges.resize( sinuEdges.size() + 1 ); + + sinuEdges.back().push_back( allEdges[i] ); + } + } + if ( sinuEdges.size() == 3 ) + { + if ( !TopExp::CommonVertex( sinuEdges.back().back(), sinuEdges[0][0], vCommon )) + return false; + vector& last = sinuEdges.back(); + last.insert( last.end(), sinuEdges[0].begin(), sinuEdges[0].end() ); + sinuEdges[0].swap( last ); + sinuEdges.resize( 2 ); + } + if ( sinuEdges.size() != 2 ) + return false; + + theSinuEdges[0].swap( sinuEdges[0] ); + theSinuEdges[1].swap( sinuEdges[1] ); + + if ( !TopExp::CommonVertex( theSinuEdges[0].back(), theShortEdges[0][0], vCommon ) || + !vCommon.IsSame( theHelper.IthVertex( 1, theSinuEdges[0].back() ))) + theShortEdges[0].swap( theShortEdges[1] ); + + theSinuFace._sinuEdges = theSinuEdges[0]; + theSinuFace._sinuEdges.insert( theSinuFace._sinuEdges.end(), + theSinuEdges[1].begin(), theSinuEdges[1].end() ); + + return ( theShortEdges[0].size() > 0 && theShortEdges[1].size() > 0 && + theSinuEdges [0].size() > 0 && theSinuEdges [1].size() > 0 ); + + // the sinuous EDGEs can be composite and C0 continuous, + // therefor we use a complex criterion to find TWO short non-sinuous EDGEs + // and the rest EDGEs will be treated as sinuous. + // A short edge should have the following features: + // a) straight + // b) short + // c) with convex corners at ends + // d) far from the other short EDGE + + // vector< double > isStraightEdge( nbEdges, 0 ); // criterion value + + // // a0) evaluate continuity + // const double contiWgt = 0.5; // weight of continuity in the criterion + // multimap< int, TopoDS_Edge > continuity; + // for ( size_t i = 0; i < nbEdges; ++I ) + // { + // BRepAdaptor_Curve curve( allEdges[i] ); + // GeomAbs_Shape C = GeomAbs_CN; + // try: + // C = curve.Continuity(); // C0, G1, C1, G2, C2, C3, CN + // catch ( Standard_Failure ) {} + // continuity.insert( make_pair( C, allEdges[i] )); + // isStraight[i] += double( C ) / double( CN ) * contiWgt; + // } + + // // try to choose by continuity + // int mostStraight = (int) continuity.rbegin()->first; + // int lessStraight = (int) continuity.begin()->first; + // if ( mostStraight != lessStraight ) + // { + // int nbStraight = continuity.count( mostStraight ); + // if ( nbStraight == 2 ) + // { + // getTwo( /*least=*/false, continuity, theShortEdges, theSinuEdges ); + // } + // else if ( nbStraight == 3 && nbEdges == 4 ) + // { + // theSinuEdges.push_back( continuity.begin()->second ); + // vector::iterator it = + // std::find( allEdges.begin(), allEdges.end(), theSinuEdges[0] ); + // int i = std::distance( allEdges.begin(), it ); + // theSinuEdges .push_back( allEdges[( i+2 )%4 ]); + // theShortEdges.push_back( allEdges[( i+1 )%4 ]); + // theShortEdges.push_back( allEdges[( i+3 )%4 ]); + // } + // if ( theShortEdges.size() == 2 ) + // return true; + // } + + // // a) curvature; evaluate aspect ratio + // { + // const double curvWgt = 0.5; + // for ( size_t i = 0; i < nbEdges; ++I ) + // { + // BRepAdaptor_Curve curve( allEdges[i] ); + // double curvature = 1; + // if ( !curve.IsClosed() ) + // { + // const double f = curve.FirstParameter(), l = curve.LastParameter(); + // gp_Pnt pf = curve.Value( f ), pl = curve.Value( l ); + // gp_Lin line( pf, pl.XYZ() - pf.XYZ() ); + // double distMax = 0; + // for ( double u = f; u < l; u += (l-f)/30. ) + // distMax = Max( distMax, line.SquareDistance( curve.Value( u ))); + // curvature = Sqrt( distMax ) / ( pf.Distance( pl )); + // } + // isStraight[i] += curvWgt / ( curvature + 1e-20 ); + // } + // } + // // b) length + // { + // const double lenWgt = 0.5; + // for ( size_t i = 0; i < nbEdges; ++I ) + // { + // double length = SMESH_Algo::Length( allEdges[i] ); + // if ( length > 0 ) + // isStraight[i] += lenWgt / length; + // } + // } + // // c) with convex corners at ends + // { + // const double cornerWgt = 0.25; + // for ( size_t i = 0; i < nbEdges; ++I ) + // { + // double convex = 0; + // int iPrev = SMESH_MesherHelper::WrapIndex( int(i)-1, nbEdges ); + // int iNext = SMESH_MesherHelper::WrapIndex( int(i)+1, nbEdges ); + // TopoDS_Vertex v = helper.IthVertex( 0, allEdges[i] ); + // double angle = SMESH_MesherHelper::GetAngle( allEdges[iPrev], allEdges[i], theFace, v ); + // if ( angle < M_PI ) // [-PI; PI] + // convex += ( angle + M_PI ) / M_PI / M_PI; + // v = helper.IthVertex( 1, allEdges[i] ); + // angle = SMESH_MesherHelper::GetAngle( allEdges[iNext], allEdges[i], theFace, v ); + // if ( angle < M_PI ) // [-PI; PI] + // convex += ( angle + M_PI ) / M_PI / M_PI; + // isStraight[i] += cornerWgt * convex; + // } + // } + } + + //================================================================================ + /*! + * \brief Creates an EDGE from a sole branch of MA + */ + //================================================================================ + + TopoDS_Edge makeEdgeFromMA( SMESH_MesherHelper& theHelper, + const SMESH_MAT2d::MedialAxis& theMA, + const double theMinSegLen) + { + if ( theMA.nbBranches() != 1 ) + return TopoDS_Edge(); + + vector< gp_XY > uv; + theMA.getPoints( theMA.getBranch(0), uv ); + if ( uv.size() < 2 ) + return TopoDS_Edge(); + + TopoDS_Face face = TopoDS::Face( theHelper.GetSubShape() ); + Handle(Geom_Surface) surface = BRep_Tool::Surface( face ); + + vector< gp_Pnt > pnt; + pnt.reserve( uv.size() * 2 ); + pnt.push_back( surface->Value( uv[0].X(), uv[0].Y() )); + for ( size_t i = 1; i < uv.size(); ++i ) + { + gp_Pnt p = surface->Value( uv[i].X(), uv[i].Y() ); + int nbDiv = int( p.Distance( pnt.back() ) / theMinSegLen ); + for ( int iD = 1; iD < nbDiv; ++iD ) + { + double R = iD / double( nbDiv ); + gp_XY uvR = uv[i-1] * (1 - R) + uv[i] * R; + pnt.push_back( surface->Value( uvR.X(), uvR.Y() )); + } + pnt.push_back( p ); + } + + // cout << "from salome.geom import geomBuilder" << endl; + // cout << "geompy = geomBuilder.New(salome.myStudy)" << endl; + Handle(TColgp_HArray1OfPnt) points = new TColgp_HArray1OfPnt(1, pnt.size()); + for ( size_t i = 0; i < pnt.size(); ++i ) + { + gp_Pnt& p = pnt[i]; + points->SetValue( i+1, p ); + // cout << "geompy.MakeVertex( "<< p.X()<<", " << p.Y()<<", " << p.Z() + // <<" theName = 'p_" << i << "')" << endl; + } + + GeomAPI_Interpolate interpol( points, /*isClosed=*/false, gp::Resolution()); + interpol.Perform(); + if ( !interpol.IsDone()) + return TopoDS_Edge(); + + TopoDS_Edge branchEdge = BRepBuilderAPI_MakeEdge(interpol.Curve()); + return branchEdge; + } + + //================================================================================ + /*! + * \brief Returns a type of shape, to which a hypothesis used to mesh a given edge is assigned + */ + //================================================================================ + + TopAbs_ShapeEnum getHypShape( SMESH_Mesh* mesh, const TopoDS_Shape& edge ) + { + TopAbs_ShapeEnum shapeType = TopAbs_SHAPE; + + SMESH_subMesh* sm = mesh->GetSubMesh( edge ); + SMESH_Algo* algo = sm->GetAlgo(); + if ( !algo ) return shapeType; + + const list & hyps = + algo->GetUsedHypothesis( *mesh, edge, /*ignoreAuxiliary=*/true ); + if ( hyps.empty() ) return shapeType; + + TopoDS_Shape shapeOfHyp = + SMESH_MesherHelper::GetShapeOfHypothesis( hyps.front(), edge, mesh); + + return SMESH_MesherHelper::GetGroupType( shapeOfHyp, /*woCompound=*/true); + } + + //================================================================================ + /*! + * \brief Discretize a sole branch of MA an returns parameters of divisions on MA + */ + //================================================================================ + + bool divideMA( SMESH_MesherHelper& theHelper, + const SMESH_MAT2d::MedialAxis& theMA, + const SinuousFace& theSinuFace, + SMESH_Algo* the1dAlgo, + const double theMinSegLen, + vector& theMAParams ) + { + // Check if all EDGEs of one size are meshed, then MA discretization is not needed + SMESH_Mesh* mesh = theHelper.GetMesh(); + size_t nbComputedEdges[2] = { 0, 0 }; + for ( size_t iS = 0; iS < 2; ++iS ) + for ( size_t i = 0; i < theSinuFace._sinuSide[iS].size(); ++i ) + { + const TopoDS_Edge& sinuEdge = theSinuFace._sinuSide[iS][i]; + SMESH_subMesh* sm = mesh->GetSubMesh( sinuEdge ); + bool isComputed = ( !sm->IsEmpty() ); + if ( isComputed ) + { + TopAbs_ShapeEnum shape = getHypShape( mesh, sinuEdge ); + if ( shape == TopAbs_SHAPE || shape <= TopAbs_FACE ) + { + // EDGE computed using global hypothesis -> clear it + bool hasComputedFace = false; + PShapeIteratorPtr faceIt = theHelper.GetAncestors( sinuEdge, *mesh, TopAbs_FACE ); + while ( const TopoDS_Shape* face = faceIt->next() ) + if (( !face->IsSame( theSinuFace.Face() )) && + ( hasComputedFace = !mesh->GetSubMesh( *face )->IsEmpty() )) + break; + if ( !hasComputedFace ) + { + sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); + isComputed = false; + } + } + } + nbComputedEdges[ iS ] += isComputed; + } + if ( nbComputedEdges[0] == theSinuFace._sinuSide[0].size() || + nbComputedEdges[1] == theSinuFace._sinuSide[1].size() ) + return true; // discretization is not needed + + // Make MA EDGE + TopoDS_Edge branchEdge = makeEdgeFromMA( theHelper, theMA, theMinSegLen ); + if ( branchEdge.IsNull() ) + return false; + + // const char* file = "/misc/dn25/salome/eap/salome/misc/tmp/MAedge.brep"; + // BRepTools::Write( branchEdge, file); + // cout << "Write " << file << endl; + + + // Find 1D algo to mesh branchEdge + + // look for a most local 1D hyp assigned to the FACE + int mostSimpleShape = -1, maxShape = TopAbs_EDGE; + TopoDS_Edge edge; + for ( size_t i = 0; i < theSinuFace._sinuEdges.size(); ++i ) + { + TopAbs_ShapeEnum shapeType = getHypShape( mesh, theSinuFace._sinuEdges[i] ); + if ( mostSimpleShape < shapeType && shapeType < maxShape ) + { + edge = theSinuFace._sinuEdges[i]; + mostSimpleShape = shapeType; + } + } + + SMESH_Algo* algo = the1dAlgo; + if ( mostSimpleShape > -1 ) + { + algo = mesh->GetSubMesh( edge )->GetAlgo(); + SMESH_Hypothesis::Hypothesis_Status status; + if ( !algo->CheckHypothesis( *mesh, edge, status )) + algo = the1dAlgo; + } + + TmpMesh tmpMesh; + tmpMesh.ShapeToMesh( branchEdge ); + try { + mesh->GetGen()->Compute( tmpMesh, branchEdge, true, true ); // make nodes on VERTEXes + if ( !algo->Compute( tmpMesh, branchEdge )) + return false; + } + catch (...) { + return false; + } + return SMESH_Algo::GetNodeParamOnEdge( tmpMesh.GetMeshDS(), branchEdge, theMAParams ); + } + + //================================================================================ + /*! + * \brief Select division parameters on MA and make them coincide at ends with + * projections of VERTEXes to MA for a given pair of opposite EDGEs + * \param [in] theEdgePairInd - index of the EDGE pair + * \param [in] theDivPoints - the BranchPoint's dividing MA into parts each + * corresponding to a unique pair of opposite EDGEs + * \param [in] theMAParams - the MA division parameters + * \param [out] theSelectedMAParams - the selected MA parameters + * \return bool - is OK + */ + //================================================================================ + + bool getParamsForEdgePair( const size_t theEdgePairInd, + const vector< SMESH_MAT2d::BranchPoint >& theDivPoints, + const vector& theMAParams, + vector& theSelectedMAParams) + { + if ( theDivPoints.empty() ) + { + theSelectedMAParams = theMAParams; + return true; + } + if ( theEdgePairInd > theDivPoints.size() || theMAParams.empty() ) + return false; + + // find a range of params to copy + + double par1 = 0; + size_t iPar1 = 0; + if ( theEdgePairInd > 0 ) + { + const SMESH_MAT2d::BranchPoint& bp = theDivPoints[ theEdgePairInd-1 ]; + bp._branch->getParameter( bp, par1 ); + while ( theMAParams[ iPar1 ] < par1 ) ++iPar1; + if ( par1 - theMAParams[ iPar1-1 ] < theMAParams[ iPar1 ] - par1 ) + --iPar1; + } + + double par2 = 1; + size_t iPar2 = theMAParams.size() - 1; + if ( theEdgePairInd < theDivPoints.size() ) + { + const SMESH_MAT2d::BranchPoint& bp = theDivPoints[ theEdgePairInd ]; + bp._branch->getParameter( bp, par2 ); + iPar2 = iPar1; + while ( theMAParams[ iPar2 ] < par2 ) ++iPar2; + if ( par2 - theMAParams[ iPar2-1 ] < theMAParams[ iPar2 ] - par2 ) + --iPar2; + } + + theSelectedMAParams.assign( theMAParams.begin() + iPar1, + theMAParams.begin() + iPar2 + 1 ); + + // adjust theSelectedMAParams to fit between par1 and par2 + + double d = par1 - theSelectedMAParams[0]; + double f = ( par2 - par1 ) / ( theSelectedMAParams.back() - theSelectedMAParams[0] ); + + for ( size_t i = 0; i < theSelectedMAParams.size(); ++i ) + { + theSelectedMAParams[i] += d; + theSelectedMAParams[i] = par1 + ( theSelectedMAParams[i] - par1 ) * f; + } + + return true; + } + + //-------------------------------------------------------------------------------- + // node or node parameter on EDGE + struct NodePoint + { + const SMDS_MeshNode* _node; + double _u; + int _edgeInd; // index in theSinuEdges vector + + NodePoint(): _node(0), _u(0), _edgeInd(-1) {} + NodePoint(const SMDS_MeshNode* n, double u, size_t iEdge ): _node(n), _u(u), _edgeInd(iEdge) {} + NodePoint(double u, size_t iEdge) : _node(0), _u(u), _edgeInd(iEdge) {} + NodePoint(const SMESH_MAT2d::BoundaryPoint& p) : _node(0), _u(p._param), _edgeInd(p._edgeIndex) {} + gp_Pnt Point(const vector< Handle(Geom_Curve) >& curves) const + { + return _node ? SMESH_TNodeXYZ(_node) : curves[ _edgeInd ]->Value( _u ); + } + }; + typedef multimap< double, pair< NodePoint, NodePoint > > TMAPar2NPoints; + + //================================================================================ + /*! + * \brief Finds a VERTEX corresponding to a point on EDGE, which is also filled + * with a node on the VERTEX, present or created + * \param [in,out] theNodePnt - the node position on the EDGE + * \param [in] theSinuEdges - the sinuous EDGEs + * \param [in] theMeshDS - the mesh + * \return bool - true if the \a theBndPnt is on VERTEX + */ + //================================================================================ + + bool findVertexAndNode( NodePoint& theNodePnt, + const vector& theSinuEdges, + SMESHDS_Mesh* theMeshDS = 0, + size_t theEdgeIndPrev = 0, + size_t theEdgeIndNext = 0) + { + if ( theNodePnt._edgeInd >= theSinuEdges.size() ) + return false; + + double f,l; + BRep_Tool::Range( theSinuEdges[ theNodePnt._edgeInd ], f,l ); + const double tol = 1e-3 * ( l - f ); + + TopoDS_Vertex V; + if ( Abs( f - theNodePnt._u ) < tol ) + V = SMESH_MesherHelper::IthVertex( 0, theSinuEdges[ theNodePnt._edgeInd ], /*CumOri=*/false); + else if ( Abs( l - theNodePnt._u ) < tol ) + V = SMESH_MesherHelper::IthVertex( 1, theSinuEdges[ theNodePnt._edgeInd ], /*CumOri=*/false); + else if ( theEdgeIndPrev != theEdgeIndNext ) + TopExp::CommonVertex( theSinuEdges[theEdgeIndPrev], theSinuEdges[theEdgeIndNext], V ); + + if ( !V.IsNull() && theMeshDS ) + { + theNodePnt._node = SMESH_Algo::VertexNode( V, theMeshDS ); + if ( !theNodePnt._node ) + { + gp_Pnt p = BRep_Tool::Pnt( V ); + theNodePnt._node = theMeshDS->AddNode( p.X(), p.Y(), p.Z() ); + theMeshDS->SetNodeOnVertex( theNodePnt._node, V ); + } + } + return !V.IsNull(); + } + + //================================================================================ + /*! + * \brief Add to the map of NodePoint's those on VERTEXes + * \param [in,out] theHelper - the helper + * \param [in] theMA - Medial Axis + * \param [in] theMinSegLen - minimal segment length + * \param [in] theDivPoints - projections of VERTEXes to MA + * \param [in] theSinuEdges - the sinuous EDGEs + * \param [in] theSideEdgeIDs - indices of sinuous EDGEs per side + * \param [in] theIsEdgeComputed - is sinuous EGDE is meshed + * \param [in,out] thePointsOnE - the map to fill + * \param [out] theNodes2Merge - the map of nodes to merge + */ + //================================================================================ + + bool projectVertices( SMESH_MesherHelper& theHelper, + const SMESH_MAT2d::MedialAxis& theMA, + vector< SMESH_MAT2d::BranchPoint >& theDivPoints, + const vector< std::size_t > & theEdgeIDs1, + const vector< std::size_t > & theEdgeIDs2, + const vector< bool >& theIsEdgeComputed, + TMAPar2NPoints & thePointsOnE, + SinuousFace& theSinuFace) + { + if ( theDivPoints.empty() ) + return true; + + SMESHDS_Mesh* meshDS = theHelper.GetMeshDS(); + const vector< TopoDS_Edge >& theSinuEdges = theSinuFace._sinuEdges; + const vector< Handle(Geom_Curve) >& theCurves = theSinuFace._sinuCurves; + + double uMA; + SMESH_MAT2d::BoundaryPoint bp[2]; // 2 sinuous sides + const SMESH_MAT2d::Branch& branch = *theMA.getBranch(0); + { + // add to thePointsOnE NodePoint's of ends of theSinuEdges + if ( !branch.getBoundaryPoints( 0., bp[0], bp[1] ) || + !theMA.getBoundary().moveToClosestEdgeEnd( bp[0] )) return false; + if ( !theSinuFace.IsRing() && + !theMA.getBoundary().moveToClosestEdgeEnd( bp[1] )) return false; + NodePoint np0( bp[0] ), np1( bp[1] ); + findVertexAndNode( np0, theSinuEdges, meshDS ); + findVertexAndNode( np1, theSinuEdges, meshDS ); + thePointsOnE.insert( make_pair( -0.1, make_pair( np0, np1 ))); + } + if ( !theSinuFace.IsRing() ) + { + if ( !branch.getBoundaryPoints( 1., bp[0], bp[1] ) || + !theMA.getBoundary().moveToClosestEdgeEnd( bp[0] ) || + !theMA.getBoundary().moveToClosestEdgeEnd( bp[1] )) return false; + NodePoint np0( bp[0] ), np1( bp[1] ); + findVertexAndNode( np0, theSinuEdges, meshDS ); + findVertexAndNode( np1, theSinuEdges, meshDS ); + thePointsOnE.insert( make_pair( 1.1, make_pair( np0, np1))); + } + else + { + // project a VERTEX of outer sinuous side corresponding to branch(0.) + // which is not included into theDivPoints + if ( ! ( theDivPoints[0]._iEdge == 0 && + theDivPoints[0]._edgeParam == 0. )) // recursive call + { + SMESH_MAT2d::BranchPoint brp( &branch, 0, 0 ); + vector< SMESH_MAT2d::BranchPoint > divPoint( 1, brp ); + vector< std::size_t > edgeIDs1(2), edgeIDs2(2); + edgeIDs1[0] = theEdgeIDs1.back(); + edgeIDs1[1] = theEdgeIDs1[0]; + edgeIDs2[0] = theEdgeIDs2.back(); + edgeIDs2[1] = theEdgeIDs2[0]; + projectVertices( theHelper, theMA, divPoint, edgeIDs1, edgeIDs2, + theIsEdgeComputed, thePointsOnE, theSinuFace ); + } + } + + // project theDivPoints + + TMAPar2NPoints::iterator u2NP; + for ( size_t i = 0; i < theDivPoints.size(); ++i ) + { + if ( !branch.getParameter( theDivPoints[i], uMA )) + return false; + if ( !branch.getBoundaryPoints( theDivPoints[i], bp[0], bp[1] )) + return false; + + NodePoint np[2] = { + NodePoint( bp[0] ), + NodePoint( bp[1] ) + }; + bool isVertex[2] = { + findVertexAndNode( np[0], theSinuEdges, meshDS, theEdgeIDs1[i], theEdgeIDs1[i+1] ), + findVertexAndNode( np[1], theSinuEdges, meshDS, theEdgeIDs2[i], theEdgeIDs2[i+1] ) + }; + const size_t iVert = isVertex[0] ? 0 : 1; // side with a VERTEX + const size_t iNode = 1 - iVert; // opposite (meshed?) side + + if ( isVertex[0] != isVertex[1] ) // try to find an opposite VERTEX + { + theMA.getBoundary().moveToClosestEdgeEnd( bp[iNode] ); // EDGE -> VERTEX + SMESH_MAT2d::BranchPoint brp; + theMA.getBoundary().getBranchPoint( bp[iNode], brp ); // WIRE -> MA + SMESH_MAT2d::BoundaryPoint bp2[2]; + branch.getBoundaryPoints( brp, bp2[0], bp2[1] ); // MA -> WIRE + NodePoint np2[2] = { NodePoint( bp2[0]), NodePoint( bp2[1]) }; + findVertexAndNode( np2[0], theSinuEdges, meshDS ); + findVertexAndNode( np2[1], theSinuEdges, meshDS ); + if ( np2[ iVert ]._node == np[ iVert ]._node && + np2[ iNode ]._node) + { + np[ iNode ] = np2[ iNode ]; + isVertex[ iNode ] = true; + } + } + + u2NP = thePointsOnE.insert( make_pair( uMA, make_pair( np[0], np[1]))); + + if ( !isVertex[0] && !isVertex[1] ) return false; // error + if ( isVertex[0] && isVertex[1] ) + continue; + + bool isOppComputed = theIsEdgeComputed[ np[ iNode ]._edgeInd ]; + if ( !isOppComputed ) + continue; + + // a VERTEX is projected on a meshed EDGE; there are two options: + // 1) a projected point is joined with a closet node if a strip between this and neighbor + // projection is WIDE enough; joining is done by creating a node coincident with the + // existing node which will be merged together after all; + // 2) a neighbor projection is merged with this one if it is TOO CLOSE; a node of deleted + // projection is set to the BoundaryPoint of this projection + + // evaluate distance to neighbor projections + const double rShort = 0.33; + bool isShortPrev[2], isShortNext[2], isPrevCloser[2]; + TMAPar2NPoints::iterator u2NPPrev = u2NP, u2NPNext = u2NP; + --u2NPPrev; ++u2NPNext; + // bool hasPrev = ( u2NP != thePointsOnE.begin() ); + // bool hasNext = ( u2NPNext != thePointsOnE.end() ); + // if ( !hasPrev ) u2NPPrev = u2NP0; + // if ( !hasNext ) u2NPNext = u2NP1; + for ( int iS = 0; iS < 2; ++iS ) // side with Vertex and side with Nodes + { + NodePoint np = get( u2NP->second, iS ); + NodePoint npPrev = get( u2NPPrev->second, iS ); + NodePoint npNext = get( u2NPNext->second, iS ); + gp_Pnt p = np .Point( theCurves ); + gp_Pnt pPrev = npPrev.Point( theCurves ); + gp_Pnt pNext = npNext.Point( theCurves ); + double distPrev = p.Distance( pPrev ); + double distNext = p.Distance( pNext ); + double r = distPrev / ( distPrev + distNext ); + isShortPrev [iS] = ( r < rShort ); + isShortNext [iS] = (( 1 - r ) > ( 1 - rShort )); + isPrevCloser[iS] = (( r < 0.5 ) && ( u2NPPrev->first > 0 )); + } + // if ( !hasPrev ) isShortPrev[0] = isShortPrev[1] = false; + // if ( !hasNext ) isShortNext[0] = isShortNext[1] = false; + + TMAPar2NPoints::iterator u2NPClose; + + if (( isShortPrev[0] && isShortPrev[1] ) || // option 2) -> remove a too close projection + ( isShortNext[0] && isShortNext[1] )) + { + u2NPClose = isPrevCloser[0] ? u2NPPrev : u2NPNext; + NodePoint& npProj = get( u2NP->second, iNode ); // NP of VERTEX projection + NodePoint npCloseN = get( u2NPClose->second, iNode ); // NP close to npProj + NodePoint npCloseV = get( u2NPClose->second, iVert ); // NP close to VERTEX + if ( !npCloseV._node ) + { + npProj = npCloseN; + thePointsOnE.erase( isPrevCloser[0] ? u2NPPrev : u2NPNext ); + continue; + } + else + { + // can't remove the neighbor projection as it is also from VERTEX, -> option 1) + } + } + // else: option 1) - wide enough -> "duplicate" existing node + { + u2NPClose = isPrevCloser[ iNode ] ? u2NPPrev : u2NPNext; + NodePoint& npProj = get( u2NP->second, iNode ); // NP of VERTEX projection + NodePoint& npCloseN = get( u2NPClose->second, iNode ); // NP close to npProj + npProj = npCloseN; + npProj._node = 0; + //npProj._edgeInd = npCloseN._edgeInd; + // npProj._u = npCloseN._u + 1e-3 * Abs( get( u2NPPrev->second, iNode )._u - + // get( u2NPNext->second, iNode )._u ); + // gp_Pnt p = npProj.Point( theCurves ); + // npProj._node = meshDS->AddNode( p.X(), p.Y(), p.Z() ); + // meshDS->SetNodeOnEdge( npProj._node, theSinuEdges[ npProj._edgeInd ], npProj._u ); + + //theNodes2Merge[ npCloseN._node ].push_back( npProj._node ); + } + } + + // remove auxiliary NodePoint's of ends of theSinuEdges + for ( u2NP = thePointsOnE.begin(); u2NP->first < 0; ) + thePointsOnE.erase( u2NP++ ); + thePointsOnE.erase( 1.1 ); + + return true; + } + + double getUOnEdgeByPoint( const size_t iEdge, + const NodePoint* point, + SinuousFace& sinuFace ) + { + if ( point->_edgeInd == iEdge ) + return point->_u; + + TopoDS_Vertex V0 = TopExp::FirstVertex( sinuFace._sinuEdges[ iEdge ]); + TopoDS_Vertex V1 = TopExp::LastVertex ( sinuFace._sinuEdges[ iEdge ]); + gp_Pnt p0 = BRep_Tool::Pnt( V0 ); + gp_Pnt p1 = BRep_Tool::Pnt( V1 ); + gp_Pnt p = point->Point( sinuFace._sinuCurves ); + + double f,l; + BRep_Tool::Range( sinuFace._sinuEdges[ iEdge ], f,l ); + return p.SquareDistance( p0 ) < p.SquareDistance( p1 ) ? f : l; + } + + //================================================================================ + /*! + * \brief Move coincident nodes to make node params on EDGE unique + * \param [in] theHelper - the helper + * \param [in] thePointsOnE - nodes on two opposite river sides + * \param [in] theSinuFace - the sinuous FACE + * \param [out] theNodes2Merge - the map of nodes to merge + */ + //================================================================================ + + void separateNodes( SMESH_MesherHelper& theHelper, + const SMESH_MAT2d::MedialAxis& theMA, + TMAPar2NPoints & thePointsOnE, + SinuousFace& theSinuFace, + const vector< bool >& theIsComputedEdge) + { + if ( thePointsOnE.size() < 2 ) + return; + + SMESHDS_Mesh* meshDS = theHelper.GetMeshDS(); + const vector& theSinuEdges = theSinuFace._sinuEdges; + const vector< Handle(Geom_Curve) >& curves = theSinuFace._sinuCurves; + + SMESH_MAT2d::BoundaryPoint bp[2]; + const SMESH_MAT2d::Branch& branch = *theMA.getBranch(0); + + typedef TMAPar2NPoints::iterator TIterator; + + for ( int iSide = 0; iSide < 2; ++iSide ) // loop on two sinuous sides + { + // get a tolerance to compare points + double tol = Precision::Confusion(); + for ( size_t i = 0; i < theSinuFace._sinuSide[ iSide ].size(); ++i ) + tol = Max( tol , BRep_Tool::Tolerance( theSinuFace._sinuSide[ iSide ][ i ])); + + // find coincident points + TIterator u2NP = thePointsOnE.begin(); + vector< TIterator > sameU2NP( 1, u2NP++ ); + while ( u2NP != thePointsOnE.end() ) + { + for ( ; u2NP != thePointsOnE.end(); ++u2NP ) + { + NodePoint& np1 = get( sameU2NP.back()->second, iSide ); + NodePoint& np2 = get( u2NP ->second, iSide ); + + if (( !np1._node || !np2._node ) && + ( np1.Point( curves ).SquareDistance( np2.Point( curves )) < tol*tol )) + { + sameU2NP.push_back( u2NP ); + } + else if ( sameU2NP.size() == 1 ) + { + sameU2NP[ 0 ] = u2NP; + } + else + { + break; + } + } + + if ( sameU2NP.size() > 1 ) + { + // find an existing node on VERTEX among sameU2NP and get underlying EDGEs + const SMDS_MeshNode* existingNode = 0; + set< int > edgeInds; + NodePoint* np; + for ( size_t i = 0; i < sameU2NP.size(); ++i ) + { + np = &get( sameU2NP[i]->second, iSide ); + if ( np->_node ) + if ( !existingNode || np->_node->GetPosition()->GetDim() == 0 ) + existingNode = np->_node; + edgeInds.insert( np->_edgeInd ); + } + list< const SMDS_MeshNode* >& mergeNodes = theSinuFace._nodesToMerge[ existingNode ]; + + TIterator u2NPprev = sameU2NP.front(); + TIterator u2NPnext = sameU2NP.back() ; + if ( u2NPprev->first < 0. ) ++u2NPprev; + if ( u2NPnext->first > 1. ) --u2NPnext; + + set< int >::iterator edgeID = edgeInds.begin(); + for ( ; edgeID != edgeInds.end(); ++edgeID ) + { + // get U range on iEdge within which the equal points will be distributed + double u0, u1; + np = &get( u2NPprev->second, iSide ); + u0 = getUOnEdgeByPoint( *edgeID, np, theSinuFace ); + + np = &get( u2NPnext->second, iSide ); + u1 = getUOnEdgeByPoint( *edgeID, np, theSinuFace ); + + if ( u0 == u1 ) + { + if ( u2NPprev != thePointsOnE.begin() ) --u2NPprev; + if ( u2NPnext != --thePointsOnE.end() ) ++u2NPnext; + np = &get( u2NPprev->second, iSide ); + u0 = getUOnEdgeByPoint( *edgeID, np, theSinuFace ); + np = &get( u2NPnext->second, iSide ); + u1 = getUOnEdgeByPoint( *edgeID, np, theSinuFace ); + } + + // distribute points and create nodes + double du = ( u1 - u0 ) / ( sameU2NP.size() + 1 /*!existingNode*/ ); + double u = u0 + du; + for ( size_t i = 0; i < sameU2NP.size(); ++i ) + { + np = &get( sameU2NP[i]->second, iSide ); + if ( !np->_node && *edgeID == np->_edgeInd ) + { + np->_u = u; + u += du; + gp_Pnt p = np->Point( curves ); + np->_node = meshDS->AddNode( p.X(), p.Y(), p.Z() ); + meshDS->SetNodeOnEdge( np->_node, theSinuEdges[ *edgeID ], np->_u ); + + if ( theIsComputedEdge[ *edgeID ]) + mergeNodes.push_back( np->_node ); + } + } + } + + sameU2NP.resize( 1 ); + u2NP = ++sameU2NP.back(); + sameU2NP[ 0 ] = u2NP; + + } // if ( sameU2NP.size() > 1 ) + } // while ( u2NP != thePointsOnE.end() ) + } // for ( int iSide = 0; iSide < 2; ++iSide ) + + return; + } // separateNodes() + + //================================================================================ + /*! + * \brief Setup sides of SinuousFace::_quad + * \param [in] theHelper - helper + * \param [in] thePointsOnEdges - NodePoint's on sinuous sides + * \param [in,out] theSinuFace - the FACE + * \param [in] the1dAlgo - algorithm to use for radial discretization of a ring FACE + * \return bool - is OK + */ + //================================================================================ + + bool setQuadSides(SMESH_MesherHelper& theHelper, + const TMAPar2NPoints& thePointsOnEdges, + SinuousFace& theFace, + SMESH_Algo* the1dAlgo) + { + SMESH_Mesh* mesh = theHelper.GetMesh(); + const TopoDS_Face& face = theFace._quad->face; + SMESH_ProxyMesh::Ptr proxyMesh = StdMeshers_ViscousLayers2D::Compute( *mesh, face ); + if ( !proxyMesh ) + return false; + + list< TopoDS_Edge > side[4]; + side[0].insert( side[0].end(), theFace._shortSide[0].begin(), theFace._shortSide[0].end() ); + side[1].insert( side[1].end(), theFace._sinuSide[1].begin(), theFace._sinuSide[1].end() ); + side[2].insert( side[2].end(), theFace._shortSide[1].begin(), theFace._shortSide[1].end() ); + side[3].insert( side[3].end(), theFace._sinuSide[0].begin(), theFace._sinuSide[0].end() ); + + for ( int i = 0; i < 4; ++i ) + { + theFace._quad->side[i] = StdMeshers_FaceSide::New( face, side[i], mesh, i < QUAD_TOP_SIDE, + /*skipMediumNodes=*/true, proxyMesh ); + } + + if ( theFace.IsRing() ) + { + // -------------------------------------- + // Discretize a ring in radial direction + // -------------------------------------- + + if ( thePointsOnEdges.size() < 4 ) + return false; + + // find most distant opposite nodes + double maxDist = 0, dist; + TMAPar2NPoints::const_iterator u2NPdist, u2NP = thePointsOnEdges.begin(); + for ( ; u2NP != thePointsOnEdges.end(); ++u2NP ) + { + SMESH_TNodeXYZ xyz( u2NP->second.first._node ); // node out + dist = xyz.SquareDistance( u2NP->second.second._node );// node in + if ( dist > maxDist ) + { + u2NPdist = u2NP; + maxDist = dist; + } + } + // compute distribution of radial nodes + list< double > params; // normalized params + static_cast< StdMeshers_QuadFromMedialAxis_1D2D::Algo1D* > + ( the1dAlgo )->ComputeDistribution( theHelper, + SMESH_TNodeXYZ( u2NPdist->second.first._node ), + SMESH_TNodeXYZ( u2NPdist->second.second._node ), + params ); + + // add a radial quad side + u2NP = thePointsOnEdges.begin(); + const SMDS_MeshNode* nOut = u2NP->second.first._node; + const SMDS_MeshNode* nIn = u2NP->second.second._node; + nOut = proxyMesh->GetProxyNode( nOut ); + nIn = proxyMesh->GetProxyNode( nIn ); + gp_XY uvOut = theHelper.GetNodeUV( face, nOut ); + gp_XY uvIn = theHelper.GetNodeUV( face, nIn ); + Handle(Geom_Surface) surface = BRep_Tool::Surface( face ); + UVPtStructVec uvsNew; UVPtStruct uvPt; + uvPt.node = nOut; + uvPt.u = uvOut.X(); + uvPt.v = uvOut.Y(); + uvsNew.push_back( uvPt ); + for (list::iterator itU = params.begin(); itU != params.end(); ++itU ) + { + gp_XY uv = ( 1 - *itU ) * uvOut + *itU * uvIn; + gp_Pnt p = surface->Value( uv.X(), uv.Y() ); + uvPt.node = theHelper.AddNode( p.X(), p.Y(), p.Z(), /*id=*/0, uv.X(), uv.Y() ); + uvPt.u = uv.X(); + uvPt.v = uv.Y(); + uvsNew.push_back( uvPt ); + } + uvPt.node = nIn; + uvPt.u = uvIn.X(); + uvPt.v = uvIn.Y(); + uvsNew.push_back( uvPt ); + + theFace._quad->side[ 0 ] = StdMeshers_FaceSide::New( uvsNew ); + theFace._quad->side[ 2 ] = theFace._quad->side[ 0 ]; + + if ( theFace._quad->side[ 1 ].GetUVPtStruct().empty() || + theFace._quad->side[ 3 ].GetUVPtStruct().empty() ) + return false; + + // assure that the outer sinuous side starts at nOut + if ( theFace._sinuSide[0].size() > 1 ) + { + const UVPtStructVec& uvsOut = theFace._quad->side[ 3 ].GetUVPtStruct(); // _sinuSide[0] + size_t i; // find UVPtStruct holding nOut + for ( i = 0; i < uvsOut.size(); ++i ) + if ( nOut == uvsOut[i].node ) + break; + if ( i == uvsOut.size() ) + return false; + + if ( i != 0 && i != uvsOut.size()-1 ) + { + // create a new OUT quad side + uvsNew.clear(); + uvsNew.reserve( uvsOut.size() ); + uvsNew.insert( uvsNew.end(), uvsOut.begin() + i, uvsOut.end() ); + uvsNew.insert( uvsNew.end(), uvsOut.begin() + 1, uvsOut.begin() + i + 1); + theFace._quad->side[ 3 ] = StdMeshers_FaceSide::New( uvsNew ); + } + } + + // rotate the IN side if opposite nodes of IN and OUT sides don't match + const SMDS_MeshNode * nIn0 = theFace._quad->side[ 1 ].First().node; + if ( nIn0 != nIn ) + { + nIn = proxyMesh->GetProxyNode( nIn ); + const UVPtStructVec& uvsIn = theFace._quad->side[ 1 ].GetUVPtStruct(); // _sinuSide[1] + size_t i; // find UVPtStruct holding nIn + for ( i = 0; i < uvsIn.size(); ++i ) + if ( nIn == uvsIn[i].node ) + break; + if ( i == uvsIn.size() ) + return false; + + // create a new IN quad side + uvsNew.clear(); + uvsNew.reserve( uvsIn.size() ); + uvsNew.insert( uvsNew.end(), uvsIn.begin() + i, uvsIn.end() ); + uvsNew.insert( uvsNew.end(), uvsIn.begin() + 1, uvsIn.begin() + i + 1); + theFace._quad->side[ 1 ] = StdMeshers_FaceSide::New( uvsNew ); + } + + if ( theFace._quad->side[ 1 ].GetUVPtStruct().empty() || + theFace._quad->side[ 3 ].GetUVPtStruct().empty() ) + return false; + + } // if ( theFace.IsRing() ) + + return true; + + } // setQuadSides() + + //================================================================================ + /*! + * \brief Divide the sinuous EDGEs by projecting the division point of Medial + * Axis to the EGDEs + * \param [in] theHelper - the helper + * \param [in] theMinSegLen - minimal segment length + * \param [in] theMA - the Medial Axis + * \param [in] theMAParams - parameters of division points of \a theMA + * \param [in] theSinuEdges - the EDGEs to make nodes on + * \param [in] theSinuSide0Size - the number of EDGEs in the 1st sinuous side + * \param [in] the1dAlgo - algorithm to use for radial discretization of a ring FACE + * \return bool - is OK or not + */ + //================================================================================ + + bool computeSinuEdges( SMESH_MesherHelper& theHelper, + double /*theMinSegLen*/, + SMESH_MAT2d::MedialAxis& theMA, + vector& theMAParams, + SinuousFace& theSinuFace, + SMESH_Algo* the1dAlgo) + { + if ( theMA.nbBranches() != 1 ) + return false; + + // normalize theMAParams + for ( size_t i = 0; i < theMAParams.size(); ++i ) + theMAParams[i] /= theMAParams.back(); + + + SMESH_Mesh* mesh = theHelper.GetMesh(); + SMESHDS_Mesh* meshDS = theHelper.GetMeshDS(); + double f,l; + + // get data of sinuous EDGEs and remove unnecessary nodes + const vector< TopoDS_Edge >& theSinuEdges = theSinuFace._sinuEdges; + vector< Handle(Geom_Curve) >& curves = theSinuFace._sinuCurves; + vector< int > edgeIDs ( theSinuEdges.size() ); // IDs in the main shape + vector< bool > isComputed( theSinuEdges.size() ); + curves.resize( theSinuEdges.size(), 0 ); + bool allComputed = true; + for ( size_t i = 0; i < theSinuEdges.size(); ++i ) + { + curves[i] = BRep_Tool::Curve( theSinuEdges[i], f,l ); + if ( !curves[i] ) + return false; + SMESH_subMesh* sm = mesh->GetSubMesh( theSinuEdges[i] ); + edgeIDs [i] = sm->GetId(); + isComputed[i] = ( !sm->IsEmpty() ); + if ( !isComputed[i] ) + allComputed = false; + } + + const SMESH_MAT2d::Branch& branch = *theMA.getBranch(0); + SMESH_MAT2d::BoundaryPoint bp[2]; + + vector< std::size_t > edgeIDs1, edgeIDs2; // indices in theSinuEdges + vector< SMESH_MAT2d::BranchPoint > divPoints; + if ( !allComputed ) + branch.getOppositeGeomEdges( edgeIDs1, edgeIDs2, divPoints ); + + for ( size_t i = 0; i < edgeIDs1.size(); ++i ) + if ( isComputed[ edgeIDs1[i]] && + isComputed[ edgeIDs2[i]] ) + { + int nbNodes1 = meshDS->MeshElements(edgeIDs[ edgeIDs1[i]] )->NbNodes(); + int nbNodes2 = meshDS->MeshElements(edgeIDs[ edgeIDs2[i]] )->NbNodes(); + if ( nbNodes1 != nbNodes2 ) + return false; + if (( i-1 >= 0 ) && + ( edgeIDs1[i-1] == edgeIDs1[i] || + edgeIDs2[i-1] == edgeIDs2[i] )) + return false; + if (( i+1 < edgeIDs1.size() ) && + ( edgeIDs1[i+1] == edgeIDs1[i] || + edgeIDs2[i+1] == edgeIDs2[i] )) + return false; + } + + // map (param on MA) to (parameters of nodes on a pair of theSinuEdges) + TMAPar2NPoints pointsOnE; + vector maParams; + set projectedEdges; // treated EDGEs which 'isComputed' + + // compute params of nodes on EDGEs by projecting division points from MA + + for ( size_t iEdgePair = 0; iEdgePair < edgeIDs1.size(); ++iEdgePair ) + // loop on pairs of opposite EDGEs + { + if ( projectedEdges.count( edgeIDs1[ iEdgePair ]) || + projectedEdges.count( edgeIDs2[ iEdgePair ]) ) + continue; + + // -------------------------------------------------------------------------------- + if ( isComputed[ edgeIDs1[ iEdgePair ]] != // one EDGE is meshed + isComputed[ edgeIDs2[ iEdgePair ]]) + { + // "projection" from one side to the other + + size_t iEdgeComputed = edgeIDs1[iEdgePair], iSideComputed = 0; + if ( !isComputed[ iEdgeComputed ]) + ++iSideComputed, iEdgeComputed = edgeIDs2[iEdgePair]; + + map< double, const SMDS_MeshNode* > nodeParams; // params of existing nodes + if ( !SMESH_Algo::GetSortedNodesOnEdge( meshDS, theSinuEdges[ iEdgeComputed ], /*skipMedium=*/true, nodeParams )) + return false; + + projectedEdges.insert( iEdgeComputed ); + + SMESH_MAT2d::BoundaryPoint& bndPnt = bp[ 1-iSideComputed ]; + SMESH_MAT2d::BranchPoint brp; + NodePoint npN, npB; // NodePoint's initialized by node and BoundaryPoint + NodePoint& np0 = iSideComputed ? npB : npN; + NodePoint& np1 = iSideComputed ? npN : npB; + + double maParam1st, maParamLast, maParam; + if ( !theMA.getBoundary().getBranchPoint( iEdgeComputed, nodeParams.begin()->first, brp )) + return false; + branch.getParameter( brp, maParam1st ); + if ( !theMA.getBoundary().getBranchPoint( iEdgeComputed, nodeParams.rbegin()->first, brp )) + return false; + branch.getParameter( brp, maParamLast ); + + map< double, const SMDS_MeshNode* >::iterator u2n = nodeParams.begin(), u2nEnd = nodeParams.end(); + TMAPar2NPoints::iterator end = pointsOnE.end(), pos = end; + TMAPar2NPoints::iterator & hint = (maParamLast > maParam1st) ? end : pos; + for ( ++u2n, --u2nEnd; u2n != u2nEnd; ++u2n ) + { + // point on EDGE (u2n) --> MA point (brp) + if ( !theMA.getBoundary().getBranchPoint( iEdgeComputed, u2n->first, brp )) + return false; + // MA point --> points on 2 EDGEs (bp) + if ( !branch.getBoundaryPoints( brp, bp[0], bp[1] ) || + !branch.getParameter( brp, maParam )) + return false; + + npN = NodePoint( u2n->second, u2n->first, iEdgeComputed ); + npB = NodePoint( bndPnt ); + pos = pointsOnE.insert( hint, make_pair( maParam, make_pair( np0, np1 ))); + } + } + // -------------------------------------------------------------------------------- + else if ( !isComputed[ edgeIDs1[ iEdgePair ]] && // none of EDGEs is meshed + !isComputed[ edgeIDs2[ iEdgePair ]]) + { + // "projection" from MA + maParams.clear(); + if ( !getParamsForEdgePair( iEdgePair, divPoints, theMAParams, maParams )) + return false; + + for ( size_t i = 1; i < maParams.size()-1; ++i ) + { + if ( !branch.getBoundaryPoints( maParams[i], bp[0], bp[1] )) + return false; + + pointsOnE.insert( pointsOnE.end(), make_pair( maParams[i], make_pair( NodePoint(bp[0]), + NodePoint(bp[1])))); + } + } + // -------------------------------------------------------------------------------- + else if ( isComputed[ edgeIDs1[ iEdgePair ]] && // equally meshed EDGES + isComputed[ edgeIDs2[ iEdgePair ]]) + { + // add existing nodes + + size_t iE0 = edgeIDs1[ iEdgePair ]; + size_t iE1 = edgeIDs2[ iEdgePair ]; + map< double, const SMDS_MeshNode* > nodeParams[2]; // params of existing nodes + if ( !SMESH_Algo::GetSortedNodesOnEdge( meshDS, theSinuEdges[ iE0 ], + /*skipMedium=*/false, nodeParams[0] ) || + !SMESH_Algo::GetSortedNodesOnEdge( meshDS, theSinuEdges[ iE1 ], + /*skipMedium=*/false, nodeParams[1] ) || + nodeParams[0].size() != nodeParams[1].size() ) + return false; + + if ( nodeParams[0].size() <= 2 ) + continue; // nodes on VERTEXes only + + bool reverse = ( theSinuEdges[0].Orientation() == theSinuEdges[1].Orientation() ); + double maParam; + SMESH_MAT2d::BranchPoint brp; + std::pair< NodePoint, NodePoint > npPair; + + map< double, const SMDS_MeshNode* >::iterator + u2n0F = ++nodeParams[0].begin(), + u2n1F = ++nodeParams[1].begin(); + map< double, const SMDS_MeshNode* >::reverse_iterator + u2n1R = ++nodeParams[1].rbegin(); + for ( ; u2n0F != nodeParams[0].end(); ++u2n0F ) + { + if ( !theMA.getBoundary().getBranchPoint( iE0, u2n0F->first, brp ) || + !branch.getParameter( brp, maParam )) + return false; + + npPair.first = NodePoint( u2n0F->second, u2n0F->first, iE0 ); + if ( reverse ) + { + npPair.second = NodePoint( u2n1R->second, u2n1R->first, iE1 ); + ++u2n1R; + } + else + { + npPair.second = NodePoint( u2n1F->second, u2n1F->first, iE1 ); + ++u2n1F; + } + pointsOnE.insert( make_pair( maParam, npPair )); + } + } + } // loop on pairs of opposite EDGEs + + if ( !projectVertices( theHelper, theMA, divPoints, edgeIDs1, edgeIDs2, + isComputed, pointsOnE, theSinuFace )) + return false; + + separateNodes( theHelper, theMA, pointsOnE, theSinuFace, isComputed ); + + // create nodes + TMAPar2NPoints::iterator u2np = pointsOnE.begin(); + for ( ; u2np != pointsOnE.end(); ++u2np ) + { + NodePoint* np[2] = { & u2np->second.first, & u2np->second.second }; + for ( int iSide = 0; iSide < 2; ++iSide ) + { + if ( np[ iSide ]->_node ) continue; + size_t iEdge = np[ iSide ]->_edgeInd; + double u = np[ iSide ]->_u; + gp_Pnt p = curves[ iEdge ]->Value( u ); + np[ iSide ]->_node = meshDS->AddNode( p.X(), p.Y(), p.Z() ); + meshDS->SetNodeOnEdge( np[ iSide ]->_node, edgeIDs[ iEdge ], u ); + } + } + + // create mesh segments on EDGEs + theHelper.SetElementsOnShape( false ); + TopoDS_Face face = TopoDS::Face( theHelper.GetSubShape() ); + for ( size_t i = 0; i < theSinuEdges.size(); ++i ) + { + SMESH_subMesh* sm = mesh->GetSubMesh( theSinuEdges[i] ); + if ( sm->GetSubMeshDS() && sm->GetSubMeshDS()->NbElements() > 0 ) + continue; + + StdMeshers_FaceSide side( face, theSinuEdges[i], mesh, + /*isFwd=*/true, /*skipMediumNodes=*/true ); + vector nodes = side.GetOrderedNodes(); + for ( size_t in = 1; in < nodes.size(); ++in ) + { + const SMDS_MeshElement* seg = theHelper.AddEdge( nodes[in-1], nodes[in], 0, false ); + meshDS->SetMeshElementOnShape( seg, edgeIDs[ i ] ); + } + } + + // update sub-meshes on VERTEXes + for ( size_t i = 0; i < theSinuEdges.size(); ++i ) + { + mesh->GetSubMesh( theHelper.IthVertex( 0, theSinuEdges[i] )) + ->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + mesh->GetSubMesh( theHelper.IthVertex( 1, theSinuEdges[i] )) + ->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + + // Setup sides of a quadrangle + if ( !setQuadSides( theHelper, pointsOnE, theSinuFace, the1dAlgo )) + return false; + + return true; + } + + //================================================================================ + /*! + * \brief Mesh short EDGEs + */ + //================================================================================ + + bool computeShortEdges( SMESH_MesherHelper& theHelper, + const vector& theShortEdges, + SMESH_Algo* the1dAlgo, + const bool theHasRadialHyp, + const bool theIs2nd) + { + SMESH_Hypothesis::Hypothesis_Status aStatus; + for ( size_t i = 0; i < theShortEdges.size(); ++i ) + { + if ( !theHasRadialHyp ) + // use global hyps + theHelper.GetGen()->Compute( *theHelper.GetMesh(), theShortEdges[i], true, true ); + + SMESH_subMesh* sm = theHelper.GetMesh()->GetSubMesh(theShortEdges[i] ); + if ( sm->IsEmpty() ) + { + // use 2D hyp or minSegLen + try { + // compute VERTEXes + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/false); + while ( smIt->more() ) + smIt->next()->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + + // compute EDGE + the1dAlgo->CheckHypothesis( *theHelper.GetMesh(), theShortEdges[i], aStatus ); + if ( !the1dAlgo->Compute( *theHelper.GetMesh(), theShortEdges[i] )) + return false; + } + catch (...) { + return false; + } + sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + if ( sm->IsEmpty() ) + return false; + } + } + return true; + } + + inline double area( const UVPtStruct& p1, const UVPtStruct& p2, const UVPtStruct& p3 ) + { + gp_XY v1 = p2.UV() - p1.UV(); + gp_XY v2 = p3.UV() - p1.UV(); + return v2 ^ v1; + } + + bool ellipticSmooth( FaceQuadStruct::Ptr quad, int nbLoops ) + { + //nbLoops = 10; + if ( quad->uv_grid.empty() ) + return true; + + int nbhoriz = quad->iSize; + int nbvertic = quad->jSize; + + const double dksi = 0.5, deta = 0.5; + const double dksi2 = dksi*dksi, deta2 = deta*deta; + double err = 0., g11, g22, g12; + int nbErr = 0; + + FaceQuadStruct& q = *quad; + UVPtStruct pNew; + + double refArea = area( q.UVPt(0,0), q.UVPt(1,0), q.UVPt(1,1) ); + + for ( int iLoop = 0; iLoop < nbLoops; ++iLoop ) + { + err = 0; + for ( int i = 1; i < nbhoriz - 1; i++ ) + for ( int j = 1; j < nbvertic - 1; j++ ) + { + g11 = ( (q.U(i,j+1) - q.U(i,j-1))*(q.U(i,j+1) - q.U(i,j-1))/dksi2 + + (q.V(i,j+1) - q.V(i,j-1))*(q.V(i,j+1) - q.V(i,j-1))/deta2 )/4; + + g22 = ( (q.U(i+1,j) - q.U(i-1,j))*(q.U(i+1,j) - q.U(i-1,j))/dksi2 + + (q.V(i+1,j) - q.V(i-1,j))*(q.V(i+1,j) - q.V(i-1,j))/deta2 )/4; + + g12 = ( (q.U(i+1,j) - q.U(i-1,j))*(q.U(i,j+1) - q.U(i,j-1))/dksi2 + + (q.V(i+1,j) - q.V(i-1,j))*(q.V(i,j+1) - q.V(i,j-1))/deta2 )/(4*dksi*deta); + + pNew.u = dksi2/(2*(g11+g22)) * (g11*(q.U(i+1,j) + q.U(i-1,j))/dksi2 + + g22*(q.U(i,j+1) + q.U(i,j-1))/dksi2 + - 0.5*g12*q.U(i+1,j+1) + 0.5*g12*q.U(i-1,j+1) + + - 0.5*g12*q.U(i-1,j-1) + 0.5*g12*q.U(i+1,j-1)); + + pNew.v = deta2/(2*(g11+g22)) * (g11*(q.V(i+1,j) + q.V(i-1,j))/deta2 + + g22*(q.V(i,j+1) + q.V(i,j-1))/deta2 + - 0.5*g12*q.V(i+1,j+1) + 0.5*g12*q.V(i-1,j+1) + + - 0.5*g12*q.V(i-1,j-1) + 0.5*g12*q.V(i+1,j-1)); + + // if (( refArea * area( q.UVPt(i-1,j-1), q.UVPt(i,j-1), pNew ) > 0 ) && + // ( refArea * area( q.UVPt(i+1,j-1), q.UVPt(i+1,j), pNew ) > 0 ) && + // ( refArea * area( q.UVPt(i+1,j+1), q.UVPt(i,j+1), pNew ) > 0 ) && + // ( refArea * area( q.UVPt(i-1,j), q.UVPt(i-1,j-1), pNew ) > 0 )) + { + err += sqrt(( q.U(i,j) - pNew.u ) * ( q.U(i,j) - pNew.u ) + + ( q.V(i,j) - pNew.v ) * ( q.V(i,j) - pNew.v )); + q.U(i,j) = pNew.u; + q.V(i,j) = pNew.v; + } + // else if ( ++nbErr < 10 ) + // { + // cout << i << ", " << j << endl; + // cout << "x = [" + // << "[ " << q.U(i-1,j-1) << ", " <first ) continue; + nodesGroups.push_back( list< const SMDS_MeshNode* >() ); + list< const SMDS_MeshNode* > & group = nodesGroups.back(); + + group.push_back( n2nn->first ); + group.splice( group.end(), n2nn->second ); + } + editor.MergeNodes( nodesGroups ); + } + +} // namespace + +//================================================================================ +/*! + * \brief Sets event listener which removes mesh from EDGEs when 2D hyps change + */ +//================================================================================ + +void StdMeshers_QuadFromMedialAxis_1D2D::SetEventListener(SMESH_subMesh* faceSubMesh) +{ + faceSubMesh->SetEventListener( new EdgeCleaner, 0, faceSubMesh ); +} + +//================================================================================ +/*! + * \brief Create quadrangle elements + * \param [in] theHelper - the helper + * \param [in] theFace - the face to mesh + * \param [in] theSinuEdges - the sinuous EDGEs + * \param [in] theShortEdges - the short EDGEs + * \return bool - is OK or not + */ +//================================================================================ + +bool StdMeshers_QuadFromMedialAxis_1D2D::computeQuads( SMESH_MesherHelper& theHelper, + FaceQuadStruct::Ptr theQuad) +{ + StdMeshers_Quadrangle_2D::myHelper = &theHelper; + StdMeshers_Quadrangle_2D::myNeedSmooth = false; + StdMeshers_Quadrangle_2D::myCheckOri = false; + StdMeshers_Quadrangle_2D::myQuadList.clear(); + + int nbNodesShort0 = theQuad->side[0].NbPoints(); + int nbNodesShort1 = theQuad->side[2].NbPoints(); + + // compute UV of internal points + myQuadList.push_back( theQuad ); + if ( !StdMeshers_Quadrangle_2D::setNormalizedGrid( theQuad )) + return false; + + // elliptic smooth of internal points to get boundary cell normal to the boundary + bool isRing = theQuad->side[0].grid->Edge(0).IsNull(); + if ( !isRing ) + ellipticSmooth( theQuad, 1 ); + + // create quadrangles + bool ok; + theHelper.SetElementsOnShape( true ); + if ( nbNodesShort0 == nbNodesShort1 ) + ok = StdMeshers_Quadrangle_2D::computeQuadDominant( *theHelper.GetMesh(), + theQuad->face, theQuad ); + else + ok = StdMeshers_Quadrangle_2D::computeTriangles( *theHelper.GetMesh(), + theQuad->face, theQuad ); + + StdMeshers_Quadrangle_2D::myHelper = 0; + + return ok; +} + +//================================================================================ +/*! + * \brief Generate quadrangle mesh + */ +//================================================================================ + +bool StdMeshers_QuadFromMedialAxis_1D2D::Compute(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape) +{ + SMESH_MesherHelper helper( theMesh ); + helper.SetSubShape( theShape ); + + TopoDS_Face F = TopoDS::Face( theShape ); + if ( F.Orientation() >= TopAbs_INTERNAL ) F.Orientation( TopAbs_FORWARD ); + + SinuousFace sinuFace( F ); + + _progress = 0.01; + + if ( getSinuousEdges( helper, sinuFace )) + { + _progress = 0.4; + + double minSegLen = getMinSegLen( helper, sinuFace._sinuEdges ); + SMESH_MAT2d::MedialAxis ma( F, sinuFace._sinuEdges, minSegLen, /*ignoreCorners=*/true ); + + if ( !_regular1D ) + _regular1D = new Algo1D( _studyId, _gen ); + _regular1D->SetSegmentLength( minSegLen ); + + vector maParams; + if ( ! divideMA( helper, ma, sinuFace, _regular1D, minSegLen, maParams )) + return error(COMPERR_BAD_SHAPE); + + _progress = 0.8; + if ( _hyp2D ) + _regular1D->SetRadialDistribution( _hyp2D ); + + if ( !computeShortEdges( helper, sinuFace._shortSide[0], _regular1D, _hyp2D, 0 ) || + !computeShortEdges( helper, sinuFace._shortSide[1], _regular1D, _hyp2D, 1 )) + return error("Failed to mesh short edges"); + + _progress = 0.85; + + if ( !computeSinuEdges( helper, minSegLen, ma, maParams, sinuFace, _regular1D )) + return error("Failed to mesh sinuous edges"); + + _progress = 0.9; + + bool ok = computeQuads( helper, sinuFace._quad ); + + if ( ok ) + mergeNodes( helper, sinuFace ); + + _progress = 1.; + + return ok; + } + + return error(COMPERR_BAD_SHAPE, "Not implemented so far"); +} + +//================================================================================ +/*! + * \brief Predict nb of elements + */ +//================================================================================ + +bool StdMeshers_QuadFromMedialAxis_1D2D::Evaluate(SMESH_Mesh & theMesh, + const TopoDS_Shape & theShape, + MapShapeNbElems& theResMap) +{ + return StdMeshers_Quadrangle_2D::Evaluate(theMesh,theShape,theResMap); +} + +//================================================================================ +/*! + * \brief Return true if the algorithm can mesh this shape + * \param [in] aShape - shape to check + * \param [in] toCheckAll - if true, this check returns OK if all shapes are OK, + * else, returns OK if at least one shape is OK + */ +//================================================================================ + +bool StdMeshers_QuadFromMedialAxis_1D2D::IsApplicable( const TopoDS_Shape & aShape, + bool toCheckAll ) +{ + TmpMesh tmpMesh; + SMESH_MesherHelper helper( tmpMesh ); + + int nbFoundFaces = 0; + for (TopExp_Explorer exp( aShape, TopAbs_FACE ); exp.More(); exp.Next(), ++nbFoundFaces ) + { + const TopoDS_Face& face = TopoDS::Face( exp.Current() ); + SinuousFace sinuFace( face ); + bool isApplicable = getSinuousEdges( helper, sinuFace ); + + if ( toCheckAll && !isApplicable ) return false; + if ( !toCheckAll && isApplicable ) return true; + } + return ( toCheckAll && nbFoundFaces != 0 ); +} + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.cpp index 3ce1d9a73f0b..1832f48e778e 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.cpp @@ -1,129 +1,424 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 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, or (at your option) any later version. // -// 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. // -// 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 // -// 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 // -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// SMESH SMESH : implementaion of SMESH idl descriptions + // File : StdMeshers_QuadToTriaAdaptor.cxx // Module : SMESH // Created : Wen May 07 16:37:07 2008 // Author : Sergey KUUL (skl) -// -#ifdef _MSC_VER -#define _USE_MATH_DEFINES -#endif // _MSC_VER -#include #include "StdMeshers_QuadToTriaAdaptor.hxx" -#include -#include -#include +#include "SMDS_SetIterator.hxx" +#include "SMESHDS_GroupBase.hxx" +#include "SMESH_Algo.hxx" +#include "SMESH_Group.hxx" +#include "SMESH_MeshAlgos.hxx" +#include "SMESH_MesherHelper.hxx" #include #include -#include +#include +#include #include #include #include #include #include -#ifndef PI -#define PI M_PI -#endif +#include "utilities.h" -#ifndef __BORLANDC__ -#include -typedef NCollection_Array1 StdMeshers_Array1OfSequenceOfInteger; -#else -#include -typedef SMESH_Array1 StdMeshers_Array1OfSequenceOfInteger; -#endif +#include +#include +#include +using namespace std; -//======================================================================= -//function : StdMeshers_QuadToTriaAdaptor -//purpose : -//======================================================================= +enum EQuadNature { NOT_QUAD, QUAD, DEGEN_QUAD, PYRAM_APEX = 4, TRIA_APEX = 0 }; -StdMeshers_QuadToTriaAdaptor::StdMeshers_QuadToTriaAdaptor() +// std-like iterator used to get coordinates of nodes of mesh element +typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator; + +namespace { + //================================================================================ + /*! + * \brief Return true if two nodes of triangles are equal + */ + //================================================================================ + + bool EqualTriangles(const SMDS_MeshElement* F1,const SMDS_MeshElement* F2) + { + return + ( F1->GetNode(1)==F2->GetNode(2) && F1->GetNode(2)==F2->GetNode(1) ) || + ( F1->GetNode(1)==F2->GetNode(1) && F1->GetNode(2)==F2->GetNode(2) ); + } + //================================================================================ + /*! + * \brief Return true if two adjacent pyramids are too close one to another + * so that a tetrahedron to built between them would have too poor quality + */ + //================================================================================ + + bool TooCloseAdjacent( const SMDS_MeshElement* PrmI, + const SMDS_MeshElement* PrmJ, + const bool hasShape) + { + const SMDS_MeshNode* nApexI = PrmI->GetNode(4); + const SMDS_MeshNode* nApexJ = PrmJ->GetNode(4); + if ( nApexI == nApexJ || + nApexI->getshapeId() != nApexJ->getshapeId() ) + return false; + + // Find two common base nodes and their indices within PrmI and PrmJ + const SMDS_MeshNode* baseNodes[2] = { 0,0 }; + int baseNodesIndI[2], baseNodesIndJ[2]; + for ( int i = 0; i < 4 ; ++i ) + { + int j = PrmJ->GetNodeIndex( PrmI->GetNode(i)); + if ( j >= 0 ) + { + int ind = baseNodes[0] ? 1:0; + if ( baseNodes[ ind ]) + return false; // pyramids with a common base face + baseNodes [ ind ] = PrmI->GetNode(i); + baseNodesIndI[ ind ] = i; + baseNodesIndJ[ ind ] = j; + } + } + if ( !baseNodes[1] ) return false; // not adjacent + + // Get normals of triangles sharing baseNodes + gp_XYZ apexI = SMESH_TNodeXYZ( nApexI ); + gp_XYZ apexJ = SMESH_TNodeXYZ( nApexJ ); + gp_XYZ base1 = SMESH_TNodeXYZ( baseNodes[0]); + gp_XYZ base2 = SMESH_TNodeXYZ( baseNodes[1]); + gp_Vec baseVec( base1, base2 ); + gp_Vec baI( base1, apexI ); + gp_Vec baJ( base1, apexJ ); + gp_Vec nI = baseVec.Crossed( baI ); + gp_Vec nJ = baseVec.Crossed( baJ ); + + // Check angle between normals + double angle = nI.Angle( nJ ); + bool tooClose = ( angle < 15. * M_PI / 180. ); + + // Check if pyramids collide + if ( !tooClose && ( baI * baJ > 0 ) && ( nI * nJ > 0 )) + { + // find out if nI points outside of PrmI or inside + int dInd = baseNodesIndI[1] - baseNodesIndI[0]; + bool isOutI = ( abs(dInd)==1 ) ? dInd < 0 : dInd > 0; + + // find out sign of projection of nJ to baI + double proj = baI * nJ; + + tooClose = isOutI ? proj > 0 : proj < 0; + } + + // Check if PrmI and PrmJ are in same domain + if ( tooClose && !hasShape ) + { + // check order of baseNodes within pyramids, it must be opposite + int dInd; + dInd = baseNodesIndI[1] - baseNodesIndI[0]; + bool isOutI = ( abs(dInd)==1 ) ? dInd < 0 : dInd > 0; + dInd = baseNodesIndJ[1] - baseNodesIndJ[0]; + bool isOutJ = ( abs(dInd)==1 ) ? dInd < 0 : dInd > 0; + if ( isOutJ == isOutI ) + return false; // other domain + + // direct both normals outside pyramid + ( isOutI ? nJ : nI ).Reverse(); + + // check absence of a face separating domains between pyramids + TIDSortedElemSet emptySet, avoidSet; + int i1, i2; + while ( const SMDS_MeshElement* f = + SMESH_MeshAlgos::FindFaceInSet( baseNodes[0], baseNodes[1], + emptySet, avoidSet, &i1, &i2 )) + { + avoidSet.insert( f ); + + // face node other than baseNodes + int otherNodeInd = 0; + while ( otherNodeInd == i1 || otherNodeInd == i2 ) otherNodeInd++; + const SMDS_MeshNode* otherFaceNode = f->GetNode( otherNodeInd ); + + if ( otherFaceNode == nApexI || otherFaceNode == nApexJ ) + continue; // f is a temporary triangle + + // check if f is a base face of either of pyramids + if ( f->NbCornerNodes() == 4 && + ( PrmI->GetNodeIndex( otherFaceNode ) >= 0 || + PrmJ->GetNodeIndex( otherFaceNode ) >= 0 )) + continue; // f is a base quadrangle + + // check projections of face direction (baOFN) to triange normals (nI and nJ) + gp_Vec baOFN( base1, SMESH_TNodeXYZ( otherFaceNode )); + if ( nI * baOFN > 0 && nJ * baOFN > 0 ) + { + tooClose = false; // f is between pyramids + break; + } + } + } + + return tooClose; + } + + //================================================================================ + /*! + * \brief Move medium nodes of merged quadratic pyramids + */ + //================================================================================ + + void UpdateQuadraticPyramids(const set& commonApex, + SMESHDS_Mesh* meshDS) + { + typedef SMDS_StdIterator< const SMDS_MeshElement*, SMDS_ElemIteratorPtr > TStdElemIterator; + TStdElemIterator itEnd; + + // shift of node index to get medium nodes between the 4 base nodes and the apex + const int base2MediumShift = 9; + + set::const_iterator nIt = commonApex.begin(); + for ( ; nIt != commonApex.end(); ++nIt ) + { + SMESH_TNodeXYZ apex( *nIt ); + + vector< const SMDS_MeshElement* > pyrams // pyramids sharing the apex node + ( TStdElemIterator( apex._node->GetInverseElementIterator( SMDSAbs_Volume )), itEnd ); + + // Select medium nodes to keep and medium nodes to remove + + typedef map < const SMDS_MeshNode*, const SMDS_MeshNode*, TIDCompare > TN2NMap; + TN2NMap base2medium; // to keep + vector< const SMDS_MeshNode* > nodesToRemove; + + for ( unsigned i = 0; i < pyrams.size(); ++i ) + for ( int baseIndex = 0; baseIndex < PYRAM_APEX; ++baseIndex ) + { + SMESH_TNodeXYZ base = pyrams[i]->GetNode( baseIndex ); + const SMDS_MeshNode* medium = pyrams[i]->GetNode( baseIndex + base2MediumShift ); + TN2NMap::iterator b2m = base2medium.insert( make_pair( base._node, medium )).first; + if ( b2m->second != medium ) + { + nodesToRemove.push_back( medium ); + } + else + { + // move the kept medium node + gp_XYZ newXYZ = 0.5 * ( apex + base ); + meshDS->MoveNode( medium, newXYZ.X(), newXYZ.Y(), newXYZ.Z() ); + } + } + + // Within pyramids, replace nodes to remove by nodes to keep + + for ( unsigned i = 0; i < pyrams.size(); ++i ) + { + vector< const SMDS_MeshNode* > nodes( pyrams[i]->begin_nodes(), + pyrams[i]->end_nodes() ); + for ( int baseIndex = 0; baseIndex < PYRAM_APEX; ++baseIndex ) + { + const SMDS_MeshNode* base = pyrams[i]->GetNode( baseIndex ); + nodes[ baseIndex + base2MediumShift ] = base2medium[ base ]; + } + meshDS->ChangeElementNodes( pyrams[i], &nodes[0], nodes.size()); + } + + // Remove the replaced nodes + + if ( !nodesToRemove.empty() ) + { + SMESHDS_SubMesh * sm = meshDS->MeshElements( nodesToRemove[0]->getshapeId() ); + for ( unsigned i = 0; i < nodesToRemove.size(); ++i ) + meshDS->RemoveFreeNode( nodesToRemove[i], sm, /*fromGroups=*/false); + } + } + } + } +//================================================================================ +/*! + * \brief Merge the two pyramids (i.e. fuse their apex) and others already merged with them + */ +//================================================================================ + +void StdMeshers_QuadToTriaAdaptor::MergePiramids( const SMDS_MeshElement* PrmI, + const SMDS_MeshElement* PrmJ, + set & nodesToMove) +{ + const SMDS_MeshNode* Nrem = PrmJ->GetNode(4); // node to remove + //int nbJ = Nrem->NbInverseElements( SMDSAbs_Volume ); + SMESH_TNodeXYZ Pj( Nrem ); + + // an apex node to make common to all merged pyramids + SMDS_MeshNode* CommonNode = const_cast(PrmI->GetNode(4)); + if ( CommonNode == Nrem ) return; // already merged + //int nbI = CommonNode->NbInverseElements( SMDSAbs_Volume ); + SMESH_TNodeXYZ Pi( CommonNode ); + gp_XYZ Pnew = /*( nbI*Pi + nbJ*Pj ) / (nbI+nbJ);*/ 0.5 * ( Pi + Pj ); + CommonNode->setXYZ( Pnew.X(), Pnew.Y(), Pnew.Z() ); + + nodesToMove.insert( CommonNode ); + nodesToMove.erase ( Nrem ); + + typedef SMDS_StdIterator< const SMDS_MeshElement*, SMDS_ElemIteratorPtr > TStdElemIterator; + TStdElemIterator itEnd; + + // find and remove coincided faces of merged pyramids + vector< const SMDS_MeshElement* > inverseElems + // copy inverse elements to avoid iteration on changing container + ( TStdElemIterator( CommonNode->GetInverseElementIterator(SMDSAbs_Face)), itEnd); + for ( unsigned i = 0; i < inverseElems.size(); ++i ) + { + const SMDS_MeshElement* FI = inverseElems[i]; + const SMDS_MeshElement* FJEqual = 0; + SMDS_ElemIteratorPtr triItJ = Nrem->GetInverseElementIterator(SMDSAbs_Face); + while ( !FJEqual && triItJ->more() ) + { + const SMDS_MeshElement* FJ = triItJ->next(); + if ( EqualTriangles( FJ, FI )) + FJEqual = FJ; + } + if ( FJEqual ) + { + removeTmpElement( FI ); + removeTmpElement( FJEqual ); + myRemovedTrias.insert( FI ); + myRemovedTrias.insert( FJEqual ); + } + } + + // set the common apex node to pyramids and triangles merged with J + inverseElems.assign( TStdElemIterator( Nrem->GetInverseElementIterator()), itEnd ); + for ( unsigned i = 0; i < inverseElems.size(); ++i ) + { + const SMDS_MeshElement* elem = inverseElems[i]; + vector< const SMDS_MeshNode* > nodes( elem->begin_nodes(), elem->end_nodes() ); + nodes[ elem->GetType() == SMDSAbs_Volume ? PYRAM_APEX : TRIA_APEX ] = CommonNode; + GetMeshDS()->ChangeElementNodes( elem, &nodes[0], nodes.size()); + } + ASSERT( Nrem->NbInverseElements() == 0 ); + GetMeshDS()->RemoveFreeNode( Nrem, + GetMeshDS()->MeshElements( Nrem->getshapeId()), + /*fromGroups=*/false); +} //================================================================================ /*! - * \brief Destructor + * \brief Merges adjacent pyramids */ //================================================================================ -StdMeshers_QuadToTriaAdaptor::~StdMeshers_QuadToTriaAdaptor() +void StdMeshers_QuadToTriaAdaptor::MergeAdjacent(const SMDS_MeshElement* PrmI, + set& nodesToMove) { - // delete temporary faces - map< const SMDS_MeshElement*, list >::iterator - f_f = myResMap.begin(), ffEnd = myResMap.end(); - for ( ; f_f != ffEnd; ++f_f ) + TIDSortedElemSet adjacentPyrams; + bool mergedPyrams = false; + for(int k=0; k<4; k++) // loop on 4 base nodes of PrmI { - list& fList = f_f->second; - list::iterator f = fList.begin(), fEnd = fList.end(); - for ( ; f != fEnd; ++f ) - delete *f; + const SMDS_MeshNode* n = PrmI->GetNode(k); + SMDS_ElemIteratorPtr vIt = n->GetInverseElementIterator( SMDSAbs_Volume ); + while ( vIt->more() ) + { + const SMDS_MeshElement* PrmJ = vIt->next(); + if ( PrmJ->NbCornerNodes() != 5 || !adjacentPyrams.insert( PrmJ ).second ) + continue; + if ( PrmI != PrmJ && TooCloseAdjacent( PrmI, PrmJ, GetMesh()->HasShapeToMesh() )) + { + MergePiramids( PrmI, PrmJ, nodesToMove ); + mergedPyrams = true; + // container of inverse elements can change + vIt = n->GetInverseElementIterator( SMDSAbs_Volume ); + } + } } - myResMap.clear(); + if ( mergedPyrams ) + { + TIDSortedElemSet::iterator prm; + for (prm = adjacentPyrams.begin(); prm != adjacentPyrams.end(); ++prm) + MergeAdjacent( *prm, nodesToMove ); + } +} + +//================================================================================ +/*! + * \brief Constructor + */ +//================================================================================ -// TF2PyramMap::iterator itp = myMapFPyram.begin(); -// for(; itp!=myMapFPyram.end(); itp++) -// cout << itp->second << endl; +StdMeshers_QuadToTriaAdaptor::StdMeshers_QuadToTriaAdaptor(): + myElemSearcher(0) +{ } +//================================================================================ +/*! + * \brief Destructor + */ +//================================================================================ + +StdMeshers_QuadToTriaAdaptor::~StdMeshers_QuadToTriaAdaptor() +{ + // temporary faces are deleted by ~SMESH_ProxyMesh() + if ( myElemSearcher ) delete myElemSearcher; + myElemSearcher=0; +} //======================================================================= //function : FindBestPoint -//purpose : Auxilare for Compute() +//purpose : Return a point P laying on the line (PC,V) so that triangle +// (P, P1, P2) to be equilateral as much as possible // V - normal to (P1,P2,PC) //======================================================================= + static gp_Pnt FindBestPoint(const gp_Pnt& P1, const gp_Pnt& P2, const gp_Pnt& PC, const gp_Vec& V) { - double a = P1.Distance(P2); - double b = P1.Distance(PC); - double c = P2.Distance(PC); + gp_Pnt Pbest = PC; + const double a = P1.Distance(P2); + const double b = P1.Distance(PC); + const double c = P2.Distance(PC); if( a < (b+c)/2 ) - return PC; - else { - // find shift along V in order to a became equal to (b+c)/2 - double shift = sqrt( a*a + (b*b-c*c)*(b*b-c*c)/16/a/a - (b*b+c*c)/2 ); - gp_Dir aDir(V); - gp_Pnt Pbest( PC.X() + aDir.X()*shift, PC.Y() + aDir.Y()*shift, - PC.Z() + aDir.Z()*shift ); return Pbest; + else { + // find shift along V in order a to became equal to (b+c)/2 + const double Vsize = V.Magnitude(); + if ( fabs( Vsize ) > std::numeric_limits::min() ) + { + const double shift = sqrt( a*a + (b*b-c*c)*(b*b-c*c)/16/a/a - (b*b+c*c)/2 ); + Pbest.ChangeCoord() += shift * V.XYZ() / Vsize; + } } + return Pbest; } - //======================================================================= //function : HasIntersection3 //purpose : Auxilare for HasIntersection() // find intersection point between triangle (P1,P2,P3) // and segment [PC,P] //======================================================================= + static bool HasIntersection3(const gp_Pnt& P, const gp_Pnt& PC, gp_Pnt& Pint, const gp_Pnt& P1, const gp_Pnt& P2, const gp_Pnt& P3) { @@ -142,7 +437,7 @@ static bool HasIntersection3(const gp_Pnt& P, const gp_Pnt& PC, gp_Pnt& Pint, return false; if( IAICQ.NbPoints() == 1 ) { gp_Pnt PIn = IAICQ.Point(1); - double preci = 1.e-6; + const double preci = 1.e-10 * P.Distance(PC); // check if this point is internal for segment [PC,P] bool IsExternal = ( (PC.X()-PIn.X())*(P.X()-PIn.X()) > preci ) || @@ -155,32 +450,34 @@ static bool HasIntersection3(const gp_Pnt& P, const gp_Pnt& PC, gp_Pnt& Pint, gp_Vec V1(PIn,P1); gp_Vec V2(PIn,P2); gp_Vec V3(PIn,P3); - if( V1.Magnitude()(myElemSearcher); + + //SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); //cout<<" CheckIntersection: meshDS->NbFaces() = "<NbFaces()<MeshElements(aShapeFace); - if ( aSubMeshDSFace ) { - SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements(); - while ( iteratorElem->more() ) { // loop on elements on a face - const SMDS_MeshElement* face = iteratorElem->next(); - Handle(TColgp_HSequenceOfPnt) aContour = new TColgp_HSequenceOfPnt; - SMDS_ElemIteratorPtr nodeIt = face->nodesIterator(); - int nbN = face->NbNodes(); - if( face->IsQuadratic() ) - nbN /= 2; - for ( int i = 0; i < nbN; ++i ) { - const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - aContour->Append(gp_Pnt(node->X(), node->Y(), node->Z())); - } - if( HasIntersection(P, PC, Pres, aContour) ) { - res = true; - double tmp = PC.Distance(Pres); - if(tmp suspectElems; + searcher->GetElementsNearLine( line, SMDSAbs_Face, suspectElems); + + for ( int i = 0; i < suspectElems.size(); ++i ) + { + const SMDS_MeshElement* face = suspectElems[i]; + if ( face == NotCheckedFace ) continue; + Handle(TColgp_HSequenceOfPnt) aContour = new TColgp_HSequenceOfPnt; + for ( int i = 0; i < face->NbCornerNodes(); ++i ) + aContour->Append( SMESH_TNodeXYZ( face->GetNode(i) )); + if( HasIntersection(P, PC, Pres, aContour) ) { + res = true; + double tmp = PC.Distance(Pres); + if(tmp& FNodes, + gp_Pnt& PC, + gp_Vec& VNorm, + const SMDS_MeshElement** volumes) { - return - ( F1->GetNode(1)==F2->GetNode(2) && F1->GetNode(2)==F2->GetNode(1) ) || - ( F1->GetNode(1)==F2->GetNode(1) && F1->GetNode(2)==F2->GetNode(2) ); -} - - -//======================================================================= -//function : IsDegenarate -//purpose : Auxilare for Preparation() -//======================================================================= -// static int IsDegenarate(const Handle(TColgp_HArray1OfPnt)& PN) -// { -// int i = 1; -// for(; i<4; i++) { -// int j = i+1; -// for(; j<=4; j++) { -// if( PN->Value(i).Distance(PN->Value(j)) < 1.e-6 ) -// return j; -// } -// } -// return 0; -// } - + if( face->NbCornerNodes() != 4 ) + { + return NOT_QUAD; + } -//======================================================================= -//function : Preparation -//purpose : Auxilare for Compute() -// : Return 0 if given face is not quad, -// 1 if given face is quad, -// 2 if given face is degenerate quad (two nodes are coincided) -//======================================================================= -int StdMeshers_QuadToTriaAdaptor::Preparation(const SMDS_MeshElement* face, - Handle(TColgp_HArray1OfPnt)& PN, - Handle(TColgp_HArray1OfVec)& VN, - std::vector& FNodes, - gp_Pnt& PC, gp_Vec& VNorm) -{ int i = 0; - double xc=0., yc=0., zc=0.; - SMDS_ElemIteratorPtr nodeIt = face->nodesIterator(); - if( !face->IsQuadratic() ) { - if( face->NbNodes() != 4 ) - return 0; - while ( nodeIt->more() ) { - i++; - const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - FNodes[i-1] = node; - PN->SetValue( i, gp_Pnt(node->X(), node->Y(), node->Z()) ); - xc += node->X(); - yc += node->Y(); - zc += node->Z(); - } - } - else { - if( face->NbNodes() != 8) - return 0; - while ( nodeIt->more() ) { - i++; - const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - FNodes[i-1] = node; - PN->SetValue( i, gp_Pnt(node->X(), node->Y(), node->Z()) ); - xc += node->X(); - yc += node->Y(); - zc += node->Z(); - if(i==4) break; - } + gp_XYZ xyzC(0., 0., 0.); + for ( i = 0; i < 4; ++i ) + { + gp_XYZ p = SMESH_TNodeXYZ( FNodes[i] = face->GetNode(i) ); + PN->SetValue( i+1, p ); + xyzC += p; } + PC = xyzC/4; int nbp = 4; @@ -368,7 +632,7 @@ int StdMeshers_QuadToTriaAdaptor::Preparation(const SMDS_MeshElement* face, hasdeg = true; gp_Pnt Pdeg = PN->Value(i); - std::list< const SMDS_MeshNode* >::iterator itdg = myDegNodes.begin(); + list< const SMDS_MeshNode* >::iterator itdg = myDegNodes.begin(); const SMDS_MeshNode* DegNode = 0; for(; itdg!=myDegNodes.end(); itdg++) { const SMDS_MeshNode* N = (*itdg); @@ -391,24 +655,15 @@ int StdMeshers_QuadToTriaAdaptor::Preparation(const SMDS_MeshElement* face, FNodes[i-1] = FNodes[i]; } nbp = 3; - //PC = gp_Pnt( PN->Value(1).X() + PN.Value } - PC = gp_Pnt(xc/4., yc/4., zc/4.); - //cout<<" PC("<SetValue(5,PN->Value(1)); PN->SetValue(nbp+1,PN->Value(1)); - //FNodes[4] = FNodes[0]; FNodes[nbp] = FNodes[0]; // find normal direction - //gp_Vec V1(PC,PN->Value(4)); gp_Vec V1(PC,PN->Value(nbp)); gp_Vec V2(PC,PN->Value(1)); VNorm = V1.Crossed(V2); - //VN->SetValue(4,VNorm); VN->SetValue(nbp,VNorm); - //for(i=1; i<4; i++) { for(i=1; iValue(i)); V2 = gp_Vec(PC,PN->Value(i+1)); @@ -416,172 +671,307 @@ int StdMeshers_QuadToTriaAdaptor::Preparation(const SMDS_MeshElement* face, VN->SetValue(i,Vtmp); VNorm += Vtmp; } + + // find volumes sharing the face + if ( volumes ) + { + volumes[0] = volumes[1] = 0; + SMDS_ElemIteratorPtr vIt = FNodes[0]->GetInverseElementIterator( SMDSAbs_Volume ); + while ( vIt->more() ) + { + const SMDS_MeshElement* vol = vIt->next(); + bool volSharesAllNodes = true; + for ( int i = 1; i < face->NbNodes() && volSharesAllNodes; ++i ) + volSharesAllNodes = ( vol->GetNodeIndex( FNodes[i] ) >= 0 ); + if ( volSharesAllNodes ) + volumes[ volumes[0] ? 1 : 0 ] = vol; + // we could additionally check that vol has all FNodes in its one face using SMDS_VolumeTool + } + // define volume position relating to the face normal + if ( volumes[0] ) + { + // get volume gc + SMDS_ElemIteratorPtr nodeIt = volumes[0]->nodesIterator(); + gp_XYZ volGC(0,0,0); + volGC = accumulate( TXyzIterator(nodeIt), TXyzIterator(), volGC ) / volumes[0]->NbNodes(); + + if ( VNorm * gp_Vec( PC, volGC ) < 0 ) + swap( volumes[0], volumes[1] ); + } + } + //cout<<" VNorm("< myPyramids; SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); SMESH_MesherHelper helper(aMesh); helper.IsQuadraticSubMesh(aShape); helper.SetElementsOnShape( true ); - for (TopExp_Explorer exp(aShape,TopAbs_FACE);exp.More();exp.Next()) { + if ( myElemSearcher ) delete myElemSearcher; + if ( aProxyMesh ) + myElemSearcher = SMESH_MeshAlgos::GetElementSearcher( *meshDS, aProxyMesh->GetFaces(aShape)); + else + myElemSearcher = SMESH_MeshAlgos::GetElementSearcher( *meshDS ); + + const SMESHDS_SubMesh * aSubMeshDSFace; + Handle(TColgp_HArray1OfPnt) PN = new TColgp_HArray1OfPnt(1,5); + Handle(TColgp_HArray1OfVec) VN = new TColgp_HArray1OfVec(1,4); + vector FNodes(5); + gp_Pnt PC; + gp_Vec VNorm; + + for (TopExp_Explorer exp(aShape,TopAbs_FACE);exp.More();exp.Next()) + { const TopoDS_Shape& aShapeFace = exp.Current(); - const SMESHDS_SubMesh * aSubMeshDSFace = meshDS->MeshElements( aShapeFace ); - if ( aSubMeshDSFace ) { - bool isRev = SMESH_Algo::IsReversedSubMesh( TopoDS::Face(aShapeFace), meshDS ); + if ( aProxyMesh ) + aSubMeshDSFace = aProxyMesh->GetSubMesh( aShapeFace ); + else + aSubMeshDSFace = meshDS->MeshElements( aShapeFace ); + + vector trias, quads; + bool hasNewTrias = false; + + if ( aSubMeshDSFace ) + { + bool isRev = false; + if ( helper.NbAncestors( aShapeFace, aMesh, aShape.ShapeType() ) > 1 ) + isRev = helper.IsReversedSubMesh( TopoDS::Face(aShapeFace) ); SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements(); - while ( iteratorElem->more() ) { // loop on elements on a face + while ( iteratorElem->more() ) // loop on elements on a geometrical face + { const SMDS_MeshElement* face = iteratorElem->next(); - //cout<GetID() = "<GetID()< FNodes(5); - gp_Pnt PC; - gp_Vec VNorm; - int stat = Preparation(face, PN, VN, FNodes, PC, VNorm); - if(stat==0) - continue; - - if(stat==2) { - // degenerate face - // add triangles to result map - std::list aList; - SMDS_FaceOfNodes* NewFace; - if(!isRev) - NewFace = new SMDS_FaceOfNodes( FNodes[0], FNodes[1], FNodes[2] ); - else - NewFace = new SMDS_FaceOfNodes( FNodes[0], FNodes[2], FNodes[1] ); - aList.push_back(NewFace); - myResMap.insert(make_pair(face,aList)); - continue; - } + // preparation step to get face info + int stat = Preparation(face, PN, VN, FNodes, PC, VNorm); + switch ( stat ) + { + case NOT_QUAD: - if(!isRev) VNorm.Reverse(); - double xc = 0., yc = 0., zc = 0.; - int i = 1; - for(; i<=4; i++) { - gp_Pnt Pbest; - if(!isRev) - Pbest = FindBestPoint(PN->Value(i), PN->Value(i+1), PC, VN->Value(i).Reversed()); - else - Pbest = FindBestPoint(PN->Value(i), PN->Value(i+1), PC, VN->Value(i)); - xc += Pbest.X(); - yc += Pbest.Y(); - zc += Pbest.Z(); - } - gp_Pnt PCbest(xc/4., yc/4., zc/4.); + trias.push_back( face ); + break; - // check PCbest - double height = PCbest.Distance(PC); - if(height<1.e-6) { - // create new PCbest using a bit shift along VNorm - PCbest = PC.XYZ() + VNorm.XYZ() * 0.001; - } - else { - // check possible intersection with other faces - gp_Pnt Pint; - bool check = CheckIntersection(PCbest, PC, Pint, aMesh, aShape, aShapeFace); - if(check) { - //cout<<"--PC("<AddFace( FNodes[0], FNodes[1], FNodes[2] ); + else + NewFace = meshDS->AddFace( FNodes[0], FNodes[2], FNodes[1] ); + storeTmpElement( NewFace ); + trias.push_back ( NewFace ); + quads.push_back( face ); + hasNewTrias = true; + break; } - else { - gp_Vec VB(PC,PCbest); - gp_Pnt PCbestTmp = PC.XYZ() + VB.XYZ() * 3.0; - bool check = CheckIntersection(PCbestTmp, PC, Pint, aMesh, aShape, aShapeFace); - if(check) { - double dist = PC.Distance(Pint)/3.; - if(distValue(i), PN->Value(i+1), PC, VN->Value(i).Reversed()); + else + Pbest = FindBestPoint(PN->Value(i), PN->Value(i+1), PC, VN->Value(i)); + xc += Pbest.X(); + yc += Pbest.Y(); + zc += Pbest.Z(); + } + gp_Pnt PCbest(xc/4., yc/4., zc/4.); + + // check PCbest + double height = PCbest.Distance(PC); + if(height<1.e-6) { + // create new PCbest using a bit shift along VNorm + PCbest = PC.XYZ() + VNorm.XYZ() * 0.001; + } + else { + // check possible intersection with other faces + gp_Pnt Pint; + bool check = CheckIntersection(PCbest, PC, Pint, aMesh, aShape, face); + if(check) { + //cout<<"--PC("< aList; - for(i=0; i<4; i++) { - SMDS_FaceOfNodes* NewFace = new SMDS_FaceOfNodes( NewNode, FNodes[i], FNodes[i+1] ); - aList.push_back(NewFace); + // create node for PCbest + SMDS_MeshNode* NewNode = helper.AddNode( PCbest.X(), PCbest.Y(), PCbest.Z() ); + + // add triangles to result map + for(i=0; i<4; i++) + { + trias.push_back ( meshDS->AddFace( NewNode, FNodes[i], FNodes[i+1] )); + storeTmpElement( trias.back() ); + } + // create a pyramid + if ( isRev ) swap( FNodes[1], FNodes[3]); + SMDS_MeshVolume* aPyram = + helper.AddVolume( FNodes[0], FNodes[1], FNodes[2], FNodes[3], NewNode ); + myPyramids.push_back(aPyram); + + quads.push_back( face ); + hasNewTrias = true; + break; + + } // case QUAD: + + } // switch ( stat ) + } // end loop on elements on a face submesh + + bool sourceSubMeshIsProxy = false; + if ( aProxyMesh ) + { + // move proxy sub-mesh from other proxy mesh to this + sourceSubMeshIsProxy = takeProxySubMesh( aShapeFace, aProxyMesh ); + // move also tmp elements added in mesh + takeTmpElemsInMesh( aProxyMesh ); + } + if ( hasNewTrias ) + { + SMESH_ProxyMesh::SubMesh* prxSubMesh = getProxySubMesh( aShapeFace ); + prxSubMesh->ChangeElements( trias.begin(), trias.end() ); + + // delete tmp quadrangles removed from aProxyMesh + if ( sourceSubMeshIsProxy ) + { + for ( unsigned i = 0; i < quads.size(); ++i ) + removeTmpElement( quads[i] ); + + delete myElemSearcher; + myElemSearcher = + SMESH_MeshAlgos::GetElementSearcher( *meshDS, aProxyMesh->GetFaces(aShape)); } - myResMap.insert(make_pair(face,aList)); - // create pyramid - SMDS_MeshVolume* aPyram = - helper.AddVolume( FNodes[0], FNodes[1], FNodes[2], FNodes[3], NewNode ); - myMapFPyram.insert(make_pair(face,aPyram)); - } // end loop on elements on a face + } } } // end for(TopExp_Explorer exp(aShape,TopAbs_FACE);exp.More();exp.Next()) { - return Compute2ndPart(aMesh); + return Compute2ndPart(aMesh, myPyramids); } - -//======================================================================= -//function : Compute -//purpose : -//======================================================================= +//================================================================================ +/*! + * \brief Computes pyramids in mesh with no shape + */ +//================================================================================ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh) { - myResMap.clear(); - myMapFPyram.clear(); + SMESH_ProxyMesh::setMesh( aMesh ); + SMESH_ProxyMesh::_allowedTypes.push_back( SMDSEntity_Triangle ); + SMESH_ProxyMesh::_allowedTypes.push_back( SMDSEntity_Quad_Triangle ); + if ( aMesh.NbQuadrangles() < 1 ) + return false; + + // find if there is a group of faces identified as skin faces, with normal going outside the volume + std::string groupName = "skinFaces"; + SMESHDS_GroupBase* groupDS = 0; + SMESH_Mesh::GroupIteratorPtr groupIt = aMesh.GetGroups(); + while ( groupIt->more() ) + { + groupDS = 0; + SMESH_Group * group = groupIt->next(); + if ( !group ) continue; + groupDS = group->GetGroupDS(); + if ( !groupDS || groupDS->IsEmpty() ) + { + groupDS = 0; + continue; + } + if (groupDS->GetType() != SMDSAbs_Face) + { + groupDS = 0; + continue; + } + std::string grpName = group->GetName(); + if (grpName == groupName) + { + MESSAGE("group skinFaces provided"); + break; + } + else + groupDS = 0; + } + + vector myPyramids; SMESH_MesherHelper helper(aMesh); helper.IsQuadraticSubMesh(aMesh.GetShapeToMesh()); helper.SetElementsOnShape( true ); SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); + SMESH_ProxyMesh::SubMesh* prxSubMesh = getProxySubMesh(); - SMDS_FaceIteratorPtr fIt = meshDS->facesIterator(); - TIDSortedElemSet sortedFaces; // 0020279: control the "random" use when using mesh algorithms - while( fIt->more()) sortedFaces.insert( fIt->next() ); + if ( !myElemSearcher ) + myElemSearcher = SMESH_MeshAlgos::GetElementSearcher( *meshDS ); + SMESH_ElementSearcher* searcher = const_cast(myElemSearcher); - TIDSortedElemSet::iterator itFace = sortedFaces.begin(), fEnd = sortedFaces.end(); - for ( ; itFace != fEnd; ++itFace ) + SMDS_FaceIteratorPtr fIt = meshDS->facesIterator(/*idInceasingOrder=*/true); + while( fIt->more()) { - const SMDS_MeshElement* face = *itFace; + const SMDS_MeshElement* face = fIt->next(); if ( !face ) continue; - //cout<GetID() = "<GetID()< FNodes(5); + vector FNodes(5); gp_Pnt PC; gp_Vec VNorm; - - int stat = Preparation(face, PN, VN, FNodes, PC, VNorm); - if(stat==0) + const SMDS_MeshElement* volumes[2]; + int what = Preparation(face, PN, VN, FNodes, PC, VNorm, volumes); + if ( what == NOT_QUAD ) continue; + if ( volumes[0] && volumes[1] ) + continue; // face is shared by two volumes - no space for a pyramid - if(stat==2) { + if ( what == DEGEN_QUAD ) + { // degenerate face - // add triangles to result map - std::list aList; - SMDS_FaceOfNodes* NewFace; - // check orientation + // add a triangle to the proxy mesh + SMDS_MeshFace* NewFace; - double tmp = PN->Value(1).Distance(PN->Value(2)) + - PN->Value(2).Distance(PN->Value(3)); + // check orientation + double tmp = PN->Value(1).Distance(PN->Value(2)) + PN->Value(2).Distance(PN->Value(3)); + // far points in VNorm direction gp_Pnt Ptmp1 = PC.XYZ() + VNorm.XYZ() * tmp * 1.e6; gp_Pnt Ptmp2 = PC.XYZ() - VNorm.XYZ() * tmp * 1.e6; // check intersection for Ptmp1 and Ptmp2 @@ -591,28 +981,19 @@ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh) double dist1 = RealLast(); double dist2 = RealLast(); gp_Pnt Pres1,Pres2; - for (TIDSortedElemSet::iterator itF = sortedFaces.begin(); itF != fEnd; ++itF ) { - const SMDS_MeshElement* F = *itF; + + gp_Ax1 line( PC, VNorm ); + vector< const SMDS_MeshElement* > suspectElems; + searcher->GetElementsNearLine( line, SMDSAbs_Face, suspectElems); + + for ( int iF = 0; iF < suspectElems.size(); ++iF ) { + const SMDS_MeshElement* F = suspectElems[iF]; if(F==face) continue; Handle(TColgp_HSequenceOfPnt) aContour = new TColgp_HSequenceOfPnt; - SMDS_ElemIteratorPtr nodeIt = F->nodesIterator(); - if( !F->IsQuadratic() ) { - while ( nodeIt->more() ) { - const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - aContour->Append(gp_Pnt(node->X(), node->Y(), node->Z())); - } - } - else { - int nn = 0; - while ( nodeIt->more() ) { - nn++; - const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - aContour->Append(gp_Pnt(node->X(), node->Y(), node->Z())); - if(nn==face->NbNodes()/2) break; - } - } + for ( int i = 0; i < 4; ++i ) + aContour->Append( SMESH_TNodeXYZ( F->GetNode(i) )); gp_Pnt PPP; - if( HasIntersection(Ptmp1, PC, PPP, aContour) ) { + if( !volumes[0] && HasIntersection(Ptmp1, PC, PPP, aContour) ) { IsOK1 = true; double tmp = PC.Distance(PPP); if(tmpAddFace( FNodes[0], FNodes[1], FNodes[2] ); else - NewFace = new SMDS_FaceOfNodes( FNodes[0], FNodes[2], FNodes[1] ); - aList.push_back(NewFace); - myResMap.insert(make_pair(face,aList)); + NewFace = meshDS->AddFace( FNodes[0], FNodes[2], FNodes[1] ); + storeTmpElement( NewFace ); + prxSubMesh->AddElement( NewFace ); continue; } - - double xc = 0., yc = 0., zc = 0.; + + // Case of non-degenerated quadrangle + + // Find pyramid peak + + gp_XYZ PCbest(0., 0., 0.); // pyramid peak int i = 1; for(; i<=4; i++) { gp_Pnt Pbest = FindBestPoint(PN->Value(i), PN->Value(i+1), PC, VN->Value(i)); - xc += Pbest.X(); - yc += Pbest.Y(); - zc += Pbest.Z(); + PCbest += Pbest.XYZ(); } - gp_Pnt PCbest(xc/4., yc/4., zc/4.); - double height = PCbest.Distance(PC); - if(height<1.e-6) { + PCbest /= 4; + + double height = PC.Distance(PCbest); // pyramid height to precise + if ( height < 1.e-6 ) { // create new PCbest using a bit shift along VNorm PCbest = PC.XYZ() + VNorm.XYZ() * 0.001; - height = PCbest.Distance(PC); + height = PC.Distance(PCbest); + if ( height < std::numeric_limits::min() ) + return false; // batterfly element } - //cout<<" PCbest("<Value(1).Distance(PN->Value(3)) + - PN->Value(2).Distance(PN->Value(4)); - gp_Dir tmpDir(V1); - gp_Pnt Ptmp1 = PC.XYZ() + tmpDir.XYZ() * tmp * 1.e6; - gp_Pnt Ptmp2 = PC.XYZ() - tmpDir.XYZ() * tmp * 1.e6; - // check intersection for Ptmp1 and Ptmp2 - bool IsRev = false; - bool IsOK1 = false; - bool IsOK2 = false; - double dist1 = RealLast(); - double dist2 = RealLast(); - gp_Pnt Pres1,Pres2; - for (TIDSortedElemSet::iterator itF = sortedFaces.begin(); itF != fEnd; ++itF ) { - const SMDS_MeshElement* F = *itF; + + // Restrict pyramid height by intersection with other faces + gp_Vec tmpDir(PC,PCbest); tmpDir.Normalize(); + double tmp = PN->Value(1).Distance(PN->Value(3)) + PN->Value(2).Distance(PN->Value(4)); + // far points: in (PC, PCbest) direction and vice-versa + gp_Pnt farPnt[2] = { PC.XYZ() + tmpDir.XYZ() * tmp * 1.e6, + PC.XYZ() - tmpDir.XYZ() * tmp * 1.e6 }; + // check intersection for farPnt1 and farPnt2 + bool intersected[2] = { false, false }; + double dist [2] = { RealLast(), RealLast() }; + gp_Pnt intPnt[2]; + + gp_Ax1 line( PC, tmpDir ); + vector< const SMDS_MeshElement* > suspectElems; + searcher->GetElementsNearLine( line, SMDSAbs_Face, suspectElems); + + for ( int iF = 0; iF < suspectElems.size(); ++iF ) + { + const SMDS_MeshElement* F = suspectElems[iF]; if(F==face) continue; Handle(TColgp_HSequenceOfPnt) aContour = new TColgp_HSequenceOfPnt; - SMDS_ElemIteratorPtr nodeIt = F->nodesIterator(); - if( !F->IsQuadratic() ) { - while ( nodeIt->more() ) { - const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - aContour->Append(gp_Pnt(node->X(), node->Y(), node->Z())); - } - } - else { - int nn = 0; - while ( nodeIt->more() ) { - nn++; - const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - aContour->Append(gp_Pnt(node->X(), node->Y(), node->Z())); - if(nn==face->NbNodes()/2) break; - } - } - gp_Pnt PPP; - if( HasIntersection(Ptmp1, PC, PPP, aContour) ) { - IsOK1 = true; - double tmp = PC.Distance(PPP); - if(tmpNbNodes() / ( F->IsQuadratic() ? 2 : 1 ); + for ( i = 0; i < nbN; ++i ) + aContour->Append( SMESH_TNodeXYZ( F->GetNode(i) )); + gp_Pnt intP; + for ( int isRev = 0; isRev < 2; ++isRev ) + { + if( !volumes[isRev] && HasIntersection(farPnt[isRev], PC, intP, aContour) ) { + intersected[isRev] = true; + double d = PC.Distance( intP ); + if( d < dist[isRev] ) + { + intPnt[isRev] = intP; + dist [isRev] = d; + } } } } - if( IsOK1 && !IsOK2 ) { - // using existed direction - double tmp = PC.Distance(Pres1)/3.; - if( height > tmp ) { - height = tmp; - PCbest = PC.XYZ() + tmpDir.XYZ() * height; - } - } - else if( !IsOK1 && IsOK2 ) { - // using opposite direction - IsRev = true; - double tmp = PC.Distance(Pres2)/3.; - if( height > tmp ) height = tmp; - PCbest = PC.XYZ() - tmpDir.XYZ() * height; + // if the face belong to the group of skinFaces, do not build a pyramid outside + if (groupDS && groupDS->Contains(face)) + { + intersected[0] = false; } - else { // IsOK1 && IsOK2 - double tmp1 = PC.Distance(Pres1)/3.; - double tmp2 = PC.Distance(Pres2)/3.; - if(tmp1 tmp1 ) { - height = tmp1; - PCbest = PC.XYZ() + tmpDir.XYZ() * height; - } - } - else { - // using opposite direction - IsRev = true; - if( height > tmp2 ) height = tmp2; - PCbest = PC.XYZ() - tmpDir.XYZ() * height; + else if ( intersected[0] && intersected[1] ) // check if one of pyramids is in a hole + { + gp_Pnt P ( PC.XYZ() + tmpDir.XYZ() * 0.5 * PC.Distance( intPnt[0] )); + if ( searcher->GetPointState( P ) == TopAbs_OUT ) + intersected[0] = false; + else + { + P = ( PC.XYZ() - tmpDir.XYZ() * 0.5 * PC.Distance( intPnt[1] )); + if ( searcher->GetPointState( P ) == TopAbs_OUT ) + intersected[1] = false; } } - // create node for PCbest - SMDS_MeshNode* NewNode = helper.AddNode( PCbest.X(), PCbest.Y(), PCbest.Z() ); - // add triangles to result map - std::list aList; - for(i=0; i<4; i++) { - SMDS_FaceOfNodes* NewFace; - if(IsRev) - NewFace = new SMDS_FaceOfNodes( NewNode, FNodes[i], FNodes[i+1] ); + // Create one or two pyramids + + for ( int isRev = 0; isRev < 2; ++isRev ) + { + if( !intersected[isRev] ) continue; + double pyramidH = Min( height, PC.Distance(intPnt[isRev])/3.); + PCbest = PC.XYZ() + tmpDir.XYZ() * (isRev ? -pyramidH : pyramidH); + + // create node for PCbest + SMDS_MeshNode* NewNode = helper.AddNode( PCbest.X(), PCbest.Y(), PCbest.Z() ); + + // add triangles to result map + for(i=0; i<4; i++) { + SMDS_MeshFace* NewFace; + if(isRev) + NewFace = meshDS->AddFace( NewNode, FNodes[i], FNodes[i+1] ); + else + NewFace = meshDS->AddFace( NewNode, FNodes[i+1], FNodes[i] ); + storeTmpElement( NewFace ); + prxSubMesh->AddElement( NewFace ); + } + // create a pyramid + SMDS_MeshVolume* aPyram; + if(isRev) + aPyram = helper.AddVolume( FNodes[0], FNodes[1], FNodes[2], FNodes[3], NewNode ); else - NewFace = new SMDS_FaceOfNodes( NewNode, FNodes[i+1], FNodes[i] ); - aList.push_back(NewFace); + aPyram = helper.AddVolume( FNodes[0], FNodes[3], FNodes[2], FNodes[1], NewNode ); + myPyramids.push_back(aPyram); } - myResMap.insert(make_pair(face,aList)); - // create pyramid - SMDS_MeshVolume* aPyram; - if(IsRev) - aPyram = helper.AddVolume( FNodes[0], FNodes[1], FNodes[2], FNodes[3], NewNode ); - else - aPyram = helper.AddVolume( FNodes[0], FNodes[3], FNodes[2], FNodes[1], NewNode ); - myMapFPyram.insert(make_pair(face,aPyram)); - } // end loop on elements on a face + } // end loop on all faces - return Compute2ndPart(aMesh); + return Compute2ndPart(aMesh, myPyramids); } +//================================================================================ +/*! + * \brief Update created pyramids and faces to avoid their intersection + */ +//================================================================================ -//======================================================================= -//function : Compute2ndPart -//purpose : -//======================================================================= - -bool StdMeshers_QuadToTriaAdaptor::Compute2ndPart(SMESH_Mesh& aMesh) +bool StdMeshers_QuadToTriaAdaptor::Compute2ndPart(SMESH_Mesh& aMesh, + const vector& myPyramids) { + if(myPyramids.empty()) + return true; + SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); + int i, j, k, myShapeID = myPyramids[0]->GetNode(4)->getshapeId(); - // check intersections between created pyramids - int NbPyram = myMapFPyram.size(); - //cout<<"NbPyram = "<(myElemSearcher); - vector< const SMDS_MeshElement* > Pyrams(NbPyram); - vector< const SMDS_MeshElement* > Faces(NbPyram); - TF2PyramMap::iterator itp = myMapFPyram.begin(); - int i = 0; - for(; itp!=myMapFPyram.end(); itp++, i++) { - Faces[i] = (*itp).first; - Pyrams[i] = (*itp).second; - } - StdMeshers_Array1OfSequenceOfInteger MergesInfo(0,NbPyram-1); - for(i=0; i nodesToMove; + + // check adjacent pyramids + + for ( i = 0; i < myPyramids.size(); ++i ) + { + const SMDS_MeshElement* PrmI = myPyramids[i]; + MergeAdjacent( PrmI, nodesToMove ); } - for(i=0; inodesIterator(); - std::vector Ps1( Prm1->NbNodes() ); - vector< const SMDS_MeshNode* > Ns1( Prm1->NbNodes() ); - int k = 0; - for ( ; k < Ns1.size(); ++k ) { - const SMDS_MeshNode* node = static_cast( nIt->next() ); - Ns1[k] = node; - Ps1[k] = gp_Pnt(node->X(), node->Y(), node->Z()); - } - bool NeedMove = false; - for(int j=i+1; jChangeElementNodes(Prm2, &Ns2[0], Ns2.size()); - // update pyramids for J - for(k=2; k<=nbJ; k++) { - const SMDS_MeshElement* tmpPrm = Pyrams[aMergesJ.Value(k)]; - SMDS_ElemIteratorPtr tmpIt = tmpPrm->nodesIterator(); - vector< const SMDS_MeshNode* > Ns( tmpPrm->NbNodes() ); - for ( int m = 0; m < Ns.size(); ++m ) - Ns[m] = static_cast( tmpIt->next() ); - Ns[4] = CommonNode; - meshDS->ChangeElementNodes(tmpPrm, &Ns[0], Ns.size()); - } + if ( hasInt ) + { + // count common nodes of base faces of two pyramids + int nbc = 0; + for (k=0; k<4; k++) + nbc += int ( PrmI->GetNodeIndex( PrmJ->GetNode(k) ) >= 0 ); - // update MergesInfo - for(k=1; k<=nbI; k++) { - int num = aMergesI.Value(k); - TColStd_SequenceOfInteger& aSeq = MergesInfo.ChangeValue(num); - for(int m=1; m<=nbJ; m++) - aSeq.Append(aMergesJ.Value(m)); - } - for(k=1; k<=nbJ; k++) { - int num = aMergesJ.Value(k); - TColStd_SequenceOfInteger& aSeq = MergesInfo.ChangeValue(num); - for(int m=1; m<=nbI; m++) - aSeq.Append(aMergesI.Value(m)); - } + if ( nbc == 4 ) + continue; // pyrams have a common base face - // update triangles for aMergesJ - for(k=1; k<=nbJ; k++) { - list< list< const SMDS_MeshNode* > > aFNodes; - list< const SMDS_MeshElement* > aFFaces; - int num = aMergesJ.Value(k); - map< const SMDS_MeshElement*, - list >::iterator itrm = myResMap.find(Faces[num]); - list& trias = itrm->second; - list::iterator itt = trias.begin(); - for(; itt!=trias.end(); itt++) { - SMDS_ElemIteratorPtr nodeIt = (*itt)->nodesIterator(); - const SMDS_MeshNode* NF[3]; - int nn = 0; - while ( nodeIt->more() ) - NF[nn++] = static_cast( nodeIt->next() ); - NF[0] = CommonNode; - SMDS_FaceOfNodes* Ftria = const_cast< SMDS_FaceOfNodes*>( (*itt) ); - Ftria->ChangeNodes(NF, 3); - } + if(nbc>0) + { + // Merge the two pyramids and others already merged with them + MergePiramids( PrmI, PrmJ, nodesToMove ); } + else { // nbc==0 - // check and remove coincided faces - //TColStd_SequenceOfInteger IdRemovedTrias; - int i1 = 1; - for(; i1<=nbI; i1++) { - int numI = aMergesI.Value(i1); - map< const SMDS_MeshElement*, - list >::iterator itrmI = myResMap.find(Faces[numI]); - list& triasI = (*itrmI).second; - list::iterator ittI = triasI.begin(); - int nbfI = triasI.size(); - vector FsI(nbfI); - k = 0; - for(; ittI!=triasI.end(); ittI++) { - FsI[k] = (*ittI); - k++; + // decrease height of pyramids + gp_XYZ PCi(0,0,0), PCj(0,0,0); + for(k=0; k<4; k++) { + PCi += PsI[k].XYZ(); + PCj += PsJ[k].XYZ(); } - int i2 = 0; - for(; i2 >::iterator itrmJ = myResMap.find(Faces[numJ]); - list& triasJ = (*itrmJ).second; - list::iterator ittJ = triasJ.begin(); - int nbfJ = triasJ.size(); - vector FsJ(nbfJ); - k = 0; - for(; ittJ!=triasJ.end(); ittJ++) { - FsJ[k] = (*ittJ); - k++; - } - int j2 = 0; - for(; j2GetID() ); - //IdRemovedTrias.Append( FJ->GetID() ); - FsI[i2] = 0; - FsJ[j2] = 0; - list new_triasI; - for(k=0; k new_triasJ; - for(k=0; kRemoveNode(Nrem); - } - else { // nbc==0 - //cout<<"decrease height of pyramids"<(PrmI->GetNode(4)); + aNode1->setXYZ( PCi.X()+VN1.X(), PCi.Y()+VN1.Y(), PCi.Z()+VN1.Z() ); + SMDS_MeshNode* aNode2 = const_cast(PrmJ->GetNode(4)); + aNode2->setXYZ( PCj.X()+VN2.X(), PCj.Y()+VN2.Y(), PCj.Z()+VN2.Z() ); + nodesToMove.insert( aNode1 ); + nodesToMove.insert( aNode2 ); } - gp_Pnt PC1(xc1/4.,yc1/4.,zc1/4.); - gp_Pnt PC2(xc2/4.,yc2/4.,zc2/4.); - gp_Vec VN1(PC1,Ps1[4]); - gp_Vec VI1(PC1,Pint); - gp_Vec VN2(PC2,Ps2[4]); - gp_Vec VI2(PC2,Pint); - double ang1 = fabs(VN1.Angle(VI1)); - double ang2 = fabs(VN2.Angle(VI2)); - double h1,h2; - if(ang1>PI/3.) - h1 = VI1.Magnitude()/2; - else - h1 = VI1.Magnitude()*cos(ang1); - if(ang2>PI/3.) - h2 = VI2.Magnitude()/2; + // fix intersections that can appear after apex movement + MergeAdjacent( PrmI, nodesToMove ); + MergeAdjacent( PrmJ, nodesToMove ); + + } // end if(hasInt) + } // loop on suspectPyrams + } // loop on 4 base nodes of PrmI + + } // loop on all pyramids + + if( !nodesToMove.empty() && !meshDS->IsEmbeddedMode() ) + { + set::iterator n = nodesToMove.begin(); + for ( ; n != nodesToMove.end(); ++n ) + meshDS->MoveNode( *n, (*n)->X(), (*n)->Y(), (*n)->Z() ); + } + + // move medium nodes of merged quadratic pyramids + if ( myPyramids[0]->IsQuadratic() ) + UpdateQuadraticPyramids( nodesToMove, GetMeshDS() ); + + // erase removed triangles from the proxy mesh + if ( !myRemovedTrias.empty() ) + { + for ( int i = 0; i <= meshDS->MaxShapeIndex(); ++i ) + if ( SMESH_ProxyMesh::SubMesh* sm = findProxySubMesh(i)) + { + vector faces; + faces.reserve( sm->NbElements() ); + SMDS_ElemIteratorPtr fIt = sm->GetElements(); + while ( fIt->more() ) + { + const SMDS_MeshElement* tria = fIt->next(); + set::iterator rmTria = myRemovedTrias.find( tria ); + if ( rmTria != myRemovedTrias.end() ) + myRemovedTrias.erase( rmTria ); else - h2 = VI2.Magnitude()*cos(ang2); - double coef1 = 0.5; - if(ang1(Ns1[4]); - VN1.Scale(coef1); - aNode1->setXYZ( PC1.X()+VN1.X(), PC1.Y()+VN1.Y(), PC1.Z()+VN1.Z() ); - SMDS_MeshNode* aNode2 = const_cast(Ns2[4]); - VN2.Scale(coef2); - aNode2->setXYZ( PC2.X()+VN2.X(), PC2.Y()+VN2.Y(), PC2.Z()+VN2.Z() ); - NeedMove = true; + faces.push_back( tria ); } - } // end if(hasInt) - else { - //cout<<" no intersec for i="< +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +//============================================================================= +/*! + * + */ +//============================================================================= +StdMeshers_QuadrangleParams::StdMeshers_QuadrangleParams(int hypId, int studyId, + SMESH_Gen * gen) + : SMESH_Hypothesis(hypId, studyId, gen) +{ + _name = "QuadrangleParams"; + _param_algo_dim = 2; + _triaVertexID = -1; + _quadType = QUAD_STANDARD; +} + +//============================================================================= +/*! + * + */ +//============================================================================= +StdMeshers_QuadrangleParams::~StdMeshers_QuadrangleParams() +{ +} + +//============================================================================= +/*! + * + */ +//============================================================================= +void StdMeshers_QuadrangleParams::SetTriaVertex (int id) +{ + if (id != _triaVertexID) { + _triaVertexID = id; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= +void StdMeshers_QuadrangleParams::SetQuadType (StdMeshers_QuadType type) +{ + if (type != _quadType) { + _quadType = type; + NotifySubMeshesHypothesisModification(); + } +} + +//================================================================================ +/*! + * \brief Set positions of enforced nodes + */ +//================================================================================ + +void StdMeshers_QuadrangleParams:: +SetEnforcedNodes( const std::vector< TopoDS_Shape >& shapes, + const std::vector< gp_Pnt >& points ) +{ + bool isChanged = ( shapes != _enforcedVertices || + points.size() != _enforcedPoints.size() ); + for ( size_t i = 0; i < points.size() && !isChanged; ++i ) + isChanged = ( _enforcedPoints[ i ].SquareDistance( points[i] ) > 1e-100 ); + + if ( isChanged ) + { + _enforcedVertices = shapes; + _enforcedPoints = points; + NotifySubMeshesHypothesisModification(); + } +} + +//================================================================================ +/*! + * \brief Returns positions of enforced nodes + */ +//================================================================================ + +void StdMeshers_QuadrangleParams:: +GetEnforcedNodes( std::vector< TopoDS_Shape >& shapes, + std::vector< gp_Pnt >& points ) const +{ + shapes = _enforcedVertices; + points = _enforcedPoints; +} + +//============================================================================= +/*! + * + */ +//============================================================================= +ostream & StdMeshers_QuadrangleParams::SaveTo(ostream & save) +{ + if (_objEntry.size() == 0) + save << _triaVertexID << " UNDEFINED " << int(_quadType); + else + save << _triaVertexID << " " << _objEntry << " " << int(_quadType); + + save << " " << _enforcedPoints.size(); + for ( size_t i = 0; i < _enforcedPoints.size(); ++i ) + save << " " << _enforcedPoints[i].X() + << " " << _enforcedPoints[i].Y() + << " " << _enforcedPoints[i].Z(); + + return save; +} + +//============================================================================= +/*! + * + */ +//============================================================================= +istream & StdMeshers_QuadrangleParams::LoadFrom(istream & load) +{ + bool isOK = true; + isOK = (bool)(load >> _triaVertexID); + if (!isOK) + load.clear(ios::badbit | load.rdstate()); + + isOK = (bool)(load >> _objEntry); + if (!isOK) + load.clear(ios::badbit | load.rdstate()); + + int type; + isOK = (bool)(load >> type); + if (isOK) + _quadType = StdMeshers_QuadType(type); + + // _enforcedVertices are loaded at StdMeshers_I level + // because GEOM objects are referred by study entry. + + int nbP = 0; + double x,y,z; + if ( load >> nbP && nbP > 0 ) + { + _enforcedPoints.reserve( nbP ); + while ( _enforcedPoints.size() < _enforcedPoints.capacity() ) + if ( load >> x && + load >> y && + load >> z ) + _enforcedPoints.push_back( gp_Pnt( x,y,z )); + else + break; + } + return load; +} + +//================================================================================ +/*! + * \brief Redifined method + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ +bool StdMeshers_QuadrangleParams::SetParametersByMesh(const SMESH_Mesh* theMesh, + const TopoDS_Shape& theShape) +{ + if ( !theMesh || theShape.IsNull() ) + return false; + + return true; +} + +//================================================================================ +/*! + * \brief Initialize my parameter values by default parameters. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ +bool StdMeshers_QuadrangleParams::SetParametersByDefaults(const TDefaults& dflts, + const SMESH_Mesh* /*mesh*/) +{ + return true; +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadranglePreference.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadranglePreference.cpp index b78c95bd4a71..1ab6d8cbeade 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadranglePreference.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadranglePreference.cpp @@ -1,28 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH StdMeshers_QuadranglePreference : implementaion of SMESH idl descriptions // File : StdMeshers_QuadranglePreference.cxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_QuadranglePreference.cxx,v 1.4.2.1 2008/11/27 13:03:50 abd Exp $ // #include "StdMeshers_QuadranglePreference.hxx" #include "utilities.h" @@ -41,7 +41,7 @@ StdMeshers_QuadranglePreference::StdMeshers_QuadranglePreference(int hyp :SMESH_Hypothesis(hypId, studyId, gen) { _name = "QuadranglePreference"; - _param_algo_dim = -2; // auxiliary used by StdMeshers_Quadrangle_2D + _param_algo_dim = -2; // auxiliary used by NETGEN 2D } //============================================================================= @@ -76,27 +76,6 @@ istream & StdMeshers_QuadranglePreference::LoadFrom(istream & load) return load; } -//============================================================================= -/*! - * - */ -//============================================================================= - -ostream & operator <<(ostream & save, StdMeshers_QuadranglePreference & hyp) -{ - return hyp.SaveTo( save ); -} - -//============================================================================= -/*! - * - */ -//============================================================================= - -istream & operator >>(istream & load, StdMeshers_QuadranglePreference & hyp) -{ - return hyp.LoadFrom( load ); -} //================================================================================ /*! * \brief Initialize my parameter values by the mesh built on the geometry @@ -126,3 +105,4 @@ bool StdMeshers_QuadranglePreference::SetParametersByDefaults(const TDefaults& { return false; } + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Quadrangle_2D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Quadrangle_2D.cpp index 98729b850007..f7ac411d9a55 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Quadrangle_2D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Quadrangle_2D.cpp @@ -1,86 +1,73 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // - // SMESH SMESH : implementaion of SMESH idl descriptions + // File : StdMeshers_Quadrangle_2D.cxx -// Moved here from SMESH_Quadrangle_2D.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx,v 1.14.2.5 2008/11/27 13:03:49 abd Exp $ -// -#include "StdMeshers_Quadrangle_2D.hxx" -#include "StdMeshers_FaceSide.hxx" +#include "StdMeshers_Quadrangle_2D.hxx" +#include "SMDS_EdgePosition.hxx" +#include "SMDS_FacePosition.hxx" +#include "SMDS_MeshElement.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMESH_Block.hxx" +#include "SMESH_Comment.hxx" #include "SMESH_Gen.hxx" +#include "SMESH_HypoFilter.hxx" #include "SMESH_Mesh.hxx" -#include "SMESH_subMesh.hxx" +#include "SMESH_MeshAlgos.hxx" #include "SMESH_MesherHelper.hxx" -#include "SMESH_Block.hxx" -#include "SMESH_Comment.hxx" - -#include "SMDS_MeshElement.hxx" -#include "SMDS_MeshNode.hxx" -#include "SMDS_EdgePosition.hxx" -#include "SMDS_FacePosition.hxx" +#include "SMESH_subMesh.hxx" +#include "StdMeshers_FaceSide.hxx" +#include "StdMeshers_QuadrangleParams.hxx" +#include "StdMeshers_ViscousLayers2D.hxx" -#include +#include +#include #include +#include +#include #include +#include #include +#include +#include #include #include #include +#include +#include #include +#include #include -#ifndef __BORLANDC__ -#include -#else -#include -#endif - #include "utilities.h" -#include "SMESH_ExceptHandlers.hxx" - -#include +#include "Utils_ExceptHandlers.hxx" #ifndef StdMeshers_Array2OfNode_HeaderFile #define StdMeshers_Array2OfNode_HeaderFile typedef const SMDS_MeshNode* SMDS_MeshNodePtr; - -#ifndef __BORLANDC__ -#if OCC_VERSION_HEX >= 0x060703 typedef NCollection_Array2 StdMeshers_Array2OfNode; -#else -DEFINE_BASECOLLECTION (StdMeshers_BaseCollectionNodePtr, SMDS_MeshNodePtr) -DEFINE_ARRAY2(StdMeshers_Array2OfNode, - StdMeshers_BaseCollectionNodePtr, SMDS_MeshNodePtr) -#endif -#else -DEFINE_BASECOLLECTION (StdMeshers_BaseCollectionNodePtr, SMDS_MeshNodePtr) -SMESH_DEFINE_ARRAY2(StdMeshers_Array2OfNode, - StdMeshers_BaseCollectionNodePtr, SMDS_MeshNodePtr) -#endif - #endif using namespace std; @@ -90,24 +77,34 @@ typedef SMESH_Comment TComm; //============================================================================= /*! - * + * */ //============================================================================= -StdMeshers_Quadrangle_2D::StdMeshers_Quadrangle_2D (int hypId, int studyId, SMESH_Gen* gen) - : SMESH_2D_Algo(hypId, studyId, gen) +StdMeshers_Quadrangle_2D::StdMeshers_Quadrangle_2D (int hypId, int studyId, + SMESH_Gen* gen) + : SMESH_2D_Algo(hypId, studyId, gen), + myQuadranglePreference(false), + myTrianglePreference(false), + myTriaVertexID(-1), + myNeedSmooth(false), + myCheckOri(false), + myParams( NULL ), + myQuadType(QUAD_STANDARD), + myHelper( NULL ) { MESSAGE("StdMeshers_Quadrangle_2D::StdMeshers_Quadrangle_2D"); _name = "Quadrangle_2D"; _shapeType = (1 << TopAbs_FACE); + _compatibleHypothesis.push_back("QuadrangleParams"); _compatibleHypothesis.push_back("QuadranglePreference"); _compatibleHypothesis.push_back("TrianglePreference"); - myTool = 0; + _compatibleHypothesis.push_back("ViscousLayers2D"); } //============================================================================= /*! - * + * */ //============================================================================= @@ -127,29 +124,84 @@ bool StdMeshers_Quadrangle_2D::CheckHypothesis const TopoDS_Shape& aShape, SMESH_Hypothesis::Hypothesis_Status& aStatus) { + myTriaVertexID = -1; + myQuadType = QUAD_STANDARD; + myQuadranglePreference = false; + myTrianglePreference = false; + myHelper = (SMESH_MesherHelper*)NULL; + myParams = NULL; + myQuadList.clear(); + bool isOk = true; - aStatus = SMESH_Hypothesis::HYP_OK; + aStatus = SMESH_Hypothesis::HYP_OK; + const list & hyps = + GetUsedHypothesis(aMesh, aShape, false); + const SMESHDS_Hypothesis * aHyp = 0; - const list &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; + bool isFirstParams = true; + + // First assigned hypothesis (if any) is processed now + if (hyps.size() > 0) { + aHyp = hyps.front(); + if (strcmp("QuadrangleParams", aHyp->GetName()) == 0) + { + myParams = (const StdMeshers_QuadrangleParams*)aHyp; + myTriaVertexID = myParams->GetTriaVertex(); + myQuadType = myParams->GetQuadType(); + if (myQuadType == QUAD_QUADRANGLE_PREF || + myQuadType == QUAD_QUADRANGLE_PREF_REVERSED) + myQuadranglePreference = true; + else if (myQuadType == QUAD_TRIANGLE_PREF) + myTrianglePreference = true; } - else if(strcmp("TrianglePreference", theHyp->GetName()) == 0){ - myQuadranglePreference= false; - myTrianglePreference= true; + else if (strcmp("QuadranglePreference", aHyp->GetName()) == 0) { + isFirstParams = false; + myQuadranglePreference = true; + } + else if (strcmp("TrianglePreference", aHyp->GetName()) == 0){ + isFirstParams = false; + myTrianglePreference = true; + } + else { + isFirstParams = false; } } - else { - myQuadranglePreference = false; - myTrianglePreference = false; + + // Second(last) assigned hypothesis (if any) is processed now + if (hyps.size() > 1) { + aHyp = hyps.back(); + if (isFirstParams) { + if (strcmp("QuadranglePreference", aHyp->GetName()) == 0) { + myQuadranglePreference = true; + myTrianglePreference = false; + myQuadType = QUAD_STANDARD; + } + else if (strcmp("TrianglePreference", aHyp->GetName()) == 0){ + myQuadranglePreference = false; + myTrianglePreference = true; + myQuadType = QUAD_STANDARD; + } + } + else { + const StdMeshers_QuadrangleParams* aHyp2 = + (const StdMeshers_QuadrangleParams*)aHyp; + myTriaVertexID = aHyp2->GetTriaVertex(); + + if (!myQuadranglePreference && !myTrianglePreference) { // priority of hypos + myQuadType = aHyp2->GetQuadType(); + if (myQuadType == QUAD_QUADRANGLE_PREF || + myQuadType == QUAD_QUADRANGLE_PREF_REVERSED) + myQuadranglePreference = true; + else if (myQuadType == QUAD_TRIANGLE_PREF) + myTrianglePreference = true; + } + } } - return isOk; + + error( StdMeshers_ViscousLayers2D::CheckHypothesis( aMesh, aShape, aStatus )); + + return aStatus == HYP_OK; } //============================================================================= @@ -158,72 +210,237 @@ bool StdMeshers_Quadrangle_2D::CheckHypothesis */ //============================================================================= -bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape)// throw (SMESH_Exception) +bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape) { - // PAL14921. Enable catching std::bad_alloc and Standard_OutOfMemory outside - //Unexpect aCatchSalomeException); + const TopoDS_Face& F = TopoDS::Face(aShape); + aMesh.GetSubMesh( F ); + + // do not initialize my fields before this as StdMeshers_ViscousLayers2D + // can call Compute() recursively + SMESH_ProxyMesh::Ptr proxyMesh = StdMeshers_ViscousLayers2D::Compute( aMesh, F ); + if ( !proxyMesh ) + return false; - SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); - aMesh.GetSubMesh(aShape); + myProxyMesh = proxyMesh; - SMESH_MesherHelper helper(aMesh); - myTool = &helper; + SMESH_MesherHelper helper (aMesh); + myHelper = &helper; - _quadraticMesh = myTool->IsQuadraticSubMesh(aShape); + _quadraticMesh = myHelper->IsQuadraticSubMesh(aShape); + myHelper->SetElementsOnShape( true ); + myNeedSmooth = false; + myCheckOri = false; - FaceQuadStruct *quad = CheckNbEdges( aMesh, aShape ); - std::auto_ptr quadDeleter( quad ); // to delete quad at exit from Compute() + FaceQuadStruct::Ptr quad = CheckNbEdges( aMesh, F, /*considerMesh=*/true ); if (!quad) return false; + myQuadList.clear(); + myQuadList.push_back( quad ); + + if ( !getEnforcedUV() ) + return false; + + updateDegenUV( quad ); - if(myQuadranglePreference) { - int n1 = quad->side[0]->NbPoints(); - int n2 = quad->side[1]->NbPoints(); - int n3 = quad->side[2]->NbPoints(); - int n4 = quad->side[3]->NbPoints(); + int n1 = quad->side[0].NbPoints(); + int n2 = quad->side[1].NbPoints(); + int n3 = quad->side[2].NbPoints(); + int n4 = quad->side[3].NbPoints(); + + enum { NOT_COMPUTED = -1, COMPUTE_FAILED = 0, COMPUTE_OK = 1 }; + int res = NOT_COMPUTED; + if ( myQuadranglePreference ) + { int nfull = n1+n2+n3+n4; - int ntmp = nfull/2; - ntmp = ntmp*2; - if( nfull==ntmp && ( (n1!=n3) || (n2!=n4) ) ) { - // special path for using only quandrangle faces - bool ok = ComputeQuadPref(aMesh, aShape, quad); - return ok; + if ((nfull % 2) == 0 && ((n1 != n3) || (n2 != n4))) + { + // special path genarating only quandrangle faces + res = computeQuadPref( aMesh, F, quad ); + } + } + else if ( myQuadType == QUAD_REDUCED ) + { + int n13 = n1 - n3; + int n24 = n2 - n4; + int n13tmp = n13/2; n13tmp = n13tmp*2; + int n24tmp = n24/2; n24tmp = n24tmp*2; + if ((n1 == n3 && n2 != n4 && n24tmp == n24) || + (n2 == n4 && n1 != n3 && n13tmp == n13)) + { + res = computeReduced( aMesh, F, quad ); + } + else + { + if ( n1 != n3 && n2 != n4 ) + error( COMPERR_WARNING, + "To use 'Reduced' transition, " + "two opposite sides should have same number of segments, " + "but actual number of segments is different on all sides. " + "'Standard' transion has been used."); + else if ( ! ( n1 == n3 && n2 == n4 )) + error( COMPERR_WARNING, + "To use 'Reduced' transition, " + "two opposite sides should have an even difference in number of segments. " + "'Standard' transion has been used."); } } - // set normalized grid on unit square in parametric domain - - if (!SetNormalizedGrid(aMesh, aShape, quad)) + if ( res == NOT_COMPUTED ) + { + if ( n1 != n3 || n2 != n4 ) + res = computeTriangles( aMesh, F, quad ); + else + res = computeQuadDominant( aMesh, F ); + } + + if ( res == COMPUTE_OK && myNeedSmooth ) + smooth( quad ); + + if ( res == COMPUTE_OK ) + res = check(); + + return ( res == COMPUTE_OK ); +} + +//================================================================================ +/*! + * \brief Compute quadrangles and triangles on the quad + */ +//================================================================================ + +bool StdMeshers_Quadrangle_2D::computeTriangles(SMESH_Mesh& aMesh, + const TopoDS_Face& aFace, + FaceQuadStruct::Ptr quad) +{ + int nb = quad->side[0].grid->NbPoints(); + int nr = quad->side[1].grid->NbPoints(); + int nt = quad->side[2].grid->NbPoints(); + int nl = quad->side[3].grid->NbPoints(); + + // rotate the quad to have nbNodeOut sides on TOP [and LEFT] + if ( nb > nt ) + quad->shift( nl > nr ? 3 : 2, true ); + else if ( nr > nl ) + quad->shift( 1, true ); + else if ( nl > nr ) + quad->shift( nt > nb ? 0 : 3, true ); + + if ( !setNormalizedGrid( quad )) + return false; + + if ( quad->nbNodeOut( QUAD_TOP_SIDE )) + { + splitQuad( quad, 0, quad->jSize-2 ); + } + if ( quad->nbNodeOut( QUAD_BOTTOM_SIDE )) // this should not happen + { + splitQuad( quad, 0, 1 ); + } + FaceQuadStruct::Ptr newQuad = myQuadList.back(); + if ( quad != newQuad ) // split done + { + { // update left side limit till where to make triangles + FaceQuadStruct::Ptr botQuad = // a bottom part + ( quad->side[ QUAD_LEFT_SIDE ].from == 0 ) ? quad : newQuad; + if ( botQuad->nbNodeOut( QUAD_LEFT_SIDE ) > 0 ) + botQuad->side[ QUAD_LEFT_SIDE ].to += botQuad->nbNodeOut( QUAD_LEFT_SIDE ); + else if ( botQuad->nbNodeOut( QUAD_RIGHT_SIDE ) > 0 ) + botQuad->side[ QUAD_RIGHT_SIDE ].to += botQuad->nbNodeOut( QUAD_RIGHT_SIDE ); + } + // make quad be a greatest one + if ( quad->side[ QUAD_LEFT_SIDE ].NbPoints() == 2 || + quad->side[ QUAD_RIGHT_SIDE ].NbPoints() == 2 ) + quad = newQuad; + if ( !setNormalizedGrid( quad )) + return false; + } + + if ( quad->nbNodeOut( QUAD_RIGHT_SIDE )) + { + splitQuad( quad, quad->iSize-2, 0 ); + } + if ( quad->nbNodeOut( QUAD_LEFT_SIDE )) + { + splitQuad( quad, 1, 0 ); + + if ( quad->nbNodeOut( QUAD_TOP_SIDE )) + { + newQuad = myQuadList.back(); + if ( newQuad == quad ) // too narrow to split + { + // update left side limit till where to make triangles + quad->side[ QUAD_LEFT_SIDE ].to--; + } + else + { + FaceQuadStruct::Ptr leftQuad = + ( quad->side[ QUAD_BOTTOM_SIDE ].from == 0 ) ? quad : newQuad; + leftQuad->nbNodeOut( QUAD_TOP_SIDE ) = 0; + } + } + } + + if ( ! computeQuadDominant( aMesh, aFace )) return false; - // --- compute 3D values on points, store points & quadrangles + // try to fix zero-area triangles near straight-angle corners - int nbdown = quad->side[0]->NbPoints(); - int nbup = quad->side[2]->NbPoints(); + return true; +} - int nbright = quad->side[1]->NbPoints(); - int nbleft = quad->side[3]->NbPoints(); +//================================================================================ +/*! + * \brief Compute quadrangles and possibly triangles on all quads of myQuadList + */ +//================================================================================ - int nbhoriz = Min(nbdown, nbup); - int nbvertic = Min(nbright, nbleft); +bool StdMeshers_Quadrangle_2D::computeQuadDominant(SMESH_Mesh& aMesh, + const TopoDS_Face& aFace) +{ + if ( !addEnforcedNodes() ) + return false; - const TopoDS_Face& F = TopoDS::Face(aShape); - Handle(Geom_Surface) S = BRep_Tool::Surface(F); + std::list< FaceQuadStruct::Ptr >::iterator quad = myQuadList.begin(); + for ( ; quad != myQuadList.end(); ++quad ) + if ( !computeQuadDominant( aMesh, aFace, *quad )) + return false; + + return true; +} + +//================================================================================ +/*! + * \brief Compute quadrangles and possibly triangles + */ +//================================================================================ + +bool StdMeshers_Quadrangle_2D::computeQuadDominant(SMESH_Mesh& aMesh, + const TopoDS_Face& aFace, + FaceQuadStruct::Ptr quad) +{ + // --- set normalized grid on unit square in parametric domain + + if ( !setNormalizedGrid( quad )) + return false; + + // --- create nodes on points, and create quadrangles + + int nbhoriz = quad->iSize; + int nbvertic = quad->jSize; // internal mesh nodes - int i, j, geomFaceID = meshDS->ShapeToIndex( F ); - for (i = 1; i < nbhoriz - 1; i++) { - for (j = 1; j < nbvertic - 1; j++) { - int ij = j * nbhoriz + i; - double u = quad->uv_grid[ij].u; - double v = quad->uv_grid[ij].v; - gp_Pnt P = S->Value(u, v); - SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z()); - meshDS->SetNodeOnFace(node, geomFaceID, u, v); - quad->uv_grid[ij].node = node; + SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); + Handle(Geom_Surface) S = BRep_Tool::Surface(aFace); + int i,j, geomFaceID = meshDS->ShapeToIndex(aFace); + for (i = 1; i < nbhoriz - 1; i++) + for (j = 1; j < nbvertic - 1; j++) + { + UVPtStruct& uvPnt = quad->UVPt( i, j ); + gp_Pnt P = S->Value( uvPnt.u, uvPnt.v ); + uvPnt.node = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace( uvPnt.node, geomFaceID, uvPnt.u, uvPnt.v ); } - } // mesh faces @@ -239,48 +456,45 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, // i // [0] - i = 0; int ilow = 0; int iup = nbhoriz - 1; - if (quad->isEdgeOut[3]) { ilow++; } else { if (quad->isEdgeOut[1]) iup--; } + if (quad->nbNodeOut(3)) { ilow++; } else { if (quad->nbNodeOut(1)) iup--; } int jlow = 0; int jup = nbvertic - 1; - if (quad->isEdgeOut[0]) { jlow++; } else { if (quad->isEdgeOut[2]) jup--; } + if (quad->nbNodeOut(0)) { jlow++; } else { if (quad->nbNodeOut(2)) jup--; } // regular quadrangles for (i = ilow; i < iup; i++) { for (j = jlow; j < jup; j++) { const SMDS_MeshNode *a, *b, *c, *d; - a = quad->uv_grid[j * nbhoriz + i].node; - b = quad->uv_grid[j * nbhoriz + i + 1].node; + a = quad->uv_grid[ j * nbhoriz + i ].node; + b = quad->uv_grid[ j * nbhoriz + i + 1].node; c = quad->uv_grid[(j + 1) * nbhoriz + i + 1].node; - d = quad->uv_grid[(j + 1) * nbhoriz + i].node; - //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 { - SplitQuad(meshDS, geomFaceID, a, b, c, d); - } + d = quad->uv_grid[(j + 1) * nbhoriz + i ].node; + myHelper->AddFace(a, b, c, d); } } - const vector& uv_e0 = quad->side[0]->GetUVPtStruct(true,0 ); - const vector& uv_e1 = quad->side[1]->GetUVPtStruct(false,1); - const vector& uv_e2 = quad->side[2]->GetUVPtStruct(true,1 ); - const vector& uv_e3 = quad->side[3]->GetUVPtStruct(false,0); + // Boundary elements (must always be on an outer boundary of the FACE) + + const vector& uv_e0 = quad->side[0].grid->GetUVPtStruct(); + const vector& uv_e1 = quad->side[1].grid->GetUVPtStruct(); + const vector& uv_e2 = quad->side[2].grid->GetUVPtStruct(); + const vector& uv_e3 = quad->side[3].grid->GetUVPtStruct(); - if ( uv_e0.empty() || uv_e1.empty() || uv_e2.empty() || uv_e3.empty() ) - return error( COMPERR_BAD_INPUT_MESH ); + if (uv_e0.empty() || uv_e1.empty() || uv_e2.empty() || uv_e3.empty()) + return error(COMPERR_BAD_INPUT_MESH); double eps = Precision::Confusion(); - // Boundary quadrangles - - if (quad->isEdgeOut[0]) { + int nbdown = (int) uv_e0.size(); + int nbup = (int) uv_e2.size(); + int nbright = (int) uv_e1.size(); + int nbleft = (int) uv_e3.size(); + + if (quad->nbNodeOut(0) && nbvertic == 2) // this should not occure + { // Down edge is out // // |___|___|___|___|___|___| @@ -297,8 +511,12 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, // number of last node of the down edge to be processed int stop = nbdown - 1; // if right edge is out, we will stop at a node, previous to the last one - if (quad->isEdgeOut[1]) stop--; - + //if (quad->nbNodeOut(1)) stop--; + if ( quad->nbNodeOut( QUAD_RIGHT_SIDE )) + quad->UVPt( nbhoriz-1, 1 ).node = uv_e1[1].node; + if ( quad->nbNodeOut( QUAD_LEFT_SIDE )) + quad->UVPt( 0, 1 ).node = uv_e3[1].node; + // for each node of the down edge find nearest node // in the first row of the regular grid and link them for (i = 0; i < stop; i++) { @@ -338,9 +556,7 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, } if (near == g) { // make triangle - //SMDS_MeshFace* face = meshDS->AddFace(a, b, c); - SMDS_MeshFace* face = myTool->AddFace(a, b, c); - meshDS->SetMeshElementOnShape(face, geomFaceID); + myHelper->AddFace(a, b, c); } else { // make quadrangle if (near - 1 < ilow) @@ -349,12 +565,11 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, d = quad->uv_grid[nbhoriz + near - 1].node; //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d); - if(!myTrianglePreference){ - SMDS_MeshFace* face = myTool->AddFace(a, b, c, d); - meshDS->SetMeshElementOnShape(face, geomFaceID); + if (!myTrianglePreference){ + myHelper->AddFace(a, b, c, d); } else { - SplitQuad(meshDS, geomFaceID, a, b, c, d); + splitQuadFace(meshDS, geomFaceID, a, b, c, d); } // if node d is not at position g - make additional triangles @@ -365,16 +580,15 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, d = uv_e3[1].node; else d = quad->uv_grid[nbhoriz + k - 1].node; - //SMDS_MeshFace* face = meshDS->AddFace(a, c, d); - SMDS_MeshFace* face = myTool->AddFace(a, c, d); - meshDS->SetMeshElementOnShape(face, geomFaceID); + myHelper->AddFace(a, c, d); } } g = near; } } } else { - if (quad->isEdgeOut[2]) { + if (quad->nbNodeOut(2) && nbvertic == 2) + { // Up edge is out // // <-<-<-<-<-<-<-<-<-<-<-<-< -- direction of processing @@ -389,17 +603,64 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, int g = nbhoriz - 1; // last processed node in the regular grid - int stop = 0; - // if left edge is out, we will stop at a second node - if (quad->isEdgeOut[3]) stop++; + ilow = 0; + iup = nbhoriz - 1; + int stop = 0; + if ( quad->side[3].grid->Edge(0).IsNull() ) // left side is simulated one + { + // quad divided at I but not at J, as nbvertic==nbright==2 + stop++; // we stop at a second node + } + else + { + if ( quad->nbNodeOut( QUAD_RIGHT_SIDE )) + quad->UVPt( nbhoriz-1, 0 ).node = uv_e1[ nbright-2 ].node; + if ( quad->nbNodeOut( QUAD_LEFT_SIDE )) + quad->UVPt( 0, 0 ).node = uv_e3[ nbleft-2 ].node; + + if ( nbright > 2 ) // there was a split at J + quad->nbNodeOut( QUAD_LEFT_SIDE ) = 0; + } + const SMDS_MeshNode *a, *b, *c, *d; + i = nbup - 1; + // avoid creating zero-area triangles near a straight-angle corner + { + a = uv_e2[i].node; + b = uv_e2[i-1].node; + c = uv_e1[nbright-2].node; + SMESH_TNodeXYZ pa( a ), pb( b ), pc( c ); + double area = 0.5 * (( pb - pa ) ^ ( pc - pa )).Modulus(); + if ( Abs( area ) < 1e-20 ) + { + --g; + d = quad->UVPt( g, nbvertic-2 ).node; + if ( myTrianglePreference ) + { + myHelper->AddFace(a, d, c); + } + else + { + if ( SMDS_MeshFace* face = myHelper->AddFace(a, b, d, c)) + { + SMESH_ComputeErrorPtr& err = aMesh.GetSubMesh( aFace )->GetComputeError(); + if ( !err || err->IsOK() || err->myName < COMPERR_WARNING ) + { + err.reset( new SMESH_ComputeError( COMPERR_WARNING, + "Bad quality quad created")); + err->myBadElements.push_back( face ); + } + } + --i; + } + } + } // for each node of the up edge find nearest node // in the first row of the regular grid and link them - for (i = nbup - 1; i > stop; i--) { - const SMDS_MeshNode *a, *b, *c, *d; + for ( ; i > stop; i--) { a = uv_e2[i].node; b = uv_e2[i - 1].node; - gp_Pnt pb (b->X(), b->Y(), b->Z()); + gp_Pnt pb = SMESH_TNodeXYZ( b ); // find node c in the grid, which will be linked with node b int near = g; @@ -415,7 +676,7 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, nk = uv_e1[nbright - 2].node; else nk = quad->uv_grid[nbhoriz*(nbvertic - 2) + k].node; - gp_Pnt pnk (nk->X(), nk->Y(), nk->Z()); + gp_Pnt pnk = SMESH_TNodeXYZ( nk ); double dist = pb.Distance(pnk); if (dist < mind - eps) { c = nk; @@ -428,9 +689,7 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, } if (near == g) { // make triangle - //SMDS_MeshFace* face = meshDS->AddFace(a, b, c); - SMDS_MeshFace* face = myTool->AddFace(a, b, c); - meshDS->SetMeshElementOnShape(face, geomFaceID); + myHelper->AddFace(a, b, c); } else { // make quadrangle if (near + 1 > iup) @@ -438,24 +697,21 @@ 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); - if(!myTrianglePreference){ - SMDS_MeshFace* face = myTool->AddFace(a, b, c, d); - meshDS->SetMeshElementOnShape(face, geomFaceID); + if (!myTrianglePreference){ + myHelper->AddFace(a, b, c, d); } else { - SplitQuad(meshDS, geomFaceID, a, b, c, d); + splitQuadFace(meshDS, geomFaceID, a, b, c, d); } - if (near + 1 < g) { // if d not is at g - make additional triangles + if (near + 1 < g) { // if d is not at g - make additional triangles for (int k = near + 1; k < g; k++) { c = quad->uv_grid[nbhoriz*(nbvertic - 2) + k].node; if (k + 1 > iup) d = uv_e1[nbright - 2].node; else d = quad->uv_grid[nbhoriz*(nbvertic - 2) + k + 1].node; - //SMDS_MeshFace* face = meshDS->AddFace(a, c, d); - SMDS_MeshFace* face = myTool->AddFace(a, c, d); - meshDS->SetMeshElementOnShape(face, geomFaceID); + myHelper->AddFace(a, c, d); } } g = near; @@ -465,12 +721,14 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, } // right or left boundary quadrangles - if (quad->isEdgeOut[1]) { -// MESSAGE("right edge is out"); + if (quad->nbNodeOut( QUAD_RIGHT_SIDE ) && nbhoriz == 2) // this should not occure + { int g = 0; // last processed node in the grid int stop = nbright - 1; - if (quad->isEdgeOut[2]) stop--; - for (i = 0; i < stop; i++) { + i = 0; + if (quad->side[ QUAD_RIGHT_SIDE ].from != i ) i++; + if (quad->side[ QUAD_RIGHT_SIDE ].to != stop ) stop--; + for ( ; i < stop; i++) { const SMDS_MeshNode *a, *b, *c, *d; a = uv_e1[i].node; b = uv_e1[i + 1].node; @@ -502,9 +760,7 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, } if (near == g) { // make triangle - //SMDS_MeshFace* face = meshDS->AddFace(a, b, c); - SMDS_MeshFace* face = myTool->AddFace(a, b, c); - meshDS->SetMeshElementOnShape(face, geomFaceID); + myHelper->AddFace(a, b, c); } else { // make quadrangle if (near - 1 < jlow) @@ -513,12 +769,11 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, d = quad->uv_grid[nbhoriz*near - 2].node; //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d); - if(!myTrianglePreference){ - SMDS_MeshFace* face = myTool->AddFace(a, b, c, d); - meshDS->SetMeshElementOnShape(face, geomFaceID); + if (!myTrianglePreference){ + myHelper->AddFace(a, b, c, d); } else { - SplitQuad(meshDS, geomFaceID, a, b, c, d); + splitQuadFace(meshDS, geomFaceID, a, b, c, d); } if (near - 1 > g) { // if d not is at g - make additional triangles @@ -528,22 +783,53 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, d = uv_e0[nbdown - 2].node; else d = quad->uv_grid[nbhoriz*k - 2].node; - //SMDS_MeshFace* face = meshDS->AddFace(a, c, d); - SMDS_MeshFace* face = myTool->AddFace(a, c, d); - meshDS->SetMeshElementOnShape(face, geomFaceID); + myHelper->AddFace(a, c, d); } } g = near; } } } else { - if (quad->isEdgeOut[3]) { + if (quad->nbNodeOut(3) && nbhoriz == 2) { // MESSAGE("left edge is out"); int g = nbvertic - 1; // last processed node in the grid int stop = 0; - if (quad->isEdgeOut[0]) stop++; - for (i = nbleft - 1; i > stop; i--) { - const SMDS_MeshNode *a, *b, *c, *d; + i = quad->side[ QUAD_LEFT_SIDE ].to-1; // nbleft - 1; + + const SMDS_MeshNode *a, *b, *c, *d; + // avoid creating zero-area triangles near a straight-angle corner + { + a = uv_e3[i].node; + b = uv_e3[i-1].node; + c = quad->UVPt( 1, g ).node; + SMESH_TNodeXYZ pa( a ), pb( b ), pc( c ); + double area = 0.5 * (( pb - pa ) ^ ( pc - pa )).Modulus(); + if ( Abs( area ) < 1e-20 ) + { + --g; + d = quad->UVPt( 1, g ).node; + if ( myTrianglePreference ) + { + myHelper->AddFace(a, d, c); + } + else + { + if ( SMDS_MeshFace* face = myHelper->AddFace(a, b, d, c)) + { + SMESH_ComputeErrorPtr& err = aMesh.GetSubMesh( aFace )->GetComputeError(); + if ( !err || err->IsOK() || err->myName < COMPERR_WARNING ) + { + err.reset( new SMESH_ComputeError( COMPERR_WARNING, + "Bad quality quad created")); + err->myBadElements.push_back( face ); + } + } + --i; + } + } + } + for (; i > stop; i--) // loop on nodes on the left side + { a = uv_e3[i].node; b = uv_e3[i - 1].node; gp_Pnt pb (b->X(), b->Y(), b->Z()); @@ -553,12 +839,13 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, if (i == stop + 1) { // down bondary reached c = quad->uv_grid[nbhoriz*jlow + 1].node; near = jlow; - } else { + } + else { double mind = RealLast(); for (int k = g; k >= jlow; k--) { const SMDS_MeshNode *nk; if (k > jup) - nk = uv_e2[1].node; + nk = quad->uv_grid[nbhoriz*jup + 1].node; //uv_e2[1].node; else nk = quad->uv_grid[nbhoriz*k + 1].node; gp_Pnt pnk (nk->X(), nk->Y(), nk->Z()); @@ -574,34 +861,28 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, } if (near == g) { // make triangle - //SMDS_MeshFace* face = meshDS->AddFace(a, b, c); - SMDS_MeshFace* face = myTool->AddFace(a, b, c); - meshDS->SetMeshElementOnShape(face, geomFaceID); + myHelper->AddFace(a, b, c); } else { // make quadrangle if (near + 1 > jup) - d = uv_e2[1].node; + d = quad->uv_grid[nbhoriz*jup + 1].node; //uv_e2[1].node; else d = quad->uv_grid[nbhoriz*(near + 1) + 1].node; - //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d); - if(!myTrianglePreference){ - SMDS_MeshFace* face = myTool->AddFace(a, b, c, d); - meshDS->SetMeshElementOnShape(face, geomFaceID); + if (!myTrianglePreference) { + myHelper->AddFace(a, b, c, d); } else { - SplitQuad(meshDS, geomFaceID, a, b, c, d); + splitQuadFace(meshDS, geomFaceID, a, b, c, d); } if (near + 1 < g) { // if d not is at g - make additional triangles for (int k = near + 1; k < g; k++) { c = quad->uv_grid[nbhoriz*k + 1].node; if (k + 1 > jup) - d = uv_e2[1].node; + d = quad->uv_grid[nbhoriz*jup + 1].node; //uv_e2[1].node; else d = quad->uv_grid[nbhoriz*(k + 1) + 1].node; - //SMDS_MeshFace* face = meshDS->AddFace(a, c, d); - SMDS_MeshFace* face = myTool->AddFace(a, c, d); - meshDS->SetMeshElementOnShape(face, geomFaceID); + myHelper->AddFace(a, c, d); } } g = near; @@ -614,6 +895,133 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, return isOk; } + +//============================================================================= +/*! + * Evaluate + */ +//============================================================================= + +bool StdMeshers_Quadrangle_2D::Evaluate(SMESH_Mesh& aMesh, + const TopoDS_Shape& aFace, + MapShapeNbElems& aResMap) + +{ + aMesh.GetSubMesh(aFace); + + std::vector aNbNodes(4); + bool IsQuadratic = false; + if (!checkNbEdgesForEvaluate(aMesh, aFace, aResMap, aNbNodes, IsQuadratic)) { + std::vector aResVec(SMDSEntity_Last); + for (int i=SMDSEntity_Node; iGetComputeError(); + smError.reset(new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); + return false; + } + + if (myQuadranglePreference) { + int n1 = aNbNodes[0]; + int n2 = aNbNodes[1]; + int n3 = aNbNodes[2]; + int n4 = aNbNodes[3]; + int nfull = n1+n2+n3+n4; + int ntmp = nfull/2; + ntmp = ntmp*2; + if (nfull==ntmp && ((n1!=n3) || (n2!=n4))) { + // special path for using only quandrangle faces + return evaluateQuadPref(aMesh, aFace, aNbNodes, aResMap, IsQuadratic); + //return true; + } + } + + int nbdown = aNbNodes[0]; + int nbup = aNbNodes[2]; + + int nbright = aNbNodes[1]; + int nbleft = aNbNodes[3]; + + int nbhoriz = Min(nbdown, nbup); + int nbvertic = Min(nbright, nbleft); + + int dh = Max(nbdown, nbup) - nbhoriz; + int dv = Max(nbright, nbleft) - nbvertic; + + //int kdh = 0; + //if (dh>0) kdh = 1; + //int kdv = 0; + //if (dv>0) kdv = 1; + + int nbNodes = (nbhoriz-2)*(nbvertic-2); + //int nbFaces3 = dh + dv + kdh*(nbvertic-1)*2 + kdv*(nbhoriz-1)*2; + int nbFaces3 = dh + dv; + //if (kdh==1 && kdv==1) nbFaces3 -= 2; + //if (dh>0 && dv>0) nbFaces3 -= 2; + //int nbFaces4 = (nbhoriz-1-kdh)*(nbvertic-1-kdv); + int nbFaces4 = (nbhoriz-1)*(nbvertic-1); + + std::vector aVec(SMDSEntity_Last); + for (int i=SMDSEntity_Node; i= 3 ) return true; + } + return ( toCheckAll && nbFoundFaces != 0 ); +} + //================================================================================ /*! * \brief Return true if only two given edges meat at their common vertex @@ -625,12 +1033,12 @@ static bool twoEdgesMeatAtVertex(const TopoDS_Edge& e1, SMESH_Mesh & mesh) { TopoDS_Vertex v; - if ( !TopExp::CommonVertex( e1, e2, v )) + if (!TopExp::CommonVertex(e1, e2, v)) return false; - TopTools_ListIteratorOfListOfShape ancestIt( mesh.GetAncestors( v )); - for ( ; ancestIt.More() ; ancestIt.Next() ) - if ( ancestIt.Value().ShapeType() == TopAbs_EDGE ) - if ( !e1.IsSame( ancestIt.Value() ) && !e2.IsSame( ancestIt.Value() )) + TopTools_ListIteratorOfListOfShape ancestIt(mesh.GetAncestors(v)); + for (; ancestIt.More() ; ancestIt.Next()) + if (ancestIt.Value().ShapeType() == TopAbs_EDGE) + if (!e1.IsSame(ancestIt.Value()) && !e2.IsSame(ancestIt.Value())) return false; return true; } @@ -641,164 +1049,355 @@ static bool twoEdgesMeatAtVertex(const TopoDS_Edge& e1, */ //============================================================================= -FaceQuadStruct* StdMeshers_Quadrangle_2D::CheckNbEdges(SMESH_Mesh & aMesh, - const TopoDS_Shape & aShape) - //throw(SMESH_Exception) +FaceQuadStruct::Ptr StdMeshers_Quadrangle_2D::CheckNbEdges(SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + const bool considerMesh) { - const TopoDS_Face & F = TopoDS::Face(aShape); + if ( !myQuadList.empty() && myQuadList.front()->face.IsSame( aShape )) + return myQuadList.front(); + + TopoDS_Face F = TopoDS::Face(aShape); + if ( F.Orientation() >= TopAbs_INTERNAL ) F.Orientation( TopAbs_FORWARD ); const bool ignoreMediumNodes = _quadraticMesh; - // verify 1 wire only, with 4 edges - TopoDS_Vertex V; + // verify 1 wire only list< TopoDS_Edge > edges; list< int > nbEdgesInWire; - int nbWire = SMESH_Block::GetOrderedEdges (F, V, edges, nbEdgesInWire); + int nbWire = SMESH_Block::GetOrderedEdges (F, edges, nbEdgesInWire); if (nbWire != 1) { error(COMPERR_BAD_SHAPE, TComm("Wrong number of wires: ") << nbWire); - return 0; + return FaceQuadStruct::Ptr(); + } + + // find corner vertices of the quad + vector corners; + int nbDegenEdges, nbSides = getCorners( F, aMesh, edges, corners, nbDegenEdges, considerMesh ); + if ( nbSides == 0 ) + { + return FaceQuadStruct::Ptr(); } - FaceQuadStruct* quad = new FaceQuadStruct; - quad->uv_grid = 0; + FaceQuadStruct::Ptr quad( new FaceQuadStruct ); quad->side.reserve(nbEdgesInWire.front()); + quad->face = F; - int nbSides = 0; list< TopoDS_Edge >::iterator edgeIt = edges.begin(); - if ( nbEdgesInWire.front() == 4 ) { // exactly 4 edges - for ( ; edgeIt != edges.end(); ++edgeIt, nbSides++ ) - quad->side.push_back( new StdMeshers_FaceSide(F, *edgeIt, &aMesh, - nbSides sideEdges; + TopoDS_Vertex nextSideV = corners[( iSide + 1 ) % 3 ]; + while ( edgeIt != edges.end() && + !nextSideV.IsSame( SMESH_MesherHelper::IthVertex( 0, *edgeIt ))) + if ( SMESH_Algo::isDegenerated( *edgeIt )) + ++edgeIt; + else + sideEdges.push_back( *edgeIt++ ); + if ( !sideEdges.empty() ) + quad->side.push_back( StdMeshers_FaceSide::New(F, sideEdges, &aMesh, iSide < QUAD_TOP_SIDE, + ignoreMediumNodes, myProxyMesh)); + else + --iSide; + } + const vector& UVPSleft = quad->side[0].GetUVPtStruct(true,0); + /* vector& UVPStop = */quad->side[1].GetUVPtStruct(false,1); + /* vector& UVPSright = */quad->side[2].GetUVPtStruct(true,1); + const SMDS_MeshNode* aNode = UVPSleft[0].node; + gp_Pnt2d aPnt2d = UVPSleft[0].UV(); + quad->side.push_back( StdMeshers_FaceSide::New( quad->side[1].grid.get(), aNode, &aPnt2d )); + myNeedSmooth = ( nbDegenEdges > 0 ); + return quad; } - else if ( nbEdgesInWire.front() > 4 ) { // more than 4 edges - try to unite some - list< TopoDS_Edge > sideEdges; - while ( !edges.empty()) { - sideEdges.clear(); - sideEdges.splice( sideEdges.end(), edges, edges.begin()); // edges.front() -> sideEdges.end() - bool sameSide = true; - while ( !edges.empty() && sameSide ) { - sameSide = SMESH_Algo::IsContinuous( sideEdges.back(), edges.front() ); - if ( sameSide ) - sideEdges.splice( sideEdges.end(), edges, edges.begin()); - } - if ( nbSides == 0 ) { // go backward from the first edge - sameSide = true; - while ( !edges.empty() && sameSide ) { - sameSide = SMESH_Algo::IsContinuous( sideEdges.front(), edges.back() ); - if ( sameSide ) - sideEdges.splice( sideEdges.begin(), edges, --edges.end()); + else // 4 sides + { + myNeedSmooth = ( corners.size() == 4 && nbDegenEdges > 0 ); + int iSide = 0, nbUsedDegen = 0, nbLoops = 0; + for ( ; edgeIt != edges.end(); ++nbLoops ) + { + list< TopoDS_Edge > sideEdges; + TopoDS_Vertex nextSideV = corners[( iSide + 1 - nbUsedDegen ) % corners.size() ]; + bool nextSideVReached = false; + do + { + const TopoDS_Edge& edge = *edgeIt; + nextSideVReached = nextSideV.IsSame( myHelper->IthVertex( 1, edge )); + if ( SMESH_Algo::isDegenerated( edge )) + { + if ( !myNeedSmooth ) // need to make a side on a degen edge + { + if ( sideEdges.empty() ) + { + sideEdges.push_back( edge ); + ++nbUsedDegen; + nextSideVReached = true; + } + else + { + break; + } + } + } + else + { + sideEdges.push_back( edge ); } + ++edgeIt; + } + while ( edgeIt != edges.end() && !nextSideVReached ); + + if ( !sideEdges.empty() ) + { + quad->side.push_back + ( StdMeshers_FaceSide::New( F, sideEdges, &aMesh, iSide < QUAD_TOP_SIDE, + ignoreMediumNodes, myProxyMesh )); + ++iSide; + } + if ( quad->side.size() == 4 ) + break; + if ( nbLoops > 8 ) + { + error(TComm("Bug: infinite loop in StdMeshers_Quadrangle_2D::CheckNbEdges()")); + quad.reset(); + break; } - quad->side.push_back( new StdMeshers_FaceSide(F, sideEdges, &aMesh, - nbSidesside.clear(); - quad->side.reserve(nbEdgesInWire.front()); - nbSides = 0; + if ( quad && quad->side.size() != 4 ) + { + error(TComm("Bug: ") << quad->side.size() << " sides found instead of 4"); + quad.reset(); + } + } - SMESH_Block::GetOrderedEdges (F, V, edges, nbEdgesInWire); - while ( !edges.empty()) { - sideEdges.clear(); - sideEdges.splice( sideEdges.end(), edges, edges.begin()); - bool sameSide = true; - while ( !edges.empty() && sameSide ) { - sameSide = - SMESH_Algo::IsContinuous( sideEdges.back(), edges.front() ) && - twoEdgesMeatAtVertex( sideEdges.back(), edges.front(), aMesh ); - if ( sameSide ) - sideEdges.splice( sideEdges.end(), edges, edges.begin()); - } - if ( nbSides == 0 ) { // go backward from the first edge - sameSide = true; - while ( !edges.empty() && sameSide ) { - sameSide = - SMESH_Algo::IsContinuous( sideEdges.front(), edges.back() ) && - twoEdgesMeatAtVertex( sideEdges.front(), edges.back(), aMesh ); - if ( sameSide ) - sideEdges.splice( sideEdges.begin(), edges, --edges.end()); + return quad; +} + + +//============================================================================= +/*! + * + */ +//============================================================================= + +bool StdMeshers_Quadrangle_2D::checkNbEdgesForEvaluate(SMESH_Mesh& aMesh, + const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap, + std::vector& aNbNodes, + bool& IsQuadratic) + +{ + const TopoDS_Face & F = TopoDS::Face(aShape); + + // verify 1 wire only, with 4 edges + list< TopoDS_Edge > edges; + list< int > nbEdgesInWire; + int nbWire = SMESH_Block::GetOrderedEdges (F, edges, nbEdgesInWire); + if (nbWire != 1) { + return false; + } + + aNbNodes.resize(4); + + int nbSides = 0; + list< TopoDS_Edge >::iterator edgeIt = edges.begin(); + SMESH_subMesh * sm = aMesh.GetSubMesh(*edgeIt); + MapShapeNbElemsItr anIt = aResMap.find(sm); + if (anIt==aResMap.end()) { + return false; + } + std::vector aVec = (*anIt).second; + IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]); + if (nbEdgesInWire.front() == 3) { // exactly 3 edges + if (myTriaVertexID>0) { + SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); + TopoDS_Vertex V = TopoDS::Vertex(meshDS->IndexToShape(myTriaVertexID)); + if (!V.IsNull()) { + TopoDS_Edge E1,E2,E3; + for (; edgeIt != edges.end(); ++edgeIt) { + TopoDS_Edge E = TopoDS::Edge(*edgeIt); + TopoDS_Vertex VF, VL; + TopExp::Vertices(E, VF, VL, true); + if (VF.IsSame(V)) + E1 = E; + else if (VL.IsSame(V)) + E3 = E; + else + E2 = E; + } + SMESH_subMesh * sm = aMesh.GetSubMesh(E1); + MapShapeNbElemsItr anIt = aResMap.find(sm); + if (anIt==aResMap.end()) return false; + std::vector aVec = (*anIt).second; + if (IsQuadratic) + aNbNodes[0] = (aVec[SMDSEntity_Node]-1)/2 + 2; + else + aNbNodes[0] = aVec[SMDSEntity_Node] + 2; + sm = aMesh.GetSubMesh(E2); + anIt = aResMap.find(sm); + if (anIt==aResMap.end()) return false; + aVec = (*anIt).second; + if (IsQuadratic) + aNbNodes[1] = (aVec[SMDSEntity_Node]-1)/2 + 2; + else + aNbNodes[1] = aVec[SMDSEntity_Node] + 2; + sm = aMesh.GetSubMesh(E3); + anIt = aResMap.find(sm); + if (anIt==aResMap.end()) return false; + aVec = (*anIt).second; + if (IsQuadratic) + aNbNodes[2] = (aVec[SMDSEntity_Node]-1)/2 + 2; + else + aNbNodes[2] = aVec[SMDSEntity_Node] + 2; + aNbNodes[3] = aNbNodes[1]; + aNbNodes.resize(5); + nbSides = 4; + } + } + } + if (nbEdgesInWire.front() == 4) { // exactly 4 edges + for (; edgeIt != edges.end(); edgeIt++) { + SMESH_subMesh * sm = aMesh.GetSubMesh(*edgeIt); + MapShapeNbElemsItr anIt = aResMap.find(sm); + if (anIt==aResMap.end()) { + return false; + } + std::vector aVec = (*anIt).second; + if (IsQuadratic) + aNbNodes[nbSides] = (aVec[SMDSEntity_Node]-1)/2 + 2; + else + aNbNodes[nbSides] = aVec[SMDSEntity_Node] + 2; + nbSides++; + } + } + else if (nbEdgesInWire.front() > 4) { // more than 4 edges - try to unite some + list< TopoDS_Edge > sideEdges; + while (!edges.empty()) { + sideEdges.clear(); + sideEdges.splice(sideEdges.end(), edges, edges.begin()); // edges.front() -> sideEdges.end() + bool sameSide = true; + while (!edges.empty() && sameSide) { + sameSide = SMESH_Algo::IsContinuous(sideEdges.back(), edges.front()); + if (sameSide) + sideEdges.splice(sideEdges.end(), edges, edges.begin()); + } + if (nbSides == 0) { // go backward from the first edge + sameSide = true; + while (!edges.empty() && sameSide) { + sameSide = SMESH_Algo::IsContinuous(sideEdges.front(), edges.back()); + if (sameSide) + sideEdges.splice(sideEdges.begin(), edges, --edges.end()); + } + } + list::iterator ite = sideEdges.begin(); + aNbNodes[nbSides] = 1; + for (; ite!=sideEdges.end(); ite++) { + SMESH_subMesh * sm = aMesh.GetSubMesh(*ite); + MapShapeNbElemsItr anIt = aResMap.find(sm); + if (anIt==aResMap.end()) { + return false; + } + std::vector aVec = (*anIt).second; + if (IsQuadratic) + aNbNodes[nbSides] += (aVec[SMDSEntity_Node]-1)/2 + 1; + else + aNbNodes[nbSides] += aVec[SMDSEntity_Node] + 1; + } + ++nbSides; + } + // issue 20222. Try to unite only edges shared by two same faces + if (nbSides < 4) { + nbSides = 0; + SMESH_Block::GetOrderedEdges (F, edges, nbEdgesInWire); + while (!edges.empty()) { + sideEdges.clear(); + sideEdges.splice(sideEdges.end(), edges, edges.begin()); + bool sameSide = true; + while (!edges.empty() && sameSide) { + sameSide = + SMESH_Algo::IsContinuous(sideEdges.back(), edges.front()) && + twoEdgesMeatAtVertex(sideEdges.back(), edges.front(), aMesh); + if (sameSide) + sideEdges.splice(sideEdges.end(), edges, edges.begin()); + } + if (nbSides == 0) { // go backward from the first edge + sameSide = true; + while (!edges.empty() && sameSide) { + sameSide = + SMESH_Algo::IsContinuous(sideEdges.front(), edges.back()) && + twoEdgesMeatAtVertex(sideEdges.front(), edges.back(), aMesh); + if (sameSide) + sideEdges.splice(sideEdges.begin(), edges, --edges.end()); + } + } + list::iterator ite = sideEdges.begin(); + aNbNodes[nbSides] = 1; + for (; ite!=sideEdges.end(); ite++) { + SMESH_subMesh * sm = aMesh.GetSubMesh(*ite); + MapShapeNbElemsItr anIt = aResMap.find(sm); + if (anIt==aResMap.end()) { + return false; } + std::vector aVec = (*anIt).second; + if (IsQuadratic) + aNbNodes[nbSides] += (aVec[SMDSEntity_Node]-1)/2 + 1; + else + aNbNodes[nbSides] += aVec[SMDSEntity_Node] + 1; } - quad->side.push_back( new StdMeshers_FaceSide(F, sideEdges, &aMesh, - nbSidesside[i]->NbEdges(); ++e ) - MESSAGE ( myTool->GetMeshDS()->ShapeToIndex( quad->side[i]->Edge( e )) << " " ); - MESSAGE ( ")\n" ); - } - //cout << endl; -#endif - if ( !nbSides ) + if (!nbSides) nbSides = nbEdgesInWire.front(); error(COMPERR_BAD_SHAPE, TComm("Face must have 4 sides but not ") << nbSides); - delete quad; - quad = 0; + return false; } - return quad; + return true; } + //============================================================================= /*! * CheckAnd2Dcompute */ //============================================================================= -FaceQuadStruct *StdMeshers_Quadrangle_2D::CheckAnd2Dcompute - (SMESH_Mesh & aMesh, - const TopoDS_Shape & aShape, - const bool CreateQuadratic) //throw(SMESH_Exception) +FaceQuadStruct::Ptr +StdMeshers_Quadrangle_2D::CheckAnd2Dcompute (SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + const bool CreateQuadratic) { _quadraticMesh = CreateQuadratic; - FaceQuadStruct *quad = CheckNbEdges(aMesh, aShape); - - if(!quad) return 0; - - // set normalized grid on unit square in parametric domain - bool stat = SetNormalizedGrid(aMesh, aShape, quad); - if(!stat) { - if(!quad) - delete quad; - quad = 0; + FaceQuadStruct::Ptr quad = CheckNbEdges(aMesh, aShape); + if ( quad ) + { + // set normalized grid on unit square in parametric domain + if ( ! setNormalizedGrid( quad )) + quad.reset(); } - return quad; } -//============================================================================= -/*! - * - */ -//============================================================================= - -faceQuadStruct::~faceQuadStruct() +namespace { - for (int i = 0; i < side.size(); i++) { - if (side[i]) delete side[i]; + inline const vector& getUVPtStructIn(FaceQuadStruct::Ptr& quad, int i, int nbSeg) + { + bool isXConst = (i == QUAD_BOTTOM_SIDE || i == QUAD_TOP_SIDE); + double constValue = (i == QUAD_BOTTOM_SIDE || i == QUAD_LEFT_SIDE) ? 0 : 1; + return + quad->nbNodeOut(i) ? + quad->side[i].grid->SimulateUVPtStruct(nbSeg,isXConst,constValue) : + quad->side[i].grid->GetUVPtStruct (isXConst,constValue); } - if (uv_grid) delete [] uv_grid; -} - -namespace { - inline const vector& GetUVPtStructIn(FaceQuadStruct* quad, int i, int nbSeg) + inline gp_UV calcUV(double x, double y, + const gp_UV& a0,const gp_UV& a1,const gp_UV& a2,const gp_UV& a3, + const gp_UV& p0,const gp_UV& p1,const gp_UV& p2,const gp_UV& p3) { - bool isXConst = ( i == BOTTOM_SIDE || i == TOP_SIDE ); - double constValue = ( i == BOTTOM_SIDE || i == LEFT_SIDE ) ? 0 : 1; return - quad->isEdgeOut[i] ? - quad->side[i]->SimulateUVPtStruct(nbSeg,isXConst,constValue) : - quad->side[i]->GetUVPtStruct(isXConst,constValue); + ((1 - y) * p0 + x * p1 + y * p2 + (1 - x) * p3 ) - + ((1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3); } } @@ -808,20 +1407,16 @@ namespace { */ //============================================================================= -bool StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh, - const TopoDS_Shape& aShape, - FaceQuadStruct* & quad) //throw (SMESH_Exception) +bool StdMeshers_Quadrangle_2D::setNormalizedGrid (FaceQuadStruct::Ptr quad) { + if ( !quad->uv_grid.empty() ) + return true; + // Algorithme décrit dans "Génération automatique de maillages" // P.L. GEORGE, MASSON, § 6.4.1 p. 84-85 // traitement dans le domaine paramétrique 2d u,v // transport - projection sur le carré unité -// MESSAGE("StdMeshers_Quadrangle_2D::SetNormalizedGrid"); -// const TopoDS_Face& F = TopoDS::Face(aShape); - - // 1 --- find orientation of the 4 edges, by test on extrema - // max min 0 x1 1 // |<----north-2-------^ a3 -------------> a2 // | | ^1 1^ @@ -833,106 +1428,141 @@ bool StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh, // min max 0 x0 1 // =down // + const FaceQuadStruct::Side & bSide = quad->side[0]; + const FaceQuadStruct::Side & rSide = quad->side[1]; + const FaceQuadStruct::Side & tSide = quad->side[2]; + const FaceQuadStruct::Side & lSide = quad->side[3]; - // 3 --- 2D normalized values on unit square [0..1][0..1] - - int nbhoriz = Min(quad->side[0]->NbPoints(), quad->side[2]->NbPoints()); - int nbvertic = Min(quad->side[1]->NbPoints(), quad->side[3]->NbPoints()); - - quad->isEdgeOut[0] = (quad->side[0]->NbPoints() > quad->side[2]->NbPoints()); - quad->isEdgeOut[1] = (quad->side[1]->NbPoints() > quad->side[3]->NbPoints()); - quad->isEdgeOut[2] = (quad->side[2]->NbPoints() > quad->side[0]->NbPoints()); - quad->isEdgeOut[3] = (quad->side[3]->NbPoints() > quad->side[1]->NbPoints()); - - UVPtStruct *uv_grid = quad->uv_grid = new UVPtStruct[nbvertic * nbhoriz]; - - const vector& uv_e0 = GetUVPtStructIn( quad, 0, nbhoriz - 1 ); - const vector& uv_e1 = GetUVPtStructIn( quad, 1, nbvertic - 1 ); - const vector& uv_e2 = GetUVPtStructIn( quad, 2, nbhoriz - 1 ); - const vector& uv_e3 = GetUVPtStructIn( quad, 3, nbvertic - 1 ); + int nbhoriz = Min( bSide.NbPoints(), tSide.NbPoints() ); + int nbvertic = Min( rSide.NbPoints(), lSide.NbPoints() ); + if ( nbhoriz < 1 || nbvertic < 1 ) + return error("Algo error: empty quad"); - if ( uv_e0.empty() || uv_e1.empty() || uv_e2.empty() || uv_e3.empty() ) - //return error( "Can't find nodes on sides"); - return error( COMPERR_BAD_INPUT_MESH ); - - // nodes Id on "in" edges - if (! quad->isEdgeOut[0]) { - int j = 0; - for (int i = 0; i < nbhoriz; i++) { // down - int ij = j * nbhoriz + i; - uv_grid[ij].node = uv_e0[i].node; + if ( myQuadList.size() == 1 ) + { + // all sub-quads must have NO sides with nbNodeOut > 0 + quad->nbNodeOut(0) = Max( 0, bSide.grid->NbPoints() - tSide.grid->NbPoints() ); + quad->nbNodeOut(1) = Max( 0, rSide.grid->NbPoints() - lSide.grid->NbPoints() ); + quad->nbNodeOut(2) = Max( 0, tSide.grid->NbPoints() - bSide.grid->NbPoints() ); + quad->nbNodeOut(3) = Max( 0, lSide.grid->NbPoints() - rSide.grid->NbPoints() ); + } + const vector& uv_e0 = bSide.GetUVPtStruct(); + const vector& uv_e1 = rSide.GetUVPtStruct(); + const vector& uv_e2 = tSide.GetUVPtStruct(); + const vector& uv_e3 = lSide.GetUVPtStruct(); + if (uv_e0.empty() || uv_e1.empty() || uv_e2.empty() || uv_e3.empty()) + //return error("Can't find nodes on sides"); + return error(COMPERR_BAD_INPUT_MESH); + + quad->uv_grid.resize( nbvertic * nbhoriz ); + quad->iSize = nbhoriz; + quad->jSize = nbvertic; + UVPtStruct *uv_grid = & quad->uv_grid[0]; + + quad->uv_box.Clear(); + + // copy data of face boundary + + FaceQuadStruct::SideIterator sideIter; + + { // BOTTOM + const int j = 0; + const double x0 = bSide.First().normParam; + const double dx = bSide.Last().normParam - bSide.First().normParam; + for ( sideIter.Init( bSide ); sideIter.More(); sideIter.Next() ) { + sideIter.UVPt().x = ( sideIter.UVPt().normParam - x0 ) / dx; + sideIter.UVPt().y = 0.; + uv_grid[ j * nbhoriz + sideIter.Count() ] = sideIter.UVPt(); + quad->uv_box.Add( sideIter.UVPt().UV() ); } } - if (! quad->isEdgeOut[1]) { - int i = nbhoriz - 1; - for (int j = 0; j < nbvertic; j++) { // right - int ij = j * nbhoriz + i; - uv_grid[ij].node = uv_e1[j].node; + { // RIGHT + const int i = nbhoriz - 1; + const double y0 = rSide.First().normParam; + const double dy = rSide.Last().normParam - rSide.First().normParam; + sideIter.Init( rSide ); + if ( quad->UVPt( i, sideIter.Count() ).node ) + sideIter.Next(); // avoid copying from a split emulated side + for ( ; sideIter.More(); sideIter.Next() ) { + sideIter.UVPt().x = 1.; + sideIter.UVPt().y = ( sideIter.UVPt().normParam - y0 ) / dy; + uv_grid[ sideIter.Count() * nbhoriz + i ] = sideIter.UVPt(); + quad->uv_box.Add( sideIter.UVPt().UV() ); } } - if (! quad->isEdgeOut[2]) { - int j = nbvertic - 1; - for (int i = 0; i < nbhoriz; i++) { // up - int ij = j * nbhoriz + i; - uv_grid[ij].node = uv_e2[i].node; + { // TOP + const int j = nbvertic - 1; + const double x0 = tSide.First().normParam; + const double dx = tSide.Last().normParam - tSide.First().normParam; + int i = 0, nb = nbhoriz; + sideIter.Init( tSide ); + if ( quad->UVPt( nb-1, j ).node ) --nb; // avoid copying from a split emulated side + for ( ; i < nb; i++, sideIter.Next()) { + sideIter.UVPt().x = ( sideIter.UVPt().normParam - x0 ) / dx; + sideIter.UVPt().y = 1.; + uv_grid[ j * nbhoriz + i ] = sideIter.UVPt(); + quad->uv_box.Add( sideIter.UVPt().UV() ); } } - if (! quad->isEdgeOut[3]) { - int i = 0; - for (int j = 0; j < nbvertic; j++) { // left - int ij = j * nbhoriz + i; - uv_grid[ij].node = uv_e3[j].node; + { // LEFT + const int i = 0; + const double y0 = lSide.First().normParam; + const double dy = lSide.Last().normParam - lSide.First().normParam; + int j = 0, nb = nbvertic; + sideIter.Init( lSide ); + if ( quad->UVPt( i, j ).node ) + ++j, sideIter.Next(); // avoid copying from a split emulated side + if ( quad->UVPt( i, nb-1 ).node ) + --nb; + for ( ; j < nb; j++, sideIter.Next()) { + sideIter.UVPt().x = 0.; + sideIter.UVPt().y = ( sideIter.UVPt().normParam - y0 ) / dy; + uv_grid[ j * nbhoriz + i ] = sideIter.UVPt(); + quad->uv_box.Add( sideIter.UVPt().UV() ); } } - // normalized 2d values on grid - for (int i = 0; i < nbhoriz; i++) + // normalized 2d parameters on grid + + for (int i = 1; i < nbhoriz-1; i++) { - for (int j = 0; j < nbvertic; j++) + const double x0 = quad->UVPt( i, 0 ).x; + const double x1 = quad->UVPt( i, nbvertic-1 ).x; + for (int j = 1; j < nbvertic-1; j++) { - int ij = j * nbhoriz + i; - // --- droite i cste : x = x0 + y(x1-x0) - double x0 = uv_e0[i].normParam; // bas - sud - double x1 = uv_e2[i].normParam; // haut - nord - // --- droite j cste : y = y0 + x(y1-y0) - double y0 = uv_e3[j].normParam; // gauche-ouest - double y1 = uv_e1[j].normParam; // droite - est + const double y0 = quad->UVPt( 0, j ).y; + const double y1 = quad->UVPt( nbhoriz-1, j ).y; // --- intersection : x=x0+(y0+x(y1-y0))(x1-x0) double x = (x0 + y0 * (x1 - x0)) / (1 - (y1 - y0) * (x1 - x0)); double y = y0 + x * (y1 - y0); + int ij = j * nbhoriz + i; uv_grid[ij].x = x; uv_grid[ij].y = y; - //MESSAGE("-xy-01 "<UVPt( 0, 0 ).UV(); + gp_UV a1 = quad->UVPt( nbhoriz-1, 0 ).UV(); + gp_UV a2 = quad->UVPt( nbhoriz-1, nbvertic-1 ).UV(); + gp_UV a3 = quad->UVPt( 0, nbvertic-1 ).UV(); - for (int i = 0; i < nbhoriz; i++) + for (int i = 1; i < nbhoriz-1; i++) { - for (int j = 0; j < nbvertic; j++) + gp_UV p0 = quad->UVPt( i, 0 ).UV(); + gp_UV p2 = quad->UVPt( i, nbvertic-1 ).UV(); + for (int j = 1; j < nbvertic-1; j++) { + gp_UV p1 = quad->UVPt( nbhoriz-1, j ).UV(); + gp_UV p3 = quad->UVPt( 0, j ).UV(); + int ij = j * nbhoriz + i; double x = uv_grid[ij].x; double y = uv_grid[ij].y; - double param_0 = uv_e0[0].normParam + x * (uv_e0.back().normParam - uv_e0[0].normParam); // sud - double param_2 = uv_e2[0].normParam + x * (uv_e2.back().normParam - uv_e2[0].normParam); // nord - double param_1 = uv_e1[0].normParam + y * (uv_e1.back().normParam - uv_e1[0].normParam); // est - double param_3 = uv_e3[0].normParam + y * (uv_e3.back().normParam - uv_e3[0].normParam); // ouest - - //MESSAGE("params "<side[0]->Value2d(param_0).XY(); - gp_UV p1 = quad->side[1]->Value2d(param_1).XY(); - gp_UV p2 = quad->side[2]->Value2d(param_2).XY(); - gp_UV p3 = quad->side[3]->Value2d(param_3).XY(); - gp_UV uv = (1 - y) * p0 + x * p1 + y * p2 + (1 - x) * p3; - uv -= (1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3; + gp_UV uv = calcUV(x,y, a0,a1,a2,a3, p0,p1,p2,p3); uv_grid[ij].u = uv.X(); uv_grid[ij].v = uv.Y(); @@ -943,169 +1573,195 @@ bool StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh, //======================================================================= //function : ShiftQuad -//purpose : auxilary function for ComputeQuadPref +//purpose : auxilary function for computeQuadPref //======================================================================= -static void ShiftQuad(FaceQuadStruct* quad, const int num, bool) +void StdMeshers_Quadrangle_2D::shiftQuad(FaceQuadStruct::Ptr& quad, const int num ) +{ + quad->shift( num, /*ori=*/true, /*keepGrid=*/myQuadList.size() > 1 ); +} + +//================================================================================ +/*! + * \brief Rotate sides of a quad CCW by given nb of quartes + * \param nb - number of rotation quartes + * \param ori - to keep orientation of sides as in an unit quad or not + * \param keepGrid - if \c true Side::grid is not changed, Side::from and Side::to + * are altered instead + */ +//================================================================================ + +void FaceQuadStruct::shift( size_t nb, bool ori, bool keepGrid ) { - StdMeshers_FaceSide* side[4] = { quad->side[0], quad->side[1], quad->side[2], quad->side[3] }; - for (int i = BOTTOM_SIDE; i < NB_SIDES; ++i ) { - int id = ( i + num ) % NB_SIDES; - bool wasForward = ( i < TOP_SIDE ); - bool newForward = ( id < TOP_SIDE ); - if ( wasForward != newForward ) - side[ i ]->Reverse(); - quad->side[ id ] = side[ i ]; + if ( nb == 0 ) return; + + nb = nb % NB_QUAD_SIDES; + + vector< Side > newSides( side.size() ); + vector< Side* > sidePtrs( side.size() ); + for (int i = QUAD_BOTTOM_SIDE; i < NB_QUAD_SIDES; ++i) + { + int id = (i + nb) % NB_QUAD_SIDES; + if ( ori ) + { + bool wasForward = (i < QUAD_TOP_SIDE); + bool newForward = (id < QUAD_TOP_SIDE); + if ( wasForward != newForward ) + side[ i ].Reverse( keepGrid ); + } + newSides[ id ] = side[ i ]; + sidePtrs[ i ] = & side[ i ]; + } + // make newSides refer newSides via Side::Contact's + for ( size_t i = 0; i < newSides.size(); ++i ) + { + FaceQuadStruct::Side& ns = newSides[ i ]; + for ( size_t iC = 0; iC < ns.contacts.size(); ++iC ) + { + FaceQuadStruct::Side* oSide = ns.contacts[iC].other_side; + vector< Side* >::iterator sIt = std::find( sidePtrs.begin(), sidePtrs.end(), oSide ); + if ( sIt != sidePtrs.end() ) + ns.contacts[iC].other_side = & newSides[ *sIt - sidePtrs[0] ]; + } + } + newSides.swap( side ); + + if ( keepGrid && !uv_grid.empty() ) + { + if ( nb == 2 ) // "PI" + { + std::reverse( uv_grid.begin(), uv_grid.end() ); + } + else + { + FaceQuadStruct newQuad; + newQuad.uv_grid.resize( uv_grid.size() ); + newQuad.iSize = jSize; + newQuad.jSize = iSize; + int i, j, iRev, jRev; + int *iNew = ( nb == 1 ) ? &jRev : &j; + int *jNew = ( nb == 1 ) ? &i : &iRev; + for ( i = 0, iRev = iSize-1; i < iSize; ++i, --iRev ) + for ( j = 0, jRev = jSize-1; j < jSize; ++j, --jRev ) + newQuad.UVPt( *iNew, *jNew ) = UVPt( i, j ); + + std::swap( iSize, jSize ); + std::swap( uv_grid, newQuad.uv_grid ); + } + } + else + { + uv_grid.clear(); } } //======================================================================= -//function : CalcUV -//purpose : auxilary function for ComputeQuadPref +//function : calcUV +//purpose : auxilary function for computeQuadPref //======================================================================= -static gp_UV CalcUV(double x0, double x1, double y0, double y1, - FaceQuadStruct* quad, +static gp_UV calcUV(double x0, double x1, double y0, double y1, + FaceQuadStruct::Ptr& quad, const gp_UV& a0, const gp_UV& a1, const gp_UV& a2, const gp_UV& a3) { - const vector& uv_eb = quad->side[0]->GetUVPtStruct(true,0 ); - const vector& uv_er = quad->side[1]->GetUVPtStruct(false,1); - const vector& uv_et = quad->side[2]->GetUVPtStruct(true,1 ); - const vector& uv_el = quad->side[3]->GetUVPtStruct(false,0); - double x = (x0 + y0 * (x1 - x0)) / (1 - (y1 - y0) * (x1 - x0)); double y = y0 + x * (y1 - y0); - double param_b = uv_eb[0].normParam + x * (uv_eb.back().normParam - uv_eb[0].normParam); - double param_t = uv_et[0].normParam + x * (uv_et.back().normParam - uv_et[0].normParam); - double param_r = uv_er[0].normParam + y * (uv_er.back().normParam - uv_er[0].normParam); - double param_l = uv_el[0].normParam + y * (uv_el.back().normParam - uv_el[0].normParam); + gp_UV p0 = quad->side[QUAD_BOTTOM_SIDE].grid->Value2d(x).XY(); + gp_UV p1 = quad->side[QUAD_RIGHT_SIDE ].grid->Value2d(y).XY(); + gp_UV p2 = quad->side[QUAD_TOP_SIDE ].grid->Value2d(x).XY(); + gp_UV p3 = quad->side[QUAD_LEFT_SIDE ].grid->Value2d(y).XY(); - gp_UV p0 = quad->side[BOTTOM_SIDE]->Value2d(param_b).XY(); - gp_UV p1 = quad->side[RIGHT_SIDE ]->Value2d(param_r).XY(); - gp_UV p2 = quad->side[TOP_SIDE ]->Value2d(param_t).XY(); - gp_UV p3 = quad->side[LEFT_SIDE ]->Value2d(param_l).XY(); - - gp_UV uv = p0 * (1 - y) + p1 * x + p2 * y + p3 * (1 - x); - - uv -= (1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3; + gp_UV uv = calcUV(x,y, a0,a1,a2,a3, p0,p1,p2,p3); return uv; } - //======================================================================= -//function : CalcUV2 -//purpose : auxilary function for ComputeQuadPref +//function : calcUV2 +//purpose : auxilary function for computeQuadPref //======================================================================= -static gp_UV CalcUV2(double x, double y, - FaceQuadStruct* quad, +static gp_UV calcUV2(double x, double y, + FaceQuadStruct::Ptr& quad, const gp_UV& a0, const gp_UV& a1, const gp_UV& a2, const gp_UV& a3) { - const vector& uv_eb = quad->side[0]->GetUVPtStruct(true,0 ); - const vector& uv_er = quad->side[1]->GetUVPtStruct(false,1); - const vector& uv_et = quad->side[2]->GetUVPtStruct(true,1 ); - const vector& uv_el = quad->side[3]->GetUVPtStruct(false,0); - - //double x = (x0 + y0 * (x1 - x0)) / (1 - (y1 - y0) * (x1 - x0)); - //double y = y0 + x * (y1 - y0); + gp_UV p0 = quad->side[QUAD_BOTTOM_SIDE].grid->Value2d(x).XY(); + gp_UV p1 = quad->side[QUAD_RIGHT_SIDE ].grid->Value2d(y).XY(); + gp_UV p2 = quad->side[QUAD_TOP_SIDE ].grid->Value2d(x).XY(); + gp_UV p3 = quad->side[QUAD_LEFT_SIDE ].grid->Value2d(y).XY(); - double param_b = uv_eb[0].normParam + x * (uv_eb.back().normParam - uv_eb[0].normParam); - double param_t = uv_et[0].normParam + x * (uv_et.back().normParam - uv_et[0].normParam); - double param_r = uv_er[0].normParam + y * (uv_er.back().normParam - uv_er[0].normParam); - double param_l = uv_el[0].normParam + y * (uv_el.back().normParam - uv_el[0].normParam); - - gp_UV p0 = quad->side[BOTTOM_SIDE]->Value2d(param_b).XY(); - gp_UV p1 = quad->side[RIGHT_SIDE ]->Value2d(param_r).XY(); - gp_UV p2 = quad->side[TOP_SIDE ]->Value2d(param_t).XY(); - gp_UV p3 = quad->side[LEFT_SIDE ]->Value2d(param_l).XY(); - - gp_UV uv = p0 * (1 - y) + p1 * x + p2 * y + p3 * (1 - x); - - uv -= (1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3; + gp_UV uv = calcUV(x,y, a0,a1,a2,a3, p0,p1,p2,p3); return uv; } + //======================================================================= /*! * Create only quandrangle faces */ //======================================================================= -bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, - const TopoDS_Shape& aShape, - FaceQuadStruct* quad) +bool StdMeshers_Quadrangle_2D::computeQuadPref (SMESH_Mesh & aMesh, + const TopoDS_Face& aFace, + FaceQuadStruct::Ptr quad) { - // Auxilary key in order to keep old variant - // of meshing after implementation new variant - // for bug 0016220 from Mantis. - bool OldVersion = false; + const bool OldVersion = (myQuadType == QUAD_QUADRANGLE_PREF_REVERSED); + const bool WisF = true; - SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); - const TopoDS_Face& F = TopoDS::Face(aShape); - Handle(Geom_Surface) S = BRep_Tool::Surface(F); -// const TopoDS_Wire& W = BRepTools::OuterWire(F); - bool WisF = true; -// if(W.Orientation()==TopAbs_FORWARD) -// WisF = true; - //if(WisF) cout<<"W is FORWARD"<ShapeToIndex( F ); - - int nb = quad->side[0]->NbPoints(); - int nr = quad->side[1]->NbPoints(); - int nt = quad->side[2]->NbPoints(); - int nl = quad->side[3]->NbPoints(); + SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); + Handle(Geom_Surface) S = BRep_Tool::Surface(aFace); + int i,j, geomFaceID = meshDS->ShapeToIndex(aFace); + + int nb = quad->side[0].NbPoints(); + int nr = quad->side[1].NbPoints(); + int nt = quad->side[2].NbPoints(); + int nl = quad->side[3].NbPoints(); int dh = abs(nb-nt); int dv = abs(nr-nl); - if( dh>=dv ) { - if( nt>nb ) { - // it is a base case => not shift quad but me be replacement is need - ShiftQuad(quad,0,WisF); - } - else { - // we have to shift quad on 2 - ShiftQuad(quad,2,WisF); - } + if ( myForcedPnts.empty() ) + { + // rotate sides to be as in the picture below and to have + // dh >= dv and nt > nb + if ( dh >= dv ) + shiftQuad( quad, ( nt > nb ) ? 0 : 2 ); + else + shiftQuad( quad, ( nr > nl ) ? 1 : 3 ); } - else { - if( nr>nl ) { - // we have to shift quad on 1 - ShiftQuad(quad,1,WisF); - } - else { - // we have to shift quad on 3 - ShiftQuad(quad,3,WisF); - } + else + { + // rotate the quad to have nt > nb [and nr > nl] + if ( nb > nt ) + shiftQuad ( quad, nr > nl ? 1 : 2 ); + else if ( nr > nl ) + shiftQuad( quad, nb == nt ? 1 : 0 ); + else if ( nl > nr ) + shiftQuad( quad, 3 ); } - nb = quad->side[0]->NbPoints(); - nr = quad->side[1]->NbPoints(); - nt = quad->side[2]->NbPoints(); - nl = quad->side[3]->NbPoints(); + nb = quad->side[0].NbPoints(); + nr = quad->side[1].NbPoints(); + nt = quad->side[2].NbPoints(); + nl = quad->side[3].NbPoints(); dh = abs(nb-nt); dv = abs(nr-nl); int nbh = Max(nb,nt); - int nbv = Max(nr,nl); + int nbv = Max(nr,nl); int addh = 0; int addv = 0; + // Orientation of face and 3 main domain for future faces // ----------- Old version --------------- - // orientation of face and 3 main domain for future faces // 0 top 1 // 1------------1 // | | | | - // | | | | + // | |C | | // | L | | R | - // left | | | | rigth + // left | |__| | rigth // | / \ | // | / C \ | // |/ \| @@ -1113,290 +1769,570 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, // 0 bottom 1 // ----------- New version --------------- - // orientation of face and 3 main domain for future faces // 0 top 1 // 1------------1 - // | |____| | - // |L / \ R| + // | |__| | + // | / \ | // | / C \ | // left |/________\| rigth // | | - // | | + // | C | // | | // 0------------0 // 0 bottom 1 - if(dh>dv) { + + const int bfrom = quad->side[0].from; + const int rfrom = quad->side[1].from; + const int tfrom = quad->side[2].from; + const int lfrom = quad->side[3].from; + { + const vector& uv_eb_vec = quad->side[0].GetUVPtStruct(true,0); + const vector& uv_er_vec = quad->side[1].GetUVPtStruct(false,1); + const vector& uv_et_vec = quad->side[2].GetUVPtStruct(true,1); + const vector& uv_el_vec = quad->side[3].GetUVPtStruct(false,0); + if (uv_eb_vec.empty() || + uv_er_vec.empty() || + uv_et_vec.empty() || + uv_el_vec.empty()) + return error(COMPERR_BAD_INPUT_MESH); + } + FaceQuadStruct::SideIterator uv_eb, uv_er, uv_et, uv_el; + uv_eb.Init( quad->side[0] ); + uv_er.Init( quad->side[1] ); + uv_et.Init( quad->side[2] ); + uv_el.Init( quad->side[3] ); + + gp_UV a0,a1,a2,a3, p0,p1,p2,p3, uv; + double x,y; + + a0 = uv_eb[ 0 ].UV(); + a1 = uv_er[ 0 ].UV(); + a2 = uv_er[ nr-1 ].UV(); + a3 = uv_et[ 0 ].UV(); + + if ( !myForcedPnts.empty() ) + { + if ( dv != 0 && dh != 0 ) // here myQuadList.size() == 1 + { + const int dmin = Min( dv, dh ); + + // Make a side separating domains L and Cb + StdMeshers_FaceSidePtr sideLCb; + UVPtStruct p3dom; // a point where 3 domains meat + { // dmin + vector pointsLCb( dmin+1 ); // 1--------1 + pointsLCb[0] = uv_eb[0]; // | | | + for ( int i = 1; i <= dmin; ++i ) // | |Ct| + { // | L | | + x = uv_et[ i ].normParam; // | |__| + y = uv_er[ i ].normParam; // | / | + p0 = quad->side[0].grid->Value2d( x ).XY(); // | / Cb |dmin + p1 = uv_er[ i ].UV(); // |/ | + p2 = uv_et[ i ].UV(); // 0--------0 + p3 = quad->side[3].grid->Value2d( y ).XY(); + uv = calcUV( x,y, a0,a1,a2,a3, p0,p1,p2,p3 ); + pointsLCb[ i ].u = uv.X(); + pointsLCb[ i ].v = uv.Y(); + } + sideLCb = StdMeshers_FaceSide::New( pointsLCb, aFace ); + p3dom = pointsLCb.back(); + + gp_Pnt xyz = S->Value( p3dom.u, p3dom.v ); + p3dom.node = myHelper->AddNode( xyz.X(), xyz.Y(), xyz.Z(), 0, p3dom.u, p3dom.v ); + pointsLCb.back() = p3dom; + } + // Make a side separating domains L and Ct + StdMeshers_FaceSidePtr sideLCt; + { + vector pointsLCt( nl ); + pointsLCt[0] = p3dom; + pointsLCt.back() = uv_et[ dmin ]; + x = uv_et[ dmin ].normParam; + p0 = quad->side[0].grid->Value2d( x ).XY(); + p2 = uv_et[ dmin ].UV(); + double y0 = uv_er[ dmin ].normParam; + for ( int i = 1; i < nl-1; ++i ) + { + y = y0 + i / ( nl-1. ) * ( 1. - y0 ); + p1 = quad->side[1].grid->Value2d( y ).XY(); + p3 = quad->side[3].grid->Value2d( y ).XY(); + uv = calcUV( x,y, a0,a1,a2,a3, p0,p1,p2,p3 ); + pointsLCt[ i ].u = uv.X(); + pointsLCt[ i ].v = uv.Y(); + } + sideLCt = StdMeshers_FaceSide::New( pointsLCt, aFace ); + } + // Make a side separating domains Cb and Ct + StdMeshers_FaceSidePtr sideCbCt; + { + vector pointsCbCt( nb ); + pointsCbCt[0] = p3dom; + pointsCbCt.back() = uv_er[ dmin ]; + y = uv_er[ dmin ].normParam; + p1 = uv_er[ dmin ].UV(); + p3 = quad->side[3].grid->Value2d( y ).XY(); + double x0 = uv_et[ dmin ].normParam; + for ( int i = 1; i < nb-1; ++i ) + { + x = x0 + i / ( nb-1. ) * ( 1. - x0 ); + p2 = quad->side[2].grid->Value2d( x ).XY(); + p0 = quad->side[0].grid->Value2d( x ).XY(); + uv = calcUV( x,y, a0,a1,a2,a3, p0,p1,p2,p3 ); + pointsCbCt[ i ].u = uv.X(); + pointsCbCt[ i ].v = uv.Y(); + } + sideCbCt = StdMeshers_FaceSide::New( pointsCbCt, aFace ); + } + // Make Cb quad + FaceQuadStruct* qCb = new FaceQuadStruct( quad->face, "Cb" ); + myQuadList.push_back( FaceQuadStruct::Ptr( qCb )); + qCb->side.resize(4); + qCb->side[0] = quad->side[0]; + qCb->side[1] = quad->side[1]; + qCb->side[2] = sideCbCt; + qCb->side[3] = sideLCb; + qCb->side[1].to = dmin+1; + // Make L quad + FaceQuadStruct* qL = new FaceQuadStruct( quad->face, "L" ); + myQuadList.push_back( FaceQuadStruct::Ptr( qL )); + qL->side.resize(4); + qL->side[0] = sideLCb; + qL->side[1] = sideLCt; + qL->side[2] = quad->side[2]; + qL->side[3] = quad->side[3]; + qL->side[2].to = dmin+1; + // Make Ct from the main quad + FaceQuadStruct::Ptr qCt = quad; + qCt->side[0] = sideCbCt; + qCt->side[3] = sideLCt; + qCt->side[1].from = dmin; + qCt->side[2].from = dmin; + qCt->uv_grid.clear(); + qCt->name = "Ct"; + + // Connect sides + qCb->side[3].AddContact( dmin, & qCb->side[2], 0 ); + qCb->side[3].AddContact( dmin, & qCt->side[3], 0 ); + qCt->side[3].AddContact( 0, & qCt->side[0], 0 ); + qCt->side[0].AddContact( 0, & qL ->side[0], dmin ); + qL ->side[0].AddContact( dmin, & qL ->side[1], 0 ); + qL ->side[0].AddContact( dmin, & qCb->side[2], 0 ); + + if ( dh == dv ) + return computeQuadDominant( aMesh, aFace ); + else + return computeQuadPref( aMesh, aFace, qCt ); + + } // if ( dv != 0 && dh != 0 ) + + const int db = quad->side[0].IsReversed() ? -1 : +1; + const int dr = quad->side[1].IsReversed() ? -1 : +1; + const int dt = quad->side[2].IsReversed() ? -1 : +1; + const int dl = quad->side[3].IsReversed() ? -1 : +1; + + // Case dv == 0, here possibly myQuadList.size() > 1 + // + // lw nb lw = dh/2 + // +------------+ + // | | | | + // | | Ct | | + // | L | | R | + // | |____| | + // | / \ | + // | / Cb \ | + // |/ \| + // +------------+ + const int lw = dh/2; // lateral width + + double yCbL, yCbR; + { + double lL = quad->side[3].Length(); + double lLwL = quad->side[2].Length( tfrom, + tfrom + ( lw ) * dt ); + yCbL = lLwL / ( lLwL + lL ); + + double lR = quad->side[1].Length(); + double lLwR = quad->side[2].Length( tfrom + ( lw + nb-1 ) * dt, + tfrom + ( lw + nb-1 + lw ) * dt); + yCbR = lLwR / ( lLwR + lR ); + } + // Make sides separating domains Cb and L and R + StdMeshers_FaceSidePtr sideLCb, sideRCb; + UVPtStruct pTBL, pTBR; // points where 3 domains meat + { + vector pointsLCb( lw+1 ), pointsRCb( lw+1 ); + pointsLCb[0] = uv_eb[ 0 ]; + pointsRCb[0] = uv_eb[ nb-1 ]; + for ( int i = 1, i2 = nt-2; i <= lw; ++i, --i2 ) + { + x = quad->side[2].Param( i ); + y = yCbL * i / lw; + p0 = quad->side[0].Value2d( x ); + p1 = quad->side[1].Value2d( y ); + p2 = uv_et[ i ].UV(); + p3 = quad->side[3].Value2d( y ); + uv = calcUV( x,y, a0,a1,a2,a3, p0,p1,p2,p3 ); + pointsLCb[ i ].u = uv.X(); + pointsLCb[ i ].v = uv.Y(); + pointsLCb[ i ].x = x; + + x = quad->side[2].Param( i2 ); + y = yCbR * i / lw; + p1 = quad->side[1].Value2d( y ); + p0 = quad->side[0].Value2d( x ); + p2 = uv_et[ i2 ].UV(); + p3 = quad->side[3].Value2d( y ); + uv = calcUV( x,y, a0,a1,a2,a3, p0,p1,p2,p3 ); + pointsRCb[ i ].u = uv.X(); + pointsRCb[ i ].v = uv.Y(); + pointsRCb[ i ].x = x; + } + sideLCb = StdMeshers_FaceSide::New( pointsLCb, aFace ); + sideRCb = StdMeshers_FaceSide::New( pointsRCb, aFace ); + pTBL = pointsLCb.back(); + pTBR = pointsRCb.back(); + { + gp_Pnt xyz = S->Value( pTBL.u, pTBL.v ); + pTBL.node = myHelper->AddNode( xyz.X(), xyz.Y(), xyz.Z(), 0, pTBL.u, pTBL.v ); + pointsLCb.back() = pTBL; + } + { + gp_Pnt xyz = S->Value( pTBR.u, pTBR.v ); + pTBR.node = myHelper->AddNode( xyz.X(), xyz.Y(), xyz.Z(), 0, pTBR.u, pTBR.v ); + pointsRCb.back() = pTBR; + } + } + // Make sides separating domains Ct and L and R + StdMeshers_FaceSidePtr sideLCt, sideRCt; + { + vector pointsLCt( nl ), pointsRCt( nl ); + pointsLCt[0] = pTBL; + pointsLCt.back() = uv_et[ lw ]; + pointsRCt[0] = pTBR; + pointsRCt.back() = uv_et[ lw + nb - 1 ]; + x = pTBL.x; + p0 = quad->side[0].Value2d( x ); + p2 = uv_et[ lw ].UV(); + int iR = lw + nb - 1; + double xR = pTBR.x; + gp_UV p0R = quad->side[0].Value2d( xR ); + gp_UV p2R = uv_et[ iR ].UV(); + for ( int i = 1; i < nl-1; ++i ) + { + y = yCbL + ( 1. - yCbL ) * i / (nl-1.); + p1 = quad->side[1].Value2d( y ); + p3 = quad->side[3].Value2d( y ); + uv = calcUV( x,y, a0,a1,a2,a3, p0,p1,p2,p3 ); + pointsLCt[ i ].u = uv.X(); + pointsLCt[ i ].v = uv.Y(); + + y = yCbR + ( 1. - yCbR ) * i / (nl-1.); + p1 = quad->side[1].Value2d( y ); + p3 = quad->side[3].Value2d( y ); + uv = calcUV( xR,y, a0,a1,a2,a3, p0R,p1,p2R,p3 ); + pointsRCt[ i ].u = uv.X(); + pointsRCt[ i ].v = uv.Y(); + } + sideLCt = StdMeshers_FaceSide::New( pointsLCt, aFace ); + sideRCt = StdMeshers_FaceSide::New( pointsRCt, aFace ); + } + // Make a side separating domains Cb and Ct + StdMeshers_FaceSidePtr sideCbCt; + { + vector pointsCbCt( nb ); + pointsCbCt[0] = pTBL; + pointsCbCt.back() = pTBR; + p1 = quad->side[1].Value2d( yCbR ); + p3 = quad->side[3].Value2d( yCbL ); + for ( int i = 1; i < nb-1; ++i ) + { + x = quad->side[2].Param( i + lw ); + y = yCbL + ( yCbR - yCbL ) * i / (nb-1.); + p2 = uv_et[ i + lw ].UV(); + p0 = quad->side[0].Value2d( x ); + uv = calcUV( x,y, a0,a1,a2,a3, p0,p1,p2,p3 ); + pointsCbCt[ i ].u = uv.X(); + pointsCbCt[ i ].v = uv.Y(); + } + sideCbCt = StdMeshers_FaceSide::New( pointsCbCt, aFace ); + } + // Make Cb quad + FaceQuadStruct* qCb = new FaceQuadStruct( quad->face, "Cb" ); + myQuadList.push_back( FaceQuadStruct::Ptr( qCb )); + qCb->side.resize(4); + qCb->side[0] = quad->side[0]; + qCb->side[1] = sideRCb; + qCb->side[2] = sideCbCt; + qCb->side[3] = sideLCb; + // Make L quad + FaceQuadStruct* qL = new FaceQuadStruct( quad->face, "L" ); + myQuadList.push_back( FaceQuadStruct::Ptr( qL )); + qL->side.resize(4); + qL->side[0] = sideLCb; + qL->side[1] = sideLCt; + qL->side[2] = quad->side[2]; + qL->side[3] = quad->side[3]; + qL->side[2].to = ( lw + 1 ) * dt + tfrom; + // Make R quad + FaceQuadStruct* qR = new FaceQuadStruct( quad->face, "R" ); + myQuadList.push_back( FaceQuadStruct::Ptr( qR )); + qR->side.resize(4); + qR->side[0] = sideRCb; + qR->side[0].from = lw; + qR->side[0].to = -1; + qR->side[0].di = -1; + qR->side[1] = quad->side[1]; + qR->side[2] = quad->side[2]; + qR->side[2].from = ( lw + nb-1 ) * dt + tfrom; + qR->side[3] = sideRCt; + // Make Ct from the main quad + FaceQuadStruct::Ptr qCt = quad; + qCt->side[0] = sideCbCt; + qCt->side[1] = sideRCt; + qCt->side[2].from = ( lw ) * dt + tfrom; + qCt->side[2].to = ( lw + nb ) * dt + tfrom; + qCt->side[3] = sideLCt; + qCt->uv_grid.clear(); + qCt->name = "Ct"; + + // Connect sides + qCb->side[3].AddContact( lw, & qCb->side[2], 0 ); + qCb->side[3].AddContact( lw, & qCt->side[3], 0 ); + qCt->side[3].AddContact( 0, & qCt->side[0], 0 ); + qCt->side[0].AddContact( 0, & qL ->side[0], lw ); + qL ->side[0].AddContact( lw, & qL ->side[1], 0 ); + qL ->side[0].AddContact( lw, & qCb->side[2], 0 ); + // + qCb->side[1].AddContact( lw, & qCb->side[2], nb-1 ); + qCb->side[1].AddContact( lw, & qCt->side[1], 0 ); + qCt->side[0].AddContact( nb-1, & qCt->side[1], 0 ); + qCt->side[0].AddContact( nb-1, & qR ->side[0], lw ); + qR ->side[3].AddContact( 0, & qR ->side[0], lw ); + qR ->side[3].AddContact( 0, & qCb->side[2], nb-1 ); + + return computeQuadDominant( aMesh, aFace ); + + } // if ( !myForcedPnts.empty() ) + + if ( dh > dv ) { addv = (dh-dv)/2; - nbv = nbv + addv; + nbv = nbv + addv; } - else { // dv>=dh + else { // dv >= dh addh = (dv-dh)/2; - nbh = nbh + addh; + nbh = nbh + addh; } - const vector& uv_eb = quad->side[0]->GetUVPtStruct(true,0 ); - const vector& uv_er = quad->side[1]->GetUVPtStruct(false,1); - const vector& uv_et = quad->side[2]->GetUVPtStruct(true,1 ); - const vector& uv_el = quad->side[3]->GetUVPtStruct(false,0); - // arrays for normalized params - //cout<<"Dump B:"<X()<<","<Y()<<","<Z()<<")"<0) { + if (dl>0) { // add top nodes - for(i=1; i<=dl; i++) + for (i=1; i<=dl; i++) NodesL.SetValue(i+1,nl,uv_et[i].node); // create and add needed nodes TColgp_SequenceOfXY UVtmp; - for(i=1; i<=dl; i++) { + for (i=1; i<=dl; i++) { double x0 = npt.Value(i+1); double x1 = x0; // diagonal node double y0 = npl.Value(i+1); double y1 = npr.Value(i+1); - gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3); + gp_UV UV = calcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3); gp_Pnt P = S->Value(UV.X(),UV.Y()); SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); NodesL.SetValue(i+1,1,N); - if(UVL.Length()Value(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); NodesL.SetValue(i+1,j,N); - if( i==dl ) UVtmp.Append(UV); + if (i==dl) UVtmp.Append(UV); } } - for(i=1; i<=UVtmp.Length() && UVL.Length()X()<<","<Y()<<","<Z()<<")"; - // } - // cout<AddFace(NodesL.Value(i,j), NodesL.Value(i+1,j), + for (i=1; i<=dl; i++) { + for (j=1; jAddFace(NodesL.Value(i,j), NodesL.Value(i+1,j), NodesL.Value(i+1,j+1), NodesL.Value(i,j+1)); - meshDS->SetMeshElementOnShape(F, geomFaceID); - } - else { - SMDS_MeshFace* F = - myTool->AddFace(NodesL.Value(i,j), NodesL.Value(i,j+1), - NodesL.Value(i+1,j+1), NodesL.Value(i+1,j)); - meshDS->SetMeshElementOnShape(F, geomFaceID); } } } } else { // fill UVL using c2d - for(i=1; i0) { + if (dr>0) { // add top nodes - for(i=1; i<=dr; i++) + for (i=1; i<=dr; i++) NodesR.SetValue(i+1,1,uv_et[nt-1-i].node); // create and add needed nodes TColgp_SequenceOfXY UVtmp; - for(i=1; i<=dr; i++) { + for (i=1; i<=dr; i++) { double x0 = npt.Value(nt-i); double x1 = x0; // diagonal node double y0 = npl.Value(i+1); double y1 = npr.Value(i+1); - gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3); + gp_UV UV = calcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3); gp_Pnt P = S->Value(UV.X(),UV.Y()); SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); NodesR.SetValue(i+1,nr,N); - if(UVR.Length()Value(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); NodesR.SetValue(i+1,j,N); - if( i==dr ) UVtmp.Prepend(UV); + if (i==dr) UVtmp.Prepend(UV); } } - for(i=1; i<=UVtmp.Length() && UVR.Length()AddFace(NodesR.Value(i,j), NodesR.Value(i+1,j), + for (i=1; i<=dr; i++) { + for (j=1; jAddFace(NodesR.Value(i,j), NodesR.Value(i+1,j), NodesR.Value(i+1,j+1), NodesR.Value(i,j+1)); - meshDS->SetMeshElementOnShape(F, geomFaceID); - } - else { - SMDS_MeshFace* F = - myTool->AddFace(NodesR.Value(i,j), NodesR.Value(i,j+1), - NodesR.Value(i+1,j+1), NodesR.Value(i+1,j)); - meshDS->SetMeshElementOnShape(F, geomFaceID); } } } } else { // fill UVR using c2d - for(i=1; iValue(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); NodesC.SetValue(i,nbv-nnn+j,N); + if ( j==1 ) + UVT.Append( UV ); } } // add diagonal layers - //cout<<"UVL.Length()="<Value(u,v); + gp_UV A2 = UVR.Value(nbv-nnn); + gp_UV A3 = UVL.Value(nbv-nnn); + for (i=1; iValue(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); - meshDS->SetNodeOnFace(N, geomFaceID, u, v); + meshDS->SetNodeOnFace(N, geomFaceID, UV.X(),UV.Y()); NodesC.SetValue(j,i+1,N); } } // create faces - for(i=1; iAddFace(NodesC.Value(i,j), NodesC.Value(i+1,j), + for (i=1; iAddFace(NodesC.Value(i,j), NodesC.Value(i+1,j), NodesC.Value(i+1,j+1), NodesC.Value(i,j+1)); - meshDS->SetMeshElementOnShape(F, geomFaceID); - } - else { - SMDS_MeshFace* F = - myTool->AddFace(NodesC.Value(i,j), NodesC.Value(i,j+1), - NodesC.Value(i+1,j+1), NodesC.Value(i+1,j)); - meshDS->SetMeshElementOnShape(F, geomFaceID); } } } @@ -1406,58 +2342,47 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, // step1: create faces for bottom rectangle domain StdMeshers_Array2OfNode NodesBRD(1,nb,1,nnn-1); // fill UVL and UVR using c2d - for(j=0; jValue(u,v); + for (j=2; jValue(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); - meshDS->SetNodeOnFace(N, geomFaceID, u, v); + meshDS->SetNodeOnFace(N, geomFaceID, UV.X(),UV.Y()); NodesBRD.SetValue(j,i+1,N); - } } - for(j=1; jAddFace(NodesBRD.Value(i,j), NodesBRD.Value(i+1,j), + for (j=1; jAddFace(NodesBRD.Value(i,j), NodesBRD.Value(i+1,j), NodesBRD.Value(i+1,j+1), NodesBRD.Value(i,j+1)); - meshDS->SetMeshElementOnShape(F, geomFaceID); - } - else { - SMDS_MeshFace* F = - myTool->AddFace(NodesBRD.Value(i,j), NodesBRD.Value(i,j+1), - NodesBRD.Value(i+1,j+1), NodesBRD.Value(i+1,j)); - meshDS->SetMeshElementOnShape(F, geomFaceID); } } } - int drl = abs(nr-nl); // create faces for region C StdMeshers_Array2OfNode NodesC(1,nb,1,drl+1+addv); // add nodes from previous region - for(j=1; j<=nb; j++) { + for (j=1; j<=nb; j++) { NodesC.SetValue(j,1,NodesBRD.Value(j,nnn-1)); } - if( (drl+addv) > 0 ) { + if ((drl+addv) > 0) { int n1,n2; - if(nr>nl) { + if (nr>nl) { n1 = 1; n2 = drl + 1; TColgp_SequenceOfXY UVtmp; double drparam = npr.Value(nr) - npr.Value(nnn-1); double dlparam = npl.Value(nnn) - npl.Value(nnn-1); double y0,y1; - for(i=1; i<=drl; i++) { + for (i=1; i<=drl; i++) { // add existed nodes from right edge NodesC.SetValue(nb,i+1,uv_er[nnn+i-2].node); //double dtparam = npt.Value(i+1); @@ -1465,10 +2390,10 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, double dpar = (y1 - npr.Value(nnn-1))/drparam; y0 = npl.Value(nnn-1) + dpar*dlparam; // param on left edge double dy = y1 - y0; - for(j=1; jValue(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -1477,15 +2402,15 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, } double dy0 = (1-y0)/(addv+1); double dy1 = (1-y1)/(addv+1); - for(i=1; i<=addv; i++) { + for (i=1; i<=addv; i++) { double yy0 = y0 + dy0*i; double yy1 = y1 + dy1*i; double dyy = yy1 - yy0; - for(j=1; j<=nb; j++) { - double x = npt.Value(i+1+drl) + - npb.Value(j) * ( npt.Value(nt-i) - npt.Value(i+1+drl) ); + for (j=1; j<=nb; j++) { + double x = npt.Value(i+1+drl) + + npb.Value(j) * (npt.Value(nt-i) - npt.Value(i+1+drl)); double y = yy0 + dyy*x; - gp_UV UV = CalcUV2(x, y, quad, a0, a1, a2, a3); + gp_UV UV = calcUV2(x, y, quad, a0, a1, a2, a3); gp_Pnt P = S->Value(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -1501,17 +2426,17 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, double drparam = npr.Value(nnn) - npr.Value(nnn-1); double y0 = npl.Value(nnn-1); double y1 = npr.Value(nnn-1); - for(i=1; i<=drl; i++) { + for (i=1; i<=drl; i++) { // add existed nodes from right edge NodesC.SetValue(1,i+1,uv_el[nnn+i-2].node); y0 = npl.Value(nnn+i-1); // param on left edge double dpar = (y0 - npl.Value(nnn-1))/dlparam; y1 = npr.Value(nnn-1) + dpar*drparam; // param on right edge double dy = y1 - y0; - for(j=2; j<=nb; j++) { + for (j=2; j<=nb; j++) { double x = npb.Value(j)*npt.Value(nt-i); double y = y0 + dy*x; - gp_UV UV = CalcUV2(x, y, quad, a0, a1, a2, a3); + gp_UV UV = calcUV2(x, y, quad, a0, a1, a2, a3); gp_Pnt P = S->Value(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -1520,15 +2445,15 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, } double dy0 = (1-y0)/(addv+1); double dy1 = (1-y1)/(addv+1); - for(i=1; i<=addv; i++) { + for (i=1; i<=addv; i++) { double yy0 = y0 + dy0*i; double yy1 = y1 + dy1*i; double dyy = yy1 - yy0; - for(j=1; j<=nb; j++) { - double x = npt.Value(i+1) + - npb.Value(j) * ( npt.Value(nt-i-drl) - npt.Value(i+1) ); + for (j=1; j<=nb; j++) { + double x = npt.Value(i+1) + + npb.Value(j) * (npt.Value(nt-i-drl) - npt.Value(i+1)); double y = yy0 + dyy*x; - gp_UV UV = CalcUV2(x, y, quad, a0, a1, a2, a3); + gp_UV UV = calcUV2(x, y, quad, a0, a1, a2, a3); gp_Pnt P = S->Value(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -1537,55 +2462,39 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, } } // create faces - for(j=1; j<=drl+addv; j++) { - for(i=1; iAddFace(NodesC.Value(i,j), NodesC.Value(i+1,j), + for (j=1; j<=drl+addv; j++) { + for (i=1; iAddFace(NodesC.Value(i,j), NodesC.Value(i+1,j), NodesC.Value(i+1,j+1), NodesC.Value(i,j+1)); - meshDS->SetMeshElementOnShape(F, geomFaceID); - } - else { - SMDS_MeshFace* F = - myTool->AddFace(NodesC.Value(i,j), NodesC.Value(i,j+1), - NodesC.Value(i+1,j+1), NodesC.Value(i+1,j)); - meshDS->SetMeshElementOnShape(F, geomFaceID); } } } // end nr=n2; i--) { + for (i=drl+addv; i>=n2; i--) { nnn++; NodesLast.SetValue(nnn,1,NodesC.Value(nb,i)); } - for(i=1; iAddFace(NodesLast.Value(i,1), NodesLast.Value(i+1,1), + for (i=1; iAddFace(NodesLast.Value(i,1), NodesLast.Value(i+1,1), NodesLast.Value(i+1,2), NodesLast.Value(i,2)); - meshDS->SetMeshElementOnShape(F, geomFaceID); - } - else { - SMDS_MeshFace* F = - myTool->AddFace(NodesLast.Value(i,1), NodesLast.Value(i,2), - NodesLast.Value(i+1,2), NodesLast.Value(i+1,2)); - meshDS->SetMeshElementOnShape(F, geomFaceID); } } - } // if( (drl+addv) > 0 ) + } // if ((drl+addv) > 0) } // end new version implementation @@ -1593,37 +2502,3198 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, return isOk; } -//============================================================================= -/*! Split quadrangle in to 2 triangles by smallest diagonal - * + +//======================================================================= +/*! + * Evaluate only quandrangle faces */ -//============================================================================= -void StdMeshers_Quadrangle_2D::SplitQuad(SMESHDS_Mesh *theMeshDS, - int theFaceID, - const SMDS_MeshNode* theNode1, - const SMDS_MeshNode* theNode2, - const SMDS_MeshNode* theNode3, - const SMDS_MeshNode* theNode4) +//======================================================================= + +bool StdMeshers_Quadrangle_2D::evaluateQuadPref(SMESH_Mesh & aMesh, + const TopoDS_Shape& aShape, + std::vector& aNbNodes, + MapShapeNbElems& aResMap, + bool IsQuadratic) { - gp_Pnt a(theNode1->X(),theNode1->Y(),theNode1->Z()); - gp_Pnt b(theNode2->X(),theNode2->Y(),theNode2->Z()); - gp_Pnt c(theNode3->X(),theNode3->Y(),theNode3->Z()); - gp_Pnt d(theNode4->X(),theNode4->Y(),theNode4->Z()); - SMDS_MeshFace* face; - Standard_Real d1 = a.Distance(c); - Standard_Real d2 = b.Distance(d); - Standard_Real d3 = d2 - d1; - if(abs(d3) < gp::Resolution() || d1 > d2){ - face = myTool->AddFace(theNode2, theNode4, theNode1); - theMeshDS->SetMeshElementOnShape(face, theFaceID ); - face = myTool->AddFace(theNode2, theNode3, theNode4); - theMeshDS->SetMeshElementOnShape(face, theFaceID ); + // Auxilary key in order to keep old variant + // of meshing after implementation new variant + // for bug 0016220 from Mantis. + bool OldVersion = false; + if (myQuadType == QUAD_QUADRANGLE_PREF_REVERSED) + OldVersion = true; + + const TopoDS_Face& F = TopoDS::Face(aShape); + Handle(Geom_Surface) S = BRep_Tool::Surface(F); + + int nb = aNbNodes[0]; + int nr = aNbNodes[1]; + int nt = aNbNodes[2]; + int nl = aNbNodes[3]; + int dh = abs(nb-nt); + int dv = abs(nr-nl); + + if (dh>=dv) { + if (nt>nb) { + // it is a base case => not shift + } + else { + // we have to shift on 2 + nb = aNbNodes[2]; + nr = aNbNodes[3]; + nt = aNbNodes[0]; + nl = aNbNodes[1]; + } } - else - { - face = myTool->AddFace(theNode1, theNode2 ,theNode3); - theMeshDS->SetMeshElementOnShape(face, theFaceID ); - face = myTool->AddFace(theNode1, theNode3, theNode4); - theMeshDS->SetMeshElementOnShape(face, theFaceID ); + else { + if (nr>nl) { + // we have to shift quad on 1 + nb = aNbNodes[3]; + nr = aNbNodes[0]; + nt = aNbNodes[1]; + nl = aNbNodes[2]; + } + else { + // we have to shift quad on 3 + nb = aNbNodes[1]; + nr = aNbNodes[2]; + nt = aNbNodes[3]; + nl = aNbNodes[0]; + } } + + dh = abs(nb-nt); + dv = abs(nr-nl); + int nbh = Max(nb,nt); + int nbv = Max(nr,nl); + int addh = 0; + int addv = 0; + + if (dh>dv) { + addv = (dh-dv)/2; + nbv = nbv + addv; + } + else { // dv>=dh + addh = (dv-dh)/2; + nbh = nbh + addh; + } + + int dl,dr; + if (OldVersion) { + // add some params to right and left after the first param + // insert to right + dr = nbv - nr; + // insert to left + dl = nbv - nl; + } + + int nnn = Min(nr,nl); + + int nbNodes = 0; + int nbFaces = 0; + if (OldVersion) { + // step1: create faces for left domain + if (dl>0) { + nbNodes += dl*(nl-1); + nbFaces += dl*(nl-1); + } + // step2: create faces for right domain + if (dr>0) { + nbNodes += dr*(nr-1); + nbFaces += dr*(nr-1); + } + // step3: create faces for central domain + nbNodes += (nb-2)*(nnn-1) + (nbv-nnn-1)*(nb-2); + nbFaces += (nb-1)*(nbv-1); + } + else { // New version (!OldVersion) + nbNodes += (nnn-2)*(nb-2); + nbFaces += (nnn-2)*(nb-1); + int drl = abs(nr-nl); + nbNodes += drl*(nb-1) + addv*nb; + nbFaces += (drl+addv)*(nb-1) + (nt-1); + } // end new version implementation + + std::vector aVec(SMDSEntity_Last); + for (int i=SMDSEntity_Node; i + SMESH_TNodeXYZ( theNode2 ).SquareDistance( theNode4 ) ) + { + myHelper->AddFace(theNode2, theNode4 , theNode1); + myHelper->AddFace(theNode2, theNode3, theNode4); + } + else + { + myHelper->AddFace(theNode1, theNode2 ,theNode3); + myHelper->AddFace(theNode1, theNode3, theNode4); + } +} + +namespace +{ + enum uvPos { UV_A0, UV_A1, UV_A2, UV_A3, UV_B, UV_R, UV_T, UV_L, UV_SIZE }; + + inline SMDS_MeshNode* makeNode( UVPtStruct & uvPt, + const double y, + FaceQuadStruct::Ptr& quad, + const gp_UV* UVs, + SMESH_MesherHelper* helper, + Handle(Geom_Surface) S) + { + const vector& uv_eb = quad->side[QUAD_BOTTOM_SIDE].GetUVPtStruct(); + const vector& uv_et = quad->side[QUAD_TOP_SIDE ].GetUVPtStruct(); + double rBot = ( uv_eb.size() - 1 ) * uvPt.normParam; + double rTop = ( uv_et.size() - 1 ) * uvPt.normParam; + int iBot = int( rBot ); + int iTop = int( rTop ); + double xBot = uv_eb[ iBot ].normParam + ( rBot - iBot ) * ( uv_eb[ iBot+1 ].normParam - uv_eb[ iBot ].normParam ); + double xTop = uv_et[ iTop ].normParam + ( rTop - iTop ) * ( uv_et[ iTop+1 ].normParam - uv_et[ iTop ].normParam ); + double x = xBot + y * ( xTop - xBot ); + + gp_UV uv = calcUV(/*x,y=*/x, y, + /*a0,...=*/UVs[UV_A0], UVs[UV_A1], UVs[UV_A2], UVs[UV_A3], + /*p0=*/quad->side[QUAD_BOTTOM_SIDE].grid->Value2d( x ).XY(), + /*p1=*/UVs[ UV_R ], + /*p2=*/quad->side[QUAD_TOP_SIDE ].grid->Value2d( x ).XY(), + /*p3=*/UVs[ UV_L ]); + gp_Pnt P = S->Value( uv.X(), uv.Y() ); + uvPt.u = uv.X(); + uvPt.v = uv.Y(); + return helper->AddNode(P.X(), P.Y(), P.Z(), 0, uv.X(), uv.Y() ); + } + + void reduce42( const vector& curr_base, + vector& next_base, + const int j, + int & next_base_len, + FaceQuadStruct::Ptr& quad, + gp_UV* UVs, + const double y, + SMESH_MesherHelper* helper, + Handle(Geom_Surface)& S) + { + // add one "HH": nodes a,b,c,d,e and faces 1,2,3,4,5,6 + // + // .-----a-----b i + 1 + // |\ 5 | 6 /| + // | \ | / | + // | c--d--e | + // |1 |2 |3 |4 | + // | | | | | + // .--.--.--.--. i + // + // j j+2 j+4 + + // a (i + 1, j + 2) + const SMDS_MeshNode*& Na = next_base[ ++next_base_len ].node; + if ( !Na ) + Na = makeNode( next_base[ next_base_len ], y, quad, UVs, helper, S ); + + // b (i + 1, j + 4) + const SMDS_MeshNode*& Nb = next_base[ ++next_base_len ].node; + if ( !Nb ) + Nb = makeNode( next_base[ next_base_len ], y, quad, UVs, helper, S ); + + // c + double u = (curr_base[j + 2].u + next_base[next_base_len - 2].u) / 2.0; + double v = (curr_base[j + 2].v + next_base[next_base_len - 2].v) / 2.0; + gp_Pnt P = S->Value(u,v); + SMDS_MeshNode* Nc = helper->AddNode(P.X(), P.Y(), P.Z(), 0, u, v); + + // d + u = (curr_base[j + 2].u + next_base[next_base_len - 1].u) / 2.0; + v = (curr_base[j + 2].v + next_base[next_base_len - 1].v) / 2.0; + P = S->Value(u,v); + SMDS_MeshNode* Nd = helper->AddNode(P.X(), P.Y(), P.Z(), 0, u, v); + + // e + u = (curr_base[j + 2].u + next_base[next_base_len].u) / 2.0; + v = (curr_base[j + 2].v + next_base[next_base_len].v) / 2.0; + P = S->Value(u,v); + SMDS_MeshNode* Ne = helper->AddNode(P.X(), P.Y(), P.Z(), 0, u, v); + + // Faces + helper->AddFace(curr_base[j + 0].node, + curr_base[j + 1].node, Nc, + next_base[next_base_len - 2].node); + + helper->AddFace(curr_base[j + 1].node, + curr_base[j + 2].node, Nd, Nc); + + helper->AddFace(curr_base[j + 2].node, + curr_base[j + 3].node, Ne, Nd); + + helper->AddFace(curr_base[j + 3].node, + curr_base[j + 4].node, Nb, Ne); + + helper->AddFace(Nc, Nd, Na, next_base[next_base_len - 2].node); + + helper->AddFace(Nd, Ne, Nb, Na); + } + + void reduce31( const vector& curr_base, + vector& next_base, + const int j, + int & next_base_len, + FaceQuadStruct::Ptr& quad, + gp_UV* UVs, + const double y, + SMESH_MesherHelper* helper, + Handle(Geom_Surface)& S) + { + // add one "H": nodes b,c,e and faces 1,2,4,5 + // + // .---------b i + 1 + // |\ 5 /| + // | \ / | + // | c---e | + // |1 |2 |4 | + // | | | | + // .--.---.--. i + // + // j j+1 j+2 j+3 + + // b (i + 1, j + 3) + const SMDS_MeshNode*& Nb = next_base[ ++next_base_len ].node; + if ( !Nb ) + Nb = makeNode( next_base[ next_base_len ], y, quad, UVs, helper, S ); + + // c and e + double u1 = (curr_base[ j ].u + next_base[ next_base_len-1 ].u ) / 2.0; + double u2 = (curr_base[ j+3 ].u + next_base[ next_base_len ].u ) / 2.0; + double u3 = (u2 - u1) / 3.0; + // + double v1 = (curr_base[ j ].v + next_base[ next_base_len-1 ].v ) / 2.0; + double v2 = (curr_base[ j+3 ].v + next_base[ next_base_len ].v ) / 2.0; + double v3 = (v2 - v1) / 3.0; + // c + double u = u1 + u3; + double v = v1 + v3; + gp_Pnt P = S->Value(u,v); + SMDS_MeshNode* Nc = helper->AddNode( P.X(), P.Y(), P.Z(), 0, u, v ); + // e + u = u1 + u3 + u3; + v = v1 + v3 + v3; + P = S->Value(u,v); + SMDS_MeshNode* Ne = helper->AddNode( P.X(), P.Y(), P.Z(), 0, u, v ); + + // Faces + // 1 + helper->AddFace( curr_base[ j + 0 ].node, + curr_base[ j + 1 ].node, + Nc, + next_base[ next_base_len - 1 ].node); + // 2 + helper->AddFace( curr_base[ j + 1 ].node, + curr_base[ j + 2 ].node, Ne, Nc); + // 4 + helper->AddFace( curr_base[ j + 2 ].node, + curr_base[ j + 3 ].node, Nb, Ne); + // 5 + helper->AddFace(Nc, Ne, Nb, + next_base[ next_base_len - 1 ].node); + } + + typedef void (* PReduceFunction) ( const vector& curr_base, + vector& next_base, + const int j, + int & next_base_len, + FaceQuadStruct::Ptr & quad, + gp_UV* UVs, + const double y, + SMESH_MesherHelper* helper, + Handle(Geom_Surface)& S); + +} // namespace + +//======================================================================= +/*! + * Implementation of Reduced algorithm (meshing with quadrangles only) + */ +//======================================================================= + +bool StdMeshers_Quadrangle_2D::computeReduced (SMESH_Mesh & aMesh, + const TopoDS_Face& aFace, + FaceQuadStruct::Ptr quad) +{ + SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); + Handle(Geom_Surface) S = BRep_Tool::Surface(aFace); + int i,j,geomFaceID = meshDS->ShapeToIndex(aFace); + + int nb = quad->side[0].NbPoints(); // bottom + int nr = quad->side[1].NbPoints(); // right + int nt = quad->side[2].NbPoints(); // top + int nl = quad->side[3].NbPoints(); // left + + // Simple Reduce 10->8->6->4 (3 steps) Multiple Reduce 10->4 (1 step) + // + // .-----.-----.-----.-----. .-----.-----.-----.-----. + // | / \ | / \ | | / \ | / \ | + // | / .--.--. \ | | / \ | / \ | + // | / / | \ \ | | / .----.----. \ | + // .---.---.---.---.---.---. | / / \ | / \ \ | + // | / / \ | / \ \ | | / / \ | / \ \ | + // | / / .-.-. \ \ | | / / .---.---. \ \ | + // | / / / | \ \ \ | | / / / \ | / \ \ \ | + // .--.--.--.--.--.--.--.--. | / / / \ | / \ \ \ | + // | / / / \ | / \ \ \ | | / / / .-.-. \ \ \ | + // | / / / .-.-. \ \ \ | | / / / / | \ \ \ \ | + // | / / / / | \ \ \ \ | | / / / / | \ \ \ \ | + // .-.-.-.--.--.--.--.-.-.-. .-.-.-.--.--.--.--.-.-.-. + + bool MultipleReduce = false; + { + int nb1 = nb; + int nr1 = nr; + int nt1 = nt; + + if (nr == nl) { + if (nb < nt) { + nt1 = nb; + nb1 = nt; + } + } + else if (nb == nt) { + nr1 = nb; // and == nt + if (nl < nr) { + nt1 = nl; + nb1 = nr; + } + else { + nt1 = nr; + nb1 = nl; + } + } + else { + return false; + } + + // number of rows and columns + int nrows = nr1 - 1; + int ncol_top = nt1 - 1; + int ncol_bot = nb1 - 1; + // number of rows needed to reduce ncol_bot to ncol_top using simple 3->1 "tree" (see below) + int nrows_tree31 = + int( ceil( log( double(ncol_bot) / ncol_top) / log( 3.))); // = log x base 3 + if ( nrows < nrows_tree31 ) + { + MultipleReduce = true; + error( COMPERR_WARNING, + SMESH_Comment("To use 'Reduced' transition, " + "number of face rows should be at least ") + << nrows_tree31 << ". Actual number of face rows is " << nrows << ". " + "'Quadrangle preference (reversed)' transion has been used."); + } + } + + if (MultipleReduce) { // == computeQuadPref QUAD_QUADRANGLE_PREF_REVERSED + //================================================== + int dh = abs(nb-nt); + int dv = abs(nr-nl); + + if (dh >= dv) { + if (nt > nb) { + // it is a base case => not shift quad but may be replacement is need + shiftQuad(quad,0); + } + else { + // we have to shift quad on 2 + shiftQuad(quad,2); + } + } + else { + if (nr > nl) { + // we have to shift quad on 1 + shiftQuad(quad,1); + } + else { + // we have to shift quad on 3 + shiftQuad(quad,3); + } + } + + nb = quad->side[0].NbPoints(); + nr = quad->side[1].NbPoints(); + nt = quad->side[2].NbPoints(); + nl = quad->side[3].NbPoints(); + dh = abs(nb-nt); + dv = abs(nr-nl); + int nbh = Max(nb,nt); + int nbv = Max(nr,nl); + int addh = 0; + int addv = 0; + + if (dh>dv) { + addv = (dh-dv)/2; + nbv = nbv + addv; + } + else { // dv>=dh + addh = (dv-dh)/2; + nbh = nbh + addh; + } + + const vector& uv_eb = quad->side[0].GetUVPtStruct(true,0); + const vector& uv_er = quad->side[1].GetUVPtStruct(false,1); + const vector& uv_et = quad->side[2].GetUVPtStruct(true,1); + const vector& uv_el = quad->side[3].GetUVPtStruct(false,0); + + if (uv_eb.size() != nb || uv_er.size() != nr || uv_et.size() != nt || uv_el.size() != nl) + return error(COMPERR_BAD_INPUT_MESH); + + // arrays for normalized params + TColStd_SequenceOfReal npb, npr, npt, npl; + for (j = 0; j < nb; j++) { + npb.Append(uv_eb[j].normParam); + } + for (i = 0; i < nr; i++) { + npr.Append(uv_er[i].normParam); + } + for (j = 0; j < nt; j++) { + npt.Append(uv_et[j].normParam); + } + for (i = 0; i < nl; i++) { + npl.Append(uv_el[i].normParam); + } + + int dl,dr; + // orientation of face and 3 main domain for future faces + // 0 top 1 + // 1------------1 + // | | | | + // | | | | + // | L | | R | + // left | | | | rigth + // | / \ | + // | / C \ | + // |/ \| + // 0------------0 + // 0 bottom 1 + + // add some params to right and left after the first param + // insert to right + dr = nbv - nr; + double dpr = (npr.Value(2) - npr.Value(1))/(dr+1); + for (i=1; i<=dr; i++) { + npr.InsertAfter(1,npr.Value(2)-dpr); + } + // insert to left + dl = nbv - nl; + dpr = (npl.Value(2) - npl.Value(1))/(dl+1); + for (i=1; i<=dl; i++) { + npl.InsertAfter(1,npl.Value(2)-dpr); + } + + gp_XY a0 (uv_eb.front().u, uv_eb.front().v); + gp_XY a1 (uv_eb.back().u, uv_eb.back().v); + gp_XY a2 (uv_et.back().u, uv_et.back().v); + gp_XY a3 (uv_et.front().u, uv_et.front().v); + + int nnn = Min(nr,nl); + // auxilary sequence of XY for creation of nodes + // in the bottom part of central domain + // it's length must be == nbv-nnn-1 + TColgp_SequenceOfXY UVL; + TColgp_SequenceOfXY UVR; + //================================================== + + // step1: create faces for left domain + StdMeshers_Array2OfNode NodesL(1,dl+1,1,nl); + // add left nodes + for (j=1; j<=nl; j++) + NodesL.SetValue(1,j,uv_el[j-1].node); + if (dl>0) { + // add top nodes + for (i=1; i<=dl; i++) + NodesL.SetValue(i+1,nl,uv_et[i].node); + // create and add needed nodes + TColgp_SequenceOfXY UVtmp; + for (i=1; i<=dl; i++) { + double x0 = npt.Value(i+1); + double x1 = x0; + // diagonal node + double y0 = npl.Value(i+1); + double y1 = npr.Value(i+1); + gp_UV UV = calcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3); + gp_Pnt P = S->Value(UV.X(),UV.Y()); + SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); + NodesL.SetValue(i+1,1,N); + if (UVL.Length()Value(UV.X(),UV.Y()); + SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); + NodesL.SetValue(i+1,j,N); + if (i==dl) UVtmp.Append(UV); + } + } + for (i=1; i<=UVtmp.Length() && UVL.Length()AddFace(NodesL.Value(i,j), NodesL.Value(i+1,j), + NodesL.Value(i+1,j+1), NodesL.Value(i,j+1)); + } + } + } + else { + // fill UVL using c2d + for (i=1; i0) { + // add top nodes + for (i=1; i<=dr; i++) + NodesR.SetValue(i+1,1,uv_et[nt-1-i].node); + // create and add needed nodes + TColgp_SequenceOfXY UVtmp; + for (i=1; i<=dr; i++) { + double x0 = npt.Value(nt-i); + double x1 = x0; + // diagonal node + double y0 = npl.Value(i+1); + double y1 = npr.Value(i+1); + gp_UV UV = calcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3); + gp_Pnt P = S->Value(UV.X(),UV.Y()); + SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); + NodesR.SetValue(i+1,nr,N); + if (UVR.Length()Value(UV.X(),UV.Y()); + SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); + NodesR.SetValue(i+1,j,N); + if (i==dr) UVtmp.Prepend(UV); + } + } + for (i=1; i<=UVtmp.Length() && UVR.Length()AddFace(NodesR.Value(i,j), NodesR.Value(i+1,j), + NodesR.Value(i+1,j+1), NodesR.Value(i,j+1)); + } + } + } + else { + // fill UVR using c2d + for (i=1; iValue(UV.X(),UV.Y()); + SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); + NodesC.SetValue(i,nbv-nnn+j,N); + } + } + // add diagonal layers + for (i=1; iValue(u,v); + SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(N, geomFaceID, u, v); + NodesC.SetValue(j,i+1,N); + } + } + // create faces + for (i=1; iAddFace(NodesC.Value(i,j), NodesC.Value(i+1,j), + NodesC.Value(i+1,j+1), NodesC.Value(i,j+1)); + } + } + } // end Multiple Reduce implementation + else { // Simple Reduce (!MultipleReduce) + //========================================================= + if (nr == nl) { + if (nt < nb) { + // it is a base case => not shift quad + //shiftQuad(quad,0,true); + } + else { + // we have to shift quad on 2 + shiftQuad(quad,2); + } + } + else { + if (nl > nr) { + // we have to shift quad on 1 + shiftQuad(quad,1); + } + else { + // we have to shift quad on 3 + shiftQuad(quad,3); + } + } + + nb = quad->side[0].NbPoints(); + nr = quad->side[1].NbPoints(); + nt = quad->side[2].NbPoints(); + nl = quad->side[3].NbPoints(); + + // number of rows and columns + int nrows = nr - 1; // and also == nl - 1 + int ncol_top = nt - 1; + int ncol_bot = nb - 1; + int npair_top = ncol_top / 2; + // maximum number of bottom elements for "linear" simple reduce 4->2 + int max_lin42 = ncol_top + npair_top * 2 * nrows; + // maximum number of bottom elements for "linear" simple reduce 3->1 + int max_lin31 = ncol_top + ncol_top * 2 * nrows; + // maximum number of bottom elements for "tree" simple reduce 4->2 + int max_tree42 = 0; + // number of rows needed to reduce ncol_bot to ncol_top using simple 4->2 "tree" + int nrows_tree42 = int( log( (double)(ncol_bot / ncol_top) )/log((double)2) ); // needed to avoid overflow at pow(2) while computing max_tree42 + if (nrows_tree42 < nrows) { + max_tree42 = npair_top * pow(2.0, nrows + 1); + if ( ncol_top > npair_top * 2 ) { + int delta = ncol_bot - max_tree42; + for (int irow = 1; irow < nrows; irow++) { + int nfour = delta / 4; + delta -= nfour * 2; + } + if (delta <= (ncol_top - npair_top * 2)) + max_tree42 = ncol_bot; + } + } + // maximum number of bottom elements for "tree" simple reduce 3->1 + //int max_tree31 = ncol_top * pow(3.0, nrows); + bool is_lin_31 = false; + bool is_lin_42 = false; + bool is_tree_31 = false; + bool is_tree_42 = false; + int max_lin = max_lin42; + if (ncol_bot > max_lin42) { + if (ncol_bot <= max_lin31) { + is_lin_31 = true; + max_lin = max_lin31; + } + } + else { + // if ncol_bot is a 3*n or not 2*n + if ((ncol_bot/3)*3 == ncol_bot || (ncol_bot/2)*2 != ncol_bot) { + is_lin_31 = true; + max_lin = max_lin31; + } + else { + is_lin_42 = true; + } + } + if (ncol_bot > max_lin) { // not "linear" + is_tree_31 = (ncol_bot > max_tree42); + if (ncol_bot <= max_tree42) { + if ((ncol_bot/3)*3 == ncol_bot || (ncol_bot/2)*2 != ncol_bot) { + is_tree_31 = true; + } + else { + is_tree_42 = true; + } + } + } + + const vector& uv_eb = quad->side[0].GetUVPtStruct(true,0); + const vector& uv_er = quad->side[1].GetUVPtStruct(false,1); + const vector& uv_et = quad->side[2].GetUVPtStruct(true,1); + const vector& uv_el = quad->side[3].GetUVPtStruct(false,0); + + if (uv_eb.size() != nb || uv_er.size() != nr || uv_et.size() != nt || uv_el.size() != nl) + return error(COMPERR_BAD_INPUT_MESH); + + gp_UV uv[ UV_SIZE ]; + uv[ UV_A0 ].SetCoord( uv_eb.front().u, uv_eb.front().v); + uv[ UV_A1 ].SetCoord( uv_eb.back().u, uv_eb.back().v ); + uv[ UV_A2 ].SetCoord( uv_et.back().u, uv_et.back().v ); + uv[ UV_A3 ].SetCoord( uv_et.front().u, uv_et.front().v); + + vector curr_base = uv_eb, next_base; + + UVPtStruct nullUVPtStruct; nullUVPtStruct.node = 0; + + int curr_base_len = nb; + int next_base_len = 0; + + if ( true ) + { // ------------------------------------------------------------------ + // New algorithm implemented by request of IPAL22856 + // "2D quadrangle mesher of reduced type works wrong" + // http://bugtracker.opencascade.com/show_bug.cgi?id=22856 + + // the algorithm is following: all reduces are centred in horizontal + // direction and are distributed among all rows + + if (ncol_bot > max_tree42) { + is_lin_31 = true; + } + else { + if ((ncol_top/3)*3 == ncol_top ) { + is_lin_31 = true; + } + else { + is_lin_42 = true; + } + } + + const int col_top_size = is_lin_42 ? 2 : 1; + const int col_base_size = is_lin_42 ? 4 : 3; + + // Compute nb of "columns" (like in "linear" simple reducing) in all rows + + vector nb_col_by_row; + + int delta_all = nb - nt; + int delta_one_col = nrows * 2; + int nb_col = delta_all / delta_one_col; + int remainder = delta_all - nb_col * delta_one_col; + if (remainder > 0) { + nb_col++; + } + if ( nb_col * col_top_size >= nt ) // == "tree" reducing situation + { + // top row is full (all elements reduced), add "columns" one by one + // in rows below until all bottom elements are reduced + nb_col = ( nt - 1 ) / col_top_size; + nb_col_by_row.resize( nrows, nb_col ); + int nbrows_not_full = nrows - 1; + int cur_top_size = nt - 1; + remainder = delta_all - nb_col * delta_one_col; + while ( remainder > 0 ) + { + delta_one_col = nbrows_not_full * 2; + int nb_col_add = remainder / delta_one_col; + cur_top_size += 2 * nb_col_by_row[ nbrows_not_full ]; + int nb_col_free = cur_top_size / col_top_size - nb_col_by_row[ nbrows_not_full-1 ]; + if ( nb_col_add > nb_col_free ) + nb_col_add = nb_col_free; + for ( int irow = 0; irow < nbrows_not_full; ++irow ) + nb_col_by_row[ irow ] += nb_col_add; + nbrows_not_full --; + remainder -= nb_col_add * delta_one_col; + } + } + else // == "linear" reducing situation + { + nb_col_by_row.resize( nrows, nb_col ); + if (remainder > 0) + for ( int irow = remainder / 2; irow < nrows; ++irow ) + nb_col_by_row[ irow ]--; + } + + // Make elements + + PReduceFunction reduceFunction = & ( is_lin_42 ? reduce42 : reduce31 ); + + const int reduce_grp_size = is_lin_42 ? 4 : 3; + + for (i = 1; i < nr; i++) // layer by layer + { + nb_col = nb_col_by_row[ i-1 ]; + int nb_next = curr_base_len - nb_col * 2; + if (nb_next < nt) nb_next = nt; + + const double y = uv_el[ i ].normParam; + + if ( i + 1 == nr ) // top + { + next_base = uv_et; + } + else + { + next_base.clear(); + next_base.resize( nb_next, nullUVPtStruct ); + next_base.front() = uv_el[i]; + next_base.back() = uv_er[i]; + + // compute normalized param u + double du = 1. / ( nb_next - 1 ); + next_base[0].normParam = 0.; + for ( j = 1; j < nb_next; ++j ) + next_base[j].normParam = next_base[j-1].normParam + du; + } + uv[ UV_L ].SetCoord( next_base.front().u, next_base.front().v ); + uv[ UV_R ].SetCoord( next_base.back().u, next_base.back().v ); + + int free_left = ( curr_base_len - 1 - nb_col * col_base_size ) / 2; + int free_middle = curr_base_len - 1 - nb_col * col_base_size - 2 * free_left; + + // not reduced left elements + for (j = 0; j < free_left; j++) + { + // f (i + 1, j + 1) + const SMDS_MeshNode*& Nf = next_base[++next_base_len].node; + if ( !Nf ) + Nf = makeNode( next_base[ next_base_len ], y, quad, uv, myHelper, S ); + + myHelper->AddFace(curr_base[ j ].node, + curr_base[ j+1 ].node, + Nf, + next_base[ next_base_len-1 ].node); + } + + for (int icol = 1; icol <= nb_col; icol++) + { + // add "H" + reduceFunction( curr_base, next_base, j, next_base_len, quad, uv, y, myHelper, S ); + + j += reduce_grp_size; + + // elements in the middle of "columns" added for symmetry + if ( free_middle > 0 && ( nb_col % 2 == 0 ) && icol == nb_col / 2 ) + { + for (int imiddle = 1; imiddle <= free_middle; imiddle++) { + // f (i + 1, j + imiddle) + const SMDS_MeshNode*& Nf = next_base[++next_base_len].node; + if ( !Nf ) + Nf = makeNode( next_base[ next_base_len ], y, quad, uv, myHelper, S ); + + myHelper->AddFace(curr_base[ j-1+imiddle ].node, + curr_base[ j +imiddle ].node, + Nf, + next_base[ next_base_len-1 ].node); + } + j += free_middle; + } + } + + // not reduced right elements + for (; j < curr_base_len-1; j++) { + // f (i + 1, j + 1) + const SMDS_MeshNode*& Nf = next_base[++next_base_len].node; + if ( !Nf ) + Nf = makeNode( next_base[ next_base_len ], y, quad, uv, myHelper, S ); + + myHelper->AddFace(curr_base[ j ].node, + curr_base[ j+1 ].node, + Nf, + next_base[ next_base_len-1 ].node); + } + + curr_base_len = next_base_len + 1; + next_base_len = 0; + curr_base.swap( next_base ); + } + + } + else if ( is_tree_42 || is_tree_31 ) + { + // "tree" simple reduce "42": 2->4->8->16->32->... + // + // .-------------------------------.-------------------------------. nr + // | \ | / | + // | \ .---------------.---------------. / | + // | | | | | + // .---------------.---------------.---------------.---------------. + // | \ | / | \ | / | + // | \ .-------.-------. / | \ .-------.-------. / | + // | | | | | | | | | + // .-------.-------.-------.-------.-------.-------.-------.-------. i + // |\ | /|\ | /|\ | /|\ | /| + // | \.---.---./ | \.---.---./ | \.---.---./ | \.---.---./ | + // | | | | | | | | | | | | | | | | | + // .---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. + // |\ | /|\ | /|\ | /|\ | /|\ | /|\ | /|\ | /|\ | /| + // | .-.-. | .-.-. | .-.-. | .-.-. | .-.-. | .-.-. | .-.-. | .-.-. | + // | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + // .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. 1 + // 1 j nb + + // "tree" simple reduce "31": 1->3->9->27->... + // + // .-----------------------------------------------------. nr + // | \ / | + // | .-----------------. | + // | | | | + // .-----------------.-----------------.-----------------. + // | \ / | \ / | \ / | + // | .-----. | .-----. | .-----. | i + // | | | | | | | | | | + // .-----.-----.-----.-----.-----.-----.-----.-----.-----. + // |\ /|\ /|\ /|\ /|\ /|\ /|\ /|\ /|\ /| + // | .-. | .-. | .-. | .-. | .-. | .-. | .-. | .-. | .-. | + // | | | | | | | | | | | | | | | | | | | | | | | | | | | | + // .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. 1 + // 1 j nb + + PReduceFunction reduceFunction = & ( is_tree_42 ? reduce42 : reduce31 ); + + const int reduce_grp_size = is_tree_42 ? 4 : 3; + + for (i = 1; i < nr; i++) // layer by layer + { + // to stop reducing, if number of nodes reaches nt + int delta = curr_base_len - nt; + + // to calculate normalized parameter, we must know number of points in next layer + int nb_reduce_groups = (curr_base_len - 1) / reduce_grp_size; + int nb_next = nb_reduce_groups * (reduce_grp_size-2) + (curr_base_len - nb_reduce_groups*reduce_grp_size); + if (nb_next < nt) nb_next = nt; + + const double y = uv_el[ i ].normParam; + + if ( i + 1 == nr ) // top + { + next_base = uv_et; + } + else + { + next_base.clear(); + next_base.resize( nb_next, nullUVPtStruct ); + next_base.front() = uv_el[i]; + next_base.back() = uv_er[i]; + + // compute normalized param u + double du = 1. / ( nb_next - 1 ); + next_base[0].normParam = 0.; + for ( j = 1; j < nb_next; ++j ) + next_base[j].normParam = next_base[j-1].normParam + du; + } + uv[ UV_L ].SetCoord( next_base.front().u, next_base.front().v ); + uv[ UV_R ].SetCoord( next_base.back().u, next_base.back().v ); + + for (j = 0; j+reduce_grp_size < curr_base_len && delta > 0; j+=reduce_grp_size, delta-=2) + { + reduceFunction( curr_base, next_base, j, next_base_len, quad, uv, y, myHelper, S ); + } + + // not reduced side elements (if any) + for (; j < curr_base_len-1; j++) + { + // f (i + 1, j + 1) + const SMDS_MeshNode*& Nf = next_base[++next_base_len].node; + if ( !Nf ) + Nf = makeNode( next_base[ next_base_len ], y, quad, uv, myHelper, S ); + + myHelper->AddFace(curr_base[ j ].node, + curr_base[ j+1 ].node, + Nf, + next_base[ next_base_len-1 ].node); + } + curr_base_len = next_base_len + 1; + next_base_len = 0; + curr_base.swap( next_base ); + } + } // end "tree" simple reduce + + else if ( is_lin_42 || is_lin_31 ) { + // "linear" simple reduce "31": 2->6->10->14 + // + // .-----------------------------.-----------------------------. nr + // | \ / | \ / | + // | .---------. | .---------. | + // | | | | | | | + // .---------.---------.---------.---------.---------.---------. + // | / \ / \ | / \ / \ | + // | / .-----. \ | / .-----. \ | i + // | / | | \ | / | | \ | + // .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----. + // | / / \ / \ \ | / / \ / \ \ | + // | / / .-. \ \ | / / .-. \ \ | + // | / / / \ \ \ | / / / \ \ \ | + // .--.----.---.-----.---.-----.-.--.----.---.-----.---.-----.-. 1 + // 1 j nb + + // "linear" simple reduce "42": 4->8->12->16 + // + // .---------------.---------------.---------------.---------------. nr + // | \ | / | \ | / | + // | \ .-------.-------. / | \ .-------.-------. / | + // | | | | | | | | | + // .-------.-------.-------.-------.-------.-------.-------.-------. + // | / \ | / \ | / \ | / \ | + // | / \.----.----./ \ | / \.----.----./ \ | i + // | / | | | \ | / | | | \ | + // .-----.----.----.----.----.-----.-----.----.----.----.----.-----. + // | / / \ | / \ \ | / / \ | / \ \ | + // | / / .-.-. \ \ | / / .-.-. \ \ | + // | / / / | \ \ \ | / / / | \ \ \ | + // .---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. 1 + // 1 j nb + + // nt = 5, nb = 7, nr = 4 + //int delta_all = 2; + //int delta_one_col = 6; + //int nb_col = 0; + //int remainder = 2; + //if (remainder > 0) nb_col++; + //nb_col = 1; + //int free_left = 1; + //free_left += 2; + //int free_middle = 4; + + int delta_all = nb - nt; + int delta_one_col = (nr - 1) * 2; + int nb_col = delta_all / delta_one_col; + int remainder = delta_all - nb_col * delta_one_col; + if (remainder > 0) { + nb_col++; + } + const int col_top_size = is_lin_42 ? 2 : 1; + int free_left = ((nt - 1) - nb_col * col_top_size) / 2; + free_left += nr - 2; + int free_middle = (nr - 2) * 2; + if (remainder > 0 && nb_col == 1) { + int nb_rows_short_col = remainder / 2; + int nb_rows_thrown = (nr - 1) - nb_rows_short_col; + free_left -= nb_rows_thrown; + } + + // nt = 5, nb = 17, nr = 4 + //int delta_all = 12; + //int delta_one_col = 6; + //int nb_col = 2; + //int remainder = 0; + //int free_left = 2; + //int free_middle = 4; + + PReduceFunction reduceFunction = & ( is_lin_42 ? reduce42 : reduce31 ); + + const int reduce_grp_size = is_lin_42 ? 4 : 3; + + for (i = 1; i < nr; i++, free_middle -= 2, free_left -= 1) // layer by layer + { + // to calculate normalized parameter, we must know number of points in next layer + int nb_next = curr_base_len - nb_col * 2; + if (remainder > 0 && i > remainder / 2) + // take into account short "column" + nb_next += 2; + if (nb_next < nt) nb_next = nt; + + const double y = uv_el[ i ].normParam; + + if ( i + 1 == nr ) // top + { + next_base = uv_et; + } + else + { + next_base.clear(); + next_base.resize( nb_next, nullUVPtStruct ); + next_base.front() = uv_el[i]; + next_base.back() = uv_er[i]; + + // compute normalized param u + double du = 1. / ( nb_next - 1 ); + next_base[0].normParam = 0.; + for ( j = 1; j < nb_next; ++j ) + next_base[j].normParam = next_base[j-1].normParam + du; + } + uv[ UV_L ].SetCoord( next_base.front().u, next_base.front().v ); + uv[ UV_R ].SetCoord( next_base.back().u, next_base.back().v ); + + // not reduced left elements + for (j = 0; j < free_left; j++) + { + // f (i + 1, j + 1) + const SMDS_MeshNode*& Nf = next_base[++next_base_len].node; + if ( !Nf ) + Nf = makeNode( next_base[ next_base_len ], y, quad, uv, myHelper, S ); + + myHelper->AddFace(curr_base[ j ].node, + curr_base[ j+1 ].node, + Nf, + next_base[ next_base_len-1 ].node); + } + + for (int icol = 1; icol <= nb_col; icol++) { + + if (remainder > 0 && icol == nb_col && i > remainder / 2) + // stop short "column" + break; + + // add "H" + reduceFunction( curr_base, next_base, j, next_base_len, quad, uv, y, myHelper, S ); + + j += reduce_grp_size; + + // not reduced middle elements + if (icol < nb_col) { + if (remainder > 0 && icol == nb_col - 1 && i > remainder / 2) + // pass middle elements before stopped short "column" + break; + + int free_add = free_middle; + if (remainder > 0 && icol == nb_col - 1) + // next "column" is short + free_add -= (nr - 1) - (remainder / 2); + + for (int imiddle = 1; imiddle <= free_add; imiddle++) { + // f (i + 1, j + imiddle) + const SMDS_MeshNode*& Nf = next_base[++next_base_len].node; + if ( !Nf ) + Nf = makeNode( next_base[ next_base_len ], y, quad, uv, myHelper, S ); + + myHelper->AddFace(curr_base[ j-1+imiddle ].node, + curr_base[ j +imiddle ].node, + Nf, + next_base[ next_base_len-1 ].node); + } + j += free_add; + } + } + + // not reduced right elements + for (; j < curr_base_len-1; j++) { + // f (i + 1, j + 1) + const SMDS_MeshNode*& Nf = next_base[++next_base_len].node; + if ( !Nf ) + Nf = makeNode( next_base[ next_base_len ], y, quad, uv, myHelper, S ); + + myHelper->AddFace(curr_base[ j ].node, + curr_base[ j+1 ].node, + Nf, + next_base[ next_base_len-1 ].node); + } + + curr_base_len = next_base_len + 1; + next_base_len = 0; + curr_base.swap( next_base ); + } + + } // end "linear" simple reduce + + else { + return false; + } + } // end Simple Reduce implementation + + bool isOk = true; + return isOk; +} + +//================================================================================ +namespace // data for smoothing +{ + struct TSmoothNode; + // -------------------------------------------------------------------------------- + /*! + * \brief Structure used to check validity of node position after smoothing. + * It holds two nodes connected to a smoothed node and belonging to + * one mesh face + */ + struct TTriangle + { + TSmoothNode* _n1; + TSmoothNode* _n2; + TTriangle( TSmoothNode* n1=0, TSmoothNode* n2=0 ): _n1(n1), _n2(n2) {} + + inline bool IsForward( gp_UV uv ) const; + }; + // -------------------------------------------------------------------------------- + /*! + * \brief Data of a smoothed node + */ + struct TSmoothNode + { + gp_XY _uv; + gp_XYZ _xyz; + vector< TTriangle > _triangles; // if empty, then node is not movable + }; + // -------------------------------------------------------------------------------- + inline bool TTriangle::IsForward( gp_UV uv ) const + { + gp_Vec2d v1( uv, _n1->_uv ), v2( uv, _n2->_uv ); + double d = v1 ^ v2; + return d > 1e-100; + } + //================================================================================ + /*! + * \brief Returns area of a triangle + */ + //================================================================================ + + double getArea( const gp_UV uv1, const gp_UV uv2, const gp_UV uv3 ) + { + gp_XY v1 = uv1 - uv2, v2 = uv3 - uv2; + double a = v2 ^ v1; + return a; + } +} + +//================================================================================ +/*! + * \brief Set UV of nodes on degenerated VERTEXes in the middle of degenerated EDGE + * + * WARNING: this method must be called AFTER retrieving UVPtStruct's from quad + */ +//================================================================================ + +void StdMeshers_Quadrangle_2D::updateDegenUV(FaceQuadStruct::Ptr quad) +{ + if ( myNeedSmooth ) + + // Set UV of nodes on degenerated VERTEXes in the middle of degenerated EDGE + // -------------------------------------------------------------------------- + for ( unsigned i = 0; i < quad->side.size(); ++i ) + { + const vector& uvVec = quad->side[i].GetUVPtStruct(); + + // find which end of the side is on degenerated shape + int degenInd = -1; + if ( myHelper->IsDegenShape( uvVec[0].node->getshapeId() )) + degenInd = 0; + else if ( myHelper->IsDegenShape( uvVec.back().node->getshapeId() )) + degenInd = uvVec.size() - 1; + else + continue; + + // find another side sharing the degenerated shape + bool isPrev = ( degenInd == 0 ); + if ( i >= QUAD_TOP_SIDE ) + isPrev = !isPrev; + int i2 = ( isPrev ? ( i + 3 ) : ( i + 1 )) % 4; + const vector& uvVec2 = quad->side[ i2 ].GetUVPtStruct(); + int degenInd2 = -1; + if ( uvVec[ degenInd ].node == uvVec2.front().node ) + degenInd2 = 0; + else if ( uvVec[ degenInd ].node == uvVec2.back().node ) + degenInd2 = uvVec2.size() - 1; + else + throw SALOME_Exception( LOCALIZED( "Logical error" )); + + // move UV in the middle + uvPtStruct& uv1 = const_cast( uvVec [ degenInd ]); + uvPtStruct& uv2 = const_cast( uvVec2[ degenInd2 ]); + uv1.u = uv2.u = 0.5 * ( uv1.u + uv2.u ); + uv1.v = uv2.v = 0.5 * ( uv1.v + uv2.v ); + } + + else if ( quad->side.size() == 4 /*&& myQuadType == QUAD_STANDARD*/) + + // Set number of nodes on a degenerated side to be same as on an opposite side + // ---------------------------------------------------------------------------- + for ( size_t i = 0; i < quad->side.size(); ++i ) + { + StdMeshers_FaceSidePtr degSide = quad->side[i]; + if ( !myHelper->IsDegenShape( degSide->EdgeID(0) )) + continue; + StdMeshers_FaceSidePtr oppSide = quad->side[( i+2 ) % quad->side.size() ]; + if ( degSide->NbSegments() == oppSide->NbSegments() ) + continue; + + // make new side data + const vector& uvVecDegOld = degSide->GetUVPtStruct(); + const SMDS_MeshNode* n = uvVecDegOld[0].node; + Handle(Geom2d_Curve) c2d = degSide->Curve2d(0); + double f = degSide->FirstU(0), l = degSide->LastU(0); + gp_Pnt2d p1 = uvVecDegOld.front().UV(); + gp_Pnt2d p2 = uvVecDegOld.back().UV(); + + quad->side[i] = StdMeshers_FaceSide::New( oppSide.get(), n, &p1, &p2, c2d, f, l ); + } +} + +//================================================================================ +/*! + * \brief Perform smoothing of 2D elements on a FACE with ignored degenerated EDGE + */ +//================================================================================ + +void StdMeshers_Quadrangle_2D::smooth (FaceQuadStruct::Ptr quad) +{ + if ( !myNeedSmooth ) return; + + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + const double tol = BRep_Tool::Tolerance( quad->face ); + Handle(ShapeAnalysis_Surface) surface = myHelper->GetSurface( quad->face ); + + if ( myHelper->HasDegeneratedEdges() && myForcedPnts.empty() ) + { + // "smooth" by computing node positions using 3D TFI and further projection + + int nbhoriz = quad->iSize; + int nbvertic = quad->jSize; + + SMESH_TNodeXYZ a0( quad->UVPt( 0, 0 ).node ); + SMESH_TNodeXYZ a1( quad->UVPt( nbhoriz-1, 0 ).node ); + SMESH_TNodeXYZ a2( quad->UVPt( nbhoriz-1, nbvertic-1 ).node ); + SMESH_TNodeXYZ a3( quad->UVPt( 0, nbvertic-1 ).node ); + + for (int i = 1; i < nbhoriz-1; i++) + { + SMESH_TNodeXYZ p0( quad->UVPt( i, 0 ).node ); + SMESH_TNodeXYZ p2( quad->UVPt( i, nbvertic-1 ).node ); + for (int j = 1; j < nbvertic-1; j++) + { + SMESH_TNodeXYZ p1( quad->UVPt( nbhoriz-1, j ).node ); + SMESH_TNodeXYZ p3( quad->UVPt( 0, j ).node ); + + UVPtStruct& uvp = quad->UVPt( i, j ); + + gp_Pnt p = myHelper->calcTFI(uvp.x,uvp.y, a0,a1,a2,a3, p0,p1,p2,p3); + gp_Pnt2d uv = surface->NextValueOfUV( uvp.UV(), p, 10*tol ); + gp_Pnt pnew = surface->Value( uv ); + + meshDS->MoveNode( uvp.node, pnew.X(), pnew.Y(), pnew.Z() ); + uvp.u = uv.X(); + uvp.v = uv.Y(); + } + } + return; + } + + // Get nodes to smooth + + typedef map< const SMDS_MeshNode*, TSmoothNode, TIDCompare > TNo2SmooNoMap; + TNo2SmooNoMap smooNoMap; + + // fixed nodes + set< const SMDS_MeshNode* > fixedNodes; + for ( size_t i = 0; i < myForcedPnts.size(); ++i ) + { + fixedNodes.insert( myForcedPnts[i].node ); + if ( myForcedPnts[i].node->getshapeId() != myHelper->GetSubShapeID() ) + { + TSmoothNode & sNode = smooNoMap[ myForcedPnts[i].node ]; + sNode._uv = myForcedPnts[i].uv; + sNode._xyz = SMESH_TNodeXYZ( myForcedPnts[i].node ); + } + } + SMESHDS_SubMesh* fSubMesh = meshDS->MeshElements( quad->face ); + SMDS_NodeIteratorPtr nIt = fSubMesh->GetNodes(); + while ( nIt->more() ) // loop on nodes bound to a FACE + { + const SMDS_MeshNode* node = nIt->next(); + TSmoothNode & sNode = smooNoMap[ node ]; + sNode._uv = myHelper->GetNodeUV( quad->face, node ); + sNode._xyz = SMESH_TNodeXYZ( node ); + if ( fixedNodes.count( node )) + continue; // fixed - no triangles + + // set sNode._triangles + SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator( SMDSAbs_Face ); + while ( fIt->more() ) + { + const SMDS_MeshElement* face = fIt->next(); + const int nbN = face->NbCornerNodes(); + const int nInd = face->GetNodeIndex( node ); + const int prevInd = myHelper->WrapIndex( nInd - 1, nbN ); + const int nextInd = myHelper->WrapIndex( nInd + 1, nbN ); + const SMDS_MeshNode* prevNode = face->GetNode( prevInd ); + const SMDS_MeshNode* nextNode = face->GetNode( nextInd ); + sNode._triangles.push_back( TTriangle( & smooNoMap[ prevNode ], + & smooNoMap[ nextNode ])); + } + } + // set _uv of smooth nodes on FACE boundary + set< StdMeshers_FaceSide* > sidesOnEdge; + list< FaceQuadStruct::Ptr >::iterator q = myQuadList.begin(); + for ( ; q != myQuadList.end() ; ++q ) + for ( size_t i = 0; i < (*q)->side.size(); ++i ) + if ( ! (*q)->side[i].grid->Edge(0).IsNull() && + //(*q)->nbNodeOut( i ) == 0 && + sidesOnEdge.insert( (*q)->side[i].grid.get() ).second ) + { + const vector& uvVec = (*q)->side[i].grid->GetUVPtStruct(); + for ( unsigned j = 0; j < uvVec.size(); ++j ) + { + TSmoothNode & sNode = smooNoMap[ uvVec[j].node ]; + sNode._uv = uvVec[j].UV(); + sNode._xyz = SMESH_TNodeXYZ( uvVec[j].node ); + } + } + + // define refernce orientation in 2D + TNo2SmooNoMap::iterator n2sn = smooNoMap.begin(); + for ( ; n2sn != smooNoMap.end(); ++n2sn ) + if ( !n2sn->second._triangles.empty() ) + break; + if ( n2sn == smooNoMap.end() ) return; + const TSmoothNode & sampleNode = n2sn->second; + const bool refForward = ( sampleNode._triangles[0].IsForward( sampleNode._uv )); + + // Smoothing + + for ( int iLoop = 0; iLoop < 5; ++iLoop ) + { + for ( n2sn = smooNoMap.begin(); n2sn != smooNoMap.end(); ++n2sn ) + { + TSmoothNode& sNode = n2sn->second; + if ( sNode._triangles.empty() ) + continue; // not movable node + + gp_XY newUV; + bool isValid = false; + bool use3D = ( iLoop > 2 ); // 3 loops in 2D and 2, in 3D + + if ( use3D ) + { + // compute a new XYZ + gp_XYZ newXYZ (0,0,0); + for ( size_t i = 0; i < sNode._triangles.size(); ++i ) + newXYZ += sNode._triangles[i]._n1->_xyz; + newXYZ /= sNode._triangles.size(); + + // compute a new UV by projection + newUV = surface->NextValueOfUV( sNode._uv, newXYZ, 10*tol ).XY(); + + // check validity of the newUV + for ( size_t i = 0; i < sNode._triangles.size() && isValid; ++i ) + isValid = ( sNode._triangles[i].IsForward( newUV ) == refForward ); + } + if ( !isValid ) + { + // compute a new UV by averaging + newUV.SetCoord(0.,0.); + for ( unsigned i = 0; i < sNode._triangles.size(); ++i ) + newUV += sNode._triangles[i]._n1->_uv; + newUV /= sNode._triangles.size(); + + // check validity of the newUV + isValid = true; + for ( unsigned i = 0; i < sNode._triangles.size() && isValid; ++i ) + isValid = ( sNode._triangles[i].IsForward( newUV ) == refForward ); + } + if ( isValid ) + { + sNode._uv = newUV; + sNode._xyz = surface->Value( newUV ).XYZ(); + } + } + } + + // Set new XYZ to the smoothed nodes + + for ( n2sn = smooNoMap.begin(); n2sn != smooNoMap.end(); ++n2sn ) + { + TSmoothNode& sNode = n2sn->second; + if ( sNode._triangles.empty() ) + continue; // not movable node + + SMDS_MeshNode* node = const_cast< SMDS_MeshNode*>( n2sn->first ); + gp_Pnt xyz = surface->Value( sNode._uv ); + meshDS->MoveNode( node, xyz.X(), xyz.Y(), xyz.Z() ); + + // store the new UV + node->SetPosition( SMDS_PositionPtr( new SMDS_FacePosition( sNode._uv.X(), sNode._uv.Y() ))); + } + + // Move medium nodes in quadratic mesh + if ( _quadraticMesh ) + { + const TLinkNodeMap& links = myHelper->GetTLinkNodeMap(); + TLinkNodeMap::const_iterator linkIt = links.begin(); + for ( ; linkIt != links.end(); ++linkIt ) + { + const SMESH_TLink& link = linkIt->first; + SMDS_MeshNode* node = const_cast< SMDS_MeshNode*>( linkIt->second ); + + if ( node->getshapeId() != myHelper->GetSubShapeID() ) + continue; // medium node is on EDGE or VERTEX + + gp_XYZ pm = 0.5 * ( SMESH_TNodeXYZ( link.node1() ) + SMESH_TNodeXYZ( link.node2() )); + gp_XY uvm = myHelper->GetNodeUV( quad->face, node ); + + gp_Pnt2d uv = surface->NextValueOfUV( uvm, pm, 10*tol ); + gp_Pnt xyz = surface->Value( uv ); + + node->SetPosition( SMDS_PositionPtr( new SMDS_FacePosition( uv.X(), uv.Y() ))); + meshDS->MoveNode( node, xyz.X(), xyz.Y(), xyz.Z() ); + } + } +} + +//================================================================================ +/*! + * \brief Checks validity of generated faces + */ +//================================================================================ + +bool StdMeshers_Quadrangle_2D::check() +{ + const bool isOK = true; + if ( !myCheckOri || myQuadList.empty() || !myQuadList.front() || !myHelper ) + return isOK; + + TopoDS_Face geomFace = TopoDS::Face( myHelper->GetSubShape() ); + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + SMESHDS_SubMesh* fSubMesh = meshDS->MeshElements( geomFace ); + bool toCheckUV; + if ( geomFace.Orientation() >= TopAbs_INTERNAL ) geomFace.Orientation( TopAbs_FORWARD ); + + // Get a reference orientation sign + + double okSign; + { + TError err; + TSideVector wireVec = + StdMeshers_FaceSide::GetFaceWires( geomFace, *myHelper->GetMesh(), true, err ); + StdMeshers_FaceSidePtr wire = wireVec[0]; + + // find a right angle VERTEX + int iVertex; + double maxAngle = -1e100; + for ( int i = 0; i < wire->NbEdges(); ++i ) + { + int iPrev = myHelper->WrapIndex( i-1, wire->NbEdges() ); + const TopoDS_Edge& e1 = wire->Edge( iPrev ); + const TopoDS_Edge& e2 = wire->Edge( i ); + double angle = myHelper->GetAngle( e1, e2, geomFace, wire->FirstVertex( i )); + if (( maxAngle < angle ) && + ( 5.* M_PI/180 < angle && angle < 175.* M_PI/180 )) + { + maxAngle = angle; + iVertex = i; + } + } + if ( maxAngle < -2*M_PI ) return isOK; + + // get a sign of 2D area of a corner face + + int iPrev = myHelper->WrapIndex( iVertex-1, wire->NbEdges() ); + const TopoDS_Edge& e1 = wire->Edge( iPrev ); + const TopoDS_Edge& e2 = wire->Edge( iVertex ); + + gp_Vec2d v1, v2; gp_Pnt2d p; + double u[2]; + { + bool rev = ( e1.Orientation() == TopAbs_REVERSED ); + Handle(Geom2d_Curve) c = BRep_Tool::CurveOnSurface( e1, geomFace, u[0], u[1] ); + c->D1( u[ !rev ], p, v1 ); + if ( !rev ) + v1.Reverse(); + } + { + bool rev = ( e2.Orientation() == TopAbs_REVERSED ); + Handle(Geom2d_Curve) c = BRep_Tool::CurveOnSurface( e2, geomFace, u[0], u[1] ); + c->D1( u[ rev ], p, v2 ); + if ( rev ) + v2.Reverse(); + } + + okSign = v2 ^ v1; + + if ( maxAngle < 0 ) + okSign *= -1; + } + + // Look for incorrectly oriented faces + + std::list badFaces; + + const SMDS_MeshNode* nn [ 8 ]; // 8 is just for safety + gp_UV uv [ 8 ]; + SMDS_ElemIteratorPtr fIt = fSubMesh->GetElements(); + while ( fIt->more() ) // loop on faces bound to a FACE + { + const SMDS_MeshElement* f = fIt->next(); + + const int nbN = f->NbCornerNodes(); + for ( int i = 0; i < nbN; ++i ) + nn[ i ] = f->GetNode( i ); + + const SMDS_MeshNode* nInFace = 0; + if ( myHelper->HasSeam() ) + for ( int i = 0; i < nbN && !nInFace; ++i ) + if ( !myHelper->IsSeamShape( nn[i]->getshapeId() )) + nInFace = nn[i]; + + toCheckUV = true; + for ( int i = 0; i < nbN; ++i ) + uv[ i ] = myHelper->GetNodeUV( geomFace, nn[i], nInFace, &toCheckUV ); + + switch ( nbN ) { + case 4: + { + double sign1 = getArea( uv[0], uv[1], uv[2] ); + double sign2 = getArea( uv[0], uv[2], uv[3] ); + if ( sign1 * sign2 < 0 ) + { + sign2 = getArea( uv[1], uv[2], uv[3] ); + sign1 = getArea( uv[1], uv[3], uv[0] ); + if ( sign1 * sign2 < 0 ) + continue; // this should not happen + } + if ( sign1 * okSign < 0 ) + badFaces.push_back ( f ); + break; + } + case 3: + { + double sign = getArea( uv[0], uv[1], uv[2] ); + if ( sign * okSign < 0 ) + badFaces.push_back ( f ); + break; + } + default:; + } + } + + if ( !badFaces.empty() ) + { + SMESH_subMesh* fSM = myHelper->GetMesh()->GetSubMesh( geomFace ); + SMESH_ComputeErrorPtr& err = fSM->GetComputeError(); + err.reset ( new SMESH_ComputeError( COMPERR_ALGO_FAILED, + "Inverted elements generated")); + err->myBadElements.swap( badFaces ); + + return !isOK; + } + + return isOK; +} + +/*//================================================================================ +/*! + * \brief Finds vertices at the most sharp face corners + * \param [in] theFace - the FACE + * \param [in,out] theWire - the ordered edges of the face. It can be modified to + * have the first VERTEX of the first EDGE in \a vertices + * \param [out] theVertices - the found corner vertices in the order corresponding to + * the order of EDGEs in \a theWire + * \param [out] theNbDegenEdges - nb of degenerated EDGEs in theFace + * \param [in] theConsiderMesh - if \c true, only meshed VERTEXes are considered + * as possible corners + * \return int - number of quad sides found: 0, 3 or 4 + */ +//================================================================================ + +int StdMeshers_Quadrangle_2D::getCorners(const TopoDS_Face& theFace, + SMESH_Mesh & theMesh, + std::list& theWire, + std::vector& theVertices, + int & theNbDegenEdges, + const bool theConsiderMesh) +{ + theNbDegenEdges = 0; + + SMESH_MesherHelper helper( theMesh ); + StdMeshers_FaceSide faceSide( theFace, theWire, &theMesh, /*isFwd=*/true, /*skipMedium=*/true); + + // sort theVertices by angle + multimap vertexByAngle; + TopTools_DataMapOfShapeReal angleByVertex; + TopoDS_Edge prevE = theWire.back(); + if ( SMESH_Algo::isDegenerated( prevE )) + { + list::reverse_iterator edge = ++theWire.rbegin(); + while ( SMESH_Algo::isDegenerated( *edge )) + ++edge; + if ( edge == theWire.rend() ) + return false; + prevE = *edge; + } + list::iterator edge = theWire.begin(); + for ( int iE = 0; edge != theWire.end(); ++edge, ++iE ) + { + if ( SMESH_Algo::isDegenerated( *edge )) + { + ++theNbDegenEdges; + continue; + } + if ( !theConsiderMesh || faceSide.VertexNode( iE )) + { + TopoDS_Vertex v = helper.IthVertex( 0, *edge ); + double angle = helper.GetAngle( prevE, *edge, theFace, v ); + vertexByAngle.insert( make_pair( angle, v )); + angleByVertex.Bind( v, angle ); + } + prevE = *edge; + } + + // find out required nb of corners (3 or 4) + int nbCorners = 4; + TopoDS_Shape triaVertex = helper.GetMeshDS()->IndexToShape( myTriaVertexID ); + if ( !triaVertex.IsNull() && + triaVertex.ShapeType() == TopAbs_VERTEX && + helper.IsSubShape( triaVertex, theFace ) && + ( vertexByAngle.size() != 4 || vertexByAngle.begin()->first < 5 * M_PI/180. )) + nbCorners = 3; + else + triaVertex.Nullify(); + + // check nb of available corners + if ( faceSide.NbEdges() < nbCorners ) + return error(COMPERR_BAD_SHAPE, + TComm("Face must have 4 sides but not ") << faceSide.NbEdges() ); + + if ( theConsiderMesh ) + { + const int nbSegments = Max( faceSide.NbPoints()-1, faceSide.NbSegments() ); + if ( nbSegments < nbCorners ) + return error(COMPERR_BAD_INPUT_MESH, TComm("Too few boundary nodes: ") << nbSegments); + } + + if ( nbCorners == 3 ) + { + if ( vertexByAngle.size() < 3 ) + return error(COMPERR_BAD_SHAPE, + TComm("Face must have 3 sides but not ") << vertexByAngle.size() ); + } + else + { + if ( vertexByAngle.size() == 3 && theNbDegenEdges == 0 ) + { + if ( myTriaVertexID < 1 ) + return error(COMPERR_BAD_PARMETERS, + "No Base vertex provided for a trilateral geometrical face"); + + TComm comment("Invalid Base vertex: "); + comment << myTriaVertexID << " its ID is not among [ "; + multimap::iterator a2v = vertexByAngle.begin(); + comment << helper.GetMeshDS()->ShapeToIndex( a2v->second ) << ", "; a2v++; + comment << helper.GetMeshDS()->ShapeToIndex( a2v->second ) << ", "; a2v++; + comment << helper.GetMeshDS()->ShapeToIndex( a2v->second ) << " ]"; + return error(COMPERR_BAD_PARMETERS, comment ); + } + if ( vertexByAngle.size() + ( theNbDegenEdges > 0 ) < 4 && + vertexByAngle.size() + theNbDegenEdges != 4 ) + return error(COMPERR_BAD_SHAPE, + TComm("Face must have 4 sides but not ") << vertexByAngle.size() ); + } + + // put all corner vertices in a map + TopTools_MapOfShape vMap; + if ( nbCorners == 3 ) + vMap.Add( triaVertex ); + multimap::reverse_iterator a2v = vertexByAngle.rbegin(); + for ( int iC = 0; a2v != vertexByAngle.rend() && iC < nbCorners; ++a2v, ++iC ) + vMap.Add( (*a2v).second ); + + // check if there are possible variations in choosing corners + bool haveVariants = false; + if ( vertexByAngle.size() > nbCorners ) + { + double lostAngle = a2v->first; + double lastAngle = ( --a2v, a2v->first ); + haveVariants = ( lostAngle * 1.1 >= lastAngle ); + } + + const double angleTol = 5.* M_PI/180; + myCheckOri = ( vertexByAngle.size() > nbCorners || + vertexByAngle.begin()->first < angleTol ); + + // make theWire begin from a corner vertex or triaVertex + if ( nbCorners == 3 ) + while ( !triaVertex.IsSame( ( helper.IthVertex( 0, theWire.front() ))) || + SMESH_Algo::isDegenerated( theWire.front() )) + theWire.splice( theWire.end(), theWire, theWire.begin() ); + else + while ( !vMap.Contains( helper.IthVertex( 0, theWire.front() )) || + SMESH_Algo::isDegenerated( theWire.front() )) + theWire.splice( theWire.end(), theWire, theWire.begin() ); + + // fill the result vector and prepare for its refinement + theVertices.clear(); + vector< double > angles; + vector< TopoDS_Edge > edgeVec; + vector< int > cornerInd, nbSeg; + int nbSegTot = 0; + angles .reserve( vertexByAngle.size() ); + edgeVec.reserve( vertexByAngle.size() ); + nbSeg .reserve( vertexByAngle.size() ); + cornerInd.reserve( nbCorners ); + for ( edge = theWire.begin(); edge != theWire.end(); ++edge ) + { + if ( SMESH_Algo::isDegenerated( *edge )) + continue; + TopoDS_Vertex v = helper.IthVertex( 0, *edge ); + bool isCorner = vMap.Contains( v ); + if ( isCorner ) + { + theVertices.push_back( v ); + cornerInd.push_back( angles.size() ); + } + angles .push_back( angleByVertex.IsBound( v ) ? angleByVertex( v ) : -M_PI ); + edgeVec.push_back( *edge ); + if ( theConsiderMesh && haveVariants ) + { + if ( SMESHDS_SubMesh* sm = helper.GetMeshDS()->MeshElements( *edge )) + nbSeg.push_back( sm->NbNodes() + 1 ); + else + nbSeg.push_back( 0 ); + nbSegTot += nbSeg.back(); + } + } + + // refine the result vector - make sides equal by length if + // there are several equal angles + if ( haveVariants ) + { + if ( nbCorners == 3 ) + angles[0] = 2 * M_PI; // not to move the base triangle VERTEX + + // here we refer to VERTEX'es and EDGEs by indices in angles and edgeVec vectors + typedef int TGeoIndex; + + // for each vertex find a vertex till which there are nbSegHalf segments + const int nbSegHalf = ( nbSegTot % 2 || nbCorners == 3 ) ? 0 : nbSegTot / 2; + vector< TGeoIndex > halfDivider( angles.size(), -1 ); + int nbHalfDividers = 0; + if ( nbSegHalf ) + { + // get min angle of corners + double minAngle = 10.; + for ( size_t iC = 0; iC < cornerInd.size(); ++iC ) + minAngle = Min( minAngle, angles[ cornerInd[ iC ]]); + + // find halfDivider's + for ( TGeoIndex iV1 = 0; iV1 < TGeoIndex( angles.size() ); ++iV1 ) + { + int nbSegs = 0; + TGeoIndex iV2 = iV1; + do { + nbSegs += nbSeg[ iV2 ]; + iV2 = helper.WrapIndex( iV2 + 1, nbSeg.size() ); + } while ( nbSegs < nbSegHalf ); + + if ( nbSegs == nbSegHalf && + angles[ iV1 ] + angleTol >= minAngle && + angles[ iV2 ] + angleTol >= minAngle ) + { + halfDivider[ iV1 ] = iV2; + ++nbHalfDividers; + } + } + } + + set< TGeoIndex > refinedCorners, treatedCorners; + for ( size_t iC = 0; iC < cornerInd.size(); ++iC ) + { + TGeoIndex iV = cornerInd[iC]; + if ( !treatedCorners.insert( iV ).second ) + continue; + list< TGeoIndex > equVerts; // inds of vertices that can become corners + equVerts.push_back( iV ); + int nbC[2] = { 0, 0 }; + // find equal angles backward and forward from the iV-th corner vertex + for ( int isFwd = 0; isFwd < 2; ++isFwd ) + { + int dV = isFwd ? +1 : -1; + int iCNext = helper.WrapIndex( iC + dV, cornerInd.size() ); + TGeoIndex iVNext = helper.WrapIndex( iV + dV, angles.size() ); + while ( iVNext != iV ) + { + bool equal = Abs( angles[iV] - angles[iVNext] ) < angleTol; + if ( equal ) + equVerts.insert( isFwd ? equVerts.end() : equVerts.begin(), iVNext ); + if ( iVNext == cornerInd[ iCNext ]) + { + if ( !equal ) + { + if ( angles[iV] < angles[iVNext] ) + refinedCorners.insert( iVNext ); + break; + } + nbC[ isFwd ]++; + treatedCorners.insert( cornerInd[ iCNext ] ); + iCNext = helper.WrapIndex( iCNext + dV, cornerInd.size() ); + } + iVNext = helper.WrapIndex( iVNext + dV, angles.size() ); + } + if ( iVNext == iV ) + break; // all angles equal + } + + const bool allCornersSame = ( nbC[0] == 3 ); + if ( allCornersSame && nbHalfDividers > 0 ) + { + // select two halfDivider's as corners + TGeoIndex hd1, hd2 = -1; + int iC2; + for ( iC2 = 0; iC2 < cornerInd.size() && hd2 < 0; ++iC2 ) + { + hd1 = cornerInd[ iC2 ]; + hd2 = halfDivider[ hd1 ]; + if ( std::find( equVerts.begin(), equVerts.end(), hd2 ) == equVerts.end() ) + hd2 = -1; // hd2-th vertex can't become a corner + else + break; + } + if ( hd2 >= 0 ) + { + angles[ hd1 ] = 2 * M_PI; // make hd1-th vertex no more "equal" + angles[ hd2 ] = 2 * M_PI; + refinedCorners.insert( hd1 ); + refinedCorners.insert( hd2 ); + treatedCorners = refinedCorners; + // update cornerInd + equVerts.push_front( equVerts.back() ); + equVerts.push_back( equVerts.front() ); + list< TGeoIndex >::iterator hdPos = + std::find( equVerts.begin(), equVerts.end(), hd2 ); + if ( hdPos == equVerts.end() ) break; + cornerInd[ helper.WrapIndex( iC2 + 0, cornerInd.size()) ] = hd1; + cornerInd[ helper.WrapIndex( iC2 + 1, cornerInd.size()) ] = *( --hdPos ); + cornerInd[ helper.WrapIndex( iC2 + 2, cornerInd.size()) ] = hd2; + cornerInd[ helper.WrapIndex( iC2 + 3, cornerInd.size()) ] = *( ++hdPos, ++hdPos ); + + theVertices[ 0 ] = helper.IthVertex( 0, edgeVec[ cornerInd[0] ]); + theVertices[ 1 ] = helper.IthVertex( 0, edgeVec[ cornerInd[1] ]); + theVertices[ 2 ] = helper.IthVertex( 0, edgeVec[ cornerInd[2] ]); + theVertices[ 3 ] = helper.IthVertex( 0, edgeVec[ cornerInd[3] ]); + iC = -1; + continue; + } + } + + // move corners to make sides equal by length + int nbEqualV = equVerts.size(); + int nbExcessV = nbEqualV - ( 1 + nbC[0] + nbC[1] ); + if ( nbExcessV > 0 ) // there is nbExcessV vertices that can become corners + { + // calculate normalized length of each "side" enclosed between neighbor equVerts + vector< double > accuLength; + double totalLen = 0; + vector< TGeoIndex > evVec( equVerts.begin(), equVerts.end() ); + int iEV = 0; + TGeoIndex iE = cornerInd[ helper.WrapIndex( iC - nbC[0] - 1, cornerInd.size() )]; + TGeoIndex iEEnd = cornerInd[ helper.WrapIndex( iC + nbC[1] + 1, cornerInd.size() )]; + while ( accuLength.size() < nbEqualV + int( !allCornersSame ) ) + { + // accumulate length of edges before iEV-th equal vertex + accuLength.push_back( totalLen ); + do { + accuLength.back() += SMESH_Algo::EdgeLength( edgeVec[ iE ]); + iE = helper.WrapIndex( iE + 1, edgeVec.size()); + if ( iEV < evVec.size() && iE == evVec[ iEV ] ) { + iEV++; + break; // equal vertex reached + } + } + while( iE != iEEnd ); + totalLen = accuLength.back(); + } + accuLength.resize( equVerts.size() ); + for ( size_t iS = 0; iS < accuLength.size(); ++iS ) + accuLength[ iS ] /= totalLen; + + // find equVerts most close to the ideal sub-division of all sides + int iBestEV = 0; + int iCorner = helper.WrapIndex( iC - nbC[0], cornerInd.size() ); + int nbSides = Min( nbCorners, 2 + nbC[0] + nbC[1] ); + for ( int iS = 1; iS < nbSides; ++iS, ++iBestEV ) + { + double idealLen = iS / double( nbSides ); + double d, bestDist = 2.; + for ( iEV = iBestEV; iEV < accuLength.size(); ++iEV ) + { + d = Abs( idealLen - accuLength[ iEV ]); + + // take into account presence of a coresponding halfDivider + const double cornerWgt = 0.5 / nbSides; + const double vertexWgt = 0.25 / nbSides; + TGeoIndex hd = halfDivider[ evVec[ iEV ]]; + if ( hd < 0 ) + d += vertexWgt; + else if( refinedCorners.count( hd )) + d -= cornerWgt; + else + d -= vertexWgt; + + // choose vertex with the best d + if ( d < bestDist ) + { + bestDist = d; + iBestEV = iEV; + } + } + if ( iBestEV > iS-1 + nbExcessV ) + iBestEV = iS-1 + nbExcessV; + theVertices[ iCorner ] = helper.IthVertex( 0, edgeVec[ evVec[ iBestEV ]]); + refinedCorners.insert( evVec[ iBestEV ]); + iCorner = helper.WrapIndex( iCorner + 1, cornerInd.size() ); + } + + } // if ( nbExcessV > 0 ) + else + { + refinedCorners.insert( cornerInd[ iC ]); + } + } // loop on cornerInd + + // make theWire begin from the cornerInd[0]-th EDGE + while ( !theWire.front().IsSame( edgeVec[ cornerInd[0] ])) + theWire.splice( theWire.begin(), theWire, --theWire.end() ); + + } // if ( haveVariants ) + + return nbCorners; +} + +//================================================================================ +/*! + * \brief Constructor of a side of quad + */ +//================================================================================ + +FaceQuadStruct::Side::Side(StdMeshers_FaceSidePtr theGrid) + : grid(theGrid), nbNodeOut(0), from(0), to(theGrid ? theGrid->NbPoints() : 0 ), di(1) +{ +} + +//============================================================================= +/*! + * \brief Constructor of a quad + */ +//============================================================================= + +FaceQuadStruct::FaceQuadStruct(const TopoDS_Face& F, const std::string& theName) + : face( F ), name( theName ) +{ + side.reserve(4); +} + +//================================================================================ +/*! + * \brief Fills myForcedPnts + */ +//================================================================================ + +bool StdMeshers_Quadrangle_2D::getEnforcedUV() +{ + myForcedPnts.clear(); + if ( !myParams ) return true; // missing hypothesis + + std::vector< TopoDS_Shape > shapes; + std::vector< gp_Pnt > points; + myParams->GetEnforcedNodes( shapes, points ); + + TopTools_IndexedMapOfShape vMap; + for ( size_t i = 0; i < shapes.size(); ++i ) + if ( !shapes[i].IsNull() ) + TopExp::MapShapes( shapes[i], TopAbs_VERTEX, vMap ); + + size_t nbPoints = points.size(); + for ( int i = 1; i <= vMap.Extent(); ++i ) + points.push_back( BRep_Tool::Pnt( TopoDS::Vertex( vMap( i )))); + + // find out if all points must be in the FACE, which is so if + // myParams is a local hypothesis on the FACE being meshed + bool isStrictCheck = false; + { + SMESH_HypoFilter paramFilter( SMESH_HypoFilter::Is( myParams )); + TopoDS_Shape assignedTo; + if ( myHelper->GetMesh()->GetHypothesis( myHelper->GetSubShape(), + paramFilter, + /*ancestors=*/true, + &assignedTo )) + isStrictCheck = ( assignedTo.IsSame( myHelper->GetSubShape() )); + } + + multimap< double, ForcedPoint > sortedFP; // sort points by distance from EDGEs + + Standard_Real u1,u2,v1,v2; + const TopoDS_Face& face = TopoDS::Face( myHelper->GetSubShape() ); + const double tol = BRep_Tool::Tolerance( face ); + Handle(ShapeAnalysis_Surface) project = myHelper->GetSurface( face ); + project->Bounds( u1,u2,v1,v2 ); + Bnd_Box bbox; + BRepBndLib::Add( face, bbox ); + double farTol = 0.01 * sqrt( bbox.SquareExtent() ); + + // get internal VERTEXes of the FACE to use them instead of equal points + typedef map< pair< double, double >, TopoDS_Vertex > TUV2VMap; + TUV2VMap uv2intV; + for ( TopExp_Explorer vExp( face, TopAbs_VERTEX, TopAbs_EDGE ); vExp.More(); vExp.Next() ) + { + TopoDS_Vertex v = TopoDS::Vertex( vExp.Current() ); + gp_Pnt2d uv = project->ValueOfUV( BRep_Tool::Pnt( v ), tol ); + uv2intV.insert( make_pair( make_pair( uv.X(), uv.Y() ), v )); + } + + for ( size_t iP = 0; iP < points.size(); ++iP ) + { + gp_Pnt2d uv = project->ValueOfUV( points[ iP ], tol ); + if ( project->Gap() > farTol ) + { + if ( isStrictCheck && iP < nbPoints ) + return error + (COMPERR_BAD_PARMETERS, TComm("An enforced point is too far from the face, dist = ") + << points[ iP ].Distance( project->Value( uv )) << " - (" + << points[ iP ].X() << ", "<< points[ iP ].Y() << ", "<< points[ iP ].Z() << " )"); + continue; + } + BRepClass_FaceClassifier clsf ( face, uv, tol ); + switch ( clsf.State() ) { + case TopAbs_IN: + { + double edgeDist = ( Min( Abs( uv.X() - u1 ), Abs( uv.X() - u2 )) + + Min( Abs( uv.Y() - v1 ), Abs( uv.Y() - v2 ))); + ForcedPoint fp; + fp.uv = uv.XY(); + fp.xyz = points[ iP ].XYZ(); + if ( iP >= nbPoints ) + fp.vertex = TopoDS::Vertex( vMap( iP - nbPoints + 1 )); + + TUV2VMap::iterator uv2v = uv2intV.lower_bound( make_pair( uv.X()-tol, uv.Y()-tol )); + for ( ; uv2v != uv2intV.end() && uv2v->first.first <= uv.X()+tol; ++uv2v ) + if ( uv.SquareDistance( gp_Pnt2d( uv2v->first.first, uv2v->first.second )) < tol*tol ) + { + fp.vertex = uv2v->second; + break; + } + + fp.node = 0; + if ( myHelper->IsSubShape( fp.vertex, myHelper->GetMesh() )) + { + SMESH_subMesh* sm = myHelper->GetMesh()->GetSubMesh( fp.vertex ); + sm->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + fp.node = SMESH_Algo::VertexNode( fp.vertex, myHelper->GetMeshDS() ); + } + else + { + fp.node = myHelper->AddNode( fp.xyz.X(), fp.xyz.Y(), fp.xyz.Z(), + 0, fp.uv.X(), fp.uv.Y() ); + } + sortedFP.insert( make_pair( edgeDist, fp )); + break; + } + case TopAbs_OUT: + { + if ( isStrictCheck && iP < nbPoints ) + return error + (COMPERR_BAD_PARMETERS, TComm("An enforced point is out of the face boundary - ") + << points[ iP ].X() << ", "<< points[ iP ].Y() << ", "<< points[ iP ].Z() << " )"); + break; + } + case TopAbs_ON: + { + if ( isStrictCheck && iP < nbPoints ) + return error + (COMPERR_BAD_PARMETERS, TComm("An enforced point is on the face boundary - ") + << points[ iP ].X() << ", "<< points[ iP ].Y() << ", "<< points[ iP ].Z() << " )"); + break; + } + default: + { + if ( isStrictCheck && iP < nbPoints ) + return error + (TComm("Classification of an enforced point ralative to the face boundary failed - ") + << points[ iP ].X() << ", "<< points[ iP ].Y() << ", "<< points[ iP ].Z() << " )"); + } + } + } + + multimap< double, ForcedPoint >::iterator d2uv = sortedFP.begin(); + for ( ; d2uv != sortedFP.end(); ++d2uv ) + myForcedPnts.push_back( (*d2uv).second ); + + return true; +} + +//================================================================================ +/*! + * \brief Splits quads by adding points of enforced nodes and create nodes on + * the sides shared by quads + */ +//================================================================================ + +bool StdMeshers_Quadrangle_2D::addEnforcedNodes() +{ + // if ( myForcedPnts.empty() ) + // return true; + + // make a map of quads sharing a side + map< StdMeshers_FaceSidePtr, vector< FaceQuadStruct::Ptr > > quadsBySide; + list< FaceQuadStruct::Ptr >::iterator quadIt = myQuadList.begin(); + for ( ; quadIt != myQuadList.end(); ++quadIt ) + for ( size_t iSide = 0; iSide < (*quadIt)->side.size(); ++iSide ) + { + if ( !setNormalizedGrid( *quadIt )) + return false; + quadsBySide[ (*quadIt)->side[iSide] ].push_back( *quadIt ); + } + + SMESH_Mesh* mesh = myHelper->GetMesh(); + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + const TopoDS_Face& face = TopoDS::Face( myHelper->GetSubShape() ); + Handle(Geom_Surface) surf = BRep_Tool::Surface( face ); + + for ( size_t iFP = 0; iFP < myForcedPnts.size(); ++iFP ) + { + bool isNodeEnforced = false; + + // look for a quad enclosing an enforced point + for ( quadIt = myQuadList.begin(); quadIt != myQuadList.end(); ++quadIt ) + { + FaceQuadStruct::Ptr quad = *quadIt; + if ( !setNormalizedGrid( *quadIt )) + return false; + int i,j; + if ( !quad->findCell( myForcedPnts[ iFP ], i, j )) + continue; + + // a grid cell is found, select a node of the cell to move + // to the enforced point to and to split the quad at + multimap< double, pair< int, int > > ijByDist; + for ( int di = 0; di < 2; ++di ) + for ( int dj = 0; dj < 2; ++dj ) + { + double dist2 = ( myForcedPnts[ iFP ].uv - quad->UVPt( i+di,j+dj ).UV() ).SquareModulus(); + ijByDist.insert( make_pair( dist2, make_pair( di,dj ))); + } + // try all nodes starting from the closest one + set< FaceQuadStruct::Ptr > changedQuads; + multimap< double, pair< int, int > >::iterator d2ij = ijByDist.begin(); + for ( ; !isNodeEnforced && d2ij != ijByDist.end(); ++d2ij ) + { + int di = d2ij->second.first; + int dj = d2ij->second.second; + + // check if a node is at a side + int iSide = -1; + if ( dj== 0 && j == 0 ) + iSide = QUAD_BOTTOM_SIDE; + else if ( dj == 1 && j+2 == quad->jSize ) + iSide = QUAD_TOP_SIDE; + else if ( di == 0 && i == 0 ) + iSide = QUAD_LEFT_SIDE; + else if ( di == 1 && i+2 == quad->iSize ) + iSide = QUAD_RIGHT_SIDE; + + if ( iSide > -1 ) // ----- node is at a side + { + FaceQuadStruct::Side& side = quad->side[ iSide ]; + // check if this node can be moved + if ( quadsBySide[ side ].size() < 2 ) + continue; // its a face boundary -> can't move the node + + int quadNodeIndex = ( iSide % 2 ) ? j : i; + int sideNodeIndex = side.ToSideIndex( quadNodeIndex ); + if ( side.IsForced( sideNodeIndex )) + { + // the node is already moved to another enforced point + isNodeEnforced = quad->isEqual( myForcedPnts[ iFP ], i, j ); + continue; + } + // make a node of a side forced + vector& points = (vector&) side.GetUVPtStruct(); + points[ sideNodeIndex ].u = myForcedPnts[ iFP ].U(); + points[ sideNodeIndex ].v = myForcedPnts[ iFP ].V(); + points[ sideNodeIndex ].node = myForcedPnts[ iFP ].node; + + updateSideUV( side, sideNodeIndex, quadsBySide ); + + // update adjacent sides + set< StdMeshers_FaceSidePtr > updatedSides; + updatedSides.insert( side ); + for ( size_t i = 0; i < side.contacts.size(); ++i ) + if ( side.contacts[i].point == sideNodeIndex ) + { + const vector< FaceQuadStruct::Ptr >& adjQuads = + quadsBySide[ *side.contacts[i].other_side ]; + if ( adjQuads.size() > 1 && + updatedSides.insert( * side.contacts[i].other_side ).second ) + { + updateSideUV( *side.contacts[i].other_side, + side.contacts[i].other_point, + quadsBySide ); + } + changedQuads.insert( adjQuads.begin(), adjQuads.end() ); + } + const vector< FaceQuadStruct::Ptr >& adjQuads = quadsBySide[ side ]; + changedQuads.insert( adjQuads.begin(), adjQuads.end() ); + + isNodeEnforced = true; + } + else // ------------------ node is inside the quad + { + i += di; + j += dj; + // make a new side passing through IJ node and split the quad + int indForced, iNewSide; + if ( quad->iSize < quad->jSize ) // split vertically + { + quad->updateUV( myForcedPnts[ iFP ].uv, i, j, /*isVert=*/true ); + indForced = j; + iNewSide = splitQuad( quad, i, 0 ); + } + else + { + quad->updateUV( myForcedPnts[ iFP ].uv, i, j, /*isVert=*/false ); + indForced = i; + iNewSide = splitQuad( quad, 0, j ); + } + FaceQuadStruct::Ptr newQuad = myQuadList.back(); + FaceQuadStruct::Side& newSide = newQuad->side[ iNewSide ]; + + vector& points = (vector&) newSide.GetUVPtStruct(); + points[ indForced ].node = myForcedPnts[ iFP ].node; + + newSide.forced_nodes.insert( indForced ); + quad->side[( iNewSide+2 ) % 4 ].forced_nodes.insert( indForced ); + + quadsBySide[ newSide ].push_back( quad ); + quadsBySide[ newQuad->side[0] ].push_back( newQuad ); + quadsBySide[ newQuad->side[1] ].push_back( newQuad ); + quadsBySide[ newQuad->side[2] ].push_back( newQuad ); + quadsBySide[ newQuad->side[3] ].push_back( newQuad ); + + isNodeEnforced = true; + + } // end of "node is inside the quad" + + } // loop on nodes of the cell + + // remove out-of-date uv grid of changedQuads + set< FaceQuadStruct::Ptr >::iterator qIt = changedQuads.begin(); + for ( ; qIt != changedQuads.end(); ++qIt ) + (*qIt)->uv_grid.clear(); + + if ( isNodeEnforced ) + break; + + } // loop on quads + + if ( !isNodeEnforced ) + { + if ( !myForcedPnts[ iFP ].vertex.IsNull() ) + return error(TComm("Unable to move any node to vertex #") + <GetMeshDS()->ShapeToIndex( myForcedPnts[ iFP ].vertex )); + else + return error(TComm("Unable to move any node to point ( ") + << myForcedPnts[iFP].xyz.X() << ", " + << myForcedPnts[iFP].xyz.Y() << ", " + << myForcedPnts[iFP].xyz.Z() << " )"); + } + myNeedSmooth = true; + + } // loop on enforced points + + // Compute nodes on all sides, where not yet present + + for ( quadIt = myQuadList.begin(); quadIt != myQuadList.end(); ++quadIt ) + { + FaceQuadStruct::Ptr quad = *quadIt; + for ( int iSide = 0; iSide < 4; ++iSide ) + { + FaceQuadStruct::Side & side = quad->side[ iSide ]; + if ( side.nbNodeOut > 0 ) + continue; // emulated side + vector< FaceQuadStruct::Ptr >& quadVec = quadsBySide[ side ]; + if ( quadVec.size() <= 1 ) + continue; // outer side + + const vector& points = side.grid->GetUVPtStruct(); + for ( size_t iC = 0; iC < side.contacts.size(); ++iC ) + { + if ( side.contacts[iC].point < side.from || + side.contacts[iC].point >= side.to ) + continue; + if ( side.contacts[iC].other_point < side.contacts[iC].other_side->from || + side.contacts[iC].other_point >= side.contacts[iC].other_side->to ) + continue; + const vector& oGrid = side.contacts[iC].other_side->grid->GetUVPtStruct(); + const UVPtStruct& uvPt = points[ side.contacts[iC].point ]; + if ( side.contacts[iC].other_point >= oGrid .size() || + side.contacts[iC].point >= points.size() ) + throw SALOME_Exception( "StdMeshers_Quadrangle_2D::addEnforcedNodes(): wrong contact" ); + if ( oGrid[ side.contacts[iC].other_point ].node ) + (( UVPtStruct& ) uvPt).node = oGrid[ side.contacts[iC].other_point ].node; + } + + bool missedNodesOnSide = false; + for ( size_t iP = 0; iP < points.size(); ++iP ) + if ( !points[ iP ].node ) + { + UVPtStruct& uvPnt = ( UVPtStruct& ) points[ iP ]; + gp_Pnt P = surf->Value( uvPnt.u, uvPnt.v ); + uvPnt.node = myHelper->AddNode(P.X(), P.Y(), P.Z(), 0, uvPnt.u, uvPnt.v ); + missedNodesOnSide = true; + } + if ( missedNodesOnSide ) + { + // clear uv_grid where nodes are missing + for ( size_t iQ = 0; iQ < quadVec.size(); ++iQ ) + quadVec[ iQ ]->uv_grid.clear(); + } + } + } + + return true; +} + +//================================================================================ +/*! + * \brief Splits a quad at I or J. Returns an index of a new side in the new quad + */ +//================================================================================ + +int StdMeshers_Quadrangle_2D::splitQuad(FaceQuadStruct::Ptr quad, int I, int J) +{ + FaceQuadStruct* newQuad = new FaceQuadStruct( quad->face ); + myQuadList.push_back( FaceQuadStruct::Ptr( newQuad )); + + vector points; + if ( I > 0 && I <= quad->iSize-2 ) + { + points.reserve( quad->jSize ); + for ( int jP = 0; jP < quad->jSize; ++jP ) + points.push_back( quad->UVPt( I, jP )); + + newQuad->side.resize( 4 ); + newQuad->side[ QUAD_BOTTOM_SIDE ] = quad->side[ QUAD_BOTTOM_SIDE ]; + newQuad->side[ QUAD_RIGHT_SIDE ] = quad->side[ QUAD_RIGHT_SIDE ]; + newQuad->side[ QUAD_TOP_SIDE ] = quad->side[ QUAD_TOP_SIDE ]; + newQuad->side[ QUAD_LEFT_SIDE ] = StdMeshers_FaceSide::New( points, quad->face ); + + FaceQuadStruct::Side& newSide = newQuad->side[ QUAD_LEFT_SIDE ]; + FaceQuadStruct::Side& newSide2 = quad->side [ QUAD_RIGHT_SIDE ]; + + quad->side[ QUAD_RIGHT_SIDE ] = newSide; + + int iBot = quad->side[ QUAD_BOTTOM_SIDE ].ToSideIndex( I ); + int iTop = quad->side[ QUAD_TOP_SIDE ].ToSideIndex( I ); + + newSide.AddContact ( 0, & quad->side[ QUAD_BOTTOM_SIDE ], iBot ); + newSide2.AddContact( 0, & quad->side[ QUAD_BOTTOM_SIDE ], iBot ); + newSide.AddContact ( quad->jSize - 1, & quad->side[ QUAD_TOP_SIDE ], iTop ); + newSide2.AddContact( quad->jSize - 1, & quad->side[ QUAD_TOP_SIDE ], iTop ); + // cout << "Contact: L " << &newSide << " "<< newSide.NbPoints() + // << " R " << &newSide2 << " "<< newSide2.NbPoints() + // << " B " << &quad->side[ QUAD_BOTTOM_SIDE ] << " "<< quad->side[ QUAD_BOTTOM_SIDE].NbPoints() + // << " T " << &quad->side[ QUAD_TOP_SIDE ] << " "<< quad->side[ QUAD_TOP_SIDE].NbPoints()<< endl; + + newQuad->side[ QUAD_BOTTOM_SIDE ].from = iBot; + newQuad->side[ QUAD_TOP_SIDE ].from = iTop; + newQuad->name = ( TComm("Right of I=") << I ); + + bool bRev = quad->side[ QUAD_BOTTOM_SIDE ].IsReversed(); + bool tRev = quad->side[ QUAD_TOP_SIDE ].IsReversed(); + quad->side[ QUAD_BOTTOM_SIDE ].to = iBot + ( bRev ? -1 : +1 ); + quad->side[ QUAD_TOP_SIDE ].to = iTop + ( tRev ? -1 : +1 ); + quad->uv_grid.clear(); + + return QUAD_LEFT_SIDE; + } + else if ( J > 0 && J <= quad->jSize-2 ) //// split horizontally, a new quad is below an old one + { + points.reserve( quad->iSize ); + for ( int iP = 0; iP < quad->iSize; ++iP ) + points.push_back( quad->UVPt( iP, J )); + + newQuad->side.resize( 4 ); + newQuad->side[ QUAD_BOTTOM_SIDE ] = quad->side[ QUAD_BOTTOM_SIDE ]; + newQuad->side[ QUAD_RIGHT_SIDE ] = quad->side[ QUAD_RIGHT_SIDE ]; + newQuad->side[ QUAD_TOP_SIDE ] = StdMeshers_FaceSide::New( points, quad->face ); + newQuad->side[ QUAD_LEFT_SIDE ] = quad->side[ QUAD_LEFT_SIDE ]; + + FaceQuadStruct::Side& newSide = newQuad->side[ QUAD_TOP_SIDE ]; + FaceQuadStruct::Side& newSide2 = quad->side [ QUAD_BOTTOM_SIDE ]; + + quad->side[ QUAD_BOTTOM_SIDE ] = newSide; + + int iLft = quad->side[ QUAD_LEFT_SIDE ].ToSideIndex( J ); + int iRgt = quad->side[ QUAD_RIGHT_SIDE ].ToSideIndex( J ); + + newSide.AddContact ( 0, & quad->side[ QUAD_LEFT_SIDE ], iLft ); + newSide2.AddContact( 0, & quad->side[ QUAD_LEFT_SIDE ], iLft ); + newSide.AddContact ( quad->iSize - 1, & quad->side[ QUAD_RIGHT_SIDE ], iRgt ); + newSide2.AddContact( quad->iSize - 1, & quad->side[ QUAD_RIGHT_SIDE ], iRgt ); + // cout << "Contact: T " << &newSide << " "<< newSide.NbPoints() + // << " B " << &newSide2 << " "<< newSide2.NbPoints() + // << " L " << &quad->side[ QUAD_LEFT_SIDE ] << " "<< quad->side[ QUAD_LEFT_SIDE].NbPoints() + // << " R " << &quad->side[ QUAD_RIGHT_SIDE ] << " "<< quad->side[ QUAD_RIGHT_SIDE].NbPoints()<< endl; + + bool rRev = newQuad->side[ QUAD_RIGHT_SIDE ].IsReversed(); + bool lRev = newQuad->side[ QUAD_LEFT_SIDE ].IsReversed(); + newQuad->side[ QUAD_RIGHT_SIDE ].to = iRgt + ( rRev ? -1 : +1 ); + newQuad->side[ QUAD_LEFT_SIDE ].to = iLft + ( lRev ? -1 : +1 ); + newQuad->name = ( TComm("Below J=") << J ); + + quad->side[ QUAD_RIGHT_SIDE ].from = iRgt; + quad->side[ QUAD_LEFT_SIDE ].from = iLft; + quad->uv_grid.clear(); + + return QUAD_TOP_SIDE; + } + + myQuadList.pop_back(); + return -1; +} + +//================================================================================ +/*! + * \brief Updates UV of a side after moving its node + */ +//================================================================================ + +void StdMeshers_Quadrangle_2D::updateSideUV( FaceQuadStruct::Side& side, + int iForced, + const TQuadsBySide& quadsBySide, + int * iNext) +{ + if ( !iNext ) + { + side.forced_nodes.insert( iForced ); + + // update parts of the side before and after iForced + + set::iterator iIt = side.forced_nodes.upper_bound( iForced ); + int iEnd = Min( side.NbPoints()-1, ( iIt == side.forced_nodes.end() ) ? int(1e7) : *iIt ); + if ( iForced + 1 < iEnd ) + updateSideUV( side, iForced, quadsBySide, &iEnd ); + + iIt = side.forced_nodes.lower_bound( iForced ); + int iBeg = Max( 0, ( iIt == side.forced_nodes.begin() ) ? 0 : *--iIt ); + if ( iForced - 1 > iBeg ) + updateSideUV( side, iForced, quadsBySide, &iBeg ); + + return; + } + + const int iFrom = Min ( iForced, *iNext ); + const int iTo = Max ( iForced, *iNext ) + 1; + const int sideSize = iTo - iFrom; + + vector points[4]; // side points of a temporary quad + + // from the quads get grid points adjacent to the side + // to make two sides of a temporary quad + vector< FaceQuadStruct::Ptr > quads = quadsBySide.find( side )->second; // copy! + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + points[ is2nd ].reserve( sideSize ); + int nbLoops = 0; + while ( points[is2nd].size() < sideSize ) + { + int iCur = iFrom + points[is2nd].size() - int( !points[is2nd].empty() ); + + // look for a quad adjacent to iCur-th point of the side + for ( size_t iQ = 0; iQ < quads.size(); ++iQ ) + { + FaceQuadStruct::Ptr q = quads[ iQ ]; + if ( !q ) + continue; + size_t iS; + for ( iS = 0; iS < q->side.size(); ++iS ) + if ( side.grid == q->side[ iS ].grid ) + break; + bool isOut; + if ( !q->side[ iS ].IsReversed() ) + isOut = ( q->side[ iS ].from > iCur || q->side[ iS ].to-1 <= iCur ); + else + isOut = ( q->side[ iS ].to >= iCur || q->side[ iS ].from <= iCur ); + if ( isOut ) + continue; + if ( !setNormalizedGrid( q )) + continue; + + // found - copy points + int i,j,di,dj,nb; + if ( iS % 2 ) // right or left + { + i = ( iS == QUAD_LEFT_SIDE ) ? 1 : q->iSize-2; + j = q->side[ iS ].ToQuadIndex( iCur ); + di = 0; + dj = ( q->side[ iS ].IsReversed() ) ? -1 : +1; + nb = ( q->side[ iS ].IsReversed() ) ? j+1 : q->jSize-j; + } + else // bottom or top + { + i = q->side[ iS ].ToQuadIndex( iCur ); + j = ( iS == QUAD_BOTTOM_SIDE ) ? 1 : q->jSize-2; + di = ( q->side[ iS ].IsReversed() ) ? -1 : +1; + dj = 0; + nb = ( q->side[ iS ].IsReversed() ) ? i+1 : q->iSize-i; + } + if ( !points[is2nd].empty() ) + { + gp_UV lastUV = points[is2nd].back().UV(); + gp_UV quadUV = q->UVPt( i, j ).UV(); + if ( ( lastUV - quadUV ).SquareModulus() > 1e-10 ) + continue; // quad is on the other side of the side + i += di; j += dj; --nb; + } + for ( ; nb > 0 ; --nb ) + { + points[ is2nd ].push_back( q->UVPt( i, j )); + if ( points[is2nd].size() >= sideSize ) + break; + i += di; j += dj; + } + quads[ iQ ].reset(); // not to use this quad anymore + + if ( points[is2nd].size() >= sideSize ) + break; + } // loop on quads + + if ( nbLoops++ > quads.size() ) + throw SALOME_Exception( "StdMeshers_Quadrangle_2D::updateSideUV() bug: infinite loop" ); + + } // while ( points[is2nd].size() < sideSize ) + } // two loops to fill points[0] and points[1] + + // points for other pair of opposite sides of the temporary quad + + enum { L,R,B,T }; // side index of points[] + + points[B].push_back( points[L].front() ); + points[B].push_back( side.GetUVPtStruct()[ iFrom ]); + points[B].push_back( points[R].front() ); + + points[T].push_back( points[L].back() ); + points[T].push_back( side.GetUVPtStruct()[ iTo-1 ]); + points[T].push_back( points[R].back() ); + + // make the temporary quad + FaceQuadStruct::Ptr tmpQuad + ( new FaceQuadStruct( TopoDS::Face( myHelper->GetSubShape() ), "tmpQuad")); + tmpQuad->side.push_back( StdMeshers_FaceSide::New( points[B] )); // bottom + tmpQuad->side.push_back( StdMeshers_FaceSide::New( points[R] )); // right + tmpQuad->side.push_back( StdMeshers_FaceSide::New( points[T] )); + tmpQuad->side.push_back( StdMeshers_FaceSide::New( points[L] )); + + // compute new UV of the side + setNormalizedGrid( tmpQuad ); + gp_UV uv = tmpQuad->UVPt(1,0).UV(); + tmpQuad->updateUV( uv, 1,0, /*isVertical=*/true ); + + // update UV of the side + vector& sidePoints = (vector&) side.GetUVPtStruct(); + for ( int i = iFrom; i < iTo; ++i ) + { + const uvPtStruct& uvPt = tmpQuad->UVPt( 1, i-iFrom ); + sidePoints[ i ].u = uvPt.u; + sidePoints[ i ].v = uvPt.v; + } +} + +//================================================================================ +/*! + * \brief Finds indices of a grid quad enclosing the given enforced UV + */ +//================================================================================ + +bool FaceQuadStruct::findCell( const gp_XY& UV, int & I, int & J ) +{ + // setNormalizedGrid() must be called before! + if ( uv_box.IsOut( UV )) + return false; + + // find an approximate position + double x = 0.5, y = 0.5; + gp_XY t0 = UVPt( iSize - 1, 0 ).UV(); + gp_XY t1 = UVPt( 0, jSize - 1 ).UV(); + gp_XY t2 = UVPt( 0, 0 ).UV(); + SMESH_MeshAlgos::GetBarycentricCoords( UV, t0, t1, t2, x, y ); + x = Min( 1., Max( 0., x )); + y = Min( 1., Max( 0., y )); + + // precise the position + normPa2IJ( x,y, I,J ); + if ( !isNear( UV, I,J )) + { + // look for the most close IJ by traversing uv_grid in the middle + double dist2, minDist2 = ( UV - UVPt( I,J ).UV() ).SquareModulus(); + for ( int isU = 0; isU < 2; ++isU ) + { + int ind1 = isU ? 0 : iSize / 2; + int ind2 = isU ? jSize / 2 : 0; + int di1 = isU ? Max( 2, iSize / 20 ) : 0; + int di2 = isU ? 0 : Max( 2, jSize / 20 ); + int i,nb = isU ? iSize / di1 : jSize / di2; + for ( i = 0; i < nb; ++i, ind1 += di1, ind2 += di2 ) + if (( dist2 = ( UV - UVPt( ind1,ind2 ).UV() ).SquareModulus() ) < minDist2 ) + { + I = ind1; + J = ind2; + if ( isNear( UV, I,J )) + return true; + minDist2 = ( UV - UVPt( I,J ).UV() ).SquareModulus(); + } + } + if ( !isNear( UV, I,J, Max( iSize, jSize ) /2 )) + return false; + } + return true; +} + +//================================================================================ +/*! + * \brief Find indices (i,j) of a point in uv_grid by normalized parameters (x,y) + */ +//================================================================================ + +void FaceQuadStruct::normPa2IJ(double X, double Y, int & I, int & J ) +{ + + I = Min( int ( iSize * X ), iSize - 2 ); + J = Min( int ( jSize * Y ), jSize - 2 ); + + int oldI, oldJ; + do + { + oldI = I, oldJ = J; + while ( X <= UVPt( I,J ).x && I != 0 ) + --I; + while ( X > UVPt( I+1,J ).x && I+2 < iSize ) + ++I; + while ( Y <= UVPt( I,J ).y && J != 0 ) + --J; + while ( Y > UVPt( I,J+1 ).y && J+2 < jSize ) + ++J; + } while ( oldI != I || oldJ != J ); +} + +//================================================================================ +/*! + * \brief Looks for UV in quads around a given (I,J) and precise (I,J) + */ +//================================================================================ + +bool FaceQuadStruct::isNear( const gp_XY& UV, int & I, int & J, int nbLoops ) +{ + if ( I+1 >= iSize ) I = iSize - 2; + if ( J+1 >= jSize ) J = jSize - 2; + + double bcI, bcJ; + gp_XY uvI, uvJ, uv0, uv1; + for ( int iLoop = 0; iLoop < nbLoops; ++iLoop ) + { + int oldI = I, oldJ = J; + + uvI = UVPt( I+1, J ).UV(); + uvJ = UVPt( I, J+1 ).UV(); + uv0 = UVPt( I, J ).UV(); + SMESH_MeshAlgos::GetBarycentricCoords( UV, uvI, uvJ, uv0, bcI, bcJ ); + if ( bcI >= 0. && bcJ >= 0. && bcI + bcJ <= 1.) + return true; + + if ( I > 0 && bcI < 0. ) --I; + if ( I+2 < iSize && bcI > 1. ) ++I; + if ( J > 0 && bcJ < 0. ) --J; + if ( J+2 < jSize && bcJ > 1. ) ++J; + + uv1 = UVPt( I+1,J+1).UV(); + if ( I != oldI || J != oldJ ) + { + uvI = UVPt( I+1, J ).UV(); + uvJ = UVPt( I, J+1 ).UV(); + } + SMESH_MeshAlgos::GetBarycentricCoords( UV, uvI, uvJ, uv1, bcI, bcJ ); + if ( bcI >= 0. && bcJ >= 0. && bcI + bcJ <= 1.) + return true; + + if ( I > 0 && bcI > 1. ) --I; + if ( I+2 < iSize && bcI < 0. ) ++I; + if ( J > 0 && bcJ > 1. ) --J; + if ( J+2 < jSize && bcJ < 0. ) ++J; + + if ( I == oldI && J == oldJ ) + return false; + + if ( iLoop+1 == nbLoops ) + { + uvI = UVPt( I+1, J ).UV(); + uvJ = UVPt( I, J+1 ).UV(); + uv0 = UVPt( I, J ).UV(); + SMESH_MeshAlgos::GetBarycentricCoords( UV, uvI, uvJ, uv0, bcI, bcJ ); + if ( bcI >= 0. && bcJ >= 0. && bcI + bcJ <= 1.) + return true; + + uv1 = UVPt( I+1,J+1).UV(); + SMESH_MeshAlgos::GetBarycentricCoords( UV, uvI, uvJ, uv1, bcI, bcJ ); + if ( bcI >= 0. && bcJ >= 0. && bcI + bcJ <= 1.) + return true; + } + } + return false; +} + +//================================================================================ +/*! + * \brief Checks if a given UV is equal to a given grid point + */ +//================================================================================ + +bool FaceQuadStruct::isEqual( const gp_XY& UV, int I, int J ) +{ + TopLoc_Location loc; + Handle(Geom_Surface) surf = BRep_Tool::Surface( face, loc ); + gp_Pnt p1 = surf->Value( UV.X(), UV.Y() ); + gp_Pnt p2 = surf->Value( UVPt( I,J ).u, UVPt( I,J ).v ); + + double dist2 = 1e100; + for ( int di = -1; di < 2; di += 2 ) + { + int i = I + di; + if ( i < 0 || i+1 >= iSize ) continue; + for ( int dj = -1; dj < 2; dj += 2 ) + { + int j = J + dj; + if ( j < 0 || j+1 >= jSize ) continue; + + dist2 = Min( dist2, + p2.SquareDistance( surf->Value( UVPt( i,j ).u, UVPt( i,j ).v ))); + } + } + double tol2 = dist2 / 1000.; + return p1.SquareDistance( p2 ) < tol2; +} + +//================================================================================ +/*! + * \brief Recompute UV of grid points around a moved point in one direction + */ +//================================================================================ + +void FaceQuadStruct::updateUV( const gp_XY& UV, int I, int J, bool isVertical ) +{ + UVPt( I, J ).u = UV.X(); + UVPt( I, J ).v = UV.Y(); + + if ( isVertical ) + { + // above J + if ( J+1 < jSize-1 ) + { + gp_UV a0 = UVPt( 0, J ).UV(); + gp_UV a1 = UVPt( iSize-1, J ).UV(); + gp_UV a2 = UVPt( iSize-1, jSize-1 ).UV(); + gp_UV a3 = UVPt( 0, jSize-1 ).UV(); + + gp_UV p0 = UVPt( I, J ).UV(); + gp_UV p2 = UVPt( I, jSize-1 ).UV(); + const double y0 = UVPt( I, J ).y, dy = 1. - y0; + for (int j = J+1; j < jSize-1; j++) + { + gp_UV p1 = UVPt( iSize-1, j ).UV(); + gp_UV p3 = UVPt( 0, j ).UV(); + + UVPtStruct& uvPt = UVPt( I, j ); + gp_UV uv = calcUV( uvPt.x, ( uvPt.y - y0 ) / dy, a0,a1,a2,a3, p0,p1,p2,p3); + uvPt.u = uv.X(); + uvPt.v = uv.Y(); + } + } + // under J + if ( J-1 > 0 ) + { + gp_UV a0 = UVPt( 0, 0 ).UV(); + gp_UV a1 = UVPt( iSize-1, 0 ).UV(); + gp_UV a2 = UVPt( iSize-1, J ).UV(); + gp_UV a3 = UVPt( 0, J ).UV(); + + gp_UV p0 = UVPt( I, 0 ).UV(); + gp_UV p2 = UVPt( I, J ).UV(); + const double y0 = 0., dy = UVPt( I, J ).y - y0; + for (int j = 1; j < J; j++) + { + gp_UV p1 = UVPt( iSize-1, j ).UV(); + gp_UV p3 = UVPt( 0, j ).UV(); + + UVPtStruct& uvPt = UVPt( I, j ); + gp_UV uv = calcUV( uvPt.x, ( uvPt.y - y0 ) / dy, a0,a1,a2,a3, p0,p1,p2,p3); + uvPt.u = uv.X(); + uvPt.v = uv.Y(); + } + } + } + else // horizontally + { + // before I + if ( I-1 > 0 ) + { + gp_UV a0 = UVPt( 0, 0 ).UV(); + gp_UV a1 = UVPt( I, 0 ).UV(); + gp_UV a2 = UVPt( I, jSize-1 ).UV(); + gp_UV a3 = UVPt( 0, jSize-1 ).UV(); + + gp_UV p1 = UVPt( I, J ).UV(); + gp_UV p3 = UVPt( 0, J ).UV(); + const double x0 = 0., dx = UVPt( I, J ).x - x0; + for (int i = 1; i < I; i++) + { + gp_UV p0 = UVPt( i, 0 ).UV(); + gp_UV p2 = UVPt( i, jSize-1 ).UV(); + + UVPtStruct& uvPt = UVPt( i, J ); + gp_UV uv = calcUV(( uvPt.x - x0 ) / dx , uvPt.y, a0,a1,a2,a3, p0,p1,p2,p3); + uvPt.u = uv.X(); + uvPt.v = uv.Y(); + } + } + // after I + if ( I+1 < iSize-1 ) + { + gp_UV a0 = UVPt( I, 0 ).UV(); + gp_UV a1 = UVPt( iSize-1, 0 ).UV(); + gp_UV a2 = UVPt( iSize-1, jSize-1 ).UV(); + gp_UV a3 = UVPt( I, jSize-1 ).UV(); + + gp_UV p1 = UVPt( iSize-1, J ).UV(); + gp_UV p3 = UVPt( I, J ).UV(); + const double x0 = UVPt( I, J ).x, dx = 1. - x0; + for (int i = I+1; i < iSize-1; i++) + { + gp_UV p0 = UVPt( i, 0 ).UV(); + gp_UV p2 = UVPt( i, jSize-1 ).UV(); + + UVPtStruct& uvPt = UVPt( i, J ); + gp_UV uv = calcUV(( uvPt.x - x0 ) / dx , uvPt.y, a0,a1,a2,a3, p0,p1,p2,p3); + uvPt.u = uv.X(); + uvPt.v = uv.Y(); + } + } + } +} + +//================================================================================ +/*! + * \brief Side copying + */ +//================================================================================ + +FaceQuadStruct::Side& FaceQuadStruct::Side::operator=(const Side& otherSide) +{ + grid = otherSide.grid; + from = otherSide.from; + to = otherSide.to; + di = otherSide.di; + forced_nodes = otherSide.forced_nodes; + contacts = otherSide.contacts; + nbNodeOut = otherSide.nbNodeOut; + + for ( size_t iC = 0; iC < contacts.size(); ++iC ) + { + FaceQuadStruct::Side* oSide = contacts[iC].other_side; + for ( size_t iOC = 0; iOC < oSide->contacts.size(); ++iOC ) + if ( oSide->contacts[iOC].other_side == & otherSide ) + { + // cout << "SHIFT old " << &otherSide << " " << otherSide.NbPoints() + // << " -> new " << this << " " << this->NbPoints() << endl; + oSide->contacts[iOC].other_side = this; + } + } + return *this; +} + +//================================================================================ +/*! + * \brief Converts node index of a quad to node index of this side + */ +//================================================================================ + +int FaceQuadStruct::Side::ToSideIndex( int quadNodeIndex ) const +{ + return from + di * quadNodeIndex; +} + +//================================================================================ +/*! + * \brief Converts node index of this side to node index of a quad + */ +//================================================================================ + +int FaceQuadStruct::Side::ToQuadIndex( int sideNodeIndex ) const +{ + return ( sideNodeIndex - from ) * di; +} + +//================================================================================ +/*! + * \brief Reverse the side + */ +//================================================================================ + +bool FaceQuadStruct::Side::Reverse(bool keepGrid) +{ + if ( grid ) + { + if ( keepGrid ) + { + from -= di; + to -= di; + std::swap( from, to ); + di *= -1; + } + else + { + grid->Reverse(); + } + } + return (bool)grid; +} + +//================================================================================ +/*! + * \brief Checks if a node is enforced + * \param [in] nodeIndex - an index of a node in a size + * \return bool - \c true if the node is forced + */ +//================================================================================ + +bool FaceQuadStruct::Side::IsForced( int nodeIndex ) const +{ + if ( nodeIndex < 0 || nodeIndex >= grid->NbPoints() ) + throw SALOME_Exception( " FaceQuadStruct::Side::IsForced(): wrong index" ); + + if ( forced_nodes.count( nodeIndex ) ) + return true; + + for ( size_t i = 0; i < this->contacts.size(); ++i ) + if ( contacts[ i ].point == nodeIndex && + contacts[ i ].other_side->forced_nodes.count( contacts[ i ].other_point )) + return true; + + return false; +} + +//================================================================================ +/*! + * \brief Sets up a contact between this and another side + */ +//================================================================================ + +void FaceQuadStruct::Side::AddContact( int ip, Side* side, int iop ) +{ + if ( ip >= GetUVPtStruct().size() || + iop >= side->GetUVPtStruct().size() ) + throw SALOME_Exception( "FaceQuadStruct::Side::AddContact(): wrong point" ); + if ( ip < from || ip >= to ) + return; + { + contacts.resize( contacts.size() + 1 ); + Contact& c = contacts.back(); + c.point = ip; + c.other_side = side; + c.other_point = iop; + } + { + side->contacts.resize( side->contacts.size() + 1 ); + Contact& c = side->contacts.back(); + c.point = iop; + c.other_side = this; + c.other_point = ip; + } +} + +//================================================================================ +/*! + * \brief Returns a normalized parameter of a point indexed within a quadrangle + */ +//================================================================================ + +double FaceQuadStruct::Side::Param( int i ) const +{ + const vector& points = GetUVPtStruct(); + return (( points[ from + i * di ].normParam - points[ from ].normParam ) / + ( points[ to - 1 * di ].normParam - points[ from ].normParam )); +} + +//================================================================================ +/*! + * \brief Returns UV by a parameter normalized within a quadrangle + */ +//================================================================================ + +gp_XY FaceQuadStruct::Side::Value2d( double x ) const +{ + const vector& points = GetUVPtStruct(); + double u = ( points[ from ].normParam + + x * ( points[ to-di ].normParam - points[ from ].normParam )); + return grid->Value2d( u ).XY(); +} + +//================================================================================ +/*! + * \brief Returns side length + */ +//================================================================================ + +double FaceQuadStruct::Side::Length(int theFrom, int theTo) const +{ + if ( IsReversed() != ( theTo < theFrom )) + std::swap( theTo, theFrom ); + + const vector& points = GetUVPtStruct(); + double r; + if ( theFrom == theTo && theTo == -1 ) + r = Abs( First().normParam - + Last ().normParam ); + else if ( IsReversed() ) + r = Abs( points[ Max( to, theTo+1 ) ].normParam - + points[ Min( from, theFrom ) ].normParam ); + else + r = Abs( points[ Min( to, theTo-1 ) ].normParam - + points[ Max( from, theFrom ) ].normParam ); + return r * grid->Length(); } diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadraticMesh.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadraticMesh.cpp index 4518f55f29db..5d8d7632f32e 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadraticMesh.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_QuadraticMesh.cpp @@ -1,28 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH StdMeshers_QuadraticMesh : implementaion of SMESH idl descriptions // File : StdMeshers_QuadraticMesh.cxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_QuadraticMesh.cxx,v 1.4.2.1 2008/11/27 13:03:49 abd Exp $ // #include "StdMeshers_QuadraticMesh.hxx" #include "utilities.h" @@ -121,3 +121,4 @@ bool StdMeshers_QuadraticMesh::SetParametersByDefaults(const TDefaults& /*dflts { return false; } + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialPrism_3D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialPrism_3D.cpp index fb6be0b1eda3..3334af950e7b 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialPrism_3D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialPrism_3D.cpp @@ -1,32 +1,36 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_RadialPrism_3D.cxx // Module : SMESH // Created : Fri Oct 20 11:37:07 2006 // Author : Edward AGAPOV (eap) // + #include "StdMeshers_RadialPrism_3D.hxx" +#include + #include "StdMeshers_ProjectionUtils.hxx" #include "StdMeshers_NumberOfLayers.hxx" #include "StdMeshers_LayerDistribution.hxx" @@ -42,27 +46,25 @@ #include "utilities.h" -#include #include #include -#include -#if OCC_VERSION_HEX >= 0x060600 -#include -#endif +#include #include +#include +#include #include #include #include #include #include - +#include using namespace std; #define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; } #define gpXYZ(n) gp_XYZ(n->X(),n->Y(),n->Z()) -typedef StdMeshers_ProjectionUtils TAssocTool; +namespace ProjectionUtils = StdMeshers_ProjectionUtils; //======================================================================= //function : StdMeshers_RadialPrism_3D @@ -73,7 +75,7 @@ StdMeshers_RadialPrism_3D::StdMeshers_RadialPrism_3D(int hypId, int studyId, SME :SMESH_3D_Algo(hypId, studyId, gen) { _name = "RadialPrism_3D"; - _shapeType = (1 << TopAbs_SOLID); // 1 bit per shape type + _shapeType = (1 << TopAbs_SOLID); // 1 bit per shape type _compatibleHypothesis.push_back("LayerDistribution"); _compatibleHypothesis.push_back("NumberOfLayers"); @@ -101,8 +103,8 @@ bool StdMeshers_RadialPrism_3D::CheckHypothesis(SMESH_Mesh& { // check aShape that must have 2 shells /* PAL16229 - if ( TAssocTool::Count( aShape, TopAbs_SOLID, 0 ) != 1 || - TAssocTool::Count( aShape, TopAbs_SHELL, 0 ) != 2 ) + if ( ProjectionUtils::Count( aShape, TopAbs_SOLID, 0 ) != 1 || + ProjectionUtils::Count( aShape, TopAbs_SHELL, 0 ) != 2 ) { aStatus = HYP_BAD_GEOMETRY; return false; @@ -163,11 +165,7 @@ bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& a // get 2 shells TopoDS_Solid solid = TopoDS::Solid( aShape ); -#if OCC_VERSION_HEX >= 0x060600 TopoDS_Shell outerShell = BRepClass3d::OuterShell( solid ); -#else - TopoDS_Shell outerShell = BRepTools::OuterShell( solid ); -#endif TopoDS_Shape innerShell; int nbShells = 0; for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells ) @@ -177,15 +175,42 @@ bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& a return error(COMPERR_BAD_SHAPE, SMESH_Comment("Must be 2 shells but not ")< shape2ShapeMaps[1].Extent() ) ? 0 : 1; + } + ProjectionUtils::TShapeShapeMap& shape2ShapeMap = shape2ShapeMaps[iMap]; + // ------------------ // Make mesh // ------------------ @@ -195,20 +220,20 @@ bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& a for ( exp.Init( outerShell, TopAbs_FACE ); exp.More(); exp.Next() ) { - // Corresponding subshapes + // Corresponding sub-shapes TopoDS_Face outFace = TopoDS::Face( exp.Current() ); TopoDS_Face inFace; - if ( !shape2ShapeMap.IsBound( outFace )) { + if ( !shape2ShapeMap.IsBound( outFace, /*isOut=*/true )) { return error(SMESH_Comment("Corresponding inner face not found for face #" ) << meshDS->ShapeToIndex( outFace )); } else { - inFace = TopoDS::Face( shape2ShapeMap( outFace )); + inFace = TopoDS::Face( shape2ShapeMap( outFace, /*isOut=*/true )); } // Find matching nodes of in and out faces - TNodeNodeMap nodeIn2OutMap; - if ( ! TAssocTool::FindMatchingNodesOnFaces( inFace, &aMesh, outFace, &aMesh, - shape2ShapeMap, nodeIn2OutMap )) + ProjectionUtils::TNodeNodeMap nodeIn2OutMap; + if ( ! ProjectionUtils::FindMatchingNodesOnFaces( inFace, &aMesh, outFace, &aMesh, + shape2ShapeMap, nodeIn2OutMap )) return error(COMPERR_BAD_INPUT_MESH,SMESH_Comment("Mesh on faces #") << meshDS->ShapeToIndex( outFace ) << " and " << meshDS->ShapeToIndex( inFace ) << " seems different" ); @@ -311,11 +336,10 @@ class TNodeDistributor: public StdMeshers_Regular_1D static TNodeDistributor* GetDistributor(SMESH_Mesh& aMesh) { const int myID = -1000; - map < int, SMESH_1D_Algo * > & algoMap = aMesh.GetGen()->_map1D_Algo; - map < int, SMESH_1D_Algo * >::iterator id_algo = algoMap.find( myID ); - if ( id_algo == algoMap.end() ) - return new TNodeDistributor( myID, 0, aMesh.GetGen() ); - return static_cast< TNodeDistributor* >( id_algo->second ); + TNodeDistributor* myHyp = dynamic_cast( aMesh.GetHypothesis( myID )); + if ( !myHyp ) + myHyp = new TNodeDistributor( myID, 0, aMesh.GetGen() ); + return myHyp; } // ----------------------------------------------------------------------------- bool Compute( vector< double > & positions, @@ -394,3 +418,225 @@ bool StdMeshers_RadialPrism_3D::computeLayerPositions(const gp_Pnt& pIn, } RETURN_BAD_RESULT("Bad hypothesis"); } + + +//======================================================================= +//function : Evaluate +//purpose : +//======================================================================= + +bool StdMeshers_RadialPrism_3D::Evaluate(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + MapShapeNbElems& aResMap) +{ + // get 2 shells + TopoDS_Solid solid = TopoDS::Solid( aShape ); + TopoDS_Shell outerShell = BRepClass3d::OuterShell( solid ); + TopoDS_Shape innerShell; + int nbShells = 0; + for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells ) + if ( !outerShell.IsSame( It.Value() )) + innerShell = It.Value(); + if ( nbShells != 2 ) { + std::vector aResVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; iGetComputeError(); + smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); + return false; + } + + // Associate sub-shapes of the shells + ProjectionUtils::TShapeShapeMap shape2ShapeMap; + if ( !ProjectionUtils::FindSubShapeAssociation( outerShell, &aMesh, + innerShell, &aMesh, + shape2ShapeMap) ) { + std::vector aResVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; iGetComputeError(); + smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); + return false; + } + + // get info for outer shell + int nb0d_Out=0, nb2d_3_Out=0, nb2d_4_Out=0; + //TopTools_SequenceOfShape FacesOut; + for (TopExp_Explorer exp(outerShell, TopAbs_FACE); exp.More(); exp.Next()) { + //FacesOut.Append(exp.Current()); + SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current()); + MapShapeNbElemsItr anIt = aResMap.find(aSubMesh); + std::vector aVec = (*anIt).second; + nb0d_Out += aVec[SMDSEntity_Node]; + nb2d_3_Out += Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]); + nb2d_4_Out += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); + } + int nb1d_Out = 0; + TopTools_MapOfShape tmpMap; + for (TopExp_Explorer exp(outerShell, TopAbs_EDGE); exp.More(); exp.Next()) { + if( tmpMap.Contains( exp.Current() ) ) + continue; + tmpMap.Add( exp.Current() ); + SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current()); + MapShapeNbElemsItr anIt = aResMap.find(aSubMesh); + std::vector aVec = (*anIt).second; + nb0d_Out += aVec[SMDSEntity_Node]; + nb1d_Out += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]); + } + tmpMap.Clear(); + for (TopExp_Explorer exp(outerShell, TopAbs_VERTEX); exp.More(); exp.Next()) { + if( tmpMap.Contains( exp.Current() ) ) + continue; + tmpMap.Add( exp.Current() ); + nb0d_Out++; + } + + // get info for inner shell + int nb0d_In=0, nb2d_3_In=0, nb2d_4_In=0; + //TopTools_SequenceOfShape FacesIn; + for (TopExp_Explorer exp(innerShell, TopAbs_FACE); exp.More(); exp.Next()) { + //FacesIn.Append(exp.Current()); + SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current()); + MapShapeNbElemsItr anIt = aResMap.find(aSubMesh); + std::vector aVec = (*anIt).second; + nb0d_In += aVec[SMDSEntity_Node]; + nb2d_3_In += Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]); + nb2d_4_In += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); + } + int nb1d_In = 0; + tmpMap.Clear(); + bool IsQuadratic = false; + bool IsFirst = true; + for (TopExp_Explorer exp(innerShell, TopAbs_EDGE); exp.More(); exp.Next()) { + if( tmpMap.Contains( exp.Current() ) ) + continue; + tmpMap.Add( exp.Current() ); + SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current()); + MapShapeNbElemsItr anIt = aResMap.find(aSubMesh); + std::vector aVec = (*anIt).second; + nb0d_In += aVec[SMDSEntity_Node]; + nb1d_In += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]); + if(IsFirst) { + IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]); + IsFirst = false; + } + } + tmpMap.Clear(); + for (TopExp_Explorer exp(innerShell, TopAbs_VERTEX); exp.More(); exp.Next()) { + if( tmpMap.Contains( exp.Current() ) ) + continue; + tmpMap.Add( exp.Current() ); + nb0d_In++; + } + + bool IsOK = (nb0d_Out==nb0d_In) && (nb1d_Out==nb1d_In) && + (nb2d_3_Out==nb2d_3_In) && (nb2d_4_Out==nb2d_4_In); + if(!IsOK) { + std::vector aResVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; iGetComputeError(); + smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); + return false; + } + + int nbLayers = 0; + if( myNbLayerHypo ) { + nbLayers = myNbLayerHypo->GetNumberOfLayers(); + } + if ( myDistributionHypo ) { + if ( !myDistributionHypo->GetLayerDistribution() ) { + std::vector aResVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; iGetComputeError(); + smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); + return false; + } + TopExp_Explorer exp(outerShell, TopAbs_VERTEX); + TopoDS_Vertex Vout = TopoDS::Vertex(exp.Current()); + TopoDS_Vertex Vin = TopoDS::Vertex( shape2ShapeMap(Vout) ); + if ( myLayerPositions.empty() ) { + gp_Pnt pIn = BRep_Tool::Pnt(Vin); + gp_Pnt pOut = BRep_Tool::Pnt(Vout); + computeLayerPositions( pIn, pOut ); + } + nbLayers = myLayerPositions.size() + 1; + } + + std::vector aResVec(SMDSEntity_Last); + for(int i=SMDSEntity_Node; i 2 ) { + if ( toCheckAll ) return false; + break; + } + shell[ nbShells-1 ] = It.Value(); + } + if ( nbShells != 2 ) { + if ( toCheckAll ) return false; + continue; + } + + int nbFaces1 = SMESH_MesherHelper:: Count( shell[0], TopAbs_FACE, 0 ); + int nbFaces2 = SMESH_MesherHelper:: Count( shell[1], TopAbs_FACE, 0 ); + if ( nbFaces1 != nbFaces2 ){ + if( toCheckAll ) return false; + continue; + } + int nbEdges1 = SMESH_MesherHelper:: Count( shell[0], TopAbs_EDGE, 0 ); + int nbEdges2 = SMESH_MesherHelper:: Count( shell[1], TopAbs_EDGE, 0 ); + if ( nbEdges1 != nbEdges2 ){ + if( toCheckAll ) return false; + continue; + } + int nbVertices1 = SMESH_MesherHelper:: Count( shell[0], TopAbs_VERTEX, 0 ); + int nbVertices2 = SMESH_MesherHelper:: Count( shell[1], TopAbs_VERTEX, 0 ); + if ( nbVertices1 != nbVertices2 ){ + if( toCheckAll ) return false; + continue; + } + if ( !toCheckAll ) return true; + } + return ( toCheckAll && nbFoundSolids != 0); +}; diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialQuadrangle_1D2D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialQuadrangle_1D2D.cpp new file mode 100644 index 000000000000..03395bd10880 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialQuadrangle_1D2D.cpp @@ -0,0 +1,1347 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// File : StdMeshers_RadialQuadrangle_1D2D.cxx +// Module : SMESH + +#include "StdMeshers_RadialQuadrangle_1D2D.hxx" + +#include "StdMeshers_NumberOfLayers.hxx" +#include "StdMeshers_LayerDistribution.hxx" +#include "StdMeshers_Regular_1D.hxx" +#include "StdMeshers_NumberOfSegments.hxx" + +#include "SMDS_MeshNode.hxx" +#include "SMESHDS_SubMesh.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_HypoFilter.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_subMeshEventListener.hxx" + +#include "utilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace std; + +#define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; } +#define gpXYZ(n) gp_XYZ(n->X(),n->Y(),n->Z()) + + +//======================================================================= +//function : StdMeshers_RadialQuadrangle_1D2D +//purpose : +//======================================================================= + +StdMeshers_RadialQuadrangle_1D2D::StdMeshers_RadialQuadrangle_1D2D(int hypId, + int studyId, + SMESH_Gen* gen) + :SMESH_2D_Algo(hypId, studyId, gen) +{ + _name = "RadialQuadrangle_1D2D"; + _shapeType = (1 << TopAbs_FACE); // 1 bit per shape type + + _compatibleHypothesis.push_back("LayerDistribution2D"); + _compatibleHypothesis.push_back("NumberOfLayers2D"); + _requireDiscreteBoundary = false; + _supportSubmeshes = true; + _neededLowerHyps[ 1 ] = true; // suppress warning on hiding a global 1D algo + + myNbLayerHypo = 0; + myDistributionHypo = 0; +} + + +//================================================================================ +/*! + * \brief Destructor + */ +//================================================================================ + +StdMeshers_RadialQuadrangle_1D2D::~StdMeshers_RadialQuadrangle_1D2D() +{} + + +//======================================================================= +//function : CheckHypothesis +//purpose : +//======================================================================= + +bool StdMeshers_RadialQuadrangle_1D2D::CheckHypothesis + (SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus) +{ + // check aShape + myNbLayerHypo = 0; + myDistributionHypo = 0; + + list ::const_iterator itl; + + const list &hyps = GetUsedHypothesis(aMesh, aShape); + if ( hyps.size() == 0 ) { + aStatus = SMESH_Hypothesis::HYP_OK; + return true; // can work with no hypothesis + } + + if ( hyps.size() > 1 ) { + aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST; + return false; + } + + const SMESHDS_Hypothesis *theHyp = hyps.front(); + + string hypName = theHyp->GetName(); + + if (hypName == "NumberOfLayers2D") { + myNbLayerHypo = static_cast(theHyp); + aStatus = SMESH_Hypothesis::HYP_OK; + return true; + } + if (hypName == "LayerDistribution2D") { + myDistributionHypo = static_cast(theHyp); + aStatus = SMESH_Hypothesis::HYP_OK; + return true; + } + aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + return true; +} + +namespace +{ + // ------------------------------------------------------------------------------ + /*! + * \brief Listener used to mark edges meshed by StdMeshers_RadialQuadrangle_1D2D + */ + class TEdgeMarker : public SMESH_subMeshEventListener + { + TEdgeMarker(): SMESH_subMeshEventListener(/*isDeletable=*/false, + "StdMeshers_RadialQuadrangle_1D2D::TEdgeMarker") {} + public: + //!< Return static listener + static SMESH_subMeshEventListener* getListener() + { + static TEdgeMarker theEdgeMarker; + return &theEdgeMarker; + } + //! Clear face sumbesh if something happens on edges + void ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* edgeSubMesh, + EventListenerData* data, + const SMESH_Hypothesis* /*hyp*/) + { + if ( data && !data->mySubMeshes.empty() && eventType == SMESH_subMesh::ALGO_EVENT) + { + ASSERT( data->mySubMeshes.front() != edgeSubMesh ); + SMESH_subMesh* faceSubMesh = data->mySubMeshes.front(); + faceSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN ); + } + } + }; + + // ------------------------------------------------------------------------------ + /*! + * \brief Mark an edge as computed by StdMeshers_RadialQuadrangle_1D2D + */ + void markEdgeAsComputedByMe(const TopoDS_Edge& edge, SMESH_subMesh* faceSubMesh) + { + if ( SMESH_subMesh* edgeSM = faceSubMesh->GetFather()->GetSubMeshContaining( edge )) + { + if ( !edgeSM->GetEventListenerData( TEdgeMarker::getListener() )) + faceSubMesh->SetEventListener( TEdgeMarker::getListener(), + SMESH_subMeshEventListenerData::MakeData(faceSubMesh), + edgeSM); + } + } + // ------------------------------------------------------------------------------ + /*! + * \brief Return true if a radial edge was meshed with StdMeshers_RadialQuadrangle_1D2D with + * the same radial distribution + */ +// bool isEdgeCompatiballyMeshed(const TopoDS_Edge& edge, SMESH_subMesh* faceSubMesh) +// { +// if ( SMESH_subMesh* edgeSM = faceSubMesh->GetFather()->GetSubMeshContaining( edge )) +// { +// if ( SMESH_subMeshEventListenerData* otherFaceData = +// edgeSM->GetEventListenerData( TEdgeMarker::getListener() )) +// { +// // compare hypothesis aplied to two disk faces sharing radial edges +// SMESH_Mesh& mesh = *faceSubMesh->GetFather(); +// SMESH_Algo* radialQuadAlgo = mesh.GetGen()->GetAlgo(mesh, faceSubMesh->GetSubShape() ); +// SMESH_subMesh* otherFaceSubMesh = otherFaceData->mySubMeshes.front(); +// list hyps1 = +// radialQuadAlgo->GetUsedHypothesis( mesh, faceSubMesh->GetSubShape()); +// list hyps2 = +// radialQuadAlgo->GetUsedHypothesis( mesh, otherFaceSubMesh->GetSubShape()); +// if( hyps1.empty() && hyps2.empty() ) +// return true; // defaul hyps +// if ( hyps1.size() != hyps2.size() ) +// return false; +// return *hyps1.front() == *hyps2.front(); +// } +// } +// return false; +// } + + //================================================================================ + /*! + * \brief Return base curve of the edge and extremum parameters + */ + //================================================================================ + + Handle(Geom_Curve) getCurve(const TopoDS_Edge& edge, double* f=0, double* l=0) + { + Handle(Geom_Curve) C; + if ( !edge.IsNull() ) + { + double first = 0., last = 0.; + C = BRep_Tool::Curve(edge, first, last); + if ( !C.IsNull() ) + { + Handle(Geom_TrimmedCurve) tc = Handle(Geom_TrimmedCurve)::DownCast(C); + while( !tc.IsNull() ) { + C = tc->BasisCurve(); + tc = Handle(Geom_TrimmedCurve)::DownCast(C); + } + if ( f ) *f = first; + if ( l ) *l = last; + } + } + return C; + } + + //================================================================================ + /*! + * \brief Return edges of the face + * \retval int - nb of edges + */ + //================================================================================ + + int analyseFace(const TopoDS_Shape& face, + TopoDS_Edge& CircEdge, + TopoDS_Edge& LinEdge1, + TopoDS_Edge& LinEdge2) + { + CircEdge.Nullify(); LinEdge1.Nullify(); LinEdge2.Nullify(); + int nbe = 0; + + for ( TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next(), ++nbe ) + { + const TopoDS_Edge& E = TopoDS::Edge( exp.Current() ); + double f,l; + Handle(Geom_Curve) C = getCurve(E,&f,&l); + if ( !C.IsNull() ) + { + if ( C->IsKind( STANDARD_TYPE(Geom_Circle))) + { + if ( CircEdge.IsNull() ) + CircEdge = E; + else + return 0; + } + else if ( LinEdge1.IsNull() ) + LinEdge1 = E; + else + LinEdge2 = E; + } + } + return nbe; + } + //================================================================================ + /*! + * \brief Checks if the common vertex between LinEdge's lies inside the circle + * and not outside + * \param [in] CircEdge - + * \param [in] LinEdge1 - + * \param [in] LinEdge2 - + * \return bool - false if there are 3 EDGEs and the corner is outside + */ + //================================================================================ + + bool isCornerInsideCircle(const TopoDS_Edge& CircEdge, + const TopoDS_Edge& LinEdge1, + const TopoDS_Edge& LinEdge2) + { + if ( !CircEdge.IsNull() && + !LinEdge1.IsNull() && + !LinEdge2.IsNull() ) + { + Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge )); + TopoDS_Vertex aCommonV; + if ( !aCirc.IsNull() && + TopExp::CommonVertex( LinEdge1, LinEdge2, aCommonV )) + { + gp_Pnt aCommonP = BRep_Tool::Pnt( aCommonV ); + gp_Pnt aCenter = aCirc->Location(); + double dist = aCenter.Distance( aCommonP ); + return dist < 0.1 * aCirc->Radius(); + } + } + return true; + } + +//================================================================================ +//================================================================================ +/*! + * \brief Class computing layers distribution using data of + * StdMeshers_LayerDistribution hypothesis + */ +//================================================================================ +//================================================================================ + +class TNodeDistributor: public StdMeshers_Regular_1D +{ + list myUsedHyps; +public: + // ----------------------------------------------------------------------------- + static TNodeDistributor* GetDistributor(SMESH_Mesh& aMesh) + { + const int myID = -1001; + TNodeDistributor* myHyp = dynamic_cast( aMesh.GetHypothesis( myID )); + if ( !myHyp ) + myHyp = new TNodeDistributor( myID, 0, aMesh.GetGen() ); + return myHyp; + } + // ----------------------------------------------------------------------------- + //! Computes distribution of nodes on a straight line ending at pIn and pOut + bool Compute( vector< double > & positions, + gp_Pnt pIn, + gp_Pnt pOut, + SMESH_Mesh& aMesh, + const SMESH_Hypothesis* hyp1d) + { + if ( !hyp1d ) return error( "Invalid LayerDistribution hypothesis"); + + double len = pIn.Distance( pOut ); + if ( len <= DBL_MIN ) return error("Too close points of inner and outer shells"); + + myUsedHyps.clear(); + myUsedHyps.push_back( hyp1d ); + + TopoDS_Edge edge = BRepBuilderAPI_MakeEdge( pIn, pOut ); + SMESH_Hypothesis::Hypothesis_Status aStatus; + if ( !StdMeshers_Regular_1D::CheckHypothesis( aMesh, edge, aStatus )) + return error( "StdMeshers_Regular_1D::CheckHypothesis() failed " + "with LayerDistribution hypothesis"); + + BRepAdaptor_Curve C3D(edge); + double f = C3D.FirstParameter(), l = C3D.LastParameter(); + list< double > params; + if ( !StdMeshers_Regular_1D::computeInternalParameters( aMesh, C3D, len, f, l, params, false )) + return error("StdMeshers_Regular_1D failed to compute layers distribution"); + + positions.clear(); + positions.reserve( params.size() ); + for (list::iterator itU = params.begin(); itU != params.end(); itU++) + positions.push_back( *itU / len ); + return true; + } + // ----------------------------------------------------------------------------- + //! Make mesh on an adge using assigned 1d hyp or defaut nb of segments + bool ComputeCircularEdge(SMESH_Mesh& aMesh, + const TopoDS_Edge& anEdge) + { + _gen->Compute( aMesh, anEdge); + SMESH_subMesh *sm = aMesh.GetSubMesh(anEdge); + if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK) + { + // find any 1d hyp assigned (there can be a hyp w/o algo) + myUsedHyps = SMESH_Algo::GetUsedHypothesis(aMesh, anEdge, /*ignoreAux=*/true); + Hypothesis_Status aStatus; + if ( !StdMeshers_Regular_1D::CheckHypothesis( aMesh, anEdge, aStatus )) + { + // no valid 1d hyp assigned, use default nb of segments + _hypType = NB_SEGMENTS; + _ivalue[ DISTR_TYPE_IND ] = StdMeshers_NumberOfSegments::DT_Regular; + _ivalue[ NB_SEGMENTS_IND ] = _gen->GetDefaultNbSegments(); + } + return StdMeshers_Regular_1D::Compute( aMesh, anEdge ); + } + return true; + } + // ----------------------------------------------------------------------------- + //! Make mesh on an adge using assigned 1d hyp or defaut nb of segments + bool EvaluateCircularEdge(SMESH_Mesh& aMesh, + const TopoDS_Edge& anEdge, + MapShapeNbElems& aResMap) + { + _gen->Evaluate( aMesh, anEdge, aResMap ); + if ( aResMap.count( aMesh.GetSubMesh( anEdge ))) + return true; + + // find any 1d hyp assigned + myUsedHyps = SMESH_Algo::GetUsedHypothesis(aMesh, anEdge, /*ignoreAux=*/true); + Hypothesis_Status aStatus; + if ( !StdMeshers_Regular_1D::CheckHypothesis( aMesh, anEdge, aStatus )) + { + // no valid 1d hyp assigned, use default nb of segments + _hypType = NB_SEGMENTS; + _ivalue[ DISTR_TYPE_IND ] = StdMeshers_NumberOfSegments::DT_Regular; + _ivalue[ NB_SEGMENTS_IND ] = _gen->GetDefaultNbSegments(); + } + return StdMeshers_Regular_1D::Evaluate( aMesh, anEdge, aResMap ); + } +protected: + // ----------------------------------------------------------------------------- + TNodeDistributor( int hypId, int studyId, SMESH_Gen* gen) + : StdMeshers_Regular_1D( hypId, studyId, gen) + { + } + // ----------------------------------------------------------------------------- + virtual const list & + GetUsedHypothesis(SMESH_Mesh &, const TopoDS_Shape &, const bool) + { + return myUsedHyps; + } + // ----------------------------------------------------------------------------- +}; +} + +//======================================================================= +/*! + * \brief Allow algo to do something after persistent restoration + * \param subMesh - restored submesh + * + * call markEdgeAsComputedByMe() + */ +//======================================================================= + +void StdMeshers_RadialQuadrangle_1D2D::SubmeshRestored(SMESH_subMesh* faceSubMesh) +{ + if ( !faceSubMesh->IsEmpty() ) + { + TopoDS_Edge CircEdge, LinEdge1, LinEdge2; + analyseFace( faceSubMesh->GetSubShape(), CircEdge, LinEdge1, LinEdge2 ); + if ( !CircEdge.IsNull() ) markEdgeAsComputedByMe( CircEdge, faceSubMesh ); + if ( !LinEdge1.IsNull() ) markEdgeAsComputedByMe( LinEdge1, faceSubMesh ); + if ( !LinEdge2.IsNull() ) markEdgeAsComputedByMe( LinEdge2, faceSubMesh ); + } +} + +//======================================================================= +//function : Compute +//purpose : +//======================================================================= + +bool StdMeshers_RadialQuadrangle_1D2D::Compute(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape) +{ + SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); + + myHelper = new SMESH_MesherHelper( aMesh ); + // to delete helper at exit from Compute() + SMESHUtils::Deleter helperDeleter( myHelper ); + + TNodeDistributor* algo1d = TNodeDistributor::GetDistributor(aMesh); + + TopoDS_Edge CircEdge, LinEdge1, LinEdge2; + int nbe = analyseFace( aShape, CircEdge, LinEdge1, LinEdge2 ); + Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge )); + if( nbe > 3 || nbe < 1 || aCirc.IsNull() ) + return error("The face must be a full circle or a part of circle (i.e. the number " + "of edges is less or equal to 3 and one of them is a circle curve)"); + + gp_Pnt P0, P1; + // points for rotation + TColgp_SequenceOfPnt Points; + // angles for rotation + TColStd_SequenceOfReal Angles; + // Nodes1 and Nodes2 - nodes along radiuses + // CNodes - nodes on circle edge + vector< const SMDS_MeshNode* > Nodes1, Nodes2, CNodes; + SMDS_MeshNode * NC; + // parameters edge nodes on face + TColgp_SequenceOfPnt2d Pnts2d1; + gp_Pnt2d PC; + + int faceID = meshDS->ShapeToIndex(aShape); + TopoDS_Face F = TopoDS::Face(aShape); + Handle(Geom_Surface) S = BRep_Tool::Surface(F); + + + if(nbe==1) + { + if (!algo1d->ComputeCircularEdge( aMesh, CircEdge )) + return error( algo1d->GetComputeError() ); + map< double, const SMDS_MeshNode* > theNodes; + if ( !GetSortedNodesOnEdge(aMesh.GetMeshDS(),CircEdge,true,theNodes)) + return error("Circular edge is incorrectly meshed"); + + myHelper->IsQuadraticSubMesh( aShape ); + + CNodes.clear(); + map< double, const SMDS_MeshNode* >::iterator itn = theNodes.begin(); + const SMDS_MeshNode* NF = (*itn).second; + CNodes.push_back( (*itn).second ); + double fang = (*itn).first; + if ( itn != theNodes.end() ) { + itn++; + for(; itn != theNodes.end(); itn++ ) { + CNodes.push_back( (*itn).second ); + double ang = (*itn).first - fang; + if( ang>M_PI ) ang = ang - 2.*M_PI; + if( ang<-M_PI ) ang = ang + 2.*M_PI; + Angles.Append( ang ); + } + } + P1 = gp_Pnt( NF->X(), NF->Y(), NF->Z() ); + P0 = aCirc->Location(); + + if ( !computeLayerPositions(P0,P1)) + return false; + + TopoDS_Vertex V1 = myHelper->IthVertex(0, CircEdge ); + gp_Pnt2d p2dV = BRep_Tool::Parameters( V1, TopoDS::Face(aShape) ); + + NC = meshDS->AddNode(P0.X(), P0.Y(), P0.Z()); + GeomAPI_ProjectPointOnSurf PPS(P0,S); + double U0,V0; + PPS.Parameters(1,U0,V0); + meshDS->SetNodeOnFace(NC, faceID, U0, V0); + PC = gp_Pnt2d(U0,V0); + + gp_Vec aVec(P0,P1); + gp_Vec2d aVec2d(PC,p2dV); + Nodes1.resize( myLayerPositions.size()+1 ); + Nodes2.resize( myLayerPositions.size()+1 ); + int i = 0; + for(; iAddNode(P.X(), P.Y(), P.Z()); + Nodes1[i] = node; + Nodes2[i] = node; + double U = PC.X() + aVec2d.X()*myLayerPositions[i]; + double V = PC.Y() + aVec2d.Y()*myLayerPositions[i]; + meshDS->SetNodeOnFace( node, faceID, U, V ); + Pnts2d1.Append(gp_Pnt2d(U,V)); + } + Nodes1[Nodes1.size()-1] = NF; + Nodes2[Nodes1.size()-1] = NF; + } + else if(nbe==2 && LinEdge1.Orientation() != TopAbs_INTERNAL ) + { + // one curve must be a half of circle and other curve must be + // a segment of line + double fp, lp; + Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge, &fp, &lp )); + if( fabs(fabs(lp-fp)-M_PI) > Precision::Confusion() ) { + // not half of circle + return error(COMPERR_BAD_SHAPE); + } + Handle(Geom_Line) aLine = Handle(Geom_Line)::DownCast( getCurve( LinEdge1 )); + if( aLine.IsNull() ) { + // other curve not line + return error(COMPERR_BAD_SHAPE); + } + + if ( !algo1d->ComputeCircularEdge( aMesh, CircEdge )) + return error( algo1d->GetComputeError() ); + map< double, const SMDS_MeshNode* > theNodes; + if ( !GetSortedNodesOnEdge(aMesh.GetMeshDS(),CircEdge,true,theNodes) ) + return error("Circular edge is incorrectly meshed"); + + myHelper->IsQuadraticSubMesh( aShape ); + + map< double, const SMDS_MeshNode* >::iterator itn = theNodes.begin(); + CNodes.clear(); + CNodes.push_back( itn->second ); + double fang = (*itn).first; + itn++; + for(; itn != theNodes.end(); itn++ ) { + CNodes.push_back( (*itn).second ); + double ang = (*itn).first - fang; + if( ang>M_PI ) ang = ang - 2.*M_PI; + if( ang<-M_PI ) ang = ang + 2.*M_PI; + Angles.Append( ang ); + } + const SMDS_MeshNode* NF = theNodes.begin()->second; + const SMDS_MeshNode* NL = theNodes.rbegin()->second; + P1 = gp_Pnt( NF->X(), NF->Y(), NF->Z() ); + gp_Pnt P2( NL->X(), NL->Y(), NL->Z() ); + P0 = aCirc->Location(); + + bool linEdgeComputed; + if ( !computeLayerPositions(P0,P1,LinEdge1,&linEdgeComputed)) + return false; + + if ( linEdgeComputed ) + { + if (!GetSortedNodesOnEdge(aMesh.GetMeshDS(),LinEdge1,true,theNodes)) + return error("Invalid mesh on a straight edge"); + + Nodes1.resize( myLayerPositions.size()+1 ); + Nodes2.resize( myLayerPositions.size()+1 ); + vector< const SMDS_MeshNode* > *pNodes1 = &Nodes1, *pNodes2 = &Nodes2; + bool nodesFromP0ToP1 = ( theNodes.rbegin()->second == NF ); + if ( !nodesFromP0ToP1 ) std::swap( pNodes1, pNodes2 ); + + map< double, const SMDS_MeshNode* >::reverse_iterator ritn = theNodes.rbegin(); + itn = theNodes.begin(); + for ( int i = Nodes1.size()-1; i > -1; ++itn, ++ritn, --i ) + { + (*pNodes1)[i] = ritn->second; + (*pNodes2)[i] = itn->second; + Points.Prepend( gpXYZ( Nodes1[i])); + Pnts2d1.Prepend( myHelper->GetNodeUV( F, Nodes1[i])); + } + NC = const_cast( itn->second ); + Points.Remove( Nodes1.size() ); + } + else + { + gp_Vec aVec(P0,P1); + int edgeID = meshDS->ShapeToIndex(LinEdge1); + // check orientation + Handle(Geom_Curve) Crv = BRep_Tool::Curve(LinEdge1,fp,lp); + gp_Pnt Ptmp; + Crv->D0(fp,Ptmp); + bool ori = true; + if( P1.Distance(Ptmp) > Precision::Confusion() ) + ori = false; + // get UV points for edge + gp_Pnt2d PF,PL; + BRep_Tool::UVPoints( LinEdge1, TopoDS::Face(aShape), PF, PL ); + PC = gp_Pnt2d( (PF.X()+PL.X())/2, (PF.Y()+PL.Y())/2 ); + gp_Vec2d V2d; + if(ori) V2d = gp_Vec2d(PC,PF); + else V2d = gp_Vec2d(PC,PL); + // add nodes on edge + double cp = (fp+lp)/2; + double dp2 = (lp-fp)/2; + NC = meshDS->AddNode(P0.X(), P0.Y(), P0.Z()); + meshDS->SetNodeOnEdge(NC, edgeID, cp); + Nodes1.resize( myLayerPositions.size()+1 ); + Nodes2.resize( myLayerPositions.size()+1 ); + int i = 0; + for(; iAddNode(P.X(), P.Y(), P.Z()); + Nodes1[i] = node; + double param; + if(ori) + param = fp + dp2*(1-myLayerPositions[i]); + else + param = cp + dp2*myLayerPositions[i]; + meshDS->SetNodeOnEdge(node, edgeID, param); + P = gp_Pnt( P0.X() - aVec.X()*myLayerPositions[i], + P0.Y() - aVec.Y()*myLayerPositions[i], + P0.Z() - aVec.Z()*myLayerPositions[i] ); + node = meshDS->AddNode(P.X(), P.Y(), P.Z()); + Nodes2[i] = node; + if(!ori) + param = fp + dp2*(1-myLayerPositions[i]); + else + param = cp + dp2*myLayerPositions[i]; + meshDS->SetNodeOnEdge(node, edgeID, param); + // parameters on face + gp_Pnt2d P2d( PC.X() + V2d.X()*myLayerPositions[i], + PC.Y() + V2d.Y()*myLayerPositions[i] ); + Pnts2d1.Append(P2d); + } + Nodes1[ myLayerPositions.size() ] = NF; + Nodes2[ myLayerPositions.size() ] = NL; + // create 1D elements on edge + vector< const SMDS_MeshNode* > tmpNodes; + tmpNodes.resize(2*Nodes1.size()+1); + for(i=0; iAddEdge( tmpNodes[i-1], tmpNodes[i] ); + if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); + } + markEdgeAsComputedByMe( LinEdge1, aMesh.GetSubMesh( F )); + } + } + else // nbe==3 or ( nbe==2 && linEdge is INTERNAL ) + { + if (nbe==2 && LinEdge1.Orientation() == TopAbs_INTERNAL ) + LinEdge2 = LinEdge1; + + // one curve must be a part of circle and other curves must be + // segments of line + double fp, lp; + Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge )); + Handle(Geom_Line) aLine1 = Handle(Geom_Line )::DownCast( getCurve( LinEdge1 )); + Handle(Geom_Line) aLine2 = Handle(Geom_Line )::DownCast( getCurve( LinEdge2 )); + if ( aCirc.IsNull() || aLine1.IsNull() || aLine2.IsNull() ) + return error(COMPERR_BAD_SHAPE); + if ( !isCornerInsideCircle( CircEdge, LinEdge1, LinEdge2 )) + return error(COMPERR_BAD_SHAPE); + + if ( !algo1d->ComputeCircularEdge( aMesh, CircEdge )) + return error( algo1d->GetComputeError() ); + map< double, const SMDS_MeshNode* > theNodes; + if ( !GetSortedNodesOnEdge( aMesh.GetMeshDS(), CircEdge, true, theNodes )) + return error("Circular edge is incorrectly meshed"); + + myHelper->IsQuadraticSubMesh( aShape ); + + const SMDS_MeshNode* NF = theNodes.begin()->second; + const SMDS_MeshNode* NL = theNodes.rbegin()->second; + CNodes.clear(); + CNodes.push_back( NF ); + map< double, const SMDS_MeshNode* >::iterator itn = theNodes.begin(); + double fang = (*itn).first; + itn++; + for(; itn != theNodes.end(); itn++ ) { + CNodes.push_back( (*itn).second ); + double ang = (*itn).first - fang; + if( ang>M_PI ) ang = ang - 2.*M_PI; + if( ang<-M_PI ) ang = ang + 2.*M_PI; + Angles.Append( ang ); + } + P1 = gp_Pnt( NF->X(), NF->Y(), NF->Z() ); + gp_Pnt P2( NL->X(), NL->Y(), NL->Z() ); + P0 = aCirc->Location(); + + // make P1 belong to LinEdge1 + TopoDS_Vertex V1 = myHelper->IthVertex( 0, LinEdge1 ); + TopoDS_Vertex V2 = myHelper->IthVertex( 1, LinEdge1 ); + gp_Pnt PE1 = BRep_Tool::Pnt(V1); + gp_Pnt PE2 = BRep_Tool::Pnt(V2); + if( ( P1.Distance(PE1) > Precision::Confusion() ) && + ( P1.Distance(PE2) > Precision::Confusion() ) ) + std::swap( LinEdge1, LinEdge2 ); + + bool linEdge1Computed, linEdge2Computed; + if ( !computeLayerPositions(P0,P1,LinEdge1,&linEdge1Computed)) + return false; + + Nodes1.resize( myLayerPositions.size()+1 ); + Nodes2.resize( myLayerPositions.size()+1 ); + + // check that both linear edges have same hypotheses + if ( !computeLayerPositions(P0,P2,LinEdge2, &linEdge2Computed)) + return false; + if ( Nodes1.size() != myLayerPositions.size()+1 ) + return error("Different hypotheses apply to radial edges"); + + // find the central vertex + TopoDS_Vertex VC = V2; + if( ( P1.Distance(PE1) > Precision::Confusion() ) && + ( P2.Distance(PE1) > Precision::Confusion() ) ) + VC = V1; + int vertID = meshDS->ShapeToIndex(VC); + + // LinEdge1 + if ( linEdge1Computed ) + { + if (!GetSortedNodesOnEdge(aMesh.GetMeshDS(),LinEdge1,true,theNodes)) + return error("Invalid mesh on a straight edge"); + + bool nodesFromP0ToP1 = ( theNodes.rbegin()->second == NF ); + NC = const_cast + ( nodesFromP0ToP1 ? theNodes.begin()->second : theNodes.rbegin()->second ); + int i = 0, ir = Nodes1.size()-1; + int * pi = nodesFromP0ToP1 ? &i : &ir; + itn = theNodes.begin(); + if ( nodesFromP0ToP1 ) ++itn; + for ( ; i < Nodes1.size(); ++i, --ir, ++itn ) + { + Nodes1[*pi] = itn->second; + } + for ( i = 0; i < Nodes1.size()-1; ++i ) + { + Points.Append( gpXYZ( Nodes1[i])); + Pnts2d1.Append( myHelper->GetNodeUV( F, Nodes1[i])); + } + } + else + { + int edgeID = meshDS->ShapeToIndex(LinEdge1); + gp_Vec aVec(P0,P1); + // check orientation + Handle(Geom_Curve) Crv = BRep_Tool::Curve(LinEdge1,fp,lp); + gp_Pnt Ptmp = Crv->Value(fp); + bool ori = false; + if( P1.Distance(Ptmp) > Precision::Confusion() ) + ori = true; + // get UV points for edge + gp_Pnt2d PF,PL; + BRep_Tool::UVPoints( LinEdge1, TopoDS::Face(aShape), PF, PL ); + gp_Vec2d V2d; + if(ori) { + V2d = gp_Vec2d(PF,PL); + PC = PF; + } + else { + V2d = gp_Vec2d(PL,PF); + PC = PL; + } + NC = const_cast( VertexNode( VC, meshDS )); + if ( !NC ) + { + NC = meshDS->AddNode(P0.X(), P0.Y(), P0.Z()); + meshDS->SetNodeOnVertex(NC, vertID); + } + double dp = lp-fp; + int i = 0; + for(; iAddNode(P.X(), P.Y(), P.Z()); + Nodes1[i] = node; + double param; + if(!ori) + param = fp + dp*(1-myLayerPositions[i]); + else + param = fp + dp*myLayerPositions[i]; + meshDS->SetNodeOnEdge(node, edgeID, param); + // parameters on face + gp_Pnt2d P2d( PC.X() + V2d.X()*myLayerPositions[i], + PC.Y() + V2d.Y()*myLayerPositions[i] ); + Pnts2d1.Append(P2d); + } + Nodes1[ myLayerPositions.size() ] = NF; + // create 1D elements on edge + SMDS_MeshEdge* ME = myHelper->AddEdge( NC, Nodes1[0] ); + if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); + for(i=1; iAddEdge( Nodes1[i-1], Nodes1[i] ); + if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); + } + if (nbe==2 && LinEdge1.Orientation() == TopAbs_INTERNAL ) + Nodes2 = Nodes1; + } + markEdgeAsComputedByMe( LinEdge1, aMesh.GetSubMesh( F )); + + // LinEdge2 + if ( linEdge2Computed ) + { + if (!GetSortedNodesOnEdge(aMesh.GetMeshDS(),LinEdge2,true,theNodes)) + return error("Invalid mesh on a straight edge"); + + bool nodesFromP0ToP2 = ( theNodes.rbegin()->second == NL ); + int i = 0, ir = Nodes1.size()-1; + int * pi = nodesFromP0ToP2 ? &i : &ir; + itn = theNodes.begin(); + if ( nodesFromP0ToP2 ) ++itn; + for ( ; i < Nodes2.size(); ++i, --ir, ++itn ) + Nodes2[*pi] = itn->second; + } + else + { + int edgeID = meshDS->ShapeToIndex(LinEdge2); + gp_Vec aVec = gp_Vec(P0,P2); + // check orientation + Handle(Geom_Curve) Crv = BRep_Tool::Curve(LinEdge2,fp,lp); + gp_Pnt Ptmp = Crv->Value(fp); + bool ori = false; + if( P2.Distance(Ptmp) > Precision::Confusion() ) + ori = true; + // get UV points for edge + gp_Pnt2d PF,PL; + BRep_Tool::UVPoints( LinEdge2, TopoDS::Face(aShape), PF, PL ); + gp_Vec2d V2d; + if(ori) { + V2d = gp_Vec2d(PF,PL); + PC = PF; + } + else { + V2d = gp_Vec2d(PL,PF); + PC = PL; + } + double dp = lp-fp; + for(int i=0; iAddNode(P.X(), P.Y(), P.Z()); + Nodes2[i] = node; + double param; + if(!ori) + param = fp + dp*(1-myLayerPositions[i]); + else + param = fp + dp*myLayerPositions[i]; + meshDS->SetNodeOnEdge(node, edgeID, param); + // parameters on face + gp_Pnt2d P2d( PC.X() + V2d.X()*myLayerPositions[i], + PC.Y() + V2d.Y()*myLayerPositions[i] ); + } + Nodes2[ myLayerPositions.size() ] = NL; + // create 1D elements on edge + SMDS_MeshEdge* ME = myHelper->AddEdge( NC, Nodes2[0] ); + if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); + for(int i=1; iAddEdge( Nodes2[i-1], Nodes2[i] ); + if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); + } + } + markEdgeAsComputedByMe( LinEdge2, aMesh.GetSubMesh( F )); + } + markEdgeAsComputedByMe( CircEdge, aMesh.GetSubMesh( F )); + + // orientation + bool IsForward = ( CircEdge.Orientation()==TopAbs_FORWARD ); + const double angleSign = ( F.Orientation() == TopAbs_REVERSED ? -1.0 : 1.0 ); + + // create nodes and mesh elements on face + // find axis of rotation + gp_Pnt P2 = gp_Pnt( CNodes[1]->X(), CNodes[1]->Y(), CNodes[1]->Z() ); + gp_Vec Vec1(P0,P1); + gp_Vec Vec2(P0,P2); + gp_Vec Axis = Vec1.Crossed(Vec2); + // create elements + int i = 1; + //cout<<"Angles.Length() = "<& aResVec = + aResMap.insert( make_pair(sm, vector(SMDSEntity_Last,0))).first->second; + + myHelper = new SMESH_MesherHelper( aMesh ); + myHelper->SetSubShape( aShape ); + auto_ptr helperDeleter( myHelper ); + + TNodeDistributor* algo1d = TNodeDistributor::GetDistributor(aMesh); + + TopoDS_Edge CircEdge, LinEdge1, LinEdge2; + int nbe = analyseFace( aShape, CircEdge, LinEdge1, LinEdge2 ); + if( nbe>3 || nbe < 1 || CircEdge.IsNull() ) + return false; + + Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge )); + if( aCirc.IsNull() ) + return error(COMPERR_BAD_SHAPE); + + gp_Pnt P0 = aCirc->Location(); + gp_Pnt P1 = aCirc->Value(0.); + computeLayerPositions( P0, P1, LinEdge1 ); + + int nb0d=0, nb2d_tria=0, nb2d_quad=0; + bool isQuadratic = false, ok = true; + if(nbe==1) + { + // C1 must be a circle + ok = algo1d->EvaluateCircularEdge( aMesh, CircEdge, aResMap ); + if(ok) { + const vector& aVec = aResMap[aMesh.GetSubMesh(CircEdge)]; + isQuadratic = aVec[SMDSEntity_Quad_Edge]>aVec[SMDSEntity_Edge]; + if(isQuadratic) { + // main nodes + nb0d = (aVec[SMDSEntity_Node]+1) * myLayerPositions.size(); + // radial medium nodes + nb0d += (aVec[SMDSEntity_Node]+1) * (myLayerPositions.size()+1); + // other medium nodes + nb0d += (aVec[SMDSEntity_Node]+1) * myLayerPositions.size(); + } + else { + nb0d = (aVec[SMDSEntity_Node]+1) * myLayerPositions.size(); + } + nb2d_tria = aVec[SMDSEntity_Node] + 1; + nb2d_quad = nb0d; + } + } + else if(nbe==2 && LinEdge1.Orientation() != TopAbs_INTERNAL) + { + // one curve must be a half of circle and other curve must be + // a segment of line + double fp, lp; + Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge, &fp, &lp )); + if( fabs(fabs(lp-fp)-M_PI) > Precision::Confusion() ) { + // not half of circle + return error(COMPERR_BAD_SHAPE); + } + Handle(Geom_Line) aLine = Handle(Geom_Line)::DownCast( getCurve( LinEdge1 )); + if( aLine.IsNull() ) { + // other curve not line + return error(COMPERR_BAD_SHAPE); + } + ok = !aResMap.count( aMesh.GetSubMesh(LinEdge1) ); + if ( !ok ) { + const vector& aVec = aResMap[ aMesh.GetSubMesh(LinEdge1) ]; + ok = ( aVec[SMDSEntity_Node] == myLayerPositions.size() ); + } + if(ok) { + ok = algo1d->EvaluateCircularEdge( aMesh, CircEdge, aResMap ); + } + if(ok) { + const vector& aVec = aResMap[ aMesh.GetSubMesh(CircEdge) ]; + isQuadratic = aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]; + if(isQuadratic) { + // main nodes + nb0d = aVec[SMDSEntity_Node] * myLayerPositions.size(); + // radial medium nodes + nb0d += aVec[SMDSEntity_Node] * (myLayerPositions.size()+1); + // other medium nodes + nb0d += (aVec[SMDSEntity_Node]+1) * myLayerPositions.size(); + } + else { + nb0d = aVec[SMDSEntity_Node] * myLayerPositions.size(); + } + nb2d_tria = aVec[SMDSEntity_Node] + 1; + nb2d_quad = nb2d_tria * myLayerPositions.size(); + // add evaluation for edges + vector aResVec(SMDSEntity_Last,0); + if(isQuadratic) { + aResVec[SMDSEntity_Node] = 4*myLayerPositions.size() + 3; + aResVec[SMDSEntity_Quad_Edge] = 2*myLayerPositions.size() + 2; + } + else { + aResVec[SMDSEntity_Node] = 2*myLayerPositions.size() + 1; + aResVec[SMDSEntity_Edge] = 2*myLayerPositions.size() + 2; + } + aResMap[ aMesh.GetSubMesh(LinEdge1) ] = aResVec; + } + } + else // nbe==3 or ( nbe==2 && linEdge is INTERNAL ) + { + if (nbe==2 && LinEdge1.Orientation() == TopAbs_INTERNAL ) + LinEdge2 = LinEdge1; + + // one curve must be a part of circle and other curves must be + // segments of line + Handle(Geom_Line) aLine1 = Handle(Geom_Line)::DownCast( getCurve( LinEdge1 )); + Handle(Geom_Line) aLine2 = Handle(Geom_Line)::DownCast( getCurve( LinEdge2 )); + if( aLine1.IsNull() || aLine2.IsNull() ) { + // other curve not line + return error(COMPERR_BAD_SHAPE); + } + int nbLayers = myLayerPositions.size(); + computeLayerPositions( P0, P1, LinEdge2 ); + if ( nbLayers != myLayerPositions.size() ) + return error("Different hypotheses apply to radial edges"); + + bool ok = !aResMap.count( aMesh.GetSubMesh(LinEdge1)); + if ( !ok ) { + if ( myDistributionHypo || myNbLayerHypo ) + ok = true; // override other 1d hyps + else { + const vector& aVec = aResMap[ aMesh.GetSubMesh(LinEdge1) ]; + ok = ( aVec[SMDSEntity_Node] == myLayerPositions.size() ); + } + } + if( ok && aResMap.count( aMesh.GetSubMesh(LinEdge2) )) { + if ( myDistributionHypo || myNbLayerHypo ) + ok = true; // override other 1d hyps + else { + const vector& aVec = aResMap[ aMesh.GetSubMesh(LinEdge2) ]; + ok = ( aVec[SMDSEntity_Node] == myLayerPositions.size() ); + } + } + if(ok) { + ok = algo1d->EvaluateCircularEdge( aMesh, CircEdge, aResMap ); + } + if(ok) { + const vector& aVec = aResMap[ aMesh.GetSubMesh(CircEdge) ]; + isQuadratic = aVec[SMDSEntity_Quad_Edge]>aVec[SMDSEntity_Edge]; + if(isQuadratic) { + // main nodes + nb0d = aVec[SMDSEntity_Node] * myLayerPositions.size(); + // radial medium nodes + nb0d += aVec[SMDSEntity_Node] * (myLayerPositions.size()+1); + // other medium nodes + nb0d += (aVec[SMDSEntity_Node]+1) * myLayerPositions.size(); + } + else { + nb0d = aVec[SMDSEntity_Node] * myLayerPositions.size(); + } + nb2d_tria = aVec[SMDSEntity_Node] + 1; + nb2d_quad = nb2d_tria * myLayerPositions.size(); + // add evaluation for edges + vector aResVec(SMDSEntity_Last, 0); + if(isQuadratic) { + aResVec[SMDSEntity_Node] = 2*myLayerPositions.size() + 1; + aResVec[SMDSEntity_Quad_Edge] = myLayerPositions.size() + 1; + } + else { + aResVec[SMDSEntity_Node] = myLayerPositions.size(); + aResVec[SMDSEntity_Edge] = myLayerPositions.size() + 1; + } + sm = aMesh.GetSubMesh(LinEdge1); + aResMap[sm] = aResVec; + sm = aMesh.GetSubMesh(LinEdge2); + aResMap[sm] = aResVec; + } + } + + if(nb0d>0) { + aResVec[0] = nb0d; + if(isQuadratic) { + aResVec[SMDSEntity_Quad_Triangle] = nb2d_tria; + aResVec[SMDSEntity_Quad_Quadrangle] = nb2d_quad; + } + else { + aResVec[SMDSEntity_Triangle] = nb2d_tria; + aResVec[SMDSEntity_Quadrangle] = nb2d_quad; + } + return true; + } + + // invalid case + sm = aMesh.GetSubMesh(aShape); + SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); + smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED, + "Submesh can not be evaluated",this)); + return false; + +} + +//================================================================================ +/*! + * \brief Return true if the algorithm can compute mesh on this shape + */ +//================================================================================ + +bool StdMeshers_RadialQuadrangle_1D2D::IsApplicable( const TopoDS_Shape & aShape, bool toCheckAll ) +{ + int nbFoundFaces = 0; + for (TopExp_Explorer exp( aShape, TopAbs_FACE ); exp.More(); exp.Next(), ++nbFoundFaces ) + { + TopoDS_Edge CircEdge, LinEdge1, LinEdge2; + int nbe = analyseFace( exp.Current(), CircEdge, LinEdge1, LinEdge2 ); + Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge )); + bool ok = ( nbe <= 3 && nbe >= 1 && !aCirc.IsNull() && + isCornerInsideCircle( CircEdge, LinEdge1, LinEdge2 )); + if( toCheckAll && !ok ) return false; + if( !toCheckAll && ok ) return true; + } + if( toCheckAll && nbFoundFaces != 0 ) return true; + return false; +}; diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Regular_1D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Regular_1D.cpp index d31a6d396419..73f11aff5983 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Regular_1D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Regular_1D.cpp @@ -1,36 +1,47 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMESH : implementaion of SMESH idl descriptions + // File : StdMeshers_Regular_1D.cxx // Moved here from SMESH_Regular_1D.cxx // Author : Paul RASCLE, EDF // Module : SMESH - +// #include "StdMeshers_Regular_1D.hxx" -#include "StdMeshers_Distribution.hxx" +#include "SMDS_MeshElement.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMESH_Comment.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_HypoFilter.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_subMeshEventListener.hxx" +#include "StdMeshers_Adaptive1D.hxx" #include "StdMeshers_Arithmetic1D.hxx" +#include "StdMeshers_Geometric1D.hxx" #include "StdMeshers_AutomaticLength.hxx" #include "StdMeshers_Deflection1D.hxx" +#include "StdMeshers_Distribution.hxx" +#include "StdMeshers_FixedPoints1D.hxx" #include "StdMeshers_LocalLength.hxx" #include "StdMeshers_MaxLength.hxx" #include "StdMeshers_NumberOfSegments.hxx" @@ -38,17 +49,7 @@ #include "StdMeshers_SegmentLengthAroundVertex.hxx" #include "StdMeshers_StartEndLength.hxx" -#include "SMESH_Gen.hxx" -#include "SMESH_Mesh.hxx" -#include "SMESH_HypoFilter.hxx" -#include "SMESH_subMesh.hxx" -#include "SMESH_subMeshEventListener.hxx" -#include "SMESH_Comment.hxx" - -#include "SMDS_MeshElement.hxx" -#include "SMDS_MeshNode.hxx" - -#include "SMESH_Exception.hxx" +#include "Utils_SALOME_Exception.hxx" #include "utilities.h" #include @@ -61,10 +62,13 @@ #include #include #include +#include #include +#include using namespace std; +using namespace StdMeshers; //============================================================================= /*! @@ -73,27 +77,33 @@ using namespace std; //============================================================================= StdMeshers_Regular_1D::StdMeshers_Regular_1D(int hypId, int studyId, - SMESH_Gen * gen):SMESH_1D_Algo(hypId, studyId, gen) + SMESH_Gen * gen) + :SMESH_1D_Algo(hypId, studyId, gen) { - MESSAGE("StdMeshers_Regular_1D::StdMeshers_Regular_1D"); - _name = "Regular_1D"; - _shapeType = (1 << TopAbs_EDGE); - - _compatibleHypothesis.push_back("LocalLength"); - _compatibleHypothesis.push_back("MaxLength"); - _compatibleHypothesis.push_back("NumberOfSegments"); - _compatibleHypothesis.push_back("StartEndLength"); - _compatibleHypothesis.push_back("Deflection1D"); - _compatibleHypothesis.push_back("Arithmetic1D"); - _compatibleHypothesis.push_back("AutomaticLength"); - - _compatibleHypothesis.push_back("QuadraticMesh"); // auxiliary !!! - _compatibleHypothesis.push_back("Propagation"); // auxiliary !!! + MESSAGE("StdMeshers_Regular_1D::StdMeshers_Regular_1D"); + _name = "Regular_1D"; + _shapeType = (1 << TopAbs_EDGE); + _fpHyp = 0; + + _compatibleHypothesis.push_back("LocalLength"); + _compatibleHypothesis.push_back("MaxLength"); + _compatibleHypothesis.push_back("NumberOfSegments"); + _compatibleHypothesis.push_back("StartEndLength"); + _compatibleHypothesis.push_back("Deflection1D"); + _compatibleHypothesis.push_back("Arithmetic1D"); + _compatibleHypothesis.push_back("GeometricProgression"); + _compatibleHypothesis.push_back("FixedPoints1D"); + _compatibleHypothesis.push_back("AutomaticLength"); + _compatibleHypothesis.push_back("Adaptive1D"); + // auxiliary: + _compatibleHypothesis.push_back("QuadraticMesh"); + _compatibleHypothesis.push_back("Propagation"); + _compatibleHypothesis.push_back("PropagOfDistribution"); } //============================================================================= /*! - * + * */ //============================================================================= @@ -103,29 +113,33 @@ StdMeshers_Regular_1D::~StdMeshers_Regular_1D() //============================================================================= /*! - * + * */ //============================================================================= -bool StdMeshers_Regular_1D::CheckHypothesis - (SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape, - SMESH_Hypothesis::Hypothesis_Status& aStatus) +bool StdMeshers_Regular_1D::CheckHypothesis( SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + Hypothesis_Status& aStatus ) { _hypType = NONE; _quadraticMesh = false; + _onlyUnaryInput = true; - const bool ignoreAuxiliaryHyps = false; const list & hyps = - GetUsedHypothesis(aMesh, aShape, ignoreAuxiliaryHyps); + GetUsedHypothesis(aMesh, aShape, /*ignoreAuxiliaryHyps=*/false); + + const SMESH_HypoFilter & propagFilter = StdMeshers_Propagation::GetFilter(); // find non-auxiliary hypothesis const SMESHDS_Hypothesis *theHyp = 0; + set< string > propagTypes; list ::const_iterator h = hyps.begin(); for ( ; h != hyps.end(); ++h ) { if ( static_cast(*h)->IsAuxiliary() ) { if ( strcmp( "QuadraticMesh", (*h)->GetName() ) == 0 ) _quadraticMesh = true; + if ( propagFilter.IsOk( static_cast< const SMESH_Hypothesis*>( *h ), aShape )) + propagTypes.insert( (*h)->GetName() ); } else { if ( !theHyp ) @@ -180,12 +194,15 @@ bool StdMeshers_Regular_1D::CheckHypothesis { case StdMeshers_NumberOfSegments::DT_Scale: _value[ SCALE_FACTOR_IND ] = hyp->GetScaleFactor(); + _revEdgesIDs = hyp->GetReversedEdges(); break; case StdMeshers_NumberOfSegments::DT_TabFunc: _vvalue[ TAB_FUNC_IND ] = hyp->GetTableFunction(); + _revEdgesIDs = hyp->GetReversedEdges(); break; case StdMeshers_NumberOfSegments::DT_ExprFunc: _svalue[ EXPR_FUNC_IND ] = hyp->GetExpressionFunction(); + _revEdgesIDs = hyp->GetReversedEdges(); break; case StdMeshers_NumberOfSegments::DT_Regular: break; @@ -209,6 +226,34 @@ bool StdMeshers_Regular_1D::CheckHypothesis _value[ END_LENGTH_IND ] = hyp->GetLength( false ); ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 ); _hypType = ARITHMETIC_1D; + + _revEdgesIDs = hyp->GetReversedEdges(); + + aStatus = SMESH_Hypothesis::HYP_OK; + } + + else if (hypName == "GeometricProgression") + { + const StdMeshers_Geometric1D * hyp = + dynamic_cast (theHyp); + ASSERT(hyp); + _value[ BEG_LENGTH_IND ] = hyp->GetStartLength(); + _value[ END_LENGTH_IND ] = hyp->GetCommonRatio(); + ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 ); + _hypType = GEOMETRIC_1D; + + _revEdgesIDs = hyp->GetReversedEdges(); + + aStatus = SMESH_Hypothesis::HYP_OK; + } + + else if (hypName == "FixedPoints1D") { + _fpHyp = dynamic_cast (theHyp); + ASSERT(_fpHyp); + _hypType = FIXED_POINTS_1D; + + _revEdgesIDs = _fpHyp->GetReversedEdges(); + aStatus = SMESH_Hypothesis::HYP_OK; } @@ -221,6 +266,9 @@ bool StdMeshers_Regular_1D::CheckHypothesis _value[ END_LENGTH_IND ] = hyp->GetLength( false ); ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 ); _hypType = BEG_END_LENGTH; + + _revEdgesIDs = hyp->GetReversedEdges(); + aStatus = SMESH_Hypothesis::HYP_OK; } @@ -241,16 +289,58 @@ bool StdMeshers_Regular_1D::CheckHypothesis (dynamic_cast (theHyp)); ASSERT(hyp); _value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength( &aMesh, aShape ); -// _value[ BEG_LENGTH_IND ] = hyp->GetLength( &aMesh, aShape ); -// _value[ END_LENGTH_IND ] = Precision::Confusion(); // ?? or set to zero? ASSERT( _value[ BEG_LENGTH_IND ] > 0 ); _hypType = MAX_LENGTH; aStatus = SMESH_Hypothesis::HYP_OK; } + else if (hypName == "Adaptive1D") + { + _adaptiveHyp = dynamic_cast < const StdMeshers_Adaptive1D* >(theHyp); + ASSERT(_adaptiveHyp); + _hypType = ADAPTIVE; + _onlyUnaryInput = false; + aStatus = SMESH_Hypothesis::HYP_OK; + } else + { aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + } + + if ( propagTypes.size() > 1 && aStatus == HYP_OK ) + { + // detect concurrent Propagation hyps + _usedHypList.clear(); + list< TopoDS_Shape > assignedTo; + if ( aMesh.GetHypotheses( aShape, propagFilter, _usedHypList, true, &assignedTo ) > 1 ) + { + // find most simple shape and a hyp on it + int simpleShape = TopAbs_COMPOUND; + const SMESHDS_Hypothesis* localHyp = 0; + list< TopoDS_Shape >::iterator shape = assignedTo.begin(); + list< const SMESHDS_Hypothesis *>::iterator hyp = _usedHypList.begin(); + for ( ; shape != assignedTo.end(); ++shape ) + if ( shape->ShapeType() > simpleShape ) + { + simpleShape = shape->ShapeType(); + localHyp = (*hyp); + } + // check if there a different hyp on simpleShape + shape = assignedTo.begin(); + hyp = _usedHypList.begin(); + for ( ; hyp != _usedHypList.end(); ++hyp, ++shape ) + if ( shape->ShapeType() == simpleShape && + !localHyp->IsSameName( **hyp )) + { + aStatus = HYP_INCOMPAT_HYPS; + return error( SMESH_Comment("Hypotheses of both \"") + << StdMeshers_Propagation::GetName() << "\" and \"" + << StdMeshers_PropagOfDistribution::GetName() + << "\" types can't be applied to the same edge"); + } + } + } - return ( _hypType != NONE ); + return ( aStatus == SMESH_Hypothesis::HYP_OK ); } static bool computeParamByFunc(Adaptor3d_Curve& C3d, double first, double last, @@ -303,6 +393,8 @@ static bool computeParamByFunc(Adaptor3d_Curve& C3d, double first, double last, return false; prevU = U; } + if ( theReverse ) + theParams.reverse(); return true; } @@ -330,7 +422,7 @@ static void compensateError(double a1, double an, bool adjustNeighbors2an = false) { int i, nPar = theParams.size(); - if ( a1 + an < length && nPar > 1 ) + if ( a1 + an <= length && nPar > 1 ) { bool reverse = ( U1 > Un ); GCPnts_AbscissaPoint Discret(C3d, reverse ? an : -an, Un); @@ -351,14 +443,23 @@ static void compensateError(double a1, double an, dUn = Utgt - theParams.back(); } - double q = dUn / ( nPar - 1 ); - if ( !adjustNeighbors2an ) { - for ( itU = theParams.rbegin(), i = 1; i < nPar; itU++, i++ ) { + if ( !adjustNeighbors2an ) + { + double q = dUn / ( Utgt - Un ); // (signed) factor of segment length change + for ( itU = theParams.rbegin(), i = 1; i < nPar; i++ ) { + double prevU = *itU; (*itU) += dUn; - dUn -= q; + ++itU; + dUn = q * (*itU - prevU) * (prevU-U1)/(Un-U1); } } - else { + else if ( nPar == 1 ) + { + theParams.back() += dUn; + } + else + { + double q = dUn / ( nPar - 1 ); theParams.back() += dUn; double sign = reverse ? -1 : 1; double prevU = theParams.back(); @@ -527,17 +628,20 @@ void StdMeshers_Regular_1D::redistributeNearVertices (SMESH_Mesh & theM double Um = *itU++; double Lm = GCPnts_AbscissaPoint::Length( theC3d, Um, *itU); double L = GCPnts_AbscissaPoint::Length( theC3d, *itU, l); - StdMeshers_Regular_1D algo( *this ); - algo._hypType = BEG_END_LENGTH; - algo._value[ BEG_LENGTH_IND ] = Lm; - algo._value[ END_LENGTH_IND ] = vertexLength; + static StdMeshers_Regular_1D* auxAlgo = 0; + if ( !auxAlgo ) { + auxAlgo = new StdMeshers_Regular_1D( _gen->GetANewId(), _studyId, _gen ); + auxAlgo->_hypType = BEG_END_LENGTH; + } + auxAlgo->_value[ BEG_LENGTH_IND ] = Lm; + auxAlgo->_value[ END_LENGTH_IND ] = vertexLength; double from = *itU, to = l; if ( isEnd1 ) { std::swap( from, to ); - std::swap( algo._value[ BEG_LENGTH_IND ], algo._value[ END_LENGTH_IND ]); + std::swap( auxAlgo->_value[ BEG_LENGTH_IND ], auxAlgo->_value[ END_LENGTH_IND ]); } list params; - if ( algo.computeInternalParameters( theMesh, theC3d, L, from, to, params, false )) + if ( auxAlgo->computeInternalParameters( theMesh, theC3d, L, from, to, params, false )) { if ( isEnd1 ) params.reverse(); while ( 1 + nHalf-- ) @@ -573,6 +677,61 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, double f = theFirstU, l = theLastU; + // Propagation Of Distribution + // + if ( !_mainEdge.IsNull() && _isPropagOfDistribution ) + { + TopoDS_Edge mainEdge = TopoDS::Edge( _mainEdge ); // should not be a reference! + _gen->Compute( theMesh, mainEdge, /*aShapeOnly=*/true, /*anUpward=*/true); + + SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( mainEdge ); + if ( !smDS ) + return error("No mesh on the source edge of Propagation Of Distribution"); + if ( smDS->NbNodes() < 1 ) + return true; // 1 segment + + map< double, const SMDS_MeshNode* > mainEdgeParamsOfNodes; + if ( ! SMESH_Algo::GetSortedNodesOnEdge( theMesh.GetMeshDS(), mainEdge, _quadraticMesh, + mainEdgeParamsOfNodes, SMDSAbs_Edge )) + return error("Bad node parameters on the source edge of Propagation Of Distribution"); + + vector< double > segLen( mainEdgeParamsOfNodes.size() - 1 ); + double totalLen = 0; + BRepAdaptor_Curve mainEdgeCurve( mainEdge ); + map< double, const SMDS_MeshNode* >::iterator + u_n2 = mainEdgeParamsOfNodes.begin(), u_n1 = u_n2++; + for ( size_t i = 1; i < mainEdgeParamsOfNodes.size(); ++i, ++u_n1, ++u_n2 ) + { + segLen[ i-1 ] = GCPnts_AbscissaPoint::Length( mainEdgeCurve, + u_n1->first, + u_n2->first); + totalLen += segLen[ i-1 ]; + } + for ( size_t i = 0; i < segLen.size(); ++i ) + segLen[ i ] *= theLength / totalLen; + + size_t iSeg = theReverse ? segLen.size()-1 : 0; + size_t dSeg = theReverse ? -1 : +1; + double param = theFirstU; + int nbParams = 0; + for ( int i = 0, nb = segLen.size()-1; i < nb; ++i, iSeg += dSeg ) + { + GCPnts_AbscissaPoint Discret( theC3d, segLen[ iSeg ], param ); + if ( !Discret.IsDone() ) break; + param = Discret.Parameter(); + theParams.push_back( param ); + ++nbParams; + } + if ( nbParams != segLen.size()-1 ) + return error( SMESH_Comment("Can't divide into ") << segLen.size() << " segements"); + + compensateError( segLen[ theReverse ? segLen.size()-1 : 0 ], + segLen[ theReverse ? 0 : segLen.size()-1 ], + f, l, theLength, theC3d, theParams, true ); + return true; + } + + switch( _hypType ) { case LOCAL_LENGTH: @@ -580,12 +739,14 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, case NB_SEGMENTS: { double eltSize = 1; + int nbSegments; if ( _hypType == MAX_LENGTH ) { double nbseg = ceil(theLength / _value[ BEG_LENGTH_IND ]); // integer sup if (nbseg <= 0) nbseg = 1; // degenerated edge eltSize = theLength / nbseg; + nbSegments = (int) nbseg; } else if ( _hypType == LOCAL_LENGTH ) { @@ -602,7 +763,7 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, bool computed = sm->IsMeshComputed(); if (!computed) { if (sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE) { - sm->ComputeStateEngine(SMESH_subMesh::COMPUTE); + _gen->Compute( theMesh, _mainEdge, /*anUpward=*/true); computed = sm->IsMeshComputed(); } } @@ -626,13 +787,14 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, if (nbseg <= 0) nbseg = 1; // degenerated edge eltSize = theLength / nbseg; + nbSegments = (int) nbseg; } else { // Number Of Segments hypothesis - int NbSegm = _ivalue[ NB_SEGMENTS_IND ]; - if ( NbSegm < 1 ) return false; - if ( NbSegm == 1 ) return true; + nbSegments = _ivalue[ NB_SEGMENTS_IND ]; + if ( nbSegments < 1 ) return false; + if ( nbSegments == 1 ) return true; switch (_ivalue[ DISTR_TYPE_IND ]) { @@ -642,8 +804,8 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, if (fabs(scale - 1.0) < Precision::Confusion()) { // special case to avoid division by zero - for (int i = 1; i < NbSegm; i++) { - double param = f + (l - f) * i / NbSegm; + for (int i = 1; i < nbSegments; i++) { + double param = f + (l - f) * i / nbSegments; theParams.push_back( param ); } } else { @@ -651,14 +813,22 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, if ( theReverse ) scale = 1.0 / scale; - double alpha = pow(scale, 1.0 / (NbSegm - 1)); - double factor = (l - f) / (1.0 - pow(alpha, NbSegm)); + double alpha = pow(scale, 1.0 / (nbSegments - 1)); + double factor = (l - f) / (1.0 - pow(alpha, nbSegments)); - for (int i = 1; i < NbSegm; i++) { + for (int i = 1; i < nbSegments; i++) { double param = f + factor * (1.0 - pow(alpha, i)); theParams.push_back( param ); } } + const double lenFactor = theLength/(l-f); + list::iterator u = theParams.begin(), uEnd = theParams.end(); + for ( ; u != uEnd; ++u ) + { + GCPnts_AbscissaPoint Discret( theC3d, ((*u)-f) * lenFactor, f ); + if ( Discret.IsDone() ) + *u = Discret.Parameter(); + } return true; } break; @@ -679,7 +849,7 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, } break; case StdMeshers_NumberOfSegments::DT_Regular: - eltSize = theLength / _ivalue[ NB_SEGMENTS_IND ]; + eltSize = theLength / nbSegments; break; default: return false; @@ -689,13 +859,13 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, if ( !Discret.IsDone() ) return error( "GCPnts_UniformAbscissa failed"); - int NbPoints = Discret.NbPoints(); - for ( int i = 2; i < NbPoints; i++ ) + int NbPoints = Min( Discret.NbPoints(), nbSegments + 1 ); + for ( int i = 2; i < NbPoints; i++ ) // skip 1st and last points { double param = Discret.Parameter(i); theParams.push_back( param ); } - compensateError( eltSize, eltSize, f, l, theLength, theC3d, theParams ); // for PAL9899 + compensateError( eltSize, eltSize, f, l, theLength, theC3d, theParams, true ); // for PAL9899 return true; } @@ -706,6 +876,9 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, double a1 = _value[ BEG_LENGTH_IND ]; double an = _value[ END_LENGTH_IND ]; double q = ( theLength - a1 ) / ( theLength - an ); + if ( q < theLength/1e6 || 1.01*theLength < a1 + an) + return error ( SMESH_Comment("Invalid segment lengths (")< numeric_limits::min() ? ( 1+( an-a1 )/q ) : ( 1+theLength/a1 )); double U1 = theReverse ? l : f; double Un = theReverse ? f : l; @@ -764,6 +940,152 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, return true; } + case GEOMETRIC_1D: { + + double a1 = _value[ BEG_LENGTH_IND ], an; + double q = _value[ END_LENGTH_IND ]; + + double U1 = theReverse ? l : f; + double Un = theReverse ? f : l; + double param = U1; + double eltSize = a1; + if ( theReverse ) + eltSize = -eltSize; + + int nbParams = 0; + while ( true ) { + // computes a point on a curve at the distance + // from the point of parameter . + GCPnts_AbscissaPoint Discret( theC3d, eltSize, param ); + if ( !Discret.IsDone() ) break; + param = Discret.Parameter(); + if ( f < param && param < l ) + theParams.push_back( param ); + else + break; + an = eltSize; + eltSize *= q; + ++nbParams; + } + if ( nbParams > 1 ) + { + if ( Abs( param - Un ) < 0.2 * Abs( param - theParams.back() )) + { + compensateError( a1, Abs(eltSize), U1, Un, theLength, theC3d, theParams ); + } + else if ( Abs( Un - theParams.back() ) < + 0.2 * Abs( theParams.back() - *(++theParams.rbegin()))) + { + theParams.pop_back(); + compensateError( a1, Abs(an), U1, Un, theLength, theC3d, theParams ); + } + } + if (theReverse) theParams.reverse(); // NPAL18025 + + return true; + } + + case FIXED_POINTS_1D: { + const std::vector& aPnts = _fpHyp->GetPoints(); + const std::vector& nbsegs = _fpHyp->GetNbSegments(); + int i = 0; + TColStd_SequenceOfReal Params; + for(; i0.9999 ) continue; + int j=1; + bool IsExist = false; + for(; j<=Params.Length(); j++) { + if( fabs(aPnts[i]-Params.Value(j)) < 1e-4 ) { + IsExist = true; + break; + } + if( aPnts[i] nbsegs.size()-1 ) ? nbsegs[0] : nbsegs[i]; + segmentSize = Params.Value(i+1)*theLength - currAbscissa; + currAbscissa += segmentSize; + GCPnts_AbscissaPoint APnt(theC3d, sign*segmentSize, par1); + if( !APnt.IsDone() ) + return error( "GCPnts_AbscissaPoint failed"); + par2 = APnt.Parameter(); + eltSize = segmentSize/nbseg; + GCPnts_UniformAbscissa Discret(theC3d, eltSize, par1, par2); + if(theReverse) + Discret.Initialize(theC3d, eltSize, par2, par1); + else + Discret.Initialize(theC3d, eltSize, par1, par2); + if ( !Discret.IsDone() ) + return error( "GCPnts_UniformAbscissa failed"); + int NbPoints = Discret.NbPoints(); + list tmpParams; + for(int i=2; i::iterator itP = tmpParams.begin(); + for(; itP != tmpParams.end(); itP++) { + theParams.push_back( *(itP) ); + } + theParams.push_back( par2 ); + + par1 = par2; + } + // add for last + int nbseg = ( nbsegs.size() > Params.Length() ) ? nbsegs[Params.Length()] : nbsegs[0]; + segmentSize = theLength - currAbscissa; + eltSize = segmentSize/nbseg; + GCPnts_UniformAbscissa Discret; + if(theReverse) + Discret.Initialize(theC3d, eltSize, par1, lp); + else + Discret.Initialize(theC3d, eltSize, lp, par1); + if ( !Discret.IsDone() ) + return error( "GCPnts_UniformAbscissa failed"); + int NbPoints = Discret.NbPoints(); + list tmpParams; + for(int i=2; i::iterator itP = tmpParams.begin(); + for(; itP != tmpParams.end(); itP++) { + theParams.push_back( *(itP) ); + } + + if (theReverse) { + theParams.reverse(); // NPAL18025 + } + return true; + } + case DEFLECTION: { GCPnts_UniformDeflection Discret(theC3d, _value[ DEFLECTION_IND ], f, l, true); @@ -796,6 +1118,13 @@ bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & t if ( _hypType == NONE ) return false; + if ( _hypType == ADAPTIVE ) + { + _adaptiveHyp->GetAlgo()->InitComputeError(); + _adaptiveHyp->GetAlgo()->Compute( theMesh, theShape ); + return error( _adaptiveHyp->GetAlgo()->GetComputeError() ); + } + SMESHDS_Mesh * meshDS = theMesh.GetMeshDS(); const TopoDS_Edge & EE = TopoDS::Edge(theShape); @@ -815,12 +1144,46 @@ bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & t if (!idFirst || !idLast) return error( COMPERR_BAD_INPUT_MESH, "No node on vertex"); + // remove elements created by e.g. patern mapping (PAL21999) + // CLEAN event is incorrectly ptopagated seemingly due to Propagation hyp + // so TEMPORARY solution is to clean the submesh manually + //theMesh.GetSubMesh(theShape)->ComputeStateEngine( SMESH_subMesh::CLEAN ); + if (SMESHDS_SubMesh * subMeshDS = meshDS->MeshElements(theShape)) + { + SMDS_ElemIteratorPtr ite = subMeshDS->GetElements(); + while (ite->more()) + meshDS->RemoveFreeElement(ite->next(), subMeshDS); + SMDS_NodeIteratorPtr itn = subMeshDS->GetNodes(); + while (itn->more()) { + const SMDS_MeshNode * node = itn->next(); + if ( node->NbInverseElements() == 0 ) + meshDS->RemoveFreeNode(node, subMeshDS); + else + meshDS->RemoveNode(node); + } + } + if (!Curve.IsNull()) { list< double > params; bool reversed = false; - if ( !_mainEdge.IsNull() ) + if ( theMesh.GetShapeToMesh().ShapeType() >= TopAbs_WIRE ) { + // if the shape to mesh is WIRE or EDGE + reversed = ( EE.Orientation() == TopAbs_REVERSED ); + } + if ( !_mainEdge.IsNull() ) { + // take into account reversing the edge the hypothesis is propagated from + // (_mainEdge.Orientation() marks mutual orientation of EDGEs in propagation chain) reversed = ( _mainEdge.Orientation() == TopAbs_REVERSED ); + if ( !_isPropagOfDistribution ) { + int mainID = meshDS->ShapeToIndex(_mainEdge); + if ( std::find( _revEdgesIDs.begin(), _revEdgesIDs.end(), mainID) != _revEdgesIDs.end()) + reversed = !reversed; + } + } + // take into account this edge reversing + if ( std::find( _revEdgesIDs.begin(), _revEdgesIDs.end(), shapeID) != _revEdgesIDs.end()) + reversed = !reversed; BRepAdaptor_Curve C3d( E ); double length = EdgeLength( E ); @@ -845,7 +1208,6 @@ bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & t parLast = f; } */ - for (list::iterator itU = params.begin(); itU != params.end(); itU++) { double param = *itU; gp_Pnt P = Curve->Value(param); @@ -930,6 +1292,85 @@ bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & t return true; } + +//============================================================================= +/*! + * + */ +//============================================================================= + +bool StdMeshers_Regular_1D::Evaluate(SMESH_Mesh & theMesh, + const TopoDS_Shape & theShape, + MapShapeNbElems& aResMap) +{ + if ( _hypType == NONE ) + return false; + + if ( _hypType == ADAPTIVE ) + { + _adaptiveHyp->GetAlgo()->InitComputeError(); + _adaptiveHyp->GetAlgo()->Evaluate( theMesh, theShape, aResMap ); + return error( _adaptiveHyp->GetAlgo()->GetComputeError() ); + } + + const TopoDS_Edge & EE = TopoDS::Edge(theShape); + TopoDS_Edge E = TopoDS::Edge(EE.Oriented(TopAbs_FORWARD)); + + double f, l; + Handle(Geom_Curve) Curve = BRep_Tool::Curve(E, f, l); + + TopoDS_Vertex VFirst, VLast; + TopExp::Vertices(E, VFirst, VLast); // Vfirst corresponds to f and Vlast to l + + ASSERT(!VFirst.IsNull()); + ASSERT(!VLast.IsNull()); + + std::vector aVec(SMDSEntity_Last,0); + + if (!Curve.IsNull()) { + list< double > params; + + BRepAdaptor_Curve C3d( E ); + double length = EdgeLength( E ); + if ( ! computeInternalParameters( theMesh, C3d, length, f, l, params, false, true )) { + SMESH_subMesh * sm = theMesh.GetSubMesh(theShape); + aResMap.insert(std::make_pair(sm,aVec)); + SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); + smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); + return false; + } + redistributeNearVertices( theMesh, C3d, length, params, VFirst, VLast ); + + if(_quadraticMesh) { + aVec[SMDSEntity_Node] = 2*params.size() + 1; + aVec[SMDSEntity_Quad_Edge] = params.size() + 1; + } + else { + aVec[SMDSEntity_Node] = params.size(); + aVec[SMDSEntity_Edge] = params.size() + 1; + } + + } + else { + //MESSAGE("************* Degenerated edge! *****************"); + // Edge is a degenerated Edge : We put n = 5 points on the edge. + if(_quadraticMesh) { + aVec[SMDSEntity_Node] = 11; + aVec[SMDSEntity_Quad_Edge] = 6; + } + else { + aVec[SMDSEntity_Node] = 5; + aVec[SMDSEntity_Edge] = 6; + } + } + + SMESH_subMesh * sm = theMesh.GetSubMesh(theShape); + aResMap.insert(std::make_pair(sm,aVec)); + + return true; +} + + //============================================================================= /*! * See comments in SMESH_Algo.cxx @@ -944,23 +1385,22 @@ StdMeshers_Regular_1D::GetUsedHypothesis(SMESH_Mesh & aMesh, _usedHypList.clear(); _mainEdge.Nullify(); - SMESH_HypoFilter auxiliaryFilter, compatibleFilter; - auxiliaryFilter.Init( SMESH_HypoFilter::IsAuxiliary() ); - const bool ignoreAux = true; - InitCompatibleHypoFilter( compatibleFilter, ignoreAux ); + SMESH_HypoFilter auxiliaryFilter( SMESH_HypoFilter::IsAuxiliary() ); + const SMESH_HypoFilter* compatibleFilter = GetCompatibleHypoFilter(/*ignoreAux=*/true ); - // get non-auxiliary assigned to aShape - int nbHyp = aMesh.GetHypotheses( aShape, compatibleFilter, _usedHypList, false ); + // get non-auxiliary assigned directly to aShape + int nbHyp = aMesh.GetHypotheses( aShape, *compatibleFilter, _usedHypList, false ); if (nbHyp == 0 && aShape.ShapeType() == TopAbs_EDGE) { // Check, if propagated from some other edge - _mainEdge = StdMeshers_Propagation::GetPropagationSource( aMesh, aShape ); + _mainEdge = StdMeshers_Propagation::GetPropagationSource( aMesh, aShape, + _isPropagOfDistribution ); if ( !_mainEdge.IsNull() ) { // Propagation of 1D hypothesis from on this edge; // get non-auxiliary assigned to _mainEdge - nbHyp = aMesh.GetHypotheses( _mainEdge, compatibleFilter, _usedHypList, true ); + nbHyp = aMesh.GetHypotheses( _mainEdge, *compatibleFilter, _usedHypList, true ); } } @@ -979,3 +1419,16 @@ StdMeshers_Regular_1D::GetUsedHypothesis(SMESH_Mesh & aMesh, return _usedHypList; } + +//================================================================================ +/*! + * \brief Pass CancelCompute() to a child algorithm + */ +//================================================================================ + +void StdMeshers_Regular_1D::CancelCompute() +{ + SMESH_Algo::CancelCompute(); + if ( _hypType == ADAPTIVE ) + _adaptiveHyp->GetAlgo()->CancelCompute(); +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Reversible1D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Reversible1D.cpp new file mode 100644 index 000000000000..010e1a50bb72 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Reversible1D.cpp @@ -0,0 +1,99 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 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, or (at your option) any later version. +// +// 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 +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// File : StdMeshers_Reversible1D.cxx +// Module : SMESH +// + +#include "StdMeshers_Reversible1D.hxx" + +//============================================================================= +/*! + * + */ +//============================================================================= + +StdMeshers_Reversible1D::StdMeshers_Reversible1D(int hypId, int studyId, SMESH_Gen * gen) + :SMESH_Hypothesis(hypId, studyId, gen) +{ + _param_algo_dim = 1; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +void StdMeshers_Reversible1D::SetReversedEdges( const std::vector& ids ) +{ + if ( ids != _edgeIDs ) + { + _edgeIDs = ids; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +std::ostream & StdMeshers_Reversible1D::SaveTo(std::ostream & save) +{ + save << " " << _edgeIDs.size() << " "; + + if ( !_edgeIDs.empty() ) + { + for ( size_t i = 0; i < _edgeIDs.size(); i++) + save << " " << _edgeIDs[i]; + save << " " << _objEntry << " "; + } + + return save; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +std::istream & StdMeshers_Reversible1D::LoadFrom(std::istream & load) +{ + bool isOK; + int intVal; + + isOK = (bool)(load >> intVal); + if (isOK && intVal > 0) { + _edgeIDs.reserve( intVal ); + for (int i = 0; i < _edgeIDs.capacity() && isOK; i++) { + isOK = (bool)(load >> intVal); + if ( isOK ) _edgeIDs.push_back( intVal ); + } + isOK = (bool)(load >> _objEntry); + } + + return load; +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_SegmentAroundVertex_0D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_SegmentAroundVertex_0D.cpp index 1b859592b5e3..9036dc18bc69 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_SegmentAroundVertex_0D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_SegmentAroundVertex_0D.cpp @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_SegmentAroundVertex_0D.cxx // Module : SMESH @@ -27,8 +28,6 @@ // #include "StdMeshers_SegmentAroundVertex_0D.hxx" -using namespace std; - //======================================================================= //function : StdMeshers_SegmentAroundVertex_0D //purpose : @@ -40,7 +39,7 @@ StdMeshers_SegmentAroundVertex_0D::StdMeshers_SegmentAroundVertex_0D { _name = "SegmentAroundVertex_0D"; // it is assigned to vertices but influence a state of EDGE submeshes - _shapeType = (1 << TopAbs_VERTEX); // 1 bit per shape type + _shapeType = (1 << TopAbs_VERTEX); // 1 bit per shape type _compatibleHypothesis.push_back("SegmentLengthAroundVertex"); } @@ -94,3 +93,18 @@ bool StdMeshers_SegmentAroundVertex_0D::Compute(SMESH_Mesh&, const TopoDS_Shape& // StdMeshers_SegmentLengthAroundVertex hypothesis return true; } + + +//======================================================================= +//function : Evaluate +//purpose : +//======================================================================= + +bool StdMeshers_SegmentAroundVertex_0D::Evaluate(SMESH_Mesh&, + const TopoDS_Shape&, + MapShapeNbElems&) +{ + // This algorithm exists in order just to enable assignation of + // StdMeshers_SegmentLengthAroundVertex hypothesis + return false; +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_SegmentLengthAroundVertex.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_SegmentLengthAroundVertex.cpp index 7ccdf956896f..c4923cccbc71 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_SegmentLengthAroundVertex.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_SegmentLengthAroundVertex.cpp @@ -1,28 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_SegmentLengthAroundVertex.cxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_SegmentLengthAroundVertex.cxx,v 1.2.2.1 2008/11/27 13:03:49 abd Exp $ // #include "StdMeshers_SegmentLengthAroundVertex.hxx" @@ -74,10 +74,10 @@ StdMeshers_SegmentLengthAroundVertex::~StdMeshers_SegmentLengthAroundVertex() */ //============================================================================= -void StdMeshers_SegmentLengthAroundVertex::SetLength(double length) throw(SMESH_Exception) +void StdMeshers_SegmentLengthAroundVertex::SetLength(double length) throw(SALOME_Exception) { if (length <= 0) - throw SMESH_Exception(LOCALIZED("length must be positive")); + throw SALOME_Exception(LOCALIZED("length must be positive")); if (_length != length) { _length = length; NotifySubMeshesHypothesisModification(); @@ -117,7 +117,7 @@ istream & StdMeshers_SegmentLengthAroundVertex::LoadFrom(istream & load) { bool isOK = true; double a; - isOK = !(load >> a).bad(); + isOK = (bool)(load >> a); if (isOK) this->_length = a; else @@ -213,3 +213,4 @@ bool StdMeshers_SegmentLengthAroundVertex::SetParametersByDefaults(const TDefaul { return false; } + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_StartEndLength.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_StartEndLength.cpp index 01cef56d174b..7a2ba18a098b 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_StartEndLength.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_StartEndLength.cpp @@ -1,28 +1,28 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 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 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, or (at your option) any later version. // -// 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. +// 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 +// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH StdMeshers_StartEndLength : implementaion of SMESH idl descriptions // File : StdMeshers_StartEndLength.cxx // Module : SMESH -// $Header: /home/server/cvs/SMESH/SMESH_SRC/src/StdMeshers/StdMeshers_StartEndLength.cxx,v 1.8.2.1 2008/11/27 13:03:49 abd Exp $ // #include "StdMeshers_StartEndLength.hxx" @@ -75,11 +75,11 @@ StdMeshers_StartEndLength::~StdMeshers_StartEndLength() //============================================================================= void StdMeshers_StartEndLength::SetLength(double length, bool isStartLength) - throw(SMESH_Exception) + throw(SALOME_Exception) { if ( (isStartLength ? _begLength : _endLength) != length ) { if (length <= 0) - throw SMESH_Exception(LOCALIZED("length must be positive")); + throw SALOME_Exception(LOCALIZED("length must be positive")); if ( isStartLength ) _begLength = length; else @@ -106,9 +106,33 @@ double StdMeshers_StartEndLength::GetLength(bool isStartLength) const */ //============================================================================= +void StdMeshers_StartEndLength::SetReversedEdges( std::vector& ids ) +{ + if ( ids != _edgeIDs ) { + _edgeIDs = ids; + + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= + ostream & StdMeshers_StartEndLength::SaveTo(ostream & save) { - save << _begLength << " " <<_endLength; + int listSize = _edgeIDs.size(); + save << _begLength << " " << _endLength << " " << listSize; + + if ( listSize > 0 ) { + for ( int i = 0; i < listSize; i++) { + save << " " << _edgeIDs[i]; + } + save << " " << _objEntry; + } + return save; } @@ -121,12 +145,25 @@ ostream & StdMeshers_StartEndLength::SaveTo(ostream & save) istream & StdMeshers_StartEndLength::LoadFrom(istream & load) { bool isOK = true; - isOK = !(load >> _begLength).bad(); + int intVal; + isOK = (bool)(load >> _begLength); if (!isOK) load.clear(ios::badbit | load.rdstate()); - isOK = !(load >> _endLength).bad(); + isOK = (bool)(load >> _endLength); + if (!isOK) load.clear(ios::badbit | load.rdstate()); + + isOK = (bool)(load >> intVal); + if (isOK && intVal > 0) { + _edgeIDs.reserve( intVal ); + for (int i = 0; i < _edgeIDs.capacity() && isOK; i++) { + isOK = (bool)(load >> intVal); + if ( isOK ) _edgeIDs.push_back( intVal ); + } + isOK = (bool)(load >> _objEntry); + } + return load; } @@ -179,7 +216,7 @@ bool StdMeshers_StartEndLength::SetParametersByMesh(const SMESH_Mesh* theMesh, { const TopoDS_Edge& edge = TopoDS::Edge( edgeMap( i )); Handle(Geom_Curve) C = BRep_Tool::Curve(edge, L, UMin, UMax); - GeomAdaptor_Curve AdaptCurve(C); + GeomAdaptor_Curve AdaptCurve(C, UMin, UMax); vector< double > params; SMESHDS_Mesh* aMeshDS = const_cast< SMESH_Mesh* >( theMesh )->GetMeshDS(); @@ -210,3 +247,4 @@ bool StdMeshers_StartEndLength::SetParametersByDefaults(const TDefaults& dflts, { return (_begLength = _endLength = dflts._elemLength ); } + diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_UseExisting_1D2D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_UseExisting_1D2D.cpp index e44345af4287..6164ef2cf003 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_UseExisting_1D2D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_UseExisting_1D2D.cpp @@ -1,24 +1,22 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 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, or (at your option) any later version. // -// 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. // -// 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 // -// 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_UseExisting_1D2D.cxx // Module : SMESH @@ -27,6 +25,9 @@ // #include "StdMeshers_UseExisting_1D2D.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_subMesh.hxx" + //======================================================================= //function : StdMeshers_UseExisting_1D //purpose : @@ -58,12 +59,30 @@ bool StdMeshers_UseExisting_1D::CheckHypothesis(SMESH_Mesh& , //purpose : //======================================================================= -bool StdMeshers_UseExisting_1D::Compute(SMESH_Mesh&, const TopoDS_Shape&) +bool StdMeshers_UseExisting_1D::Compute(SMESH_Mesh& mesh, const TopoDS_Shape& edge) { - // This algorithm exists to allow mesh generation by mesh edition functions in TUI mode + // This algorithm exists to allow mesh generation by mesh + // edition functions in TUI mode + mesh.GetSubMesh( edge )->SetIsAlwaysComputed( true ); return true; } + +//======================================================================= +//function : Evaluate +//purpose : +//======================================================================= + +bool StdMeshers_UseExisting_1D::Evaluate(SMESH_Mesh&, + const TopoDS_Shape&, + MapShapeNbElems&) +{ + // This algorithm exists to allow mesh generation by mesh + // edition functions in TUI mode + return false; +} + + //======================================================================= //function : StdMeshers_UseExisting_2D //purpose : @@ -95,8 +114,25 @@ bool StdMeshers_UseExisting_2D::CheckHypothesis(SMESH_Mesh& , //purpose : //======================================================================= -bool StdMeshers_UseExisting_2D::Compute(SMESH_Mesh&, const TopoDS_Shape&) +bool StdMeshers_UseExisting_2D::Compute(SMESH_Mesh& mesh, const TopoDS_Shape& face) { - // This algorithm exists to allow mesh generation by mesh edition functions in TUI mode + // This algorithm exists to allow mesh generation by mesh edition + // functions in TUI mode + mesh.GetSubMesh( face )->SetIsAlwaysComputed( true ); return true; } + + +//======================================================================= +//function : Evaluate +//purpose : +//======================================================================= + +bool StdMeshers_UseExisting_2D::Evaluate(SMESH_Mesh&, + const TopoDS_Shape&, + MapShapeNbElems&) +{ + // This algorithm exists to allow mesh generation by mesh edition + // functions in TUI mode + return false; +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ViscousLayers.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ViscousLayers.cpp new file mode 100644 index 000000000000..f19ea54b83d7 --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ViscousLayers.cpp @@ -0,0 +1,7799 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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_ViscousLayers.cxx +// Created : Wed Dec 1 15:15:34 2010 +// Author : Edward AGAPOV (eap) + +#include "StdMeshers_ViscousLayers.hxx" + +#include "SMDS_EdgePosition.hxx" +#include "SMDS_FaceOfNodes.hxx" +#include "SMDS_FacePosition.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMDS_SetIterator.hxx" +#include "SMESHDS_Group.hxx" +#include "SMESHDS_Hypothesis.hxx" +#include "SMESH_Algo.hxx" +#include "SMESH_ComputeError.hxx" +#include "SMESH_ControlsDef.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_Group.hxx" +#include "SMESH_HypoFilter.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MeshAlgos.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_ProxyMesh.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_subMeshEventListener.hxx" +#include "StdMeshers_FaceSide.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef _DEBUG_ +//#define __myDEBUG +//#define __NOT_INVALIDATE_BAD_SMOOTH +#endif + +using namespace std; + +//================================================================================ +namespace VISCOUS_3D +{ + typedef int TGeomID; + + enum UIndex { U_TGT = 1, U_SRC, LEN_TGT }; + + const double theMinSmoothCosin = 0.1; + const double theSmoothThickToElemSizeRatio = 0.3; + + // what part of thickness is allowed till intersection + // (defined by SALOME_TESTS/Grids/smesh/viscous_layers_00/A5) + const double theThickToIntersection = 1.5; + + bool needSmoothing( double cosin, double tgtThick, double elemSize ) + { + return cosin * tgtThick > theSmoothThickToElemSizeRatio * elemSize; + } + + /*! + * \brief SMESH_ProxyMesh computed by _ViscousBuilder for a SOLID. + * It is stored in a SMESH_subMesh of the SOLID as SMESH_subMeshEventListenerData + */ + struct _MeshOfSolid : public SMESH_ProxyMesh, + public SMESH_subMeshEventListenerData + { + bool _n2nMapComputed; + SMESH_ComputeErrorPtr _warning; + + _MeshOfSolid( SMESH_Mesh* mesh) + :SMESH_subMeshEventListenerData( /*isDeletable=*/true),_n2nMapComputed(false) + { + SMESH_ProxyMesh::setMesh( *mesh ); + } + + // returns submesh for a geom face + SMESH_ProxyMesh::SubMesh* getFaceSubM(const TopoDS_Face& F, bool create=false) + { + TGeomID i = SMESH_ProxyMesh::shapeIndex(F); + return create ? SMESH_ProxyMesh::getProxySubMesh(i) : findProxySubMesh(i); + } + void setNode2Node(const SMDS_MeshNode* srcNode, + const SMDS_MeshNode* proxyNode, + const SMESH_ProxyMesh::SubMesh* subMesh) + { + SMESH_ProxyMesh::setNode2Node( srcNode,proxyNode,subMesh); + } + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Listener of events of 3D sub-meshes computed with viscous layers. + * It is used to clear an inferior dim sub-meshes modified by viscous layers + */ + class _ShrinkShapeListener : SMESH_subMeshEventListener + { + _ShrinkShapeListener() + : SMESH_subMeshEventListener(/*isDeletable=*/false, + "StdMeshers_ViscousLayers::_ShrinkShapeListener") {} + public: + static SMESH_subMeshEventListener* Get() { static _ShrinkShapeListener l; return &l; } + virtual void ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* solidSM, + SMESH_subMeshEventListenerData* data, + const SMESH_Hypothesis* hyp) + { + if ( SMESH_subMesh::COMPUTE_EVENT == eventType && solidSM->IsEmpty() && data ) + { + SMESH_subMeshEventListener::ProcessEvent(event,eventType,solidSM,data,hyp); + } + } + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Listener of events of 3D sub-meshes computed with viscous layers. + * It is used to store data computed by _ViscousBuilder for a sub-mesh and to + * delete the data as soon as it has been used + */ + class _ViscousListener : SMESH_subMeshEventListener + { + _ViscousListener(): + SMESH_subMeshEventListener(/*isDeletable=*/false, + "StdMeshers_ViscousLayers::_ViscousListener") {} + static SMESH_subMeshEventListener* Get() { static _ViscousListener l; return &l; } + public: + virtual void ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* subMesh, + SMESH_subMeshEventListenerData* data, + const SMESH_Hypothesis* hyp) + { + if ( SMESH_subMesh::COMPUTE_EVENT == eventType && + SMESH_subMesh::CHECK_COMPUTE_STATE != event) + { + // delete SMESH_ProxyMesh containing temporary faces + subMesh->DeleteEventListener( this ); + } + } + // Finds or creates proxy mesh of the solid + static _MeshOfSolid* GetSolidMesh(SMESH_Mesh* mesh, + const TopoDS_Shape& solid, + bool toCreate=false) + { + if ( !mesh ) return 0; + SMESH_subMesh* sm = mesh->GetSubMesh(solid); + _MeshOfSolid* data = (_MeshOfSolid*) sm->GetEventListenerData( Get() ); + if ( !data && toCreate ) + { + data = new _MeshOfSolid(mesh); + data->mySubMeshes.push_back( sm ); // to find SOLID by _MeshOfSolid + sm->SetEventListener( Get(), data, sm ); + } + return data; + } + // Removes proxy mesh of the solid + static void RemoveSolidMesh(SMESH_Mesh* mesh, const TopoDS_Shape& solid) + { + mesh->GetSubMesh(solid)->DeleteEventListener( _ViscousListener::Get() ); + } + }; + + //================================================================================ + /*! + * \brief sets a sub-mesh event listener to clear sub-meshes of sub-shapes of + * the main shape when sub-mesh of the main shape is cleared, + * for example to clear sub-meshes of FACEs when sub-mesh of a SOLID + * is cleared + */ + //================================================================================ + + void ToClearSubWithMain( SMESH_subMesh* sub, const TopoDS_Shape& main) + { + SMESH_subMesh* mainSM = sub->GetFather()->GetSubMesh( main ); + SMESH_subMeshEventListenerData* data = + mainSM->GetEventListenerData( _ShrinkShapeListener::Get()); + if ( data ) + { + if ( find( data->mySubMeshes.begin(), data->mySubMeshes.end(), sub ) == + data->mySubMeshes.end()) + data->mySubMeshes.push_back( sub ); + } + else + { + data = SMESH_subMeshEventListenerData::MakeData( /*dependent=*/sub ); + sub->SetEventListener( _ShrinkShapeListener::Get(), data, /*whereToListenTo=*/mainSM ); + } + } + struct _SolidData; + //-------------------------------------------------------------------------------- + /*! + * \brief Simplex (triangle or tetrahedron) based on 1 (tria) or 2 (tet) nodes of + * _LayerEdge and 2 nodes of the mesh surface beening smoothed. + * The class is used to check validity of face or volumes around a smoothed node; + * it stores only 2 nodes as the other nodes are stored by _LayerEdge. + */ + struct _Simplex + { + const SMDS_MeshNode *_nPrev, *_nNext; // nodes on a smoothed mesh surface + const SMDS_MeshNode *_nOpp; // in 2D case, a node opposite to a smoothed node in QUAD + _Simplex(const SMDS_MeshNode* nPrev=0, + const SMDS_MeshNode* nNext=0, + const SMDS_MeshNode* nOpp=0) + : _nPrev(nPrev), _nNext(nNext), _nOpp(nOpp) {} + bool IsForward(const SMDS_MeshNode* nSrc, const gp_XYZ* pntTgt, double& vol) const + { + const double M[3][3] = + {{ _nNext->X() - nSrc->X(), _nNext->Y() - nSrc->Y(), _nNext->Z() - nSrc->Z() }, + { pntTgt->X() - nSrc->X(), pntTgt->Y() - nSrc->Y(), pntTgt->Z() - nSrc->Z() }, + { _nPrev->X() - nSrc->X(), _nPrev->Y() - nSrc->Y(), _nPrev->Z() - nSrc->Z() }}; + vol = ( + M[0][0]*M[1][1]*M[2][2] + + M[0][1]*M[1][2]*M[2][0] + + M[0][2]*M[1][0]*M[2][1] + - M[0][0]*M[1][2]*M[2][1] + - M[0][1]*M[1][0]*M[2][2] + - M[0][2]*M[1][1]*M[2][0]); + return vol > 1e-100; + } + bool IsForward(const gp_XY& tgtUV, + const SMDS_MeshNode* smoothedNode, + const TopoDS_Face& face, + SMESH_MesherHelper& helper, + const double refSign) const + { + gp_XY prevUV = helper.GetNodeUV( face, _nPrev, smoothedNode ); + gp_XY nextUV = helper.GetNodeUV( face, _nNext, smoothedNode ); + gp_Vec2d v1( tgtUV, prevUV ), v2( tgtUV, nextUV ); + double d = v1 ^ v2; + return d*refSign > 1e-100; + } + bool IsNeighbour(const _Simplex& other) const + { + return _nPrev == other._nNext || _nNext == other._nPrev; + } + static void GetSimplices( const SMDS_MeshNode* node, + vector<_Simplex>& simplices, + const set& ingnoreShapes, + const _SolidData* dataToCheckOri = 0, + const bool toSort = false); + static void SortSimplices(vector<_Simplex>& simplices); + }; + //-------------------------------------------------------------------------------- + /*! + * Structure used to take into account surface curvature while smoothing + */ + struct _Curvature + { + double _r; // radius + double _k; // factor to correct node smoothed position + double _h2lenRatio; // avgNormProj / (2*avgDist) + public: + static _Curvature* New( double avgNormProj, double avgDist ) + { + _Curvature* c = 0; + if ( fabs( avgNormProj / avgDist ) > 1./200 ) + { + c = new _Curvature; + c->_r = avgDist * avgDist / avgNormProj; + c->_k = avgDist * avgDist / c->_r / c->_r; + //c->_k = avgNormProj / c->_r; + c->_k *= ( c->_r < 0 ? 1/1.1 : 1.1 ); // not to be too restrictive + c->_h2lenRatio = avgNormProj / ( avgDist + avgDist ); + } + return c; + } + double lenDelta(double len) const { return _k * ( _r + len ); } + double lenDeltaByDist(double dist) const { return dist * _h2lenRatio; } + }; + //-------------------------------------------------------------------------------- + + struct _2NearEdges; + struct _LayerEdge; + struct _EdgesOnShape; + typedef map< const SMDS_MeshNode*, _LayerEdge*, TIDCompare > TNode2Edge; + + //-------------------------------------------------------------------------------- + /*! + * \brief Edge normal to surface, connecting a node on solid surface (_nodes[0]) + * and a node of the most internal layer (_nodes.back()) + */ + struct _LayerEdge + { + typedef gp_XYZ (_LayerEdge::*PSmooFun)(); + + vector< const SMDS_MeshNode*> _nodes; + + gp_XYZ _normal; // to solid surface + vector _pos; // points computed during inflation + double _len; // length achived with the last inflation step + double _cosin; // of angle (_normal ^ surface) + double _lenFactor; // to compute _len taking _cosin into account + + // face or edge w/o layer along or near which _LayerEdge is inflated + //TopoDS_Shape* _sWOL; + // simplices connected to the source node (_nodes[0]); + // used for smoothing and quality check of _LayerEdge's based on the FACE + vector<_Simplex> _simplices; + PSmooFun _smooFunction; // smoothing function + // data for smoothing of _LayerEdge's based on the EDGE + _2NearEdges* _2neibors; + + _Curvature* _curvature; + // TODO:: detele _Curvature, _plnNorm + + void SetNewLength( double len, _EdgesOnShape& eos, SMESH_MesherHelper& helper ); + bool SetNewLength2d( Handle(Geom_Surface)& surface, + const TopoDS_Face& F, + _EdgesOnShape& eos, + SMESH_MesherHelper& helper ); + void SetDataByNeighbors( const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const _EdgesOnShape& eos, + SMESH_MesherHelper& helper); + void InvalidateStep( int curStep, const _EdgesOnShape& eos, bool restoreLength=false ); + void ChooseSmooFunction(const set< TGeomID >& concaveVertices, + const TNode2Edge& n2eMap); + int Smooth(const int step, const bool isConcaveFace, const bool findBest); + bool SmoothOnEdge(Handle(Geom_Surface)& surface, + const TopoDS_Face& F, + SMESH_MesherHelper& helper); + bool FindIntersection( SMESH_ElementSearcher& searcher, + double & distance, + const double& epsilon, + _EdgesOnShape& eos, + const SMDS_MeshElement** face = 0); + bool SegTriaInter( const gp_Ax1& lastSegment, + const SMDS_MeshNode* n0, + const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + double& dist, + const double& epsilon) const; + gp_Ax1 LastSegment(double& segLen, _EdgesOnShape& eos) const; + gp_XY LastUV( const TopoDS_Face& F, _EdgesOnShape& eos ) const; + bool IsOnEdge() const { return _2neibors; } + gp_XYZ Copy( _LayerEdge& other, _EdgesOnShape& eos, SMESH_MesherHelper& helper ); + void SetCosin( double cosin ); + int NbSteps() const { return _pos.size() - 1; } // nb inlation steps + + gp_XYZ smoothLaplacian(); + gp_XYZ smoothAngular(); + gp_XYZ smoothLengthWeighted(); + gp_XYZ smoothCentroidal(); + gp_XYZ smoothNefPolygon(); + + enum { FUN_LAPLACIAN, FUN_LENWEIGHTED, FUN_CENTROIDAL, FUN_NEFPOLY, FUN_ANGULAR, FUN_NB }; + static const int theNbSmooFuns = FUN_NB; + static PSmooFun _funs[theNbSmooFuns]; + static const char* _funNames[theNbSmooFuns+1]; + int smooFunID( PSmooFun fun=0) const; + }; + _LayerEdge::PSmooFun _LayerEdge::_funs[theNbSmooFuns] = { &_LayerEdge::smoothLaplacian, + &_LayerEdge::smoothLengthWeighted, + &_LayerEdge::smoothCentroidal, + &_LayerEdge::smoothNefPolygon, + &_LayerEdge::smoothAngular }; + const char* _LayerEdge::_funNames[theNbSmooFuns+1] = { "Laplacian", + "LengthWeighted", + "Centroidal", + "NefPolygon", + "Angular", + "None"}; + struct _LayerEdgeCmp + { + bool operator () (const _LayerEdge* e1, const _LayerEdge* e2) const + { + const bool cmpNodes = ( e1 && e2 && e1->_nodes.size() && e2->_nodes.size() ); + return cmpNodes ? ( e1->_nodes[0]->GetID() < e2->_nodes[0]->GetID()) : ( e1 < e2 ); + } + }; + //-------------------------------------------------------------------------------- + /*! + * A 2D half plane used by _LayerEdge::smoothNefPolygon() + */ + struct _halfPlane + { + gp_XY _pos, _dir, _inNorm; + bool IsOut( const gp_XY p, const double tol ) const + { + return _inNorm * ( p - _pos ) < -tol; + } + bool FindInterestion( const _halfPlane& hp, gp_XY & intPnt ) + { + const double eps = 1e-10; + double D = _dir.Crossed( hp._dir ); + if ( fabs(D) < std::numeric_limits::min()) + return false; + gp_XY vec21 = _pos - hp._pos; + double u = hp._dir.Crossed( vec21 ) / D; + intPnt = _pos + _dir * u; + return true; + } + }; + //-------------------------------------------------------------------------------- + /*! + * Structure used to smooth a _LayerEdge based on an EDGE. + */ + struct _2NearEdges + { + double _wgt [2]; // weights of _nodes + _LayerEdge* _edges[2]; + + // normal to plane passing through _LayerEdge._normal and tangent of EDGE + gp_XYZ* _plnNorm; + + _2NearEdges() { _edges[0]=_edges[1]=0; _plnNorm = 0; } + const SMDS_MeshNode* tgtNode(bool is2nd) { + return _edges[is2nd] ? _edges[is2nd]->_nodes.back() : 0; + } + const SMDS_MeshNode* srcNode(bool is2nd) { + return _edges[is2nd] ? _edges[is2nd]->_nodes[0] : 0; + } + void reverse() { + std::swap( _wgt [0], _wgt [1] ); + std::swap( _edges[0], _edges[1] ); + } + }; + + + //-------------------------------------------------------------------------------- + /*! + * \brief Layers parameters got by averaging several hypotheses + */ + struct AverageHyp + { + AverageHyp( const StdMeshers_ViscousLayers* hyp = 0 ) + :_nbLayers(0), _nbHyps(0), _thickness(0), _stretchFactor(0), _method(0) + { + Add( hyp ); + } + void Add( const StdMeshers_ViscousLayers* hyp ) + { + if ( hyp ) + { + _nbHyps++; + _nbLayers = hyp->GetNumberLayers(); + //_thickness += hyp->GetTotalThickness(); + _thickness = Max( _thickness, hyp->GetTotalThickness() ); + _stretchFactor += hyp->GetStretchFactor(); + _method = hyp->GetMethod(); + } + } + double GetTotalThickness() const { return _thickness; /*_nbHyps ? _thickness / _nbHyps : 0;*/ } + double GetStretchFactor() const { return _nbHyps ? _stretchFactor / _nbHyps : 0; } + int GetNumberLayers() const { return _nbLayers; } + int GetMethod() const { return _method; } + + bool UseSurfaceNormal() const + { return _method == StdMeshers_ViscousLayers::SURF_OFFSET_SMOOTH; } + bool ToSmooth() const + { return _method == StdMeshers_ViscousLayers::SURF_OFFSET_SMOOTH; } + bool IsOffsetMethod() const + { return _method == StdMeshers_ViscousLayers::FACE_OFFSET; } + + private: + int _nbLayers, _nbHyps, _method; + double _thickness, _stretchFactor; + }; + + //-------------------------------------------------------------------------------- + /*! + * \brief _LayerEdge's on a shape and other shape data + */ + struct _EdgesOnShape + { + vector< _LayerEdge* > _edges; + + TopoDS_Shape _shape; + TGeomID _shapeID; + SMESH_subMesh * _subMesh; + // face or edge w/o layer along or near which _edges are inflated + TopoDS_Shape _sWOL; + // averaged StdMeshers_ViscousLayers parameters + AverageHyp _hyp; + bool _toSmooth; + + vector< gp_XYZ > _faceNormals; // if _shape is FACE + vector< _EdgesOnShape* > _faceEOS; // to get _faceNormals of adjacent FACEs + + TopAbs_ShapeEnum ShapeType() const + { return _shape.IsNull() ? TopAbs_SHAPE : _shape.ShapeType(); } + TopAbs_ShapeEnum SWOLType() const + { return _sWOL.IsNull() ? TopAbs_SHAPE : _sWOL.ShapeType(); } + bool GetNormal( const SMDS_MeshElement* face, gp_Vec& norm ); + }; + + //-------------------------------------------------------------------------------- + /*! + * \brief Convex FACE whose radius of curvature is less than the thickness of + * layers. It is used to detect distortion of prisms based on a convex + * FACE and to update normals to enable further increasing the thickness + */ + struct _ConvexFace + { + TopoDS_Face _face; + + // edges whose _simplices are used to detect prism destorsion + vector< _LayerEdge* > _simplexTestEdges; + + // map a sub-shape to _SolidData::_edgesOnShape + map< TGeomID, _EdgesOnShape* > _subIdToEOS; + + bool _normalsFixed; + + bool GetCenterOfCurvature( _LayerEdge* ledge, + BRepLProp_SLProps& surfProp, + SMESH_MesherHelper& helper, + gp_Pnt & center ) const; + bool CheckPrisms() const; + }; + + //-------------------------------------------------------------------------------- + /*! + * \brief Data of a SOLID + */ + struct _SolidData + { + typedef const StdMeshers_ViscousLayers* THyp; + TopoDS_Shape _solid; + TGeomID _index; // SOLID id + _MeshOfSolid* _proxyMesh; + list< THyp > _hyps; + list< TopoDS_Shape > _hypShapes; + map< TGeomID, THyp > _face2hyp; // filled if _hyps.size() > 1 + set< TGeomID > _reversedFaceIds; + set< TGeomID > _ignoreFaceIds; // WOL FACEs and FACEs of other SOLIDs + + double _stepSize, _stepSizeCoeff, _geomSize; + const SMDS_MeshNode* _stepSizeNodes[2]; + + TNode2Edge _n2eMap; // nodes and _LayerEdge's based on them + + // map to find _n2eMap of another _SolidData by a shrink shape shared by two _SolidData's + map< TGeomID, TNode2Edge* > _s2neMap; + // _LayerEdge's with underlying shapes + vector< _EdgesOnShape > _edgesOnShape; + + // key: an id of shape (EDGE or VERTEX) shared by a FACE with + // layers and a FACE w/o layers + // value: the shape (FACE or EDGE) to shrink mesh on. + // _LayerEdge's basing on nodes on key shape are inflated along the value shape + map< TGeomID, TopoDS_Shape > _shrinkShape2Shape; + + // Convex FACEs whose radius of curvature is less than the thickness of layers + map< TGeomID, _ConvexFace > _convexFaces; + + // shapes (EDGEs and VERTEXes) srink from which is forbidden due to collisions with + // the adjacent SOLID + set< TGeomID > _noShrinkShapes; + + int _nbShapesToSmooth; + + // to -- for analytic smooth + map< TGeomID,Handle(Geom_Curve)> _edge2curve; + + set< TGeomID > _concaveFaces; + + double _maxThickness; // of all _hyps + double _minThickness; // of all _hyps + + double _epsilon; // precision for SegTriaInter() + + _SolidData(const TopoDS_Shape& s=TopoDS_Shape(), + _MeshOfSolid* m=0) + :_solid(s), _proxyMesh(m) {} + ~_SolidData(); + + Handle(Geom_Curve) CurveForSmooth( const TopoDS_Edge& E, + _EdgesOnShape& eos, + SMESH_MesherHelper& helper); + + void SortOnEdge( const TopoDS_Edge& E, + vector< _LayerEdge* >& edges, + SMESH_MesherHelper& helper); + + void Sort2NeiborsOnEdge( vector< _LayerEdge* >& edges ); + + _ConvexFace* GetConvexFace( const TGeomID faceID ) + { + map< TGeomID, _ConvexFace >::iterator id2face = _convexFaces.find( faceID ); + return id2face == _convexFaces.end() ? 0 : & id2face->second; + } + _EdgesOnShape* GetShapeEdges(const TGeomID shapeID ); + _EdgesOnShape* GetShapeEdges(const TopoDS_Shape& shape ); + _EdgesOnShape* GetShapeEdges(const _LayerEdge* edge ) + { return GetShapeEdges( edge->_nodes[0]->getshapeId() ); } + + void AddShapesToSmooth( const set< _EdgesOnShape* >& shape ); + + void PrepareEdgesToSmoothOnFace( _EdgesOnShape* eof, bool substituteSrcNodes ); + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Container of centers of curvature at nodes on an EDGE bounding _ConvexFace + */ + struct _CentralCurveOnEdge + { + bool _isDegenerated; + vector< gp_Pnt > _curvaCenters; + vector< _LayerEdge* > _ledges; + vector< gp_XYZ > _normals; // new normal for each of _ledges + vector< double > _segLength2; + + TopoDS_Edge _edge; + TopoDS_Face _adjFace; + bool _adjFaceToSmooth; + + void Append( const gp_Pnt& center, _LayerEdge* ledge ) + { + if ( _curvaCenters.size() > 0 ) + _segLength2.push_back( center.SquareDistance( _curvaCenters.back() )); + _curvaCenters.push_back( center ); + _ledges.push_back( ledge ); + _normals.push_back( ledge->_normal ); + } + bool FindNewNormal( const gp_Pnt& center, gp_XYZ& newNormal ); + void SetShapes( const TopoDS_Edge& edge, + const _ConvexFace& convFace, + _SolidData& data, + SMESH_MesherHelper& helper); + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Data of node on a shrinked FACE + */ + struct _SmoothNode + { + const SMDS_MeshNode* _node; + vector<_Simplex> _simplices; // for quality check + + enum SmoothType { LAPLACIAN, CENTROIDAL, ANGULAR, TFI }; + + bool Smooth(int& badNb, + Handle(Geom_Surface)& surface, + SMESH_MesherHelper& helper, + const double refSign, + SmoothType how, + bool set3D); + + gp_XY computeAngularPos(vector& uv, + const gp_XY& uvToFix, + const double refSign ); + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Builder of viscous layers + */ + class _ViscousBuilder + { + public: + _ViscousBuilder(); + // does it's job + SMESH_ComputeErrorPtr Compute(SMESH_Mesh& mesh, + const TopoDS_Shape& shape); + // check validity of hypotheses + SMESH_ComputeErrorPtr CheckHypotheses( SMESH_Mesh& mesh, + const TopoDS_Shape& shape ); + + // restore event listeners used to clear an inferior dim sub-mesh modified by viscous layers + void RestoreListeners(); + + // computes SMESH_ProxyMesh::SubMesh::_n2n; + bool MakeN2NMap( _MeshOfSolid* pm ); + + private: + + bool findSolidsWithLayers(); + bool findFacesWithLayers(const bool onlyWith=false); + void getIgnoreFaces(const TopoDS_Shape& solid, + const StdMeshers_ViscousLayers* hyp, + const TopoDS_Shape& hypShape, + set& ignoreFaces); + bool makeLayer(_SolidData& data); + void setShapeData( _EdgesOnShape& eos, SMESH_subMesh* sm, _SolidData& data ); + bool setEdgeData(_LayerEdge& edge, _EdgesOnShape& eos, const set& subIds, + SMESH_MesherHelper& helper, _SolidData& data); + gp_XYZ getFaceNormal(const SMDS_MeshNode* n, + const TopoDS_Face& face, + SMESH_MesherHelper& helper, + bool& isOK, + bool shiftInside=false); + bool getFaceNormalAtSingularity(const gp_XY& uv, + const TopoDS_Face& face, + SMESH_MesherHelper& helper, + gp_Dir& normal ); + gp_XYZ getWeigthedNormal( const SMDS_MeshNode* n, + std::pair< TopoDS_Face, gp_XYZ > fId2Normal[], + int nbFaces ); + bool findNeiborsOnEdge(const _LayerEdge* edge, + const SMDS_MeshNode*& n1, + const SMDS_MeshNode*& n2, + _EdgesOnShape& eos, + _SolidData& data); + void findSimplexTestEdges( _SolidData& data, + vector< vector<_LayerEdge*> >& edgesByGeom); + void computeGeomSize( _SolidData& data ); + bool findShapesToSmooth( _SolidData& data); + void limitStepSizeByCurvature( _SolidData& data ); + void limitStepSize( _SolidData& data, + const SMDS_MeshElement* face, + const _LayerEdge* maxCosinEdge ); + void limitStepSize( _SolidData& data, const double minSize); + bool inflate(_SolidData& data); + bool smoothAndCheck(_SolidData& data, const int nbSteps, double & distToIntersection); + bool smoothAnalyticEdge( _SolidData& data, + _EdgesOnShape& eos, + Handle(Geom_Surface)& surface, + const TopoDS_Face& F, + SMESH_MesherHelper& helper); + bool updateNormals( _SolidData& data, SMESH_MesherHelper& helper, int stepNb ); + bool updateNormalsOfConvexFaces( _SolidData& data, + SMESH_MesherHelper& helper, + int stepNb ); + bool refine(_SolidData& data); + bool shrink(); + bool prepareEdgeToShrink( _LayerEdge& edge, _EdgesOnShape& eos, + SMESH_MesherHelper& helper, + const SMESHDS_SubMesh* faceSubMesh ); + void restoreNoShrink( _LayerEdge& edge ) const; + void fixBadFaces(const TopoDS_Face& F, + SMESH_MesherHelper& helper, + const bool is2D, + const int step, + set * involvedNodes=NULL); + bool addBoundaryElements(); + + bool error( const string& text, int solidID=-1 ); + SMESHDS_Mesh* getMeshDS() const { return _mesh->GetMeshDS(); } + + // debug + void makeGroupOfLE(); + + SMESH_Mesh* _mesh; + SMESH_ComputeErrorPtr _error; + + vector< _SolidData > _sdVec; + int _tmpFaceID; + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Shrinker of nodes on the EDGE + */ + class _Shrinker1D + { + TopoDS_Edge _geomEdge; + vector _initU; + vector _normPar; + vector _nodes; + const _LayerEdge* _edges[2]; + bool _done; + public: + void AddEdge( const _LayerEdge* e, _EdgesOnShape& eos, SMESH_MesherHelper& helper ); + void Compute(bool set3D, SMESH_MesherHelper& helper); + void RestoreParams(); + void SwapSrcTgtNodes(SMESHDS_Mesh* mesh); + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Class of temporary mesh face. + * We can't use SMDS_FaceOfNodes since it's impossible to set it's ID which is + * needed because SMESH_ElementSearcher internaly uses set of elements sorted by ID + */ + struct _TmpMeshFace : public SMDS_MeshElement + { + vector _nn; + _TmpMeshFace( const vector& nodes, int id, int faceID=-1): + SMDS_MeshElement(id), _nn(nodes) { setShapeId(faceID); } + virtual const SMDS_MeshNode* GetNode(const int ind) const { return _nn[ind]; } + virtual SMDSAbs_ElementType GetType() const { return SMDSAbs_Face; } + virtual vtkIdType GetVtkType() const { return -1; } + virtual SMDSAbs_EntityType GetEntityType() const { return SMDSEntity_Last; } + virtual SMDSAbs_GeometryType GetGeomType() const + { return _nn.size() == 3 ? SMDSGeom_TRIANGLE : SMDSGeom_QUADRANGLE; } + virtual SMDS_ElemIteratorPtr elementsIterator(SMDSAbs_ElementType) const + { return SMDS_ElemIteratorPtr( new SMDS_NodeVectorElemIterator( _nn.begin(), _nn.end()));} + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Class of temporary mesh face storing _LayerEdge it's based on + */ + struct _TmpMeshFaceOnEdge : public _TmpMeshFace + { + _LayerEdge *_le1, *_le2; + _TmpMeshFaceOnEdge( _LayerEdge* le1, _LayerEdge* le2, int ID ): + _TmpMeshFace( vector(4), ID ), _le1(le1), _le2(le2) + { + _nn[0]=_le1->_nodes[0]; + _nn[1]=_le1->_nodes.back(); + _nn[2]=_le2->_nodes.back(); + _nn[3]=_le2->_nodes[0]; + } + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Retriever of node coordinates either directly or from a surface by node UV. + * \warning Location of a surface is ignored + */ + struct _NodeCoordHelper + { + SMESH_MesherHelper& _helper; + const TopoDS_Face& _face; + Handle(Geom_Surface) _surface; + gp_XYZ (_NodeCoordHelper::* _fun)(const SMDS_MeshNode* n) const; + + _NodeCoordHelper(const TopoDS_Face& F, SMESH_MesherHelper& helper, bool is2D) + : _helper( helper ), _face( F ) + { + if ( is2D ) + { + TopLoc_Location loc; + _surface = BRep_Tool::Surface( _face, loc ); + } + if ( _surface.IsNull() ) + _fun = & _NodeCoordHelper::direct; + else + _fun = & _NodeCoordHelper::byUV; + } + gp_XYZ operator()(const SMDS_MeshNode* n) const { return (this->*_fun)( n ); } + + private: + gp_XYZ direct(const SMDS_MeshNode* n) const + { + return SMESH_TNodeXYZ( n ); + } + gp_XYZ byUV (const SMDS_MeshNode* n) const + { + gp_XY uv = _helper.GetNodeUV( _face, n ); + return _surface->Value( uv.X(), uv.Y() ).XYZ(); + } + }; + +} // namespace VISCOUS_3D + + + +//================================================================================ +// StdMeshers_ViscousLayers hypothesis +// +StdMeshers_ViscousLayers::StdMeshers_ViscousLayers(int hypId, int studyId, SMESH_Gen* gen) + :SMESH_Hypothesis(hypId, studyId, gen), + _isToIgnoreShapes(1), _nbLayers(1), _thickness(1), _stretchFactor(1), + _method( SURF_OFFSET_SMOOTH ) +{ + _name = StdMeshers_ViscousLayers::GetHypType(); + _param_algo_dim = -3; // auxiliary hyp used by 3D algos +} // -------------------------------------------------------------------------------- +void StdMeshers_ViscousLayers::SetBndShapes(const std::vector& faceIds, bool toIgnore) +{ + if ( faceIds != _shapeIds ) + _shapeIds = faceIds, NotifySubMeshesHypothesisModification(); + if ( _isToIgnoreShapes != toIgnore ) + _isToIgnoreShapes = toIgnore, NotifySubMeshesHypothesisModification(); +} // -------------------------------------------------------------------------------- +void StdMeshers_ViscousLayers::SetTotalThickness(double thickness) +{ + if ( thickness != _thickness ) + _thickness = thickness, NotifySubMeshesHypothesisModification(); +} // -------------------------------------------------------------------------------- +void StdMeshers_ViscousLayers::SetNumberLayers(int nb) +{ + if ( _nbLayers != nb ) + _nbLayers = nb, NotifySubMeshesHypothesisModification(); +} // -------------------------------------------------------------------------------- +void StdMeshers_ViscousLayers::SetStretchFactor(double factor) +{ + if ( _stretchFactor != factor ) + _stretchFactor = factor, NotifySubMeshesHypothesisModification(); +} // -------------------------------------------------------------------------------- +void StdMeshers_ViscousLayers::SetMethod( ExtrusionMethod method ) +{ + if ( _method != method ) + _method = method, NotifySubMeshesHypothesisModification(); +} // -------------------------------------------------------------------------------- +SMESH_ProxyMesh::Ptr +StdMeshers_ViscousLayers::Compute(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + const bool toMakeN2NMap) const +{ + using namespace VISCOUS_3D; + _ViscousBuilder bulder; + SMESH_ComputeErrorPtr err = bulder.Compute( theMesh, theShape ); + if ( err && !err->IsOK() ) + return SMESH_ProxyMesh::Ptr(); + + vector components; + TopExp_Explorer exp( theShape, TopAbs_SOLID ); + for ( ; exp.More(); exp.Next() ) + { + if ( _MeshOfSolid* pm = + _ViscousListener::GetSolidMesh( &theMesh, exp.Current(), /*toCreate=*/false)) + { + if ( toMakeN2NMap && !pm->_n2nMapComputed ) + if ( !bulder.MakeN2NMap( pm )) + return SMESH_ProxyMesh::Ptr(); + components.push_back( SMESH_ProxyMesh::Ptr( pm )); + pm->myIsDeletable = false; // it will de deleted by boost::shared_ptr + + if ( pm->_warning && !pm->_warning->IsOK() ) + { + SMESH_subMesh* sm = theMesh.GetSubMesh( exp.Current() ); + SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); + if ( !smError || smError->IsOK() ) + smError = pm->_warning; + } + } + _ViscousListener::RemoveSolidMesh ( &theMesh, exp.Current() ); + } + switch ( components.size() ) + { + case 0: break; + + case 1: return components[0]; + + default: return SMESH_ProxyMesh::Ptr( new SMESH_ProxyMesh( components )); + } + return SMESH_ProxyMesh::Ptr(); +} // -------------------------------------------------------------------------------- +std::ostream & StdMeshers_ViscousLayers::SaveTo(std::ostream & save) +{ + save << " " << _nbLayers + << " " << _thickness + << " " << _stretchFactor + << " " << _shapeIds.size(); + for ( size_t i = 0; i < _shapeIds.size(); ++i ) + save << " " << _shapeIds[i]; + save << " " << !_isToIgnoreShapes; // negate to keep the behavior in old studies. + save << " " << _method; + return save; +} // -------------------------------------------------------------------------------- +std::istream & StdMeshers_ViscousLayers::LoadFrom(std::istream & load) +{ + int nbFaces, faceID, shapeToTreat, method; + load >> _nbLayers >> _thickness >> _stretchFactor >> nbFaces; + while ( _shapeIds.size() < nbFaces && load >> faceID ) + _shapeIds.push_back( faceID ); + if ( load >> shapeToTreat ) { + _isToIgnoreShapes = !shapeToTreat; + if ( load >> method ) + _method = (ExtrusionMethod) method; + } + else { + _isToIgnoreShapes = true; // old behavior + } + return load; +} // -------------------------------------------------------------------------------- +bool StdMeshers_ViscousLayers::SetParametersByMesh(const SMESH_Mesh* theMesh, + const TopoDS_Shape& theShape) +{ + // TODO + return false; +} // -------------------------------------------------------------------------------- +SMESH_ComputeErrorPtr +StdMeshers_ViscousLayers::CheckHypothesis(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + SMESH_Hypothesis::Hypothesis_Status& theStatus) +{ + VISCOUS_3D::_ViscousBuilder bulder; + SMESH_ComputeErrorPtr err = bulder.CheckHypotheses( theMesh, theShape ); + if ( err && !err->IsOK() ) + theStatus = SMESH_Hypothesis::HYP_INCOMPAT_HYPS; + else + theStatus = SMESH_Hypothesis::HYP_OK; + + return err; +} +// -------------------------------------------------------------------------------- +bool StdMeshers_ViscousLayers::IsShapeWithLayers(int shapeIndex) const +{ + bool isIn = + ( std::find( _shapeIds.begin(), _shapeIds.end(), shapeIndex ) != _shapeIds.end() ); + return IsToIgnoreShapes() ? !isIn : isIn; +} +// END StdMeshers_ViscousLayers hypothesis +//================================================================================ + +namespace VISCOUS_3D +{ + gp_XYZ getEdgeDir( const TopoDS_Edge& E, const TopoDS_Vertex& fromV ) + { + gp_Vec dir; + double f,l; + Handle(Geom_Curve) c = BRep_Tool::Curve( E, f, l ); + gp_Pnt p = BRep_Tool::Pnt( fromV ); + double distF = p.SquareDistance( c->Value( f )); + double distL = p.SquareDistance( c->Value( l )); + c->D1(( distF < distL ? f : l), p, dir ); + if ( distL < distF ) dir.Reverse(); + return dir.XYZ(); + } + //-------------------------------------------------------------------------------- + gp_XYZ getEdgeDir( const TopoDS_Edge& E, const SMDS_MeshNode* atNode, + SMESH_MesherHelper& helper) + { + gp_Vec dir; + double f,l; gp_Pnt p; + Handle(Geom_Curve) c = BRep_Tool::Curve( E, f, l ); + if ( c.IsNull() ) return gp_XYZ( 1e100, 1e100, 1e100 ); + double u = helper.GetNodeU( E, atNode ); + c->D1( u, p, dir ); + return dir.XYZ(); + } + //-------------------------------------------------------------------------------- + gp_XYZ getFaceDir( const TopoDS_Face& F, const TopoDS_Vertex& fromV, + const SMDS_MeshNode* node, SMESH_MesherHelper& helper, bool& ok, + double* cosin=0); + //-------------------------------------------------------------------------------- + gp_XYZ getFaceDir( const TopoDS_Face& F, const TopoDS_Edge& fromE, + const SMDS_MeshNode* node, SMESH_MesherHelper& helper, bool& ok) + { + double f,l; + Handle(Geom_Curve) c = BRep_Tool::Curve( fromE, f, l ); + if ( c.IsNull() ) + { + TopoDS_Vertex v = helper.IthVertex( 0, fromE ); + return getFaceDir( F, v, node, helper, ok ); + } + gp_XY uv = helper.GetNodeUV( F, node, 0, &ok ); + Handle(Geom_Surface) surface = BRep_Tool::Surface( F ); + gp_Pnt p; gp_Vec du, dv, norm; + surface->D1( uv.X(),uv.Y(), p, du,dv ); + norm = du ^ dv; + + double u = helper.GetNodeU( fromE, node, 0, &ok ); + c->D1( u, p, du ); + TopAbs_Orientation o = helper.GetSubShapeOri( F.Oriented(TopAbs_FORWARD), fromE); + if ( o == TopAbs_REVERSED ) + du.Reverse(); + + gp_Vec dir = norm ^ du; + + if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX && + helper.IsClosedEdge( fromE )) + { + if ( fabs(u-f) < fabs(u-l)) c->D1( l, p, dv ); + else c->D1( f, p, dv ); + if ( o == TopAbs_REVERSED ) + dv.Reverse(); + gp_Vec dir2 = norm ^ dv; + dir = dir.Normalized() + dir2.Normalized(); + } + return dir.XYZ(); + } + //-------------------------------------------------------------------------------- + gp_XYZ getFaceDir( const TopoDS_Face& F, const TopoDS_Vertex& fromV, + const SMDS_MeshNode* node, SMESH_MesherHelper& helper, + bool& ok, double* cosin) + { + TopoDS_Face faceFrw = F; + faceFrw.Orientation( TopAbs_FORWARD ); + double f,l; TopLoc_Location loc; + TopoDS_Edge edges[2]; // sharing a vertex + int nbEdges = 0; + { + TopoDS_Vertex VV[2]; + TopExp_Explorer exp( faceFrw, TopAbs_EDGE ); + for ( ; exp.More() && nbEdges < 2; exp.Next() ) + { + const TopoDS_Edge& e = TopoDS::Edge( exp.Current() ); + if ( SMESH_Algo::isDegenerated( e )) continue; + TopExp::Vertices( e, VV[0], VV[1], /*CumOri=*/true ); + if ( VV[1].IsSame( fromV )) { + nbEdges += edges[ 0 ].IsNull(); + edges[ 0 ] = e; + } + else if ( VV[0].IsSame( fromV )) { + nbEdges += edges[ 1 ].IsNull(); + edges[ 1 ] = e; + } + } + } + gp_XYZ dir(0,0,0), edgeDir[2]; + if ( nbEdges == 2 ) + { + // get dirs of edges going fromV + ok = true; + for ( size_t i = 0; i < nbEdges && ok; ++i ) + { + edgeDir[i] = getEdgeDir( edges[i], fromV ); + double size2 = edgeDir[i].SquareModulus(); + if (( ok = size2 > numeric_limits::min() )) + edgeDir[i] /= sqrt( size2 ); + } + if ( !ok ) return dir; + + // get angle between the 2 edges + gp_Vec faceNormal; + double angle = helper.GetAngle( edges[0], edges[1], faceFrw, fromV, &faceNormal ); + if ( Abs( angle ) < 5 * M_PI/180 ) + { + dir = ( faceNormal.XYZ() ^ edgeDir[0].Reversed()) + ( faceNormal.XYZ() ^ edgeDir[1] ); + } + else + { + dir = edgeDir[0] + edgeDir[1]; + if ( angle < 0 ) + dir.Reverse(); + } + if ( cosin ) { + double angle = gp_Vec( edgeDir[0] ).Angle( dir ); + *cosin = Cos( angle ); + } + } + else if ( nbEdges == 1 ) + { + dir = getFaceDir( faceFrw, edges[ edges[0].IsNull() ], node, helper, ok ); + if ( cosin ) *cosin = 1.; + } + else + { + ok = false; + } + + return dir; + } + + //================================================================================ + /*! + * \brief Finds concave VERTEXes of a FACE + */ + //================================================================================ + + bool getConcaveVertices( const TopoDS_Face& F, + SMESH_MesherHelper& helper, + set< TGeomID >* vertices = 0) + { + // check angles at VERTEXes + TError error; + TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, *helper.GetMesh(), 0, error ); + for ( size_t iW = 0; iW < wires.size(); ++iW ) + { + const int nbEdges = wires[iW]->NbEdges(); + if ( nbEdges < 2 && SMESH_Algo::isDegenerated( wires[iW]->Edge(0))) + continue; + for ( int iE1 = 0; iE1 < nbEdges; ++iE1 ) + { + if ( SMESH_Algo::isDegenerated( wires[iW]->Edge( iE1 ))) continue; + int iE2 = ( iE1 + 1 ) % nbEdges; + while ( SMESH_Algo::isDegenerated( wires[iW]->Edge( iE2 ))) + iE2 = ( iE2 + 1 ) % nbEdges; + TopoDS_Vertex V = wires[iW]->FirstVertex( iE2 ); + double angle = helper.GetAngle( wires[iW]->Edge( iE1 ), + wires[iW]->Edge( iE2 ), F, V ); + if ( angle < -5. * M_PI / 180. ) + { + if ( !vertices ) + return true; + vertices->insert( helper.GetMeshDS()->ShapeToIndex( V )); + } + } + } + return vertices ? !vertices->empty() : false; + } + + //================================================================================ + /*! + * \brief Returns true if a FACE is bound by a concave EDGE + */ + //================================================================================ + + bool isConcave( const TopoDS_Face& F, + SMESH_MesherHelper& helper, + set< TGeomID >* vertices = 0 ) + { + bool isConcv = false; + // if ( helper.Count( F, TopAbs_WIRE, /*useMap=*/false) > 1 ) + // return true; + gp_Vec2d drv1, drv2; + gp_Pnt2d p; + TopExp_Explorer eExp( F.Oriented( TopAbs_FORWARD ), TopAbs_EDGE ); + for ( ; eExp.More(); eExp.Next() ) + { + const TopoDS_Edge& E = TopoDS::Edge( eExp.Current() ); + if ( SMESH_Algo::isDegenerated( E )) continue; + // check if 2D curve is concave + BRepAdaptor_Curve2d curve( E, F ); + const int nbIntervals = curve.NbIntervals( GeomAbs_C2 ); + TColStd_Array1OfReal intervals(1, nbIntervals + 1 ); + curve.Intervals( intervals, GeomAbs_C2 ); + bool isConvex = true; + for ( int i = 1; i <= nbIntervals && isConvex; ++i ) + { + double u1 = intervals( i ); + double u2 = intervals( i+1 ); + curve.D2( 0.5*( u1+u2 ), p, drv1, drv2 ); + double cross = drv2 ^ drv1; + if ( E.Orientation() == TopAbs_REVERSED ) + cross = -cross; + isConvex = ( cross > 0.1 ); //-1e-9 ); + } + if ( !isConvex ) + { + //cout << "Concave FACE " << helper.GetMeshDS()->ShapeToIndex( F ) << endl; + isConcv = true; + if ( vertices ) + break; + else + return true; + } + } + + // check angles at VERTEXes + if ( getConcaveVertices( F, helper, vertices )) + isConcv = true; + + return isConcv; + } + + //================================================================================ + /*! + * \brief Computes mimimal distance of face in-FACE nodes from an EDGE + * \param [in] face - the mesh face to treat + * \param [in] nodeOnEdge - a node on the EDGE + * \param [out] faceSize - the computed distance + * \return bool - true if faceSize computed + */ + //================================================================================ + + bool getDistFromEdge( const SMDS_MeshElement* face, + const SMDS_MeshNode* nodeOnEdge, + double & faceSize ) + { + faceSize = Precision::Infinite(); + bool done = false; + + int nbN = face->NbCornerNodes(); + int iOnE = face->GetNodeIndex( nodeOnEdge ); + int iNext[2] = { SMESH_MesherHelper::WrapIndex( iOnE+1, nbN ), + SMESH_MesherHelper::WrapIndex( iOnE-1, nbN ) }; + const SMDS_MeshNode* nNext[2] = { face->GetNode( iNext[0] ), + face->GetNode( iNext[1] ) }; + gp_XYZ segVec, segEnd = SMESH_TNodeXYZ( nodeOnEdge ); // segment on EDGE + double segLen = -1.; + // look for two neighbor not in-FACE nodes of face + for ( int i = 0; i < 2; ++i ) + { + if ( nNext[i]->GetPosition()->GetDim() != 2 && + nNext[i]->GetID() < nodeOnEdge->GetID() ) + { + // look for an in-FACE node + for ( int iN = 0; iN < nbN; ++iN ) + { + if ( iN == iOnE || iN == iNext[i] ) + continue; + SMESH_TNodeXYZ pInFace = face->GetNode( iN ); + gp_XYZ v = pInFace - segEnd; + if ( segLen < 0 ) + { + segVec = SMESH_TNodeXYZ( nNext[i] ) - segEnd; + segLen = segVec.Modulus(); + } + double distToSeg = v.Crossed( segVec ).Modulus() / segLen; + faceSize = Min( faceSize, distToSeg ); + done = true; + } + segLen = -1; + } + } + return done; + } + //================================================================================ + /*! + * \brief Return direction of axis or revolution of a surface + */ + //================================================================================ + + bool getRovolutionAxis( const Adaptor3d_Surface& surface, + gp_Dir & axis ) + { + switch ( surface.GetType() ) { + case GeomAbs_Cone: + { + gp_Cone cone = surface.Cone(); + axis = cone.Axis().Direction(); + break; + } + case GeomAbs_Sphere: + { + gp_Sphere sphere = surface.Sphere(); + axis = sphere.Position().Direction(); + break; + } + case GeomAbs_SurfaceOfRevolution: + { + axis = surface.AxeOfRevolution().Direction(); + break; + } + //case GeomAbs_SurfaceOfExtrusion: + case GeomAbs_OffsetSurface: + { + Handle(Adaptor3d_HSurface) base = surface.BasisSurface(); + return getRovolutionAxis( base->Surface(), axis ); + } + default: return false; + } + return true; + } + + //-------------------------------------------------------------------------------- + // DEBUG. Dump intermediate node positions into a python script + // HOWTO use: run python commands written in a console to see + // construction steps of viscous layers +#ifdef __myDEBUG + ofstream* py; + int theNbPyFunc; + struct PyDump { + PyDump(SMESH_Mesh& m) { + int tag = 3 + m.GetId(); + const char* fname = "/tmp/viscous.py"; + cout << "execfile('"<GetID()<< ", "<< n->X() + << ", "<Y()<<", "<< n->Z()<< ")\t\t # "<< ln <<" "<< txt << endl; } + void _dumpCmd(const string& txt, int ln) + { if (py) *py<< " "<GetID()<<", ["; + for ( int i=1; i < f->NbNodes(); ++i ) *py << f->GetNode(i-1)->GetID()<<", "; + *py << f->GetNode( f->NbNodes()-1 )->GetID() << " ])"<< endl; }} +#define debugMsg( txt ) { cout << txt << " (line: " << __LINE__ << ")" << endl; } +#else + struct PyDump { PyDump(SMESH_Mesh&) {} void Finish() {} }; +#define dumpFunction(f) f +#define dumpMove(n) +#define dumpMoveComm(n,txt) +#define dumpCmd(txt) +#define dumpFunctionEnd() +#define dumpChangeNodes(f) +#define debugMsg( txt ) {} +#endif +} + +using namespace VISCOUS_3D; + +//================================================================================ +/*! + * \brief Constructor of _ViscousBuilder + */ +//================================================================================ + +_ViscousBuilder::_ViscousBuilder() +{ + _error = SMESH_ComputeError::New(COMPERR_OK); + _tmpFaceID = 0; +} + +//================================================================================ +/*! + * \brief Stores error description and returns false + */ +//================================================================================ + +bool _ViscousBuilder::error(const string& text, int solidId ) +{ + const string prefix = string("Viscous layers builder: "); + _error->myName = COMPERR_ALGO_FAILED; + _error->myComment = prefix + text; + if ( _mesh ) + { + SMESH_subMesh* sm = _mesh->GetSubMeshContaining( solidId ); + if ( !sm && !_sdVec.empty() ) + sm = _mesh->GetSubMeshContaining( solidId = _sdVec[0]._index ); + if ( sm && sm->GetSubShape().ShapeType() == TopAbs_SOLID ) + { + SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); + if ( smError && smError->myAlgo ) + _error->myAlgo = smError->myAlgo; + smError = _error; + sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + // set KO to all solids + for ( size_t i = 0; i < _sdVec.size(); ++i ) + { + if ( _sdVec[i]._index == solidId ) + continue; + sm = _mesh->GetSubMesh( _sdVec[i]._solid ); + if ( !sm->IsEmpty() ) + continue; + SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); + if ( !smError || smError->IsOK() ) + { + smError = SMESH_ComputeError::New( COMPERR_ALGO_FAILED, prefix + "failed"); + sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + } + } + makeGroupOfLE(); // debug + + return false; +} + +//================================================================================ +/*! + * \brief At study restoration, restore event listeners used to clear an inferior + * dim sub-mesh modified by viscous layers + */ +//================================================================================ + +void _ViscousBuilder::RestoreListeners() +{ + // TODO +} + +//================================================================================ +/*! + * \brief computes SMESH_ProxyMesh::SubMesh::_n2n + */ +//================================================================================ + +bool _ViscousBuilder::MakeN2NMap( _MeshOfSolid* pm ) +{ + SMESH_subMesh* solidSM = pm->mySubMeshes.front(); + TopExp_Explorer fExp( solidSM->GetSubShape(), TopAbs_FACE ); + for ( ; fExp.More(); fExp.Next() ) + { + SMESHDS_SubMesh* srcSmDS = pm->GetMeshDS()->MeshElements( fExp.Current() ); + const SMESH_ProxyMesh::SubMesh* prxSmDS = pm->GetProxySubMesh( fExp.Current() ); + + if ( !srcSmDS || !prxSmDS || !srcSmDS->NbElements() || !prxSmDS->NbElements() ) + continue; + if ( srcSmDS->GetElements()->next() == prxSmDS->GetElements()->next()) + continue; + + if ( srcSmDS->NbElements() != prxSmDS->NbElements() ) + return error( "Different nb elements in a source and a proxy sub-mesh", solidSM->GetId()); + + SMDS_ElemIteratorPtr srcIt = srcSmDS->GetElements(); + SMDS_ElemIteratorPtr prxIt = prxSmDS->GetElements(); + while( prxIt->more() ) + { + const SMDS_MeshElement* fSrc = srcIt->next(); + const SMDS_MeshElement* fPrx = prxIt->next(); + if ( fSrc->NbNodes() != fPrx->NbNodes()) + return error( "Different elements in a source and a proxy sub-mesh", solidSM->GetId()); + for ( int i = 0 ; i < fPrx->NbNodes(); ++i ) + pm->setNode2Node( fSrc->GetNode(i), fPrx->GetNode(i), prxSmDS ); + } + } + pm->_n2nMapComputed = true; + return true; +} + +//================================================================================ +/*! + * \brief Does its job + */ +//================================================================================ + +SMESH_ComputeErrorPtr _ViscousBuilder::Compute(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape) +{ + // TODO: set priority of solids during Gen::Compute() + + _mesh = & theMesh; + + // check if proxy mesh already computed + TopExp_Explorer exp( theShape, TopAbs_SOLID ); + if ( !exp.More() ) + return error("No SOLID's in theShape"), _error; + + if ( _ViscousListener::GetSolidMesh( _mesh, exp.Current(), /*toCreate=*/false)) + return SMESH_ComputeErrorPtr(); // everything already computed + + PyDump debugDump( theMesh ); + + // TODO: ignore already computed SOLIDs + if ( !findSolidsWithLayers()) + return _error; + + if ( !findFacesWithLayers() ) + return _error; + + for ( size_t i = 0; i < _sdVec.size(); ++i ) + { + if ( ! makeLayer(_sdVec[i]) ) + return _error; + + if ( _sdVec[i]._n2eMap.size() == 0 ) + continue; + + if ( ! inflate(_sdVec[i]) ) + return _error; + + if ( ! refine(_sdVec[i]) ) + return _error; + } + if ( !shrink() ) + return _error; + + addBoundaryElements(); + + makeGroupOfLE(); // debug + debugDump.Finish(); + + return _error; +} + +//================================================================================ +/*! + * \brief Check validity of hypotheses + */ +//================================================================================ + +SMESH_ComputeErrorPtr _ViscousBuilder::CheckHypotheses( SMESH_Mesh& mesh, + const TopoDS_Shape& shape ) +{ + _mesh = & mesh; + + if ( _ViscousListener::GetSolidMesh( _mesh, shape, /*toCreate=*/false)) + return SMESH_ComputeErrorPtr(); // everything already computed + + + findSolidsWithLayers(); + bool ok = findFacesWithLayers( true ); + + // remove _MeshOfSolid's of _SolidData's + for ( size_t i = 0; i < _sdVec.size(); ++i ) + _ViscousListener::RemoveSolidMesh( _mesh, _sdVec[i]._solid ); + + if ( !ok ) + return _error; + + return SMESH_ComputeErrorPtr(); +} + +//================================================================================ +/*! + * \brief Finds SOLIDs to compute using viscous layers. Fills _sdVec + */ +//================================================================================ + +bool _ViscousBuilder::findSolidsWithLayers() +{ + // get all solids + TopTools_IndexedMapOfShape allSolids; + TopExp::MapShapes( _mesh->GetShapeToMesh(), TopAbs_SOLID, allSolids ); + _sdVec.reserve( allSolids.Extent()); + + SMESH_Gen* gen = _mesh->GetGen(); + SMESH_HypoFilter filter; + for ( int i = 1; i <= allSolids.Extent(); ++i ) + { + // find StdMeshers_ViscousLayers hyp assigned to the i-th solid + SMESH_Algo* algo = gen->GetAlgo( *_mesh, allSolids(i) ); + if ( !algo ) continue; + // TODO: check if algo is hidden + const list & allHyps = + algo->GetUsedHypothesis(*_mesh, allSolids(i), /*ignoreAuxiliary=*/false); + _SolidData* soData = 0; + list< const SMESHDS_Hypothesis *>::const_iterator hyp = allHyps.begin(); + const StdMeshers_ViscousLayers* viscHyp = 0; + for ( ; hyp != allHyps.end(); ++hyp ) + if ( viscHyp = dynamic_cast( *hyp )) + { + TopoDS_Shape hypShape; + filter.Init( filter.Is( viscHyp )); + _mesh->GetHypothesis( allSolids(i), filter, true, &hypShape ); + + if ( !soData ) + { + _MeshOfSolid* proxyMesh = _ViscousListener::GetSolidMesh( _mesh, + allSolids(i), + /*toCreate=*/true); + _sdVec.push_back( _SolidData( allSolids(i), proxyMesh )); + soData = & _sdVec.back(); + soData->_index = getMeshDS()->ShapeToIndex( allSolids(i)); + } + soData->_hyps.push_back( viscHyp ); + soData->_hypShapes.push_back( hypShape ); + } + } + if ( _sdVec.empty() ) + return error + ( SMESH_Comment(StdMeshers_ViscousLayers::GetHypType()) << " hypothesis not found",0); + + return true; +} + +//================================================================================ +/*! + * \brief + */ +//================================================================================ + +bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith) +{ + SMESH_MesherHelper helper( *_mesh ); + TopExp_Explorer exp; + TopTools_IndexedMapOfShape solids; + + // collect all faces-to-ignore defined by hyp + for ( size_t i = 0; i < _sdVec.size(); ++i ) + { + solids.Add( _sdVec[i]._solid ); + + // get faces-to-ignore defined by each hyp + typedef const StdMeshers_ViscousLayers* THyp; + typedef std::pair< set, THyp > TFacesOfHyp; + list< TFacesOfHyp > ignoreFacesOfHyps; + list< THyp >::iterator hyp = _sdVec[i]._hyps.begin(); + list< TopoDS_Shape >::iterator hypShape = _sdVec[i]._hypShapes.begin(); + for ( ; hyp != _sdVec[i]._hyps.end(); ++hyp, ++hypShape ) + { + ignoreFacesOfHyps.push_back( TFacesOfHyp( set(), *hyp )); + getIgnoreFaces( _sdVec[i]._solid, *hyp, *hypShape, ignoreFacesOfHyps.back().first ); + } + + // fill _SolidData::_face2hyp and check compatibility of hypotheses + const int nbHyps = _sdVec[i]._hyps.size(); + if ( nbHyps > 1 ) + { + // check if two hypotheses define different parameters for the same FACE + list< TFacesOfHyp >::iterator igFacesOfHyp; + for ( exp.Init( _sdVec[i]._solid, TopAbs_FACE ); exp.More(); exp.Next() ) + { + const TGeomID faceID = getMeshDS()->ShapeToIndex( exp.Current() ); + THyp hyp = 0; + igFacesOfHyp = ignoreFacesOfHyps.begin(); + for ( ; igFacesOfHyp != ignoreFacesOfHyps.end(); ++igFacesOfHyp ) + if ( ! igFacesOfHyp->first.count( faceID )) + { + if ( hyp ) + return error(SMESH_Comment("Several hypotheses define " + "Viscous Layers on the face #") << faceID ); + hyp = igFacesOfHyp->second; + } + if ( hyp ) + _sdVec[i]._face2hyp.insert( make_pair( faceID, hyp )); + else + _sdVec[i]._ignoreFaceIds.insert( faceID ); + } + + // check if two hypotheses define different number of viscous layers for + // adjacent faces of a solid + set< int > nbLayersSet; + igFacesOfHyp = ignoreFacesOfHyps.begin(); + for ( ; igFacesOfHyp != ignoreFacesOfHyps.end(); ++igFacesOfHyp ) + { + nbLayersSet.insert( igFacesOfHyp->second->GetNumberLayers() ); + } + if ( nbLayersSet.size() > 1 ) + { + for ( exp.Init( _sdVec[i]._solid, TopAbs_EDGE ); exp.More(); exp.Next() ) + { + PShapeIteratorPtr fIt = helper.GetAncestors( exp.Current(), *_mesh, TopAbs_FACE ); + THyp hyp1 = 0, hyp2 = 0; + while( const TopoDS_Shape* face = fIt->next() ) + { + const TGeomID faceID = getMeshDS()->ShapeToIndex( *face ); + map< TGeomID, THyp >::iterator f2h = _sdVec[i]._face2hyp.find( faceID ); + if ( f2h != _sdVec[i]._face2hyp.end() ) + { + ( hyp1 ? hyp2 : hyp1 ) = f2h->second; + } + } + if ( hyp1 && hyp2 && + hyp1->GetNumberLayers() != hyp2->GetNumberLayers() ) + { + return error("Two hypotheses define different number of " + "viscous layers on adjacent faces"); + } + } + } + } // if ( nbHyps > 1 ) + else + { + _sdVec[i]._ignoreFaceIds.swap( ignoreFacesOfHyps.back().first ); + } + } // loop on _sdVec + + if ( onlyWith ) // is called to check hypotheses compatibility only + return true; + + // fill _SolidData::_reversedFaceIds + for ( size_t i = 0; i < _sdVec.size(); ++i ) + { + exp.Init( _sdVec[i]._solid.Oriented( TopAbs_FORWARD ), TopAbs_FACE ); + for ( ; exp.More(); exp.Next() ) + { + const TopoDS_Face& face = TopoDS::Face( exp.Current() ); + const TGeomID faceID = getMeshDS()->ShapeToIndex( face ); + if ( //!sdVec[i]._ignoreFaceIds.count( faceID ) && + helper.NbAncestors( face, *_mesh, TopAbs_SOLID ) > 1 && + helper.IsReversedSubMesh( face )) + { + _sdVec[i]._reversedFaceIds.insert( faceID ); + } + } + } + + // Find faces to shrink mesh on (solution 2 in issue 0020832); + TopTools_IndexedMapOfShape shapes; + for ( size_t i = 0; i < _sdVec.size(); ++i ) + { + shapes.Clear(); + TopExp::MapShapes(_sdVec[i]._solid, TopAbs_EDGE, shapes); + for ( int iE = 1; iE <= shapes.Extent(); ++iE ) + { + const TopoDS_Shape& edge = shapes(iE); + // find 2 faces sharing an edge + TopoDS_Shape FF[2]; + PShapeIteratorPtr fIt = helper.GetAncestors(edge, *_mesh, TopAbs_FACE); + while ( fIt->more()) + { + const TopoDS_Shape* f = fIt->next(); + if ( helper.IsSubShape( *f, _sdVec[i]._solid)) + FF[ int( !FF[0].IsNull()) ] = *f; + } + if( FF[1].IsNull() ) continue; // seam edge can be shared by 1 FACE only + // check presence of layers on them + int ignore[2]; + for ( int j = 0; j < 2; ++j ) + ignore[j] = _sdVec[i]._ignoreFaceIds.count ( getMeshDS()->ShapeToIndex( FF[j] )); + if ( ignore[0] == ignore[1] ) + continue; // nothing interesting + TopoDS_Shape fWOL = FF[ ignore[0] ? 0 : 1 ]; + // check presence of layers on fWOL within an adjacent SOLID + bool collision = false; + PShapeIteratorPtr sIt = helper.GetAncestors( fWOL, *_mesh, TopAbs_SOLID ); + while ( const TopoDS_Shape* solid = sIt->next() ) + if ( !solid->IsSame( _sdVec[i]._solid )) + { + int iSolid = solids.FindIndex( *solid ); + int iFace = getMeshDS()->ShapeToIndex( fWOL ); + if ( iSolid > 0 && !_sdVec[ iSolid-1 ]._ignoreFaceIds.count( iFace )) + { + //_sdVec[i]._noShrinkShapes.insert( iFace ); + //fWOL.Nullify(); + collision = true; + } + } + // add edge to maps + if ( !fWOL.IsNull()) + { + TGeomID edgeInd = getMeshDS()->ShapeToIndex( edge ); + _sdVec[i]._shrinkShape2Shape.insert( make_pair( edgeInd, fWOL )); + if ( collision ) + { + // _shrinkShape2Shape will be used to temporary inflate _LayerEdge's based + // on the edge but shrink won't be performed + _sdVec[i]._noShrinkShapes.insert( edgeInd ); + } + } + } + } + // Exclude from _shrinkShape2Shape FACE's that can't be shrinked since + // the algo of the SOLID sharing the FACE does not support it + set< string > notSupportAlgos; notSupportAlgos.insert("Hexa_3D"); + for ( size_t i = 0; i < _sdVec.size(); ++i ) + { + map< TGeomID, TopoDS_Shape >::iterator e2f = _sdVec[i]._shrinkShape2Shape.begin(); + for ( ; e2f != _sdVec[i]._shrinkShape2Shape.end(); ++e2f ) + { + const TopoDS_Shape& fWOL = e2f->second; + const TGeomID edgeID = e2f->first; + bool notShrinkFace = false; + PShapeIteratorPtr soIt = helper.GetAncestors(fWOL, *_mesh, TopAbs_SOLID); + while ( soIt->more() ) + { + const TopoDS_Shape* solid = soIt->next(); + if ( _sdVec[i]._solid.IsSame( *solid )) continue; + SMESH_Algo* algo = _mesh->GetGen()->GetAlgo( *_mesh, *solid ); + if ( !algo || !notSupportAlgos.count( algo->GetName() )) continue; + notShrinkFace = true; + size_t iSolid = 0; + for ( ; iSolid < _sdVec.size(); ++iSolid ) + { + if ( _sdVec[iSolid]._solid.IsSame( *solid ) ) { + if ( _sdVec[iSolid]._shrinkShape2Shape.count( edgeID )) + notShrinkFace = false; + break; + } + } + if ( notShrinkFace ) + { + _sdVec[i]._noShrinkShapes.insert( edgeID ); + + // add VERTEXes of the edge in _noShrinkShapes + TopoDS_Shape edge = getMeshDS()->IndexToShape( edgeID ); + for ( TopoDS_Iterator vIt( edge ); vIt.More(); vIt.Next() ) + _sdVec[i]._noShrinkShapes.insert( getMeshDS()->ShapeToIndex( vIt.Value() )); + + // check if there is a collision with to-shrink-from EDGEs in iSolid + if ( iSolid == _sdVec.size() ) + continue; // no VL in the solid + shapes.Clear(); + TopExp::MapShapes( fWOL, TopAbs_EDGE, shapes); + for ( int iE = 1; iE <= shapes.Extent(); ++iE ) + { + const TopoDS_Edge& E = TopoDS::Edge( shapes( iE )); + const TGeomID eID = getMeshDS()->ShapeToIndex( E ); + if ( eID == edgeID || + !_sdVec[iSolid]._shrinkShape2Shape.count( eID ) || + _sdVec[i]._noShrinkShapes.count( eID )) + continue; + for ( int is1st = 0; is1st < 2; ++is1st ) + { + TopoDS_Vertex V = helper.IthVertex( is1st, E ); + if ( _sdVec[i]._noShrinkShapes.count( getMeshDS()->ShapeToIndex( V ) )) + { + // _sdVec[i]._noShrinkShapes.insert( eID ); + // V = helper.IthVertex( !is1st, E ); + // _sdVec[i]._noShrinkShapes.insert( getMeshDS()->ShapeToIndex( V )); + //iE = 0; // re-start the loop on EDGEs of fWOL + return error("No way to make a conformal mesh with " + "the given set of faces with layers", _sdVec[i]._index); + } + } + } + } + + } // while ( soIt->more() ) + } // loop on _sdVec[i]._shrinkShape2Shape + } // loop on _sdVec to fill in _SolidData::_noShrinkShapes + + // Find the SHAPE along which to inflate _LayerEdge based on VERTEX + + for ( size_t i = 0; i < _sdVec.size(); ++i ) + { + shapes.Clear(); + TopExp::MapShapes(_sdVec[i]._solid, TopAbs_VERTEX, shapes); + for ( int iV = 1; iV <= shapes.Extent(); ++iV ) + { + const TopoDS_Shape& vertex = shapes(iV); + // find faces WOL sharing the vertex + vector< TopoDS_Shape > facesWOL; + int totalNbFaces = 0; + PShapeIteratorPtr fIt = helper.GetAncestors(vertex, *_mesh, TopAbs_FACE); + while ( fIt->more()) + { + const TopoDS_Shape* f = fIt->next(); + if ( helper.IsSubShape( *f, _sdVec[i]._solid ) ) + { + totalNbFaces++; + const int fID = getMeshDS()->ShapeToIndex( *f ); + if ( _sdVec[i]._ignoreFaceIds.count ( fID ) /*&& + !_sdVec[i]._noShrinkShapes.count( fID )*/) + facesWOL.push_back( *f ); + } + } + if ( facesWOL.size() == totalNbFaces || facesWOL.empty() ) + continue; // no layers at this vertex or no WOL + TGeomID vInd = getMeshDS()->ShapeToIndex( vertex ); + switch ( facesWOL.size() ) + { + case 1: + { + helper.SetSubShape( facesWOL[0] ); + if ( helper.IsRealSeam( vInd )) // inflate along a seam edge? + { + TopoDS_Shape seamEdge; + PShapeIteratorPtr eIt = helper.GetAncestors(vertex, *_mesh, TopAbs_EDGE); + while ( eIt->more() && seamEdge.IsNull() ) + { + const TopoDS_Shape* e = eIt->next(); + if ( helper.IsRealSeam( *e ) ) + seamEdge = *e; + } + if ( !seamEdge.IsNull() ) + { + _sdVec[i]._shrinkShape2Shape.insert( make_pair( vInd, seamEdge )); + break; + } + } + _sdVec[i]._shrinkShape2Shape.insert( make_pair( vInd, facesWOL[0] )); + break; + } + case 2: + { + // find an edge shared by 2 faces + PShapeIteratorPtr eIt = helper.GetAncestors(vertex, *_mesh, TopAbs_EDGE); + while ( eIt->more()) + { + const TopoDS_Shape* e = eIt->next(); + if ( helper.IsSubShape( *e, facesWOL[0]) && + helper.IsSubShape( *e, facesWOL[1])) + { + _sdVec[i]._shrinkShape2Shape.insert( make_pair( vInd, *e )); break; + } + } + break; + } + default: + return error("Not yet supported case", _sdVec[i]._index); + } + } + } + + // add FACEs of other SOLIDs to _ignoreFaceIds + for ( size_t i = 0; i < _sdVec.size(); ++i ) + { + shapes.Clear(); + TopExp::MapShapes(_sdVec[i]._solid, TopAbs_FACE, shapes); + + for ( exp.Init( _mesh->GetShapeToMesh(), TopAbs_FACE ); exp.More(); exp.Next() ) + { + if ( !shapes.Contains( exp.Current() )) + _sdVec[i]._ignoreFaceIds.insert( getMeshDS()->ShapeToIndex( exp.Current() )); + } + } + + return true; +} + +//================================================================================ +/*! + * \brief Finds FACEs w/o layers for a given SOLID by an hypothesis + */ +//================================================================================ + +void _ViscousBuilder::getIgnoreFaces(const TopoDS_Shape& solid, + const StdMeshers_ViscousLayers* hyp, + const TopoDS_Shape& hypShape, + set& ignoreFaceIds) +{ + TopExp_Explorer exp; + + vector ids = hyp->GetBndShapes(); + if ( hyp->IsToIgnoreShapes() ) // FACEs to ignore are given + { + for ( size_t ii = 0; ii < ids.size(); ++ii ) + { + const TopoDS_Shape& s = getMeshDS()->IndexToShape( ids[ii] ); + if ( !s.IsNull() && s.ShapeType() == TopAbs_FACE ) + ignoreFaceIds.insert( ids[ii] ); + } + } + else // FACEs with layers are given + { + exp.Init( solid, TopAbs_FACE ); + for ( ; exp.More(); exp.Next() ) + { + TGeomID faceInd = getMeshDS()->ShapeToIndex( exp.Current() ); + if ( find( ids.begin(), ids.end(), faceInd ) == ids.end() ) + ignoreFaceIds.insert( faceInd ); + } + } + + // ignore internal FACEs if inlets and outlets are specified + if ( hyp->IsToIgnoreShapes() ) + { + TopTools_IndexedDataMapOfShapeListOfShape solidsOfFace; + TopExp::MapShapesAndAncestors( hypShape, + TopAbs_FACE, TopAbs_SOLID, solidsOfFace); + + for ( exp.Init( solid, TopAbs_FACE ); exp.More(); exp.Next() ) + { + const TopoDS_Face& face = TopoDS::Face( exp.Current() ); + if ( SMESH_MesherHelper::NbAncestors( face, *_mesh, TopAbs_SOLID ) < 2 ) + continue; + + int nbSolids = solidsOfFace.FindFromKey( face ).Extent(); + if ( nbSolids > 1 ) + ignoreFaceIds.insert( getMeshDS()->ShapeToIndex( face )); + } + } +} + +//================================================================================ +/*! + * \brief Create the inner surface of the viscous layer and prepare data for infation + */ +//================================================================================ + +bool _ViscousBuilder::makeLayer(_SolidData& data) +{ + // get all sub-shapes to make layers on + set subIds, faceIds; + subIds = data._noShrinkShapes; + TopExp_Explorer exp( data._solid, TopAbs_FACE ); + for ( ; exp.More(); exp.Next() ) + { + SMESH_subMesh* fSubM = _mesh->GetSubMesh( exp.Current() ); + if ( ! data._ignoreFaceIds.count( fSubM->GetId() )) + { + faceIds.insert( fSubM->GetId() ); + SMESH_subMeshIteratorPtr subIt = fSubM->getDependsOnIterator(/*includeSelf=*/true); + while ( subIt->more() ) + subIds.insert( subIt->next()->GetId() ); + } + } + + // make a map to find new nodes on sub-shapes shared with other SOLID + map< TGeomID, TNode2Edge* >::iterator s2ne; + map< TGeomID, TopoDS_Shape >::iterator s2s = data._shrinkShape2Shape.begin(); + for (; s2s != data._shrinkShape2Shape.end(); ++s2s ) + { + TGeomID shapeInd = s2s->first; + for ( size_t i = 0; i < _sdVec.size(); ++i ) + { + if ( _sdVec[i]._index == data._index ) continue; + map< TGeomID, TopoDS_Shape >::iterator s2s2 = _sdVec[i]._shrinkShape2Shape.find( shapeInd ); + if ( s2s2 != _sdVec[i]._shrinkShape2Shape.end() && + *s2s == *s2s2 && !_sdVec[i]._n2eMap.empty() ) + { + data._s2neMap.insert( make_pair( shapeInd, &_sdVec[i]._n2eMap )); + break; + } + } + } + + // Create temporary faces and _LayerEdge's + + dumpFunction(SMESH_Comment("makeLayers_")< newNodes; // of a mesh face + TNode2Edge::iterator n2e2; + + // collect _LayerEdge's of shapes they are based on + vector< _EdgesOnShape >& edgesByGeom = data._edgesOnShape; + const int nbShapes = getMeshDS()->MaxShapeIndex(); + edgesByGeom.resize( nbShapes+1 ); + + // set data of _EdgesOnShape's + if ( SMESH_subMesh* sm = _mesh->GetSubMesh( data._solid )) + { + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/false); + while ( smIt->more() ) + { + sm = smIt->next(); + if ( sm->GetSubShape().ShapeType() == TopAbs_FACE && + !faceIds.count( sm->GetId() )) + continue; + setShapeData( edgesByGeom[ sm->GetId() ], sm, data ); + } + } + // make _LayerEdge's + for ( set::iterator id = faceIds.begin(); id != faceIds.end(); ++id ) + { + const TopoDS_Face& F = TopoDS::Face( getMeshDS()->IndexToShape( *id )); + SMESH_subMesh* sm = _mesh->GetSubMesh( F ); + SMESH_ProxyMesh::SubMesh* proxySub = + data._proxyMesh->getFaceSubM( F, /*create=*/true); + + SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); + if ( !smDS ) return error(SMESH_Comment("Not meshed face ") << *id, data._index ); + + SMDS_ElemIteratorPtr eIt = smDS->GetElements(); + while ( eIt->more() ) + { + const SMDS_MeshElement* face = eIt->next(); + double faceMaxCosin = -1; + _LayerEdge* maxCosinEdge = 0; + int nbDegenNodes = 0; + + newNodes.resize( face->NbCornerNodes() ); + for ( size_t i = 0 ; i < newNodes.size(); ++i ) + { + const SMDS_MeshNode* n = face->GetNode( i ); + const int shapeID = n->getshapeId(); + const bool onDegenShap = helper.IsDegenShape( shapeID ); + const bool onDegenEdge = ( onDegenShap && n->GetPosition()->GetDim() == 1 ); + if ( onDegenShap ) + { + if ( onDegenEdge ) + { + // substitute n on a degenerated EDGE with a node on a corresponding VERTEX + const TopoDS_Shape& E = getMeshDS()->IndexToShape( shapeID ); + TopoDS_Vertex V = helper.IthVertex( 0, TopoDS::Edge( E )); + if ( const SMDS_MeshNode* vN = SMESH_Algo::VertexNode( V, getMeshDS() )) { + n = vN; + nbDegenNodes++; + } + } + else + { + nbDegenNodes++; + } + } + TNode2Edge::iterator n2e = data._n2eMap.insert( make_pair( n, (_LayerEdge*)0 )).first; + if ( !(*n2e).second ) + { + // add a _LayerEdge + _LayerEdge* edge = new _LayerEdge(); + edge->_nodes.push_back( n ); + n2e->second = edge; + edgesByGeom[ shapeID ]._edges.push_back( edge ); + const bool noShrink = data._noShrinkShapes.count( shapeID ); + + SMESH_TNodeXYZ xyz( n ); + + // set edge data or find already refined _LayerEdge and get data from it + if (( !noShrink ) && + ( n->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE ) && + (( s2ne = data._s2neMap.find( shapeID )) != data._s2neMap.end() ) && + (( n2e2 = (*s2ne).second->find( n )) != s2ne->second->end() )) + { + _LayerEdge* foundEdge = (*n2e2).second; + gp_XYZ lastPos = edge->Copy( *foundEdge, edgesByGeom[ shapeID ], helper ); + foundEdge->_pos.push_back( lastPos ); + // location of the last node is modified and we restore it by foundEdge->_pos.back() + const_cast< SMDS_MeshNode* > + ( edge->_nodes.back() )->setXYZ( xyz.X(), xyz.Y(), xyz.Z() ); + } + else + { + if ( !noShrink ) + { + edge->_nodes.push_back( helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() )); + } + if ( !setEdgeData( *edge, edgesByGeom[ shapeID ], subIds, helper, data )) + return false; + } + dumpMove(edge->_nodes.back()); + + if ( edge->_cosin > faceMaxCosin ) + { + faceMaxCosin = edge->_cosin; + maxCosinEdge = edge; + } + } + newNodes[ i ] = n2e->second->_nodes.back(); + + if ( onDegenEdge ) + data._n2eMap.insert( make_pair( face->GetNode( i ), n2e->second )); + } + if ( newNodes.size() - nbDegenNodes < 2 ) + continue; + + // create a temporary face + const SMDS_MeshElement* newFace = + new _TmpMeshFace( newNodes, --_tmpFaceID, face->getshapeId() ); + proxySub->AddElement( newFace ); + + // compute inflation step size by min size of element on a convex surface + if ( faceMaxCosin > theMinSmoothCosin ) + limitStepSize( data, face, maxCosinEdge ); + + } // loop on 2D elements on a FACE + } // loop on FACEs of a SOLID + + data._epsilon = 1e-7; + if ( data._stepSize < 1. ) + data._epsilon *= data._stepSize; + + if ( !findShapesToSmooth( data )) + return false; + + // limit data._stepSize depending on surface curvature and fill data._convexFaces + limitStepSizeByCurvature( data ); // !!! it must be before node substitution in _Simplex + + // Set target nodes into _Simplex and _LayerEdge's to _2NearEdges + TNode2Edge::iterator n2e; + const SMDS_MeshNode* nn[2]; + for ( size_t iS = 0; iS < data._edgesOnShape.size(); ++iS ) + { + _EdgesOnShape& eos = data._edgesOnShape[iS]; + vector< _LayerEdge* >& localEdges = eos._edges; + for ( size_t i = 0; i < localEdges.size(); ++i ) + { + _LayerEdge* edge = localEdges[i]; + if ( edge->IsOnEdge() ) + { + // get neighbor nodes + bool hasData = ( edge->_2neibors->_edges[0] ); + if ( hasData ) // _LayerEdge is a copy of another one + { + nn[0] = edge->_2neibors->srcNode(0); + nn[1] = edge->_2neibors->srcNode(1); + } + else if ( !findNeiborsOnEdge( edge, nn[0],nn[1], eos, data )) + { + return false; + } + // set neighbor _LayerEdge's + for ( int j = 0; j < 2; ++j ) + { + if (( n2e = data._n2eMap.find( nn[j] )) == data._n2eMap.end() ) + return error("_LayerEdge not found by src node", data._index); + edge->_2neibors->_edges[j] = n2e->second; + } + if ( !hasData ) + edge->SetDataByNeighbors( nn[0], nn[1], eos, helper ); + } + + for ( size_t j = 0; j < edge->_simplices.size(); ++j ) + { + _Simplex& s = edge->_simplices[j]; + s._nNext = data._n2eMap[ s._nNext ]->_nodes.back(); + s._nPrev = data._n2eMap[ s._nPrev ]->_nodes.back(); + } + + // For an _LayerEdge on a degenerated EDGE, copy some data from + // a corresponding _LayerEdge on a VERTEX + // (issue 52453, pb on a downloaded SampleCase2-Tet-netgen-mephisto.hdf) + if ( helper.IsDegenShape( edge->_nodes[0]->getshapeId() )) + { + // Generally we should not get here + if ( eos.ShapeType() != TopAbs_EDGE ) + continue; + TopoDS_Vertex V = helper.IthVertex( 0, TopoDS::Edge( eos._shape )); + const SMDS_MeshNode* vN = SMESH_Algo::VertexNode( V, getMeshDS() ); + if (( n2e = data._n2eMap.find( vN )) == data._n2eMap.end() ) + continue; + const _LayerEdge* vEdge = n2e->second; + edge->_normal = vEdge->_normal; + edge->_lenFactor = vEdge->_lenFactor; + edge->_cosin = vEdge->_cosin; + } + } + } + + // fix _LayerEdge::_2neibors on EDGEs to smooth + map< TGeomID,Handle(Geom_Curve)>::iterator e2c = data._edge2curve.begin(); + for ( ; e2c != data._edge2curve.end(); ++e2c ) + if ( !e2c->second.IsNull() ) + { + if ( _EdgesOnShape* eos = data.GetShapeEdges( e2c->first )) + data.Sort2NeiborsOnEdge( eos->_edges ); + } + + dumpFunctionEnd(); + return true; +} + +//================================================================================ +/*! + * \brief Compute inflation step size by min size of element on a convex surface + */ +//================================================================================ + +void _ViscousBuilder::limitStepSize( _SolidData& data, + const SMDS_MeshElement* face, + const _LayerEdge* maxCosinEdge ) +{ + int iN = 0; + double minSize = 10 * data._stepSize; + const int nbNodes = face->NbCornerNodes(); + for ( int i = 0; i < nbNodes; ++i ) + { + const SMDS_MeshNode* nextN = face->GetNode( SMESH_MesherHelper::WrapIndex( i+1, nbNodes )); + const SMDS_MeshNode* curN = face->GetNode( i ); + if ( nextN->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE || + curN-> GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) + { + double dist = SMESH_TNodeXYZ( curN ).Distance( nextN ); + if ( dist < minSize ) + minSize = dist, iN = i; + } + } + double newStep = 0.8 * minSize / maxCosinEdge->_lenFactor; + if ( newStep < data._stepSize ) + { + data._stepSize = newStep; + data._stepSizeCoeff = 0.8 / maxCosinEdge->_lenFactor; + data._stepSizeNodes[0] = face->GetNode( iN ); + data._stepSizeNodes[1] = face->GetNode( SMESH_MesherHelper::WrapIndex( iN+1, nbNodes )); + } +} + +//================================================================================ +/*! + * \brief Compute inflation step size by min size of element on a convex surface + */ +//================================================================================ + +void _ViscousBuilder::limitStepSize( _SolidData& data, const double minSize ) +{ + if ( minSize < data._stepSize ) + { + data._stepSize = minSize; + if ( data._stepSizeNodes[0] ) + { + double dist = + SMESH_TNodeXYZ(data._stepSizeNodes[0]).Distance(data._stepSizeNodes[1]); + data._stepSizeCoeff = data._stepSize / dist; + } + } +} + +//================================================================================ +/*! + * \brief Limit data._stepSize by evaluating curvature of shapes and fill data._convexFaces + */ +//================================================================================ + +void _ViscousBuilder::limitStepSizeByCurvature( _SolidData& data ) +{ + const int nbTestPnt = 5; // on a FACE sub-shape + + BRepLProp_SLProps surfProp( 2, 1e-6 ); + SMESH_MesherHelper helper( *_mesh ); + + data._convexFaces.clear(); + + for ( size_t iS = 0; iS < data._edgesOnShape.size(); ++iS ) + { + _EdgesOnShape& eof = data._edgesOnShape[iS]; + if ( eof.ShapeType() != TopAbs_FACE || + data._ignoreFaceIds.count( eof._shapeID )) + continue; + + TopoDS_Face F = TopoDS::Face( eof._shape ); + SMESH_subMesh * sm = eof._subMesh; + const TGeomID faceID = eof._shapeID; + + BRepAdaptor_Surface surface( F, false ); + surfProp.SetSurface( surface ); + + bool isTooCurved = false; + + _ConvexFace cnvFace; + const double oriFactor = ( F.Orientation() == TopAbs_REVERSED ? +1. : -1. ); + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true); + while ( smIt->more() ) + { + sm = smIt->next(); + const TGeomID subID = sm->GetId(); + // find _LayerEdge's of a sub-shape + _EdgesOnShape* eos; + if (( eos = data.GetShapeEdges( subID ))) + cnvFace._subIdToEOS.insert( make_pair( subID, eos )); + else + continue; + // check concavity and curvature and limit data._stepSize + const double minCurvature = + 1. / ( eos->_hyp.GetTotalThickness() * ( 1+theThickToIntersection )); + size_t iStep = Max( 1, eos->_edges.size() / nbTestPnt ); + for ( size_t i = 0; i < eos->_edges.size(); i += iStep ) + { + gp_XY uv = helper.GetNodeUV( F, eos->_edges[ i ]->_nodes[0] ); + surfProp.SetParameters( uv.X(), uv.Y() ); + if ( !surfProp.IsCurvatureDefined() ) + continue; + if ( surfProp.MaxCurvature() * oriFactor > minCurvature ) + { + limitStepSize( data, 0.9 / surfProp.MaxCurvature() * oriFactor ); + isTooCurved = true; + } + if ( surfProp.MinCurvature() * oriFactor > minCurvature ) + { + limitStepSize( data, 0.9 / surfProp.MinCurvature() * oriFactor ); + isTooCurved = true; + } + } + } // loop on sub-shapes of the FACE + + if ( !isTooCurved ) continue; + + _ConvexFace & convFace = + data._convexFaces.insert( make_pair( faceID, cnvFace )).first->second; + + convFace._face = F; + convFace._normalsFixed = false; + + // Fill _ConvexFace::_simplexTestEdges. These _LayerEdge's are used to detect + // prism distortion. + map< TGeomID, _EdgesOnShape* >::iterator id2eos = convFace._subIdToEOS.find( faceID ); + if ( id2eos != convFace._subIdToEOS.end() && !id2eos->second->_edges.empty() ) + { + // there are _LayerEdge's on the FACE it-self; + // select _LayerEdge's near EDGEs + _EdgesOnShape& eos = * id2eos->second; + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + _LayerEdge* ledge = eos._edges[ i ]; + for ( size_t j = 0; j < ledge->_simplices.size(); ++j ) + if ( ledge->_simplices[j]._nNext->GetPosition()->GetDim() < 2 ) + { + convFace._simplexTestEdges.push_back( ledge ); + break; + } + } + } + else + { + // where there are no _LayerEdge's on a _ConvexFace, + // as e.g. on a fillet surface with no internal nodes - issue 22580, + // so that collision of viscous internal faces is not detected by check of + // intersection of _LayerEdge's with the viscous internal faces. + + set< const SMDS_MeshNode* > usedNodes; + + // look for _LayerEdge's with null _sWOL + id2eos = convFace._subIdToEOS.begin(); + for ( ; id2eos != convFace._subIdToEOS.end(); ++id2eos ) + { + _EdgesOnShape& eos = * id2eos->second; + if ( !eos._sWOL.IsNull() ) + continue; + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + _LayerEdge* ledge = eos._edges[ i ]; + const SMDS_MeshNode* srcNode = ledge->_nodes[0]; + if ( !usedNodes.insert( srcNode ).second ) continue; + + _Simplex::GetSimplices( srcNode, ledge->_simplices, data._ignoreFaceIds, &data ); + for ( size_t i = 0; i < ledge->_simplices.size(); ++i ) + { + usedNodes.insert( ledge->_simplices[i]._nPrev ); + usedNodes.insert( ledge->_simplices[i]._nNext ); + } + convFace._simplexTestEdges.push_back( ledge ); + } + } + } + } // loop on FACEs of data._solid +} + +//================================================================================ +/*! + * \brief Detect shapes (and _LayerEdge's on them) to smooth + */ +//================================================================================ + +bool _ViscousBuilder::findShapesToSmooth( _SolidData& data ) +{ + // define allowed thickness + computeGeomSize( data ); // compute data._geomSize + + data._maxThickness = 0; + data._minThickness = 1e100; + list< const StdMeshers_ViscousLayers* >::iterator hyp = data._hyps.begin(); + for ( ; hyp != data._hyps.end(); ++hyp ) + { + data._maxThickness = Max( data._maxThickness, (*hyp)->GetTotalThickness() ); + data._minThickness = Min( data._minThickness, (*hyp)->GetTotalThickness() ); + } + const double tgtThick = /*Min( 0.5 * data._geomSize, */data._maxThickness; + + // Find shapes needing smoothing; such a shape has _LayerEdge._normal on it's + // boundry inclined to the shape at a sharp angle + + //list< TGeomID > shapesToSmooth; + TopTools_MapOfShape edgesOfSmooFaces; + + SMESH_MesherHelper helper( *_mesh ); + bool ok = true; + + vector< _EdgesOnShape >& edgesByGeom = data._edgesOnShape; + data._nbShapesToSmooth = 0; + + for ( size_t iS = 0; iS < edgesByGeom.size(); ++iS ) // check FACEs + { + _EdgesOnShape& eos = edgesByGeom[iS]; + eos._toSmooth = false; + if ( eos._edges.empty() || eos.ShapeType() != TopAbs_FACE ) + continue; + + TopExp_Explorer eExp( edgesByGeom[iS]._shape, TopAbs_EDGE ); + for ( ; eExp.More() && !eos._toSmooth; eExp.Next() ) + { + TGeomID iE = getMeshDS()->ShapeToIndex( eExp.Current() ); + vector<_LayerEdge*>& eE = edgesByGeom[ iE ]._edges; + if ( eE.empty() ) continue; + // TopLoc_Location loc; + // Handle(Geom_Surface) surface = BRep_Tool::Surface( TopoDS::Face( S ), loc ); + // bool isPlane = GeomLib_IsPlanarSurface( surface ).IsPlanar(); + //if ( eE[0]->_sWOL.IsNull() ) + { + double faceSize; + for ( size_t i = 0; i < eE.size() && !eos._toSmooth; ++i ) + if ( eE[i]->_cosin > theMinSmoothCosin ) + { + SMDS_ElemIteratorPtr fIt = eE[i]->_nodes[0]->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() && !eos._toSmooth ) + { + const SMDS_MeshElement* face = fIt->next(); + if ( getDistFromEdge( face, eE[i]->_nodes[0], faceSize )) + eos._toSmooth = needSmoothing( eE[i]->_cosin, tgtThick, faceSize ); + } + } + } + // else + // { + // const TopoDS_Face& F1 = TopoDS::Face( S ); + // const TopoDS_Face& F2 = TopoDS::Face( eE[0]->_sWOL ); + // const TopoDS_Edge& E = TopoDS::Edge( eExp.Current() ); + // for ( size_t i = 0; i < eE.size() && !eos._toSmooth; ++i ) + // { + // gp_Vec dir1 = getFaceDir( F1, E, eE[i]->_nodes[0], helper, ok ); + // gp_Vec dir2 = getFaceDir( F2, E, eE[i]->_nodes[0], helper, ok ); + // double angle = dir1.Angle( ); + // double cosin = cos( angle ); + // eos._toSmooth = ( cosin > theMinSmoothCosin ); + // } + // } + } + if ( eos._toSmooth ) + { + for ( eExp.ReInit(); eExp.More(); eExp.Next() ) + edgesOfSmooFaces.Add( eExp.Current() ); + + data.PrepareEdgesToSmoothOnFace( &edgesByGeom[iS], /*substituteSrcNodes=*/false ); + } + data._nbShapesToSmooth += eos._toSmooth; + + } // check FACEs + + for ( size_t iS = 0; iS < edgesByGeom.size(); ++iS ) // check EDGEs + { + _EdgesOnShape& eos = edgesByGeom[iS]; + if ( eos._edges.empty() || eos.ShapeType() != TopAbs_EDGE ) continue; + if ( !eos._hyp.ToSmooth() ) continue; + + const TopoDS_Edge& E = TopoDS::Edge( edgesByGeom[iS]._shape ); + if ( SMESH_Algo::isDegenerated( E ) || !edgesOfSmooFaces.Contains( E )) + continue; + + for ( TopoDS_Iterator vIt( E ); vIt.More() && !eos._toSmooth; vIt.Next() ) + { + TGeomID iV = getMeshDS()->ShapeToIndex( vIt.Value() ); + vector<_LayerEdge*>& eV = edgesByGeom[ iV ]._edges; + if ( eV.empty() ) continue; + gp_Vec eDir = getEdgeDir( E, TopoDS::Vertex( vIt.Value() )); + double angle = eDir.Angle( eV[0]->_normal ); + double cosin = Cos( angle ); + double cosinAbs = Abs( cosin ); + if ( cosinAbs > theMinSmoothCosin ) + { + // always smooth analytic EDGEs + eos._toSmooth = ! data.CurveForSmooth( E, eos, helper ).IsNull(); + + // compare tgtThick with the length of an end segment + SMDS_ElemIteratorPtr eIt = eV[0]->_nodes[0]->GetInverseElementIterator(SMDSAbs_Edge); + while ( eIt->more() && !eos._toSmooth ) + { + const SMDS_MeshElement* endSeg = eIt->next(); + if ( endSeg->getshapeId() == iS ) + { + double segLen = + SMESH_TNodeXYZ( endSeg->GetNode(0) ).Distance( endSeg->GetNode(1 )); + eos._toSmooth = needSmoothing( cosinAbs, tgtThick, segLen ); + } + } + } + } + data._nbShapesToSmooth += eos._toSmooth; + + } // check EDGEs + + // Reset _cosin if no smooth is allowed by the user + for ( size_t iS = 0; iS < edgesByGeom.size(); ++iS ) + { + _EdgesOnShape& eos = edgesByGeom[iS]; + if ( eos._edges.empty() ) continue; + + if ( !eos._hyp.ToSmooth() ) + for ( size_t i = 0; i < eos._edges.size(); ++i ) + eos._edges[i]->SetCosin( 0 ); + } + + + // int nbShapes = 0; + // for ( size_t iS = 0; iS < edgesByGeom.size(); ++iS ) + // { + // nbShapes += ( edgesByGeom[iS]._edges.size() > 0 ); + // } + // data._edgesOnShape.reserve( nbShapes ); + + // // first we put _LayerEdge's on shapes to smooth (EGDEs go first) + // vector< _LayerEdge* > edges; + // list< TGeomID >::iterator gIt = shapesToSmooth.begin(); + // for ( ; gIt != shapesToSmooth.end(); ++gIt ) + // { + // _EdgesOnShape& eos = edgesByGeom[ *gIt ]; + // if ( eos._edges.empty() ) continue; + // eos._edges.swap( edges ); // avoid copying array + // eos._toSmooth = true; + // data._edgesOnShape.push_back( eos ); + // data._edgesOnShape.back()._edges.swap( edges ); + // } + + // // then the rest _LayerEdge's + // for ( size_t iS = 0; iS < edgesByGeom.size(); ++iS ) + // { + // _EdgesOnShape& eos = edgesByGeom[ *gIt ]; + // if ( eos._edges.empty() ) continue; + // eos._edges.swap( edges ); // avoid copying array + // eos._toSmooth = false; + // data._edgesOnShape.push_back( eos ); + // data._edgesOnShape.back()._edges.swap( edges ); + // } + + return ok; +} + +//================================================================================ +/*! + * \brief initialize data of _EdgesOnShape + */ +//================================================================================ + +void _ViscousBuilder::setShapeData( _EdgesOnShape& eos, + SMESH_subMesh* sm, + _SolidData& data ) +{ + if ( !eos._shape.IsNull() || + sm->GetSubShape().ShapeType() == TopAbs_WIRE ) + return; + + SMESH_MesherHelper helper( *_mesh ); + + eos._subMesh = sm; + eos._shapeID = sm->GetId(); + eos._shape = sm->GetSubShape(); + if ( eos.ShapeType() == TopAbs_FACE ) + eos._shape.Orientation( helper.GetSubShapeOri( data._solid, eos._shape )); + eos._toSmooth = false; + + // set _SWOL + map< TGeomID, TopoDS_Shape >::const_iterator s2s = + data._shrinkShape2Shape.find( eos._shapeID ); + if ( s2s != data._shrinkShape2Shape.end() ) + eos._sWOL = s2s->second; + + // set _hyp + if ( data._hyps.size() == 1 ) + { + eos._hyp = data._hyps.back(); + } + else + { + // compute average StdMeshers_ViscousLayers parameters + map< TGeomID, const StdMeshers_ViscousLayers* >::iterator f2hyp; + if ( eos.ShapeType() == TopAbs_FACE ) + { + if (( f2hyp = data._face2hyp.find( eos._shapeID )) != data._face2hyp.end() ) + eos._hyp = f2hyp->second; + } + else + { + PShapeIteratorPtr fIt = helper.GetAncestors( eos._shape, *_mesh, TopAbs_FACE ); + while ( const TopoDS_Shape* face = fIt->next() ) + { + TGeomID faceID = getMeshDS()->ShapeToIndex( *face ); + if (( f2hyp = data._face2hyp.find( faceID )) != data._face2hyp.end() ) + eos._hyp.Add( f2hyp->second ); + } + } + } + + // set _faceNormals + if ( ! eos._hyp.UseSurfaceNormal() ) + { + if ( eos.ShapeType() == TopAbs_FACE ) // get normals to elements on a FACE + { + SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); + eos._faceNormals.resize( smDS->NbElements() ); + + SMDS_ElemIteratorPtr eIt = smDS->GetElements(); + for ( int iF = 0; eIt->more(); ++iF ) + { + const SMDS_MeshElement* face = eIt->next(); + if ( !SMESH_MeshAlgos::FaceNormal( face, eos._faceNormals[iF], /*normalized=*/true )) + eos._faceNormals[iF].SetCoord( 0,0,0 ); + } + + if ( !helper.IsReversedSubMesh( TopoDS::Face( eos._shape ))) + for ( size_t iF = 0; iF < eos._faceNormals.size(); ++iF ) + eos._faceNormals[iF].Reverse(); + } + else // find EOS of adjacent FACEs + { + PShapeIteratorPtr fIt = helper.GetAncestors( eos._shape, *_mesh, TopAbs_FACE ); + while ( const TopoDS_Shape* face = fIt->next() ) + { + TGeomID faceID = getMeshDS()->ShapeToIndex( *face ); + eos._faceEOS.push_back( & data._edgesOnShape[ faceID ]); + if ( eos._faceEOS.back()->_shape.IsNull() ) + // avoid using uninitialised _shapeID in GetNormal() + eos._faceEOS.back()->_shapeID = faceID; + } + } + } +} + +//================================================================================ +/*! + * \brief Returns normal of a face + */ +//================================================================================ + +bool _EdgesOnShape::GetNormal( const SMDS_MeshElement* face, gp_Vec& norm ) +{ + bool ok = false; + const _EdgesOnShape* eos = 0; + + if ( face->getshapeId() == _shapeID ) + { + eos = this; + } + else + { + for ( size_t iF = 0; iF < _faceEOS.size() && !eos; ++iF ) + if ( face->getshapeId() == _faceEOS[ iF ]->_shapeID ) + eos = _faceEOS[ iF ]; + } + + if (( eos ) && + ( ok = ( face->getIdInShape() < eos->_faceNormals.size() ))) + { + norm = eos->_faceNormals[ face->getIdInShape() ]; + } + else if ( !eos ) + { + debugMsg( "_EdgesOnShape::Normal() failed for face "<GetID() + << " on _shape #" << _shapeID ); + } + return ok; +} + + +//================================================================================ +/*! + * \brief Set data of _LayerEdge needed for smoothing + * \param subIds - ids of sub-shapes of a SOLID to take into account faces from + */ +//================================================================================ + +bool _ViscousBuilder::setEdgeData(_LayerEdge& edge, + _EdgesOnShape& eos, + const set& subIds, + SMESH_MesherHelper& helper, + _SolidData& data) +{ + const SMDS_MeshNode* node = edge._nodes[0]; // source node + + edge._len = 0; + edge._2neibors = 0; + edge._curvature = 0; + + // -------------------------- + // Compute _normal and _cosin + // -------------------------- + + edge._cosin = 0; + edge._normal.SetCoord(0,0,0); + + int totalNbFaces = 0; + TopoDS_Face F; + std::pair< TopoDS_Face, gp_XYZ > face2Norm[20]; + gp_Vec geomNorm; + bool normOK = true; + + const bool onShrinkShape = !eos._sWOL.IsNull(); + const bool useGeometry = (( eos._hyp.UseSurfaceNormal() ) || + ( eos.ShapeType() != TopAbs_FACE && !onShrinkShape )); + + // get geom FACEs the node lies on + //if ( useGeometry ) + { + set faceIds; + if ( eos.ShapeType() == TopAbs_FACE ) + { + faceIds.insert( eos._shapeID ); + } + else + { + SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + faceIds.insert( fIt->next()->getshapeId() ); + } + set::iterator id = faceIds.begin(); + for ( ; id != faceIds.end(); ++id ) + { + const TopoDS_Shape& s = getMeshDS()->IndexToShape( *id ); + if ( s.IsNull() || s.ShapeType() != TopAbs_FACE || !subIds.count( *id )) + continue; + F = TopoDS::Face( s ); + face2Norm[ totalNbFaces ].first = F; + totalNbFaces++; + } + } + + // find _normal + if ( useGeometry ) + { + if ( onShrinkShape ) // one of faces the node is on has no layers + { + if ( eos.SWOLType() == TopAbs_EDGE ) + { + // inflate from VERTEX along EDGE + edge._normal = getEdgeDir( TopoDS::Edge( eos._sWOL ), TopoDS::Vertex( eos._shape )); + } + else if ( eos.ShapeType() == TopAbs_VERTEX ) + { + // inflate from VERTEX along FACE + edge._normal = getFaceDir( TopoDS::Face( eos._sWOL ), TopoDS::Vertex( eos._shape ), + node, helper, normOK, &edge._cosin); + } + else + { + // inflate from EDGE along FACE + edge._normal = getFaceDir( TopoDS::Face( eos._sWOL ), TopoDS::Edge( eos._shape ), + node, helper, normOK); + } + } + + // layers are on all faces of SOLID the node is on + else + { + int nbOkNorms = 0; + for ( int iF = 0; iF < totalNbFaces; ++iF ) + { + F = TopoDS::Face( face2Norm[ iF ].first ); + geomNorm = getFaceNormal( node, F, helper, normOK ); + if ( !normOK ) continue; + nbOkNorms++; + + if ( helper.GetSubShapeOri( data._solid, F ) != TopAbs_REVERSED ) + geomNorm.Reverse(); + face2Norm[ iF ].second = geomNorm.XYZ(); + edge._normal += geomNorm.XYZ(); + } + if ( nbOkNorms == 0 ) + return error(SMESH_Comment("Can't get normal to node ") << node->GetID(), data._index); + + if ( edge._normal.Modulus() < 1e-3 && nbOkNorms > 1 ) + { + // opposite normals, re-get normals at shifted positions (IPAL 52426) + edge._normal.SetCoord( 0,0,0 ); + for ( int iF = 0; iF < totalNbFaces; ++iF ) + { + const TopoDS_Face& F = face2Norm[iF].first; + geomNorm = getFaceNormal( node, F, helper, normOK, /*shiftInside=*/true ); + if ( helper.GetSubShapeOri( data._solid, F ) != TopAbs_REVERSED ) + geomNorm.Reverse(); + if ( normOK ) + face2Norm[ iF ].second = geomNorm.XYZ(); + edge._normal += face2Norm[ iF ].second; + } + } + + if ( totalNbFaces < 3 ) + { + //edge._normal /= totalNbFaces; + } + else + { + edge._normal = getWeigthedNormal( node, face2Norm, totalNbFaces ); + } + } + } + else // !useGeometry - get _normal using surrounding mesh faces + { + set faceIds; + + SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + { + const SMDS_MeshElement* face = fIt->next(); + if ( eos.GetNormal( face, geomNorm )) + { + if ( onShrinkShape && !faceIds.insert( face->getshapeId() ).second ) + continue; // use only one mesh face on FACE + edge._normal += geomNorm.XYZ(); + totalNbFaces++; + } + } + } + + // compute _cosin + //if ( eos._hyp.UseSurfaceNormal() ) + { + switch ( eos.ShapeType() ) + { + case TopAbs_FACE: { + edge._cosin = 0; + break; + } + case TopAbs_EDGE: { + TopoDS_Edge E = TopoDS::Edge( eos._shape ); + gp_Vec inFaceDir = getFaceDir( F, E, node, helper, normOK ); + double angle = inFaceDir.Angle( edge._normal ); // [0,PI] + edge._cosin = Cos( angle ); + //cout << "Cosin on EDGE " << edge._cosin << " node " << node->GetID() << endl; + break; + } + case TopAbs_VERTEX: { + if ( eos.SWOLType() != TopAbs_FACE ) { // else _cosin is set by getFaceDir() + TopoDS_Vertex V = TopoDS::Vertex( eos._shape ); + gp_Vec inFaceDir = getFaceDir( F, V, node, helper, normOK ); + double angle = inFaceDir.Angle( edge._normal ); // [0,PI] + edge._cosin = Cos( angle ); + if ( totalNbFaces > 2 || helper.IsSeamShape( node->getshapeId() )) + for ( int iF = totalNbFaces-2; iF >=0; --iF ) + { + F = face2Norm[ iF ].first; + inFaceDir = getFaceDir( F, V, node, helper, normOK=true ); + if ( normOK ) { + double angle = inFaceDir.Angle( edge._normal ); + edge._cosin = Max( edge._cosin, Cos( angle )); + } + } + } + //cout << "Cosin on VERTEX " << edge._cosin << " node " << node->GetID() << endl; + break; + } + default: + return error(SMESH_Comment("Invalid shape position of node ")<::min() ) + return error(SMESH_Comment("Bad normal at node ")<< node->GetID(), data._index ); + + edge._normal /= sqrt( normSize ); + + // TODO: if ( !normOK ) then get normal by mesh faces + + // Set the rest data + // -------------------- + if ( onShrinkShape ) + { + SMDS_MeshNode* tgtNode = const_cast( edge._nodes.back() ); + if ( SMESHDS_SubMesh* sm = getMeshDS()->MeshElements( data._solid )) + sm->RemoveNode( tgtNode , /*isNodeDeleted=*/false ); + + // set initial position which is parameters on _sWOL in this case + if ( eos.SWOLType() == TopAbs_EDGE ) + { + double u = helper.GetNodeU( TopoDS::Edge( eos._sWOL ), node, 0, &normOK ); + edge._pos.push_back( gp_XYZ( u, 0, 0 )); + if ( edge._nodes.size() > 1 ) + getMeshDS()->SetNodeOnEdge( tgtNode, TopoDS::Edge( eos._sWOL ), u ); + } + else // TopAbs_FACE + { + gp_XY uv = helper.GetNodeUV( TopoDS::Face( eos._sWOL ), node, 0, &normOK ); + edge._pos.push_back( gp_XYZ( uv.X(), uv.Y(), 0)); + if ( edge._nodes.size() > 1 ) + getMeshDS()->SetNodeOnFace( tgtNode, TopoDS::Face( eos._sWOL ), uv.X(), uv.Y() ); + } + } + else + { + edge._pos.push_back( SMESH_TNodeXYZ( node )); + + if ( eos.ShapeType() == TopAbs_FACE ) + { + _Simplex::GetSimplices( node, edge._simplices, data._ignoreFaceIds, &data ); + } + } + + // Set neighbour nodes for a _LayerEdge based on EDGE + + if ( eos.ShapeType() == TopAbs_EDGE /*|| + ( onShrinkShape && posType == SMDS_TOP_VERTEX && fabs( edge._cosin ) < 1e-10 )*/) + { + edge._2neibors = new _2NearEdges; + // target node instead of source ones will be set later + // if ( ! findNeiborsOnEdge( &edge, + // edge._2neibors->_nodes[0], + // edge._2neibors->_nodes[1], eos, + // data)) + // return false; + // edge.SetDataByNeighbors( edge._2neibors->_nodes[0], + // edge._2neibors->_nodes[1], + // helper); + } + + edge.SetCosin( edge._cosin ); // to update edge._lenFactor + + return true; +} + +//================================================================================ +/*! + * \brief Return normal to a FACE at a node + * \param [in] n - node + * \param [in] face - FACE + * \param [in] helper - helper + * \param [out] isOK - true or false + * \param [in] shiftInside - to find normal at a position shifted inside the face + * \return gp_XYZ - normal + */ +//================================================================================ + +gp_XYZ _ViscousBuilder::getFaceNormal(const SMDS_MeshNode* node, + const TopoDS_Face& face, + SMESH_MesherHelper& helper, + bool& isOK, + bool shiftInside) +{ + gp_XY uv; + if ( shiftInside ) + { + // get a shifted position + gp_Pnt p = SMESH_TNodeXYZ( node ); + gp_XYZ shift( 0,0,0 ); + TopoDS_Shape S = helper.GetSubShapeByNode( node, helper.GetMeshDS() ); + switch ( S.ShapeType() ) { + case TopAbs_VERTEX: + { + shift = getFaceDir( face, TopoDS::Vertex( S ), node, helper, isOK ); + break; + } + case TopAbs_EDGE: + { + shift = getFaceDir( face, TopoDS::Edge( S ), node, helper, isOK ); + break; + } + default: + isOK = false; + } + if ( isOK ) + shift.Normalize(); + p.Translate( shift * 1e-5 ); + + TopLoc_Location loc; + GeomAPI_ProjectPointOnSurf& projector = helper.GetProjector( face, loc, 1e-7 ); + + if ( !loc.IsIdentity() ) p.Transform( loc.Transformation().Inverted() ); + + projector.Perform( p ); + if ( !projector.IsDone() || projector.NbPoints() < 1 ) + { + isOK = false; + return p.XYZ(); + } + Quantity_Parameter U,V; + projector.LowerDistanceParameters(U,V); + uv.SetCoord( U,V ); + } + else + { + uv = helper.GetNodeUV( face, node, 0, &isOK ); + } + + gp_Dir normal; + isOK = false; + + Handle(Geom_Surface) surface = BRep_Tool::Surface( face ); + + if ( !shiftInside && + helper.IsDegenShape( node->getshapeId() ) && + getFaceNormalAtSingularity( uv, face, helper, normal )) + { + isOK = true; + return normal.XYZ(); + } + + int pointKind = GeomLib::NormEstim( surface, uv, 1e-5, normal ); + enum { REGULAR = 0, QUASYSINGULAR, CONICAL, IMPOSSIBLE }; + + if ( pointKind == IMPOSSIBLE && + node->GetPosition()->GetDim() == 2 ) // node inside the FACE + { + // probably NormEstim() failed due to a too high tolerance + pointKind = GeomLib::NormEstim( surface, uv, 1e-20, normal ); + isOK = ( pointKind < IMPOSSIBLE ); + } + if ( pointKind < IMPOSSIBLE ) + { + if ( pointKind != REGULAR && + !shiftInside && + node->GetPosition()->GetDim() < 2 ) // FACE boundary + { + gp_XYZ normShift = getFaceNormal( node, face, helper, isOK, /*shiftInside=*/true ); + if ( normShift * normal.XYZ() < 0. ) + normal = normShift; + } + isOK = true; + } + + if ( !isOK ) // hard singularity, to call with shiftInside=true ? + { + const TGeomID faceID = helper.GetMeshDS()->ShapeToIndex( face ); + + SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + if ( f->getshapeId() == faceID ) + { + isOK = SMESH_MeshAlgos::FaceNormal( f, (gp_XYZ&) normal.XYZ(), /*normalized=*/true ); + if ( isOK ) + { + TopoDS_Face ff = face; + ff.Orientation( TopAbs_FORWARD ); + if ( helper.IsReversedSubMesh( ff )) + normal.Reverse(); + break; + } + } + } + } + return normal.XYZ(); +} + +//================================================================================ +/*! + * \brief Try to get normal at a singularity of a surface basing on it's nature + */ +//================================================================================ + +bool _ViscousBuilder::getFaceNormalAtSingularity( const gp_XY& uv, + const TopoDS_Face& face, + SMESH_MesherHelper& helper, + gp_Dir& normal ) +{ + BRepAdaptor_Surface surface( face ); + gp_Dir axis; + if ( !getRovolutionAxis( surface, axis )) + return false; + + double f,l, d, du, dv; + f = surface.FirstUParameter(); + l = surface.LastUParameter(); + d = ( uv.X() - f ) / ( l - f ); + du = ( d < 0.5 ? +1. : -1 ) * 1e-5 * ( l - f ); + f = surface.FirstVParameter(); + l = surface.LastVParameter(); + d = ( uv.Y() - f ) / ( l - f ); + dv = ( d < 0.5 ? +1. : -1 ) * 1e-5 * ( l - f ); + + gp_Dir refDir; + gp_Pnt2d testUV = uv; + enum { REGULAR = 0, QUASYSINGULAR, CONICAL, IMPOSSIBLE }; + double tol = 1e-5; + Handle(Geom_Surface) geomsurf = surface.Surface().Surface(); + for ( int iLoop = 0; true ; ++iLoop ) + { + testUV.SetCoord( testUV.X() + du, testUV.Y() + dv ); + if ( GeomLib::NormEstim( geomsurf, testUV, tol, refDir ) == REGULAR ) + break; + if ( iLoop > 20 ) + return false; + tol /= 10.; + } + + if ( axis * refDir < 0. ) + axis.Reverse(); + + normal = axis; + + return true; +} + +//================================================================================ +/*! + * \brief Return a normal at a node weighted with angles taken by FACEs + * \param [in] n - the node + * \param [in] fId2Normal - FACE ids and normals + * \param [in] nbFaces - nb of FACEs meeting at the node + * \return gp_XYZ - computed normal + */ +//================================================================================ + +gp_XYZ _ViscousBuilder::getWeigthedNormal( const SMDS_MeshNode* n, + std::pair< TopoDS_Face, gp_XYZ > fId2Normal[], + int nbFaces ) +{ + gp_XYZ resNorm(0,0,0); + TopoDS_Shape V = SMESH_MesherHelper::GetSubShapeByNode( n, getMeshDS() ); + if ( V.ShapeType() != TopAbs_VERTEX ) + { + for ( int i = 0; i < nbFaces; ++i ) + resNorm += fId2Normal[i].second; + return resNorm; + } + + // exclude equal normals + int nbUniqNorms = nbFaces; + for ( int i = 0; i < nbFaces; ++i ) { + for ( int j = i+1; j < nbFaces; ++j ) + if ( fId2Normal[i].second.IsEqual( fId2Normal[j].second, 0.1 )) + { + fId2Normal[i].second.SetCoord( 0,0,0 ); + --nbUniqNorms; + break; + } + } + for ( int i = 0; i < nbFaces; ++i ) + resNorm += fId2Normal[i].second; + + // assure that resNorm is visible by every FACE (IPAL0052675) + if ( nbUniqNorms > 3 ) + { + bool change = false; + for ( int nbAttempts = 0; nbAttempts < nbFaces; ++nbAttempts) + { + for ( int i = 0; i < nbFaces; ++i ) + if ( resNorm * fId2Normal[i].second < 0.5 ) + { + resNorm += fId2Normal[i].second; + change = true; + } + if ( !change ) break; + } + } + + // double angles[30]; + // for ( int i = 0; i < nbFaces; ++i ) + // { + // const TopoDS_Face& F = fId2Normal[i].first; + + // // look for two EDGEs shared by F and other FACEs within fId2Normal + // TopoDS_Edge ee[2]; + // int nbE = 0; + // PShapeIteratorPtr eIt = SMESH_MesherHelper::GetAncestors( V, *_mesh, TopAbs_EDGE ); + // while ( const TopoDS_Shape* E = eIt->next() ) + // { + // if ( !SMESH_MesherHelper::IsSubShape( *E, F )) + // continue; + // bool isSharedEdge = false; + // for ( int j = 0; j < nbFaces && !isSharedEdge; ++j ) + // { + // if ( i == j ) continue; + // const TopoDS_Shape& otherF = fId2Normal[j].first; + // isSharedEdge = SMESH_MesherHelper::IsSubShape( *E, otherF ); + // } + // if ( !isSharedEdge ) + // continue; + // ee[ nbE ] = TopoDS::Edge( *E ); + // ee[ nbE ].Orientation( SMESH_MesherHelper::GetSubShapeOri( F, *E )); + // if ( ++nbE == 2 ) + // break; + // } + + // // get an angle between the two EDGEs + // angles[i] = 0; + // if ( nbE < 1 ) continue; + // if ( nbE == 1 ) + // { + // ee[ 1 ] == ee[ 0 ]; + // } + // else + // { + // if ( !V.IsSame( SMESH_MesherHelper::IthVertex( 0, ee[ 1 ] ))) + // std::swap( ee[0], ee[1] ); + // } + // angles[i] = SMESH_MesherHelper::GetAngle( ee[0], ee[1], F, TopoDS::Vertex( V )); + // } + + // // compute a weighted normal + // double sumAngle = 0; + // for ( int i = 0; i < nbFaces; ++i ) + // { + // angles[i] = ( angles[i] > 2*M_PI ) ? 0 : M_PI - angles[i]; + // sumAngle += angles[i]; + // } + // for ( int i = 0; i < nbFaces; ++i ) + // resNorm += angles[i] / sumAngle * fId2Normal[i].second; + + return resNorm; +} + +//================================================================================ +/*! + * \brief Find 2 neigbor nodes of a node on EDGE + */ +//================================================================================ + +bool _ViscousBuilder::findNeiborsOnEdge(const _LayerEdge* edge, + const SMDS_MeshNode*& n1, + const SMDS_MeshNode*& n2, + _EdgesOnShape& eos, + _SolidData& data) +{ + const SMDS_MeshNode* node = edge->_nodes[0]; + const int shapeInd = eos._shapeID; + SMESHDS_SubMesh* edgeSM = 0; + if ( eos.ShapeType() == TopAbs_EDGE ) + { + edgeSM = eos._subMesh->GetSubMeshDS(); + if ( !edgeSM || edgeSM->NbElements() == 0 ) + return error(SMESH_Comment("Not meshed EDGE ") << shapeInd, data._index); + } + int iN = 0; + n2 = 0; + SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Edge); + while ( eIt->more() && !n2 ) + { + const SMDS_MeshElement* e = eIt->next(); + const SMDS_MeshNode* nNeibor = e->GetNode( 0 ); + if ( nNeibor == node ) nNeibor = e->GetNode( 1 ); + if ( edgeSM ) + { + if (!edgeSM->Contains(e)) continue; + } + else + { + TopoDS_Shape s = SMESH_MesherHelper::GetSubShapeByNode( nNeibor, getMeshDS() ); + if ( !SMESH_MesherHelper::IsSubShape( s, eos._sWOL )) continue; + } + ( iN++ ? n2 : n1 ) = nNeibor; + } + if ( !n2 ) + return error(SMESH_Comment("Wrongly meshed EDGE ") << shapeInd, data._index); + return true; +} + +//================================================================================ +/*! + * \brief Set _curvature and _2neibors->_plnNorm by 2 neigbor nodes residing the same EDGE + */ +//================================================================================ + +void _LayerEdge::SetDataByNeighbors( const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const _EdgesOnShape& eos, + SMESH_MesherHelper& helper) +{ + if ( eos.ShapeType() != TopAbs_EDGE ) + return; + + gp_XYZ pos = SMESH_TNodeXYZ( _nodes[0] ); + gp_XYZ vec1 = pos - SMESH_TNodeXYZ( n1 ); + gp_XYZ vec2 = pos - SMESH_TNodeXYZ( n2 ); + + // Set _curvature + + double sumLen = vec1.Modulus() + vec2.Modulus(); + _2neibors->_wgt[0] = 1 - vec1.Modulus() / sumLen; + _2neibors->_wgt[1] = 1 - vec2.Modulus() / sumLen; + double avgNormProj = 0.5 * ( _normal * vec1 + _normal * vec2 ); + double avgLen = 0.5 * ( vec1.Modulus() + vec2.Modulus() ); + if ( _curvature ) delete _curvature; + _curvature = _Curvature::New( avgNormProj, avgLen ); + // if ( _curvature ) + // debugMsg( _nodes[0]->GetID() + // << " CURV r,k: " << _curvature->_r<<","<<_curvature->_k + // << " proj = "<second; + for ( size_t iN = 1; iN < le->_nodes.size(); ++iN ) + dumpCmd(SMESH_Comment("mesh.AddEdge([ ") <_nodes[iN-1]->GetID() + << ", " << le->_nodes[iN]->GetID() <<"])"); + } + dumpFunctionEnd(); + + dumpFunction( SMESH_Comment("makeNormals") << i ); + for ( n2e = _sdVec[i]._n2eMap.begin(); n2e != _sdVec[i]._n2eMap.end(); ++n2e ) + { + _LayerEdge* edge = n2e->second; + SMESH_TNodeXYZ nXYZ( edge->_nodes[0] ); + nXYZ += edge->_normal * _sdVec[i]._stepSize; + dumpCmd(SMESH_Comment("mesh.AddEdge([ ") << edge->_nodes[0]->GetID() + << ", mesh.AddNode( " << nXYZ.X()<<","<< nXYZ.Y()<<","<< nXYZ.Z()<<")])"); + } + dumpFunctionEnd(); + + dumpFunction( SMESH_Comment("makeTmpFaces_") << i ); + dumpCmd( "faceId1 = mesh.NbElements()" ); + TopExp_Explorer fExp( _sdVec[i]._solid, TopAbs_FACE ); + for ( ; fExp.More(); fExp.Next() ) + { + if (const SMESHDS_SubMesh* sm = _sdVec[i]._proxyMesh->GetProxySubMesh( fExp.Current())) + { + if ( sm->NbElements() == 0 ) continue; + SMDS_ElemIteratorPtr fIt = sm->GetElements(); + while ( fIt->more()) + { + const SMDS_MeshElement* e = fIt->next(); + SMESH_Comment cmd("mesh.AddFace(["); + for ( int j=0; j < e->NbCornerNodes(); ++j ) + cmd << e->GetNode(j)->GetID() << (j+1NbCornerNodes() ? ",": "])"); + dumpCmd( cmd ); + } + } + } + dumpCmd( "faceId2 = mesh.NbElements()" ); + dumpCmd( SMESH_Comment( "mesh.MakeGroup( 'tmpFaces_" ) << i << "'," + << "SMESH.FACE, SMESH.FT_RangeOfIds,'='," + << "'%s-%s' % (faceId1+1, faceId2))"); + dumpFunctionEnd(); + } +#endif +} + +//================================================================================ +/*! + * \brief Find maximal _LayerEdge length (layer thickness) limited by geometry + */ +//================================================================================ + +void _ViscousBuilder::computeGeomSize( _SolidData& data ) +{ + data._geomSize = Precision::Infinite(); + double intersecDist; + auto_ptr searcher + ( SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), + data._proxyMesh->GetFaces( data._solid )) ); + + for ( size_t iS = 0; iS < data._edgesOnShape.size(); ++iS ) + { + _EdgesOnShape& eos = data._edgesOnShape[ iS ]; + if ( eos._edges.empty() || eos.ShapeType() == TopAbs_EDGE ) + continue; + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + eos._edges[i]->FindIntersection( *searcher, intersecDist, data._epsilon, eos ); + if ( data._geomSize > intersecDist && intersecDist > 0 ) + data._geomSize = intersecDist; + } + } +} + +//================================================================================ +/*! + * \brief Increase length of _LayerEdge's to reach the required thickness of layers + */ +//================================================================================ + +bool _ViscousBuilder::inflate(_SolidData& data) +{ + SMESH_MesherHelper helper( *_mesh ); + + // Limit inflation step size by geometry size found by itersecting + // normals of _LayerEdge's with mesh faces + if ( data._stepSize > 0.3 * data._geomSize ) + limitStepSize( data, 0.3 * data._geomSize ); + + const double tgtThick = data._maxThickness; + if ( data._stepSize > data._minThickness ) + limitStepSize( data, data._minThickness ); + + if ( data._stepSize < 1. ) + data._epsilon = data._stepSize * 1e-7; + + debugMsg( "-- geomSize = " << data._geomSize << ", stepSize = " << data._stepSize ); + + const double safeFactor = ( 2*data._maxThickness < data._geomSize ) ? 1 : theThickToIntersection; + + double avgThick = 0, curThick = 0, distToIntersection = Precision::Infinite(); + int nbSteps = 0, nbRepeats = 0; + while ( avgThick < 0.99 ) + { + // new target length + curThick += data._stepSize; + if ( curThick > tgtThick ) + { + curThick = tgtThick + tgtThick*( 1.-avgThick ) * nbRepeats; + nbRepeats++; + } + + // Elongate _LayerEdge's + dumpFunction(SMESH_Comment("inflate")<SetNewLength( shapeCurThick, eos, helper ); + } + } + dumpFunctionEnd(); + + if ( !updateNormals( data, helper, nbSteps )) + return false; + + // Improve and check quality + if ( !smoothAndCheck( data, nbSteps, distToIntersection )) + { + if ( nbSteps > 0 ) + { +#ifdef __NOT_INVALIDATE_BAD_SMOOTH + debugMsg("NOT INVALIDATED STEP!"); + return error("Smoothing failed", data._index); +#endif + dumpFunction(SMESH_Comment("invalidate")<InvalidateStep( nbSteps+1, eos ); + } + dumpFunctionEnd(); + } + break; // no more inflating possible + } + nbSteps++; + + // Evaluate achieved thickness + avgThick = 0; + for ( size_t iS = 0; iS < data._edgesOnShape.size(); ++iS ) + { + _EdgesOnShape& eos = data._edgesOnShape[iS]; + if ( eos._edges.empty() ) continue; + + const double shapeTgtThick = eos._hyp.GetTotalThickness(); + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + avgThick += Min( 1., eos._edges[i]->_len / shapeTgtThick ); + } + } + avgThick /= data._n2eMap.size(); + debugMsg( "-- Thickness " << curThick << " ("<< avgThick*100 << "%) reached" ); + + if ( distToIntersection < tgtThick * avgThick * safeFactor && avgThick < 0.9 ) + { + debugMsg( "-- Stop inflation since " + << " distToIntersection( "<_warning || data._proxyMesh->_warning->IsOK() ) + { + data._proxyMesh->_warning.reset + ( new SMESH_ComputeError (COMPERR_WARNING, + SMESH_Comment("Thickness ") << tgtThick << + " of viscous layers not reached," + " average reached thickness is " << avgThick*tgtThick)); + } + } + + // Restore position of src nodes moved by infaltion on _noShrinkShapes + dumpFunction(SMESH_Comment("restoNoShrink_So")<_nodes.size() == 1 ) + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + restoreNoShrink( *eos._edges[ i ] ); + } + } + dumpFunctionEnd(); + + return true; +} + +//================================================================================ +/*! + * \brief Improve quality of layer inner surface and check intersection + */ +//================================================================================ + +bool _ViscousBuilder::smoothAndCheck(_SolidData& data, + const int nbSteps, + double & distToIntersection) +{ + if ( data._nbShapesToSmooth == 0 ) + return true; // no shapes needing smoothing + + bool moved, improved; + vector< _LayerEdge* > badSmooEdges; + + SMESH_MesherHelper helper(*_mesh); + Handle(Geom_Surface) surface; + TopoDS_Face F; + + for ( int isFace = 0; isFace < 2; ++isFace ) // smooth on [ EDGEs, FACEs ] + { + const TopAbs_ShapeEnum shapeType = isFace ? TopAbs_FACE : TopAbs_EDGE; + + for ( int iS = 0; iS < data._edgesOnShape.size(); ++iS ) + { + _EdgesOnShape& eos = data._edgesOnShape[ iS ]; + if ( !eos._toSmooth || + eos.ShapeType() != shapeType || + eos._edges.empty() ) + continue; + + // already smoothed? + bool toSmooth = ( eos._edges[ 0 ]->NbSteps() >= nbSteps+1 ); + if ( !toSmooth ) continue; + + if ( !eos._hyp.ToSmooth() ) + { + // smooth disabled by the user; check validy only + if ( !isFace ) continue; + double vol; + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + _LayerEdge* edge = eos._edges[i]; + const gp_XYZ& curPos ( ); + for ( size_t iF = 0; iF < edge->_simplices.size(); ++iF ) + if ( !edge->_simplices[iF].IsForward( edge->_nodes[0], + &edge->_pos.back(), vol )) + return false; + } + continue; // goto to the next EDGE or FACE + } + + // prepare data + if ( eos.SWOLType() == TopAbs_FACE ) + { + if ( !F.IsSame( eos._sWOL )) { + F = TopoDS::Face( eos._sWOL ); + helper.SetSubShape( F ); + surface = BRep_Tool::Surface( F ); + } + } + else + { + F.Nullify(); surface.Nullify(); + } + const TGeomID sInd = eos._shapeID; + + // perform smoothing + + if ( eos.ShapeType() == TopAbs_EDGE ) + { + dumpFunction(SMESH_Comment("smooth")<SmoothOnEdge( surface, F, helper ); + } + dumpCmd( SMESH_Comment("# end step ")<Smooth( step, isConcaveFace, false )) + badSmooEdges.push_back( eos._edges[i] ); + } + + else { + for ( int i = eos._edges.size()-1; i >= 0; --i ) // iterate backward + if ( eos._edges[i]->Smooth( step, isConcaveFace, false )) + badSmooEdges.push_back( eos._edges[i] ); + } + badNb = badSmooEdges.size(); + improved = ( badNb < oldBadNb ); + + if ( !badSmooEdges.empty() && step >= stepLimit / 2 ) + { + // look for the best smooth of _LayerEdge's neighboring badSmooEdges + vector<_Simplex> simplices; + for ( size_t i = 0; i < badSmooEdges.size(); ++i ) + { + _LayerEdge* ledge = badSmooEdges[i]; + _Simplex::GetSimplices( ledge->_nodes[0], simplices, data._ignoreFaceIds ); + for ( size_t iS = 0; iS < simplices.size(); ++iS ) + { + TNode2Edge::iterator n2e = data._n2eMap.find( simplices[iS]._nNext ); + if ( n2e != data._n2eMap.end()) { + _LayerEdge* ledge2 = n2e->second; + if ( ledge2->_nodes[0]->getshapeId() == sInd ) + ledge2->Smooth( step, isConcaveFace, /*findBest=*/true ); + } + } + } + } + // issue 22576 -- no bad faces but still there are intersections to fix + // if ( improved && badNb == 0 ) + // stepLimit = step + 3; + + dumpFunctionEnd(); + } + if ( badNb > 0 ) + { +#ifdef __myDEBUG + double vol = 0; + for ( int i = 0; i < eos._edges.size(); ++i ) + { + _LayerEdge* edge = eos._edges[i]; + SMESH_TNodeXYZ tgtXYZ( edge->_nodes.back() ); + for ( size_t j = 0; j < edge->_simplices.size(); ++j ) + if ( !edge->_simplices[j].IsForward( edge->_nodes[0], &tgtXYZ, vol )) + { + cout << "Bad simplex ( " << edge->_nodes[0]->GetID()<< " "<< tgtXYZ._node->GetID() + << " "<< edge->_simplices[j]._nPrev->GetID() + << " "<< edge->_simplices[j]._nNext->GetID() << " )" << endl; + return false; + } + } +#endif + return false; + } + } // // smooth on FACE's + } // loop on shapes + } // smooth on [ EDGEs, FACEs ] + + // Check orientation of simplices of _ConvexFace::_simplexTestEdges + map< TGeomID, _ConvexFace >::iterator id2face = data._convexFaces.begin(); + for ( ; id2face != data._convexFaces.end(); ++id2face ) + { + _ConvexFace & convFace = (*id2face).second; + if ( !convFace._simplexTestEdges.empty() && + convFace._simplexTestEdges[0]->_nodes[0]->GetPosition()->GetDim() == 2 ) + continue; // _simplexTestEdges are based on FACE -- already checked while smoothing + + if ( !convFace.CheckPrisms() ) + return false; + } + + // Check if the last segments of _LayerEdge intersects 2D elements; + // checked elements are either temporary faces or faces on surfaces w/o the layers + + auto_ptr searcher + ( SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), + data._proxyMesh->GetFaces( data._solid )) ); + + distToIntersection = Precision::Infinite(); + double dist; + const SMDS_MeshElement* intFace = 0; + const SMDS_MeshElement* closestFace = 0; + _LayerEdge* le = 0; + for ( int iS = 0; iS < data._edgesOnShape.size(); ++iS ) + { + _EdgesOnShape& eos = data._edgesOnShape[ iS ]; + if ( eos._edges.empty() || !eos._sWOL.IsNull() ) + continue; + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + if ( eos._edges[i]->FindIntersection( *searcher, dist, data._epsilon, eos, &intFace )) + return false; + if ( distToIntersection > dist ) + { + // ignore intersection of a _LayerEdge based on a _ConvexFace with a face + // lying on this _ConvexFace + if ( _ConvexFace* convFace = data.GetConvexFace( intFace->getshapeId() )) + if ( convFace->_subIdToEOS.count ( eos._shapeID )) + continue; + + // ignore intersection of a _LayerEdge based on a FACE with an element on this FACE + // ( avoid limiting the thickness on the case of issue 22576) + if ( intFace->getshapeId() == eos._shapeID ) + continue; + + distToIntersection = dist; + le = eos._edges[i]; + closestFace = intFace; + } + } + } +#ifdef __myDEBUG + if ( closestFace ) + { + SMDS_MeshElement::iterator nIt = closestFace->begin_nodes(); + cout << "Shortest distance: _LayerEdge nodes: tgt " << le->_nodes.back()->GetID() + << " src " << le->_nodes[0]->GetID()<< ", intersection with face (" + << (*nIt++)->GetID()<<" "<< (*nIt++)->GetID()<<" "<< (*nIt++)->GetID() + << ") distance = " << distToIntersection<< endl; + } +#endif + + return true; +} + +//================================================================================ +/*! + * \brief Return a curve of the EDGE to be used for smoothing and arrange + * _LayerEdge's to be in a consequent order + */ +//================================================================================ + +Handle(Geom_Curve) _SolidData::CurveForSmooth( const TopoDS_Edge& E, + _EdgesOnShape& eos, + SMESH_MesherHelper& helper) +{ + const TGeomID eIndex = eos._shapeID; + + map< TGeomID, Handle(Geom_Curve)>::iterator i2curve = _edge2curve.find( eIndex ); + + if ( i2curve == _edge2curve.end() ) + { + // sort _LayerEdge's by position on the EDGE + SortOnEdge( E, eos._edges, helper ); + + SMESHDS_SubMesh* smDS = eos._subMesh->GetSubMeshDS(); + + TopLoc_Location loc; double f,l; + + Handle(Geom_Line) line; + Handle(Geom_Circle) circle; + bool isLine, isCirc; + if ( eos._sWOL.IsNull() ) /////////////////////////////////////////// 3D case + { + // check if the EDGE is a line + Handle(Geom_Curve) curve = BRep_Tool::Curve( E, loc, f, l); + if ( curve->IsKind( STANDARD_TYPE( Geom_TrimmedCurve ))) + curve = Handle(Geom_TrimmedCurve)::DownCast( curve )->BasisCurve(); + + line = Handle(Geom_Line)::DownCast( curve ); + circle = Handle(Geom_Circle)::DownCast( curve ); + isLine = (!line.IsNull()); + isCirc = (!circle.IsNull()); + + if ( !isLine && !isCirc ) // Check if the EDGE is close to a line + { + // Bnd_B3d bndBox; + // SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); + // while ( nIt->more() ) + // bndBox.Add( SMESH_TNodeXYZ( nIt->next() )); + // gp_XYZ size = bndBox.CornerMax() - bndBox.CornerMin(); + + // gp_Pnt p0, p1; + // if ( eos._edges.size() > 1 ) { + // p0 = SMESH_TNodeXYZ( eos._edges[0]->_nodes[0] ); + // p1 = SMESH_TNodeXYZ( eos._edges[1]->_nodes[0] ); + // } + // else { + // p0 = curve->Value( f ); + // p1 = curve->Value( l ); + // } + // const double lineTol = 1e-2 * p0.Distance( p1 ); + // for ( int i = 0; i < 3 && !isLine; ++i ) + // isLine = ( size.Coord( i+1 ) <= lineTol ); ////////// <--- WRONG + + isLine = SMESH_Algo::IsStraight( E ); + + if ( isLine ) + line = new Geom_Line( gp::OX() ); // only type does matter + } + if ( !isLine && !isCirc && eos._edges.size() > 2) // Check if the EDGE is close to a circle + { + // TODO + } + } + else //////////////////////////////////////////////////////////////////////// 2D case + { + const TopoDS_Face& F = TopoDS::Face( eos._sWOL ); + + // check if the EDGE is a line + Handle(Geom2d_Curve) curve = BRep_Tool::CurveOnSurface( E, F, f, l); + if ( curve->IsKind( STANDARD_TYPE( Geom2d_TrimmedCurve ))) + curve = Handle(Geom2d_TrimmedCurve)::DownCast( curve )->BasisCurve(); + + Handle(Geom2d_Line) line2d = Handle(Geom2d_Line)::DownCast( curve ); + Handle(Geom2d_Circle) circle2d = Handle(Geom2d_Circle)::DownCast( curve ); + isLine = (!line2d.IsNull()); + isCirc = (!circle2d.IsNull()); + + if ( !isLine && !isCirc) // Check if the EDGE is close to a line + { + Bnd_B2d bndBox; + SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); + while ( nIt->more() ) + bndBox.Add( helper.GetNodeUV( F, nIt->next() )); + gp_XY size = bndBox.CornerMax() - bndBox.CornerMin(); + + const double lineTol = 1e-2 * sqrt( bndBox.SquareExtent() ); + for ( int i = 0; i < 2 && !isLine; ++i ) + isLine = ( size.Coord( i+1 ) <= lineTol ); + } + if ( !isLine && !isCirc && eos._edges.size() > 2) // Check if the EDGE is close to a circle + { + // TODO + } + if ( isLine ) + { + line = new Geom_Line( gp::OX() ); // only type does matter + } + else if ( isCirc ) + { + gp_Pnt2d p = circle2d->Location(); + gp_Ax2 ax( gp_Pnt( p.X(), p.Y(), 0), gp::DX()); + circle = new Geom_Circle( ax, 1.); // only center position does matter + } + } + + Handle(Geom_Curve)& res = _edge2curve[ eIndex ]; + if ( isLine ) + res = line; + else if ( isCirc ) + res = circle; + + return res; + } + return i2curve->second; +} + +//================================================================================ +/*! + * \brief Sort _LayerEdge's by a parameter on a given EDGE + */ +//================================================================================ + +void _SolidData::SortOnEdge( const TopoDS_Edge& E, + vector< _LayerEdge* >& edges, + SMESH_MesherHelper& helper) +{ + map< double, _LayerEdge* > u2edge; + for ( size_t i = 0; i < edges.size(); ++i ) + u2edge.insert( make_pair( helper.GetNodeU( E, edges[i]->_nodes[0] ), edges[i] )); + + ASSERT( u2edge.size() == edges.size() ); + map< double, _LayerEdge* >::iterator u2e = u2edge.begin(); + for ( int i = 0; i < edges.size(); ++i, ++u2e ) + edges[i] = u2e->second; + + Sort2NeiborsOnEdge( edges ); +} + +//================================================================================ +/*! + * \brief Set _2neibors according to the order of _LayerEdge on EDGE + */ +//================================================================================ + +void _SolidData::Sort2NeiborsOnEdge( vector< _LayerEdge* >& edges ) +{ + for ( size_t i = 0; i < edges.size()-1; ++i ) + if ( edges[i]->_2neibors->tgtNode(1) != edges[i+1]->_nodes.back() ) + edges[i]->_2neibors->reverse(); + + const size_t iLast = edges.size() - 1; + if ( edges.size() > 1 && + edges[iLast]->_2neibors->tgtNode(0) != edges[iLast-1]->_nodes.back() ) + edges[iLast]->_2neibors->reverse(); +} + +//================================================================================ +/*! + * \brief Return _EdgesOnShape* corresponding to the shape + */ +//================================================================================ + +_EdgesOnShape* _SolidData::GetShapeEdges(const TGeomID shapeID ) +{ + if ( shapeID < _edgesOnShape.size() && + _edgesOnShape[ shapeID ]._shapeID == shapeID ) + return & _edgesOnShape[ shapeID ]; + + for ( size_t i = 0; i < _edgesOnShape.size(); ++i ) + if ( _edgesOnShape[i]._shapeID == shapeID ) + return & _edgesOnShape[i]; + + return 0; +} + +//================================================================================ +/*! + * \brief Return _EdgesOnShape* corresponding to the shape + */ +//================================================================================ + +_EdgesOnShape* _SolidData::GetShapeEdges(const TopoDS_Shape& shape ) +{ + SMESHDS_Mesh* meshDS = _proxyMesh->GetMesh()->GetMeshDS(); + return GetShapeEdges( meshDS->ShapeToIndex( shape )); +} + +//================================================================================ +/*! + * \brief Prepare data of the _LayerEdge for smoothing on FACE + */ +//================================================================================ + +void _SolidData::PrepareEdgesToSmoothOnFace( _EdgesOnShape* eof, bool substituteSrcNodes ) +{ + set< TGeomID > vertices; + SMESH_MesherHelper helper( *_proxyMesh->GetMesh() ); + if ( isConcave( TopoDS::Face( eof->_shape ), helper, &vertices )) + _concaveFaces.insert( eof->_shapeID ); + + for ( size_t i = 0; i < eof->_edges.size(); ++i ) + eof->_edges[i]->_smooFunction = 0; + + for ( size_t i = 0; i < eof->_edges.size(); ++i ) + { + _LayerEdge* edge = eof->_edges[i]; + _Simplex::GetSimplices + ( edge->_nodes[0], edge->_simplices, _ignoreFaceIds, this, /*sort=*/true ); + + edge->ChooseSmooFunction( vertices, _n2eMap ); + + double avgNormProj = 0, avgLen = 0; + for ( size_t i = 0; i < edge->_simplices.size(); ++i ) + { + _Simplex& s = edge->_simplices[i]; + + gp_XYZ vec = edge->_pos.back() - SMESH_TNodeXYZ( s._nPrev ); + avgNormProj += edge->_normal * vec; + avgLen += vec.Modulus(); + if ( substituteSrcNodes ) + { + s._nNext = _n2eMap[ s._nNext ]->_nodes.back(); + s._nPrev = _n2eMap[ s._nPrev ]->_nodes.back(); + } + } + avgNormProj /= edge->_simplices.size(); + avgLen /= edge->_simplices.size(); + edge->_curvature = _Curvature::New( avgNormProj, avgLen ); + } +} + +//================================================================================ +/*! + * \brief Add faces for smoothing + */ +//================================================================================ + +void _SolidData::AddShapesToSmooth( const set< _EdgesOnShape* >& eosSet ) +{ + set< _EdgesOnShape * >::const_iterator eos = eosSet.begin(); + for ( ; eos != eosSet.end(); ++eos ) + { + if ( !*eos || (*eos)->_toSmooth ) continue; + + (*eos)->_toSmooth = true; + + if ( (*eos)->ShapeType() == TopAbs_FACE ) + { + PrepareEdgesToSmoothOnFace( *eos, /*substituteSrcNodes=*/true ); + } + } +} + +//================================================================================ +/*! + * \brief smooth _LayerEdge's on a staight EDGE or circular EDGE + */ +//================================================================================ + +bool _ViscousBuilder::smoothAnalyticEdge( _SolidData& data, + _EdgesOnShape& eos, + Handle(Geom_Surface)& surface, + const TopoDS_Face& F, + SMESH_MesherHelper& helper) +{ + const TopoDS_Edge& E = TopoDS::Edge( eos._shape ); + + Handle(Geom_Curve) curve = data.CurveForSmooth( E, eos, helper ); + if ( curve.IsNull() ) return false; + + const size_t iFrom = 0, iTo = eos._edges.size(); + + // compute a relative length of segments + vector< double > len( iTo-iFrom+1 ); + { + double curLen, prevLen = len[0] = 1.0; + for ( int i = iFrom; i < iTo; ++i ) + { + curLen = prevLen * eos._edges[i]->_2neibors->_wgt[0] / eos._edges[i]->_2neibors->_wgt[1]; + len[i-iFrom+1] = len[i-iFrom] + curLen; + prevLen = curLen; + } + } + + if ( curve->IsKind( STANDARD_TYPE( Geom_Line ))) + { + if ( F.IsNull() ) // 3D + { + SMESH_TNodeXYZ p0( eos._edges[iFrom]->_2neibors->tgtNode(0)); + SMESH_TNodeXYZ p1( eos._edges[iTo-1]->_2neibors->tgtNode(1)); + for ( int i = iFrom; i < iTo; ++i ) + { + double r = len[i-iFrom] / len.back(); + gp_XYZ newPos = p0 * ( 1. - r ) + p1 * r; + eos._edges[i]->_pos.back() = newPos; + SMDS_MeshNode* tgtNode = const_cast( eos._edges[i]->_nodes.back() ); + tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() ); + dumpMove( tgtNode ); + } + } + else + { + // gp_XY uv0 = helper.GetNodeUV( F, eos._edges[iFrom]->_2neibors->tgtNode(0)); + // gp_XY uv1 = helper.GetNodeUV( F, eos._edges[iTo-1]->_2neibors->tgtNode(1)); + _LayerEdge* e0 = eos._edges[iFrom]->_2neibors->_edges[0]; + _LayerEdge* e1 = eos._edges[iTo-1]->_2neibors->_edges[1]; + gp_XY uv0 = e0->LastUV( F, *data.GetShapeEdges( e0 )); + gp_XY uv1 = e1->LastUV( F, *data.GetShapeEdges( e1 )); + if ( eos._edges[iFrom]->_2neibors->tgtNode(0) == + eos._edges[iTo-1]->_2neibors->tgtNode(1) ) // closed edge + { + int iPeriodic = helper.GetPeriodicIndex(); + if ( iPeriodic == 1 || iPeriodic == 2 ) + { + uv1.SetCoord( iPeriodic, helper.GetOtherParam( uv1.Coord( iPeriodic ))); + if ( uv0.Coord( iPeriodic ) > uv1.Coord( iPeriodic )) + std::swap( uv0, uv1 ); + } + } + const gp_XY rangeUV = uv1 - uv0; + for ( int i = iFrom; i < iTo; ++i ) + { + double r = len[i-iFrom] / len.back(); + gp_XY newUV = uv0 + r * rangeUV; + eos._edges[i]->_pos.back().SetCoord( newUV.X(), newUV.Y(), 0 ); + + gp_Pnt newPos = surface->Value( newUV.X(), newUV.Y() ); + SMDS_MeshNode* tgtNode = const_cast( eos._edges[i]->_nodes.back() ); + tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() ); + dumpMove( tgtNode ); + + SMDS_FacePosition* pos = static_cast( tgtNode->GetPosition() ); + pos->SetUParameter( newUV.X() ); + pos->SetVParameter( newUV.Y() ); + } + } + return true; + } + + if ( curve->IsKind( STANDARD_TYPE( Geom_Circle ))) + { + Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast( curve ); + gp_Pnt center3D = circle->Location(); + + if ( F.IsNull() ) // 3D + { + if ( eos._edges[iFrom]->_2neibors->tgtNode(0) == + eos._edges[iTo-1]->_2neibors->tgtNode(1) ) + return true; // closed EDGE - nothing to do + + return false; // TODO ??? + } + else // 2D + { + const gp_XY center( center3D.X(), center3D.Y() ); + + _LayerEdge* e0 = eos._edges[iFrom]->_2neibors->_edges[0]; + _LayerEdge* eM = eos._edges[iFrom]; + _LayerEdge* e1 = eos._edges[iTo-1]->_2neibors->_edges[1]; + gp_XY uv0 = e0->LastUV( F, *data.GetShapeEdges( e0 ) ); + gp_XY uvM = eM->LastUV( F, *data.GetShapeEdges( eM ) ); + gp_XY uv1 = e1->LastUV( F, *data.GetShapeEdges( e1 ) ); + gp_Vec2d vec0( center, uv0 ); + gp_Vec2d vecM( center, uvM ); + gp_Vec2d vec1( center, uv1 ); + double uLast = vec0.Angle( vec1 ); // -PI - +PI + double uMidl = vec0.Angle( vecM ); + if ( uLast * uMidl <= 0. ) + uLast += ( uMidl > 0 ? +2. : -2. ) * M_PI; + const double radius = 0.5 * ( vec0.Magnitude() + vec1.Magnitude() ); + + gp_Ax2d axis( center, vec0 ); + gp_Circ2d circ( axis, radius ); + for ( int i = iFrom; i < iTo; ++i ) + { + double newU = uLast * len[i-iFrom] / len.back(); + gp_Pnt2d newUV = ElCLib::Value( newU, circ ); + eos._edges[i]->_pos.back().SetCoord( newUV.X(), newUV.Y(), 0 ); + + gp_Pnt newPos = surface->Value( newUV.X(), newUV.Y() ); + SMDS_MeshNode* tgtNode = const_cast( eos._edges[i]->_nodes.back() ); + tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() ); + dumpMove( tgtNode ); + + SMDS_FacePosition* pos = static_cast( tgtNode->GetPosition() ); + pos->SetUParameter( newUV.X() ); + pos->SetVParameter( newUV.Y() ); + } + } + return true; + } + + return false; +} + +//================================================================================ +/*! + * \brief Modify normals of _LayerEdge's on EDGE's to avoid intersection with + * _LayerEdge's on neighbor EDGE's + */ +//================================================================================ + +bool _ViscousBuilder::updateNormals( _SolidData& data, + SMESH_MesherHelper& helper, + int stepNb ) +{ + if ( stepNb > 0 ) + return updateNormalsOfConvexFaces( data, helper, stepNb ); + + // make temporary quadrangles got by extrusion of + // mesh edges along _LayerEdge._normal's + + vector< const SMDS_MeshElement* > tmpFaces; + { + set< SMESH_TLink > extrudedLinks; // contains target nodes + vector< const SMDS_MeshNode*> nodes(4); // of a tmp mesh face + + dumpFunction(SMESH_Comment("makeTmpFacesOnEdges")<_nodes.back(); + for ( int j = 0; j < 2; ++j ) // loop on _2NearEdges + { + const SMDS_MeshNode* tgt2 = edge->_2neibors->tgtNode(j); + pair< set< SMESH_TLink >::iterator, bool > link_isnew = + extrudedLinks.insert( SMESH_TLink( tgt1, tgt2 )); + if ( !link_isnew.second ) + { + extrudedLinks.erase( link_isnew.first ); + continue; // already extruded and will no more encounter + } + // a _LayerEdge containg tgt2 + _LayerEdge* neiborEdge = edge->_2neibors->_edges[j]; + + _TmpMeshFaceOnEdge* f = new _TmpMeshFaceOnEdge( edge, neiborEdge, --_tmpFaceID ); + tmpFaces.push_back( f ); + + dumpCmd(SMESH_Comment("mesh.AddFace([ ") + <_nn[0]->GetID()<<", "<_nn[1]->GetID()<<", " + <_nn[2]->GetID()<<", "<_nn[3]->GetID()<<" ])"); + } + } + } + dumpFunctionEnd(); + } + // Check if _LayerEdge's based on EDGE's intersects tmpFaces. + // Perform two loops on _LayerEdge on EDGE's: + // 1) to find and fix intersection + // 2) to check that no new intersection appears as result of 1) + + SMDS_ElemIteratorPtr fIt( new SMDS_ElementVectorIterator( tmpFaces.begin(), + tmpFaces.end())); + auto_ptr searcher + ( SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), fIt )); + + // 1) Find intersections + double dist; + const SMDS_MeshElement* face; + typedef map< _LayerEdge*, set< _LayerEdge*, _LayerEdgeCmp >, _LayerEdgeCmp > TLEdge2LEdgeSet; + TLEdge2LEdgeSet edge2CloseEdge; + + const double eps = data._epsilon * data._epsilon; + for ( size_t iS = 0; iS < data._edgesOnShape.size(); ++iS ) + { + _EdgesOnShape& eos = data._edgesOnShape[ iS ]; + if (( eos.ShapeType() != TopAbs_EDGE ) && + ( eos._sWOL.IsNull() || eos.SWOLType() != TopAbs_FACE )) + continue; + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + _LayerEdge* edge = eos._edges[i]; + if ( edge->FindIntersection( *searcher, dist, eps, eos, &face )) + { + const _TmpMeshFaceOnEdge* f = (const _TmpMeshFaceOnEdge*) face; + set< _LayerEdge*, _LayerEdgeCmp > & ee = edge2CloseEdge[ edge ]; + ee.insert( f->_le1 ); + ee.insert( f->_le2 ); + if ( f->_le1->IsOnEdge() && data.GetShapeEdges( f->_le1 )->_sWOL.IsNull() ) + edge2CloseEdge[ f->_le1 ].insert( edge ); + if ( f->_le2->IsOnEdge() && data.GetShapeEdges( f->_le2 )->_sWOL.IsNull() ) + edge2CloseEdge[ f->_le2 ].insert( edge ); + } + } + } + + // Set _LayerEdge._normal + + if ( !edge2CloseEdge.empty() ) + { + dumpFunction(SMESH_Comment("updateNormals")< shapesToSmooth; + + // vector to store new _normal and _cosin for each edge in edge2CloseEdge + vector< pair< _LayerEdge*, _LayerEdge > > edge2newEdge( edge2CloseEdge.size() ); + + TLEdge2LEdgeSet::iterator e2ee = edge2CloseEdge.begin(); + for ( size_t iE = 0; e2ee != edge2CloseEdge.end(); ++e2ee, ++iE ) + { + _LayerEdge* edge1 = e2ee->first; + _LayerEdge* edge2 = 0; + set< _LayerEdge*, _LayerEdgeCmp >& ee = e2ee->second; + + edge2newEdge[ iE ].first = NULL; + + _EdgesOnShape* eos1 = data.GetShapeEdges( edge1 ); + if ( !eos1 ) continue; + + // find EDGEs the edges reside + // TopoDS_Edge E1, E2; + // TopoDS_Shape S = helper.GetSubShapeByNode( edge1->_nodes[0], getMeshDS() ); + // if ( S.ShapeType() != TopAbs_EDGE ) + // continue; // TODO: find EDGE by VERTEX + // E1 = TopoDS::Edge( S ); + set< _LayerEdge*, _LayerEdgeCmp >::iterator eIt = ee.begin(); + for ( ; !edge2 && eIt != ee.end(); ++eIt ) + { + if ( eos1->_sWOL == data.GetShapeEdges( *eIt )->_sWOL ) + edge2 = *eIt; + } + if ( !edge2 ) continue; + + edge2newEdge[ iE ].first = edge1; + _LayerEdge& newEdge = edge2newEdge[ iE ].second; + // while ( E2.IsNull() && eIt != ee.end()) + // { + // _LayerEdge* e2 = *eIt++; + // TopoDS_Shape S = helper.GetSubShapeByNode( e2->_nodes[0], getMeshDS() ); + // if ( S.ShapeType() == TopAbs_EDGE ) + // E2 = TopoDS::Edge( S ), edge2 = e2; + // } + // if ( E2.IsNull() ) continue; // TODO: find EDGE by VERTEX + + // find 3 FACEs sharing 2 EDGEs + + // TopoDS_Face FF1[2], FF2[2]; + // PShapeIteratorPtr fIt = helper.GetAncestors(E1, *_mesh, TopAbs_FACE); + // while ( fIt->more() && FF1[1].IsNull() ) + // { + // const TopoDS_Face *F = (const TopoDS_Face*) fIt->next(); + // if ( helper.IsSubShape( *F, data._solid)) + // FF1[ FF1[0].IsNull() ? 0 : 1 ] = *F; + // } + // fIt = helper.GetAncestors(E2, *_mesh, TopAbs_FACE); + // while ( fIt->more() && FF2[1].IsNull()) + // { + // const TopoDS_Face *F = (const TopoDS_Face*) fIt->next(); + // if ( helper.IsSubShape( *F, data._solid)) + // FF2[ FF2[0].IsNull() ? 0 : 1 ] = *F; + // } + // // exclude a FACE common to E1 and E2 (put it to FFn[1] ) + // if ( FF1[0].IsSame( FF2[0]) || FF1[0].IsSame( FF2[1])) + // std::swap( FF1[0], FF1[1] ); + // if ( FF2[0].IsSame( FF1[0]) ) + // std::swap( FF2[0], FF2[1] ); + // if ( FF1[0].IsNull() || FF2[0].IsNull() ) + // continue; + + // get a new normal for edge1 + //bool ok; + gp_Vec dir1 = edge1->_normal, dir2 = edge2->_normal; + // if ( edge1->_cosin < 0 ) + // dir1 = getFaceDir( FF1[0], E1, edge1->_nodes[0], helper, ok ).Normalized(); + // if ( edge2->_cosin < 0 ) + // dir2 = getFaceDir( FF2[0], E2, edge2->_nodes[0], helper, ok ).Normalized(); + + double cos1 = Abs( edge1->_cosin ), cos2 = Abs( edge2->_cosin ); + double wgt1 = ( cos1 + 0.001 ) / ( cos1 + cos2 + 0.002 ); + double wgt2 = ( cos2 + 0.001 ) / ( cos1 + cos2 + 0.002 ); + newEdge._normal = ( wgt1 * dir1 + wgt2 * dir2 ).XYZ(); + newEdge._normal.Normalize(); + + // cout << edge1->_nodes[0]->GetID() << " " + // << edge2->_nodes[0]->GetID() << " NORM: " + // << newEdge._normal.X() << ", " << newEdge._normal.Y() << ", " << newEdge._normal.Z() << endl; + + // get new cosin + if ( cos1 < theMinSmoothCosin ) + { + newEdge._cosin = edge2->_cosin; + } + else if ( cos2 > theMinSmoothCosin ) // both cos1 and cos2 > theMinSmoothCosin + { + // gp_Vec dirInFace; + // if ( edge1->_cosin < 0 ) + // dirInFace = dir1; + // else + // dirInFace = getFaceDir( FF1[0], E1, edge1->_nodes[0], helper, ok ); + // double angle = dirInFace.Angle( edge1->_normal ); // [0,PI] + // edge1->SetCosin( Cos( angle )); + //newEdge._cosin = 0; // ??????????? + newEdge._cosin = ( wgt1 * cos1 + wgt2 * cos2 ) * edge1->_cosin / cos1; + } + else + { + newEdge._cosin = edge1->_cosin; + } + + // find shapes that need smoothing due to change of _normal + if ( edge1->_cosin < theMinSmoothCosin && + newEdge._cosin > theMinSmoothCosin ) + { + if ( eos1->_sWOL.IsNull() ) + { + SMDS_ElemIteratorPtr fIt = edge1->_nodes[0]->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + shapesToSmooth.insert( data.GetShapeEdges( fIt->next()->getshapeId() )); + //limitStepSize( data, fIt->next(), edge1->_cosin ); // too late + } + else // edge1 inflates along a FACE + { + TopoDS_Shape V = helper.GetSubShapeByNode( edge1->_nodes[0], getMeshDS() ); + PShapeIteratorPtr eIt = helper.GetAncestors( V, *_mesh, TopAbs_EDGE ); + while ( const TopoDS_Shape* E = eIt->next() ) + { + if ( !helper.IsSubShape( *E, /*FACE=*/eos1->_sWOL )) + continue; + gp_Vec edgeDir = getEdgeDir( TopoDS::Edge( *E ), TopoDS::Vertex( V )); + double angle = edgeDir.Angle( newEdge._normal ); // [0,PI] + if ( angle < M_PI / 2 ) + shapesToSmooth.insert( data.GetShapeEdges( *E )); + } + } + } + } + + data.AddShapesToSmooth( shapesToSmooth ); + + // Update data of edges depending on a new _normal + + for ( size_t iE = 0; iE < edge2newEdge.size(); ++iE ) + { + _LayerEdge* edge1 = edge2newEdge[ iE ].first; + _LayerEdge& newEdge = edge2newEdge[ iE ].second; + if ( !edge1 ) continue; + _EdgesOnShape* eos1 = data.GetShapeEdges( edge1 ); + if ( !eos1 ) continue; + + edge1->_normal = newEdge._normal; + edge1->SetCosin( newEdge._cosin ); + edge1->InvalidateStep( 1, *eos1 ); + edge1->_len = 0; + edge1->SetNewLength( data._stepSize, *eos1, helper ); + if ( edge1->IsOnEdge() ) + { + const SMDS_MeshNode * n1 = edge1->_2neibors->srcNode(0); + const SMDS_MeshNode * n2 = edge1->_2neibors->srcNode(1); + edge1->SetDataByNeighbors( n1, n2, *eos1, helper ); + } + + // Update normals and other dependent data of not intersecting _LayerEdge's + // neighboring the intersecting ones + + if ( !edge1->_2neibors ) + continue; + for ( int j = 0; j < 2; ++j ) // loop on 2 neighbors + { + _LayerEdge* neighbor = edge1->_2neibors->_edges[j]; + if ( edge2CloseEdge.count ( neighbor )) + continue; // j-th neighbor is also intersected + _EdgesOnShape* eos = data.GetShapeEdges( neighbor ); + if ( !eos ) continue; + _LayerEdge* prevEdge = edge1; + const int nbSteps = 10; + for ( int step = nbSteps; step; --step ) // step from edge1 in j-th direction + { + if ( !neighbor->_2neibors ) + break; // neighbor is on VERTEX + int iNext = 0; + _LayerEdge* nextEdge = neighbor->_2neibors->_edges[iNext]; + if ( nextEdge == prevEdge ) + nextEdge = neighbor->_2neibors->_edges[ ++iNext ]; + double r = double(step-1)/nbSteps; + if ( !nextEdge->_2neibors ) + r = 0.5; + + gp_XYZ newNorm = prevEdge->_normal * r + nextEdge->_normal * (1-r); + newNorm.Normalize(); + + neighbor->_normal = newNorm; + neighbor->SetCosin( prevEdge->_cosin * r + nextEdge->_cosin * (1-r) ); + neighbor->SetDataByNeighbors( prevEdge->_nodes[0], nextEdge->_nodes[0], *eos, helper ); + + neighbor->InvalidateStep( 1, *eos ); + neighbor->_len = 0; + neighbor->SetNewLength( data._stepSize, *eos, helper ); + + // goto the next neighbor + prevEdge = neighbor; + neighbor = nextEdge; + } + } + } + dumpFunctionEnd(); + } + // 2) Check absence of intersections + // TODO? + + for ( size_t i = 0 ; i < tmpFaces.size(); ++i ) + delete tmpFaces[i]; + + return true; +} + +//================================================================================ +/*! + * \brief Modify normals of _LayerEdge's on _ConvexFace's + */ +//================================================================================ + +bool _ViscousBuilder::updateNormalsOfConvexFaces( _SolidData& data, + SMESH_MesherHelper& helper, + int stepNb ) +{ + SMESHDS_Mesh* meshDS = helper.GetMeshDS(); + bool isOK; + + map< TGeomID, _ConvexFace >::iterator id2face = data._convexFaces.begin(); + for ( ; id2face != data._convexFaces.end(); ++id2face ) + { + _ConvexFace & convFace = (*id2face).second; + if ( convFace._normalsFixed ) + continue; // already fixed + if ( convFace.CheckPrisms() ) + continue; // nothing to fix + + convFace._normalsFixed = true; + + BRepAdaptor_Surface surface ( convFace._face, false ); + BRepLProp_SLProps surfProp( surface, 2, 1e-6 ); + + // check if the convex FACE is of spherical shape + + Bnd_B3d centersBox; // bbox of centers of curvature of _LayerEdge's on VERTEXes + Bnd_B3d nodesBox; + gp_Pnt center; + + map< TGeomID, _EdgesOnShape* >::iterator id2eos = convFace._subIdToEOS.begin(); + for ( ; id2eos != convFace._subIdToEOS.end(); ++id2eos ) + { + _EdgesOnShape& eos = *(id2eos->second); + if ( eos.ShapeType() == TopAbs_VERTEX ) + { + _LayerEdge* ledge = eos._edges[ 0 ]; + if ( convFace.GetCenterOfCurvature( ledge, surfProp, helper, center )) + centersBox.Add( center ); + } + for ( size_t i = 0; i < eos._edges.size(); ++i ) + nodesBox.Add( SMESH_TNodeXYZ( eos._edges[ i ]->_nodes[0] )); + } + if ( centersBox.IsVoid() ) + { + debugMsg( "Error: centersBox.IsVoid()" ); + return false; + } + const bool isSpherical = + ( centersBox.SquareExtent() < 1e-6 * nodesBox.SquareExtent() ); + + int nbEdges = helper.Count( convFace._face, TopAbs_EDGE, /*ignoreSame=*/false ); + vector < _CentralCurveOnEdge > centerCurves( nbEdges ); + + if ( isSpherical ) + { + // set _LayerEdge::_normal as average of all normals + + // WARNING: different density of nodes on EDGEs is not taken into account that + // can lead to an improper new normal + + gp_XYZ avgNormal( 0,0,0 ); + nbEdges = 0; + id2eos = convFace._subIdToEOS.begin(); + for ( ; id2eos != convFace._subIdToEOS.end(); ++id2eos ) + { + _EdgesOnShape& eos = *(id2eos->second); + // set data of _CentralCurveOnEdge + if ( eos.ShapeType() == TopAbs_EDGE ) + { + _CentralCurveOnEdge& ceCurve = centerCurves[ nbEdges++ ]; + ceCurve.SetShapes( TopoDS::Edge( eos._shape ), convFace, data, helper ); + if ( !eos._sWOL.IsNull() ) + ceCurve._adjFace.Nullify(); + else + ceCurve._ledges.insert( ceCurve._ledges.end(), + eos._edges.begin(), eos._edges.end()); + } + // summarize normals + for ( size_t i = 0; i < eos._edges.size(); ++i ) + avgNormal += eos._edges[ i ]->_normal; + } + double normSize = avgNormal.SquareModulus(); + if ( normSize < 1e-200 ) + { + debugMsg( "updateNormalsOfConvexFaces(): zero avgNormal" ); + return false; + } + avgNormal /= Sqrt( normSize ); + + // compute new _LayerEdge::_cosin on EDGEs + double avgCosin = 0; + int nbCosin = 0; + gp_Vec inFaceDir; + for ( size_t iE = 0; iE < centerCurves.size(); ++iE ) + { + _CentralCurveOnEdge& ceCurve = centerCurves[ iE ]; + if ( ceCurve._adjFace.IsNull() ) + continue; + for ( size_t iLE = 0; iLE < ceCurve._ledges.size(); ++iLE ) + { + const SMDS_MeshNode* node = ceCurve._ledges[ iLE ]->_nodes[0]; + inFaceDir = getFaceDir( ceCurve._adjFace, ceCurve._edge, node, helper, isOK ); + if ( isOK ) + { + double angle = inFaceDir.Angle( avgNormal ); // [0,PI] + ceCurve._ledges[ iLE ]->_cosin = Cos( angle ); + avgCosin += ceCurve._ledges[ iLE ]->_cosin; + nbCosin++; + } + } + } + if ( nbCosin > 0 ) + avgCosin /= nbCosin; + + // set _LayerEdge::_normal = avgNormal + id2eos = convFace._subIdToEOS.begin(); + for ( ; id2eos != convFace._subIdToEOS.end(); ++id2eos ) + { + _EdgesOnShape& eos = *(id2eos->second); + if ( eos.ShapeType() != TopAbs_EDGE ) + for ( size_t i = 0; i < eos._edges.size(); ++i ) + eos._edges[ i ]->_cosin = avgCosin; + + for ( size_t i = 0; i < eos._edges.size(); ++i ) + eos._edges[ i ]->_normal = avgNormal; + } + } + else // if ( isSpherical ) + { + // We suppose that centers of curvature at all points of the FACE + // lie on some curve, let's call it "central curve". For all _LayerEdge's + // having a common center of curvature we define the same new normal + // as a sum of normals of _LayerEdge's on EDGEs among them. + + // get all centers of curvature for each EDGE + + helper.SetSubShape( convFace._face ); + _LayerEdge* vertexLEdges[2], **edgeLEdge, **edgeLEdgeEnd; + + TopExp_Explorer edgeExp( convFace._face, TopAbs_EDGE ); + for ( int iE = 0; edgeExp.More(); edgeExp.Next(), ++iE ) + { + const TopoDS_Edge& edge = TopoDS::Edge( edgeExp.Current() ); + + // set adjacent FACE + centerCurves[ iE ].SetShapes( edge, convFace, data, helper ); + + // get _LayerEdge's of the EDGE + TGeomID edgeID = meshDS->ShapeToIndex( edge ); + _EdgesOnShape* eos = data.GetShapeEdges( edgeID ); + if ( !eos || eos->_edges.empty() ) + { + // no _LayerEdge's on EDGE, use _LayerEdge's on VERTEXes + for ( int iV = 0; iV < 2; ++iV ) + { + TopoDS_Vertex v = helper.IthVertex( iV, edge ); + TGeomID vID = meshDS->ShapeToIndex( v ); + eos = data.GetShapeEdges( vID ); + vertexLEdges[ iV ] = eos->_edges[ 0 ]; + } + edgeLEdge = &vertexLEdges[0]; + edgeLEdgeEnd = edgeLEdge + 2; + + centerCurves[ iE ]._adjFace.Nullify(); + } + else + { + if ( ! eos->_toSmooth ) + data.SortOnEdge( edge, eos->_edges, helper ); + edgeLEdge = &eos->_edges[ 0 ]; + edgeLEdgeEnd = edgeLEdge + eos->_edges.size(); + vertexLEdges[0] = eos->_edges.front()->_2neibors->_edges[0]; + vertexLEdges[1] = eos->_edges.back() ->_2neibors->_edges[1]; + + if ( ! eos->_sWOL.IsNull() ) + centerCurves[ iE ]._adjFace.Nullify(); + } + + // Get curvature centers + + centersBox.Clear(); + + if ( edgeLEdge[0]->IsOnEdge() && + convFace.GetCenterOfCurvature( vertexLEdges[0], surfProp, helper, center )) + { // 1st VERTEX + centerCurves[ iE ].Append( center, vertexLEdges[0] ); + centersBox.Add( center ); + } + for ( ; edgeLEdge < edgeLEdgeEnd; ++edgeLEdge ) + if ( convFace.GetCenterOfCurvature( *edgeLEdge, surfProp, helper, center )) + { // EDGE or VERTEXes + centerCurves[ iE ].Append( center, *edgeLEdge ); + centersBox.Add( center ); + } + if ( edgeLEdge[-1]->IsOnEdge() && + convFace.GetCenterOfCurvature( vertexLEdges[1], surfProp, helper, center )) + { // 2nd VERTEX + centerCurves[ iE ].Append( center, vertexLEdges[1] ); + centersBox.Add( center ); + } + centerCurves[ iE ]._isDegenerated = + ( centersBox.IsVoid() || centersBox.SquareExtent() < 1e-6 * nodesBox.SquareExtent() ); + + } // loop on EDGES of convFace._face to set up data of centerCurves + + // Compute new normals for _LayerEdge's on EDGEs + + double avgCosin = 0; + int nbCosin = 0; + gp_Vec inFaceDir; + for ( size_t iE1 = 0; iE1 < centerCurves.size(); ++iE1 ) + { + _CentralCurveOnEdge& ceCurve = centerCurves[ iE1 ]; + if ( ceCurve._isDegenerated ) + continue; + const vector< gp_Pnt >& centers = ceCurve._curvaCenters; + vector< gp_XYZ > & newNormals = ceCurve._normals; + for ( size_t iC1 = 0; iC1 < centers.size(); ++iC1 ) + { + isOK = false; + for ( size_t iE2 = 0; iE2 < centerCurves.size() && !isOK; ++iE2 ) + { + if ( iE1 != iE2 ) + isOK = centerCurves[ iE2 ].FindNewNormal( centers[ iC1 ], newNormals[ iC1 ]); + } + if ( isOK && !ceCurve._adjFace.IsNull() ) + { + // compute new _LayerEdge::_cosin + const SMDS_MeshNode* node = ceCurve._ledges[ iC1 ]->_nodes[0]; + inFaceDir = getFaceDir( ceCurve._adjFace, ceCurve._edge, node, helper, isOK ); + if ( isOK ) + { + double angle = inFaceDir.Angle( newNormals[ iC1 ] ); // [0,PI] + ceCurve._ledges[ iC1 ]->_cosin = Cos( angle ); + avgCosin += ceCurve._ledges[ iC1 ]->_cosin; + nbCosin++; + } + } + } + } + // set new normals to _LayerEdge's of NOT degenerated central curves + for ( size_t iE = 0; iE < centerCurves.size(); ++iE ) + { + if ( centerCurves[ iE ]._isDegenerated ) + continue; + for ( size_t iLE = 0; iLE < centerCurves[ iE ]._ledges.size(); ++iLE ) + centerCurves[ iE ]._ledges[ iLE ]->_normal = centerCurves[ iE ]._normals[ iLE ]; + } + // set new normals to _LayerEdge's of degenerated central curves + for ( size_t iE = 0; iE < centerCurves.size(); ++iE ) + { + if ( !centerCurves[ iE ]._isDegenerated || + centerCurves[ iE ]._ledges.size() < 3 ) + continue; + // new normal is an average of new normals at VERTEXes that + // was computed on non-degenerated _CentralCurveOnEdge's + gp_XYZ newNorm = ( centerCurves[ iE ]._ledges.front()->_normal + + centerCurves[ iE ]._ledges.back ()->_normal ); + double sz = newNorm.Modulus(); + if ( sz < 1e-200 ) + continue; + newNorm /= sz; + double newCosin = ( 0.5 * centerCurves[ iE ]._ledges.front()->_cosin + + 0.5 * centerCurves[ iE ]._ledges.back ()->_cosin ); + for ( size_t iLE = 1, nb = centerCurves[ iE ]._ledges.size() - 1; iLE < nb; ++iLE ) + { + centerCurves[ iE ]._ledges[ iLE ]->_normal = newNorm; + centerCurves[ iE ]._ledges[ iLE ]->_cosin = newCosin; + } + } + + // Find new normals for _LayerEdge's based on FACE + + if ( nbCosin > 0 ) + avgCosin /= nbCosin; + const TGeomID faceID = meshDS->ShapeToIndex( convFace._face ); + map< TGeomID, _EdgesOnShape* >::iterator id2eos = convFace._subIdToEOS.find( faceID ); + if ( id2eos != convFace._subIdToEOS.end() ) + { + int iE = 0; + gp_XYZ newNorm; + _EdgesOnShape& eos = * ( id2eos->second ); + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + _LayerEdge* ledge = eos._edges[ i ]; + if ( !convFace.GetCenterOfCurvature( ledge, surfProp, helper, center )) + continue; + for ( size_t i = 0; i < centerCurves.size(); ++i, ++iE ) + { + iE = iE % centerCurves.size(); + if ( centerCurves[ iE ]._isDegenerated ) + continue; + newNorm.SetCoord( 0,0,0 ); + if ( centerCurves[ iE ].FindNewNormal( center, newNorm )) + { + ledge->_normal = newNorm; + ledge->_cosin = avgCosin; + break; + } + } + } + } + + } // not a quasi-spherical FACE + + // Update _LayerEdge's data according to a new normal + + dumpFunction(SMESH_Comment("updateNormalsOfConvexFaces")<ShapeToIndex( convFace._face )); + + id2eos = convFace._subIdToEOS.begin(); + for ( ; id2eos != convFace._subIdToEOS.end(); ++id2eos ) + { + _EdgesOnShape& eos = * ( id2eos->second ); + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + _LayerEdge* & ledge = eos._edges[ i ]; + double len = ledge->_len; + ledge->InvalidateStep( stepNb + 1, eos, /*restoreLength=*/true ); + ledge->SetCosin( ledge->_cosin ); + ledge->SetNewLength( len, eos, helper ); + } + + } // loop on sub-shapes of convFace._face + + // Find FACEs adjacent to convFace._face that got necessity to smooth + // as a result of normals modification + + set< _EdgesOnShape* > adjFacesToSmooth; + for ( size_t iE = 0; iE < centerCurves.size(); ++iE ) + { + if ( centerCurves[ iE ]._adjFace.IsNull() || + centerCurves[ iE ]._adjFaceToSmooth ) + continue; + for ( size_t iLE = 0; iLE < centerCurves[ iE ]._ledges.size(); ++iLE ) + { + if ( centerCurves[ iE ]._ledges[ iLE ]->_cosin > theMinSmoothCosin ) + { + adjFacesToSmooth.insert( data.GetShapeEdges( centerCurves[ iE ]._adjFace )); + break; + } + } + } + data.AddShapesToSmooth( adjFacesToSmooth ); + + dumpFunctionEnd(); + + + } // loop on data._convexFaces + + return true; +} + +//================================================================================ +/*! + * \brief Finds a center of curvature of a surface at a _LayerEdge + */ +//================================================================================ + +bool _ConvexFace::GetCenterOfCurvature( _LayerEdge* ledge, + BRepLProp_SLProps& surfProp, + SMESH_MesherHelper& helper, + gp_Pnt & center ) const +{ + gp_XY uv = helper.GetNodeUV( _face, ledge->_nodes[0] ); + surfProp.SetParameters( uv.X(), uv.Y() ); + if ( !surfProp.IsCurvatureDefined() ) + return false; + + const double oriFactor = ( _face.Orientation() == TopAbs_REVERSED ? +1. : -1. ); + double surfCurvatureMax = surfProp.MaxCurvature() * oriFactor; + double surfCurvatureMin = surfProp.MinCurvature() * oriFactor; + if ( surfCurvatureMin > surfCurvatureMax ) + center = surfProp.Value().Translated( surfProp.Normal().XYZ() / surfCurvatureMin * oriFactor ); + else + center = surfProp.Value().Translated( surfProp.Normal().XYZ() / surfCurvatureMax * oriFactor ); + + return true; +} + +//================================================================================ +/*! + * \brief Check that prisms are not distorted + */ +//================================================================================ + +bool _ConvexFace::CheckPrisms() const +{ + double vol = 0; + for ( size_t i = 0; i < _simplexTestEdges.size(); ++i ) + { + const _LayerEdge* edge = _simplexTestEdges[i]; + SMESH_TNodeXYZ tgtXYZ( edge->_nodes.back() ); + for ( size_t j = 0; j < edge->_simplices.size(); ++j ) + if ( !edge->_simplices[j].IsForward( edge->_nodes[0], &tgtXYZ, vol )) + { + debugMsg( "Bad simplex of _simplexTestEdges (" + << " "<< edge->_nodes[0]->GetID()<< " "<< tgtXYZ._node->GetID() + << " "<< edge->_simplices[j]._nPrev->GetID() + << " "<< edge->_simplices[j]._nNext->GetID() << " )" ); + return false; + } + } + return true; +} + +//================================================================================ +/*! + * \brief Try to compute a new normal by interpolating normals of _LayerEdge's + * stored in this _CentralCurveOnEdge. + * \param [in] center - curvature center of a point of another _CentralCurveOnEdge. + * \param [in,out] newNormal - current normal at this point, to be redefined + * \return bool - true if succeeded. + */ +//================================================================================ + +bool _CentralCurveOnEdge::FindNewNormal( const gp_Pnt& center, gp_XYZ& newNormal ) +{ + if ( this->_isDegenerated ) + return false; + + // find two centers the given one lies between + + for ( size_t i = 0, nb = _curvaCenters.size()-1; i < nb; ++i ) + { + double sl2 = 1.001 * _segLength2[ i ]; + + double d1 = center.SquareDistance( _curvaCenters[ i ]); + if ( d1 > sl2 ) + continue; + + double d2 = center.SquareDistance( _curvaCenters[ i+1 ]); + if ( d2 > sl2 || d2 + d1 < 1e-100 ) + continue; + + d1 = Sqrt( d1 ); + d2 = Sqrt( d2 ); + double r = d1 / ( d1 + d2 ); + gp_XYZ norm = (( 1. - r ) * _ledges[ i ]->_normal + + ( r ) * _ledges[ i+1 ]->_normal ); + norm.Normalize(); + + newNormal += norm; + double sz = newNormal.Modulus(); + if ( sz < 1e-200 ) + break; + newNormal /= sz; + return true; + } + return false; +} + +//================================================================================ +/*! + * \brief Set shape members + */ +//================================================================================ + +void _CentralCurveOnEdge::SetShapes( const TopoDS_Edge& edge, + const _ConvexFace& convFace, + _SolidData& data, + SMESH_MesherHelper& helper) +{ + _edge = edge; + + PShapeIteratorPtr fIt = helper.GetAncestors( edge, *helper.GetMesh(), TopAbs_FACE ); + while ( const TopoDS_Shape* F = fIt->next()) + if ( !convFace._face.IsSame( *F )) + { + _adjFace = TopoDS::Face( *F ); + _adjFaceToSmooth = false; + // _adjFace already in a smoothing queue ? + if ( _EdgesOnShape* eos = data.GetShapeEdges( _adjFace )) + _adjFaceToSmooth = eos->_toSmooth; + break; + } +} + +//================================================================================ +/*! + * \brief Looks for intersection of it's last segment with faces + * \param distance - returns shortest distance from the last node to intersection + */ +//================================================================================ + +bool _LayerEdge::FindIntersection( SMESH_ElementSearcher& searcher, + double & distance, + const double& epsilon, + _EdgesOnShape& eos, + const SMDS_MeshElement** face) +{ + vector< const SMDS_MeshElement* > suspectFaces; + double segLen; + gp_Ax1 lastSegment = LastSegment( segLen, eos ); + searcher.GetElementsNearLine( lastSegment, SMDSAbs_Face, suspectFaces ); + + bool segmentIntersected = false; + distance = Precision::Infinite(); + int iFace = -1; // intersected face + for ( size_t j = 0 ; j < suspectFaces.size() /*&& !segmentIntersected*/; ++j ) + { + const SMDS_MeshElement* face = suspectFaces[j]; + if ( face->GetNodeIndex( _nodes.back() ) >= 0 || + face->GetNodeIndex( _nodes[0] ) >= 0 ) + continue; // face sharing _LayerEdge node + const int nbNodes = face->NbCornerNodes(); + bool intFound = false; + double dist; + SMDS_MeshElement::iterator nIt = face->begin_nodes(); + if ( nbNodes == 3 ) + { + intFound = SegTriaInter( lastSegment, *nIt++, *nIt++, *nIt++, dist, epsilon ); + } + else + { + const SMDS_MeshNode* tria[3]; + tria[0] = *nIt++; + tria[1] = *nIt++; + for ( int n2 = 2; n2 < nbNodes && !intFound; ++n2 ) + { + tria[2] = *nIt++; + intFound = SegTriaInter(lastSegment, tria[0], tria[1], tria[2], dist, epsilon ); + tria[1] = tria[2]; + } + } + if ( intFound ) + { + if ( dist < segLen*(1.01) && dist > -(_len*_lenFactor-segLen) ) + segmentIntersected = true; + if ( distance > dist ) + distance = dist, iFace = j; + } + } + if ( iFace != -1 && face ) *face = suspectFaces[iFace]; + + if ( segmentIntersected ) + { +#ifdef __myDEBUG + SMDS_MeshElement::iterator nIt = suspectFaces[iFace]->begin_nodes(); + gp_XYZ intP( lastSegment.Location().XYZ() + lastSegment.Direction().XYZ() * distance ); + cout << "nodes: tgt " << _nodes.back()->GetID() << " src " << _nodes[0]->GetID() + << ", intersection with face (" + << (*nIt++)->GetID()<<" "<< (*nIt++)->GetID()<<" "<< (*nIt++)->GetID() + << ") at point (" << intP.X() << ", " << intP.Y() << ", " << intP.Z() + << ") distance = " << distance - segLen<< endl; +#endif + } + + distance -= segLen; + + return segmentIntersected; +} + +//================================================================================ +/*! + * \brief Returns size and direction of the last segment + */ +//================================================================================ + +gp_Ax1 _LayerEdge::LastSegment(double& segLen, _EdgesOnShape& eos) const +{ + // find two non-coincident positions + gp_XYZ orig = _pos.back(); + gp_XYZ dir; + int iPrev = _pos.size() - 2; + const double tol = ( _len > 0 ) ? 0.3*_len : 1e-100; // adjusted for IPAL52478 + PAL22576 + while ( iPrev >= 0 ) + { + dir = orig - _pos[iPrev]; + if ( dir.SquareModulus() > tol*tol ) + break; + else + iPrev--; + } + + // make gp_Ax1 + gp_Ax1 segDir; + if ( iPrev < 0 ) + { + segDir.SetLocation( SMESH_TNodeXYZ( _nodes[0] )); + segDir.SetDirection( _normal ); + segLen = 0; + } + else + { + gp_Pnt pPrev = _pos[ iPrev ]; + if ( !eos._sWOL.IsNull() ) + { + TopLoc_Location loc; + if ( eos.SWOLType() == TopAbs_EDGE ) + { + double f,l; + Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge( eos._sWOL ), loc, f,l); + pPrev = curve->Value( pPrev.X() ).Transformed( loc ); + } + else + { + Handle(Geom_Surface) surface = BRep_Tool::Surface( TopoDS::Face( eos._sWOL ), loc ); + pPrev = surface->Value( pPrev.X(), pPrev.Y() ).Transformed( loc ); + } + dir = SMESH_TNodeXYZ( _nodes.back() ) - pPrev.XYZ(); + } + segDir.SetLocation( pPrev ); + segDir.SetDirection( dir ); + segLen = dir.Modulus(); + } + + return segDir; +} + +//================================================================================ +/*! + * \brief Return the last position of the target node on a FACE. + * \param [in] F - the FACE this _LayerEdge is inflated along + * \return gp_XY - result UV + */ +//================================================================================ + +gp_XY _LayerEdge::LastUV( const TopoDS_Face& F, _EdgesOnShape& eos ) const +{ + if ( F.IsSame( eos._sWOL )) // F is my FACE + return gp_XY( _pos.back().X(), _pos.back().Y() ); + + if ( eos.SWOLType() != TopAbs_EDGE ) // wrong call + return gp_XY( 1e100, 1e100 ); + + // _sWOL is EDGE of F; _pos.back().X() is the last U on the EDGE + double f, l, u = _pos.back().X(); + Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( TopoDS::Edge(eos._sWOL), F, f,l); + if ( !C2d.IsNull() && f <= u && u <= l ) + return C2d->Value( u ).XY(); + + return gp_XY( 1e100, 1e100 ); +} + +//================================================================================ +/*! + * \brief Test intersection of the last segment with a given triangle + * using Moller-Trumbore algorithm + * Intersection is detected if distance to intersection is less than _LayerEdge._len + */ +//================================================================================ + +bool _LayerEdge::SegTriaInter( const gp_Ax1& lastSegment, + const SMDS_MeshNode* n0, + const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + double& t, + const double& EPSILON) const +{ + //const double EPSILON = 1e-6; + + const gp_Pnt& orig = lastSegment.Location(); + const gp_Dir& dir = lastSegment.Direction(); + + SMESH_TNodeXYZ vert0( n0 ); + SMESH_TNodeXYZ vert1( n1 ); + SMESH_TNodeXYZ vert2( n2 ); + + /* calculate distance from vert0 to ray origin */ + gp_XYZ tvec = orig.XYZ() - vert0; + + //if ( tvec * dir > EPSILON ) + // intersected face is at back side of the temporary face this _LayerEdge belongs to + //return false; + + gp_XYZ edge1 = vert1 - vert0; + gp_XYZ edge2 = vert2 - vert0; + + /* begin calculating determinant - also used to calculate U parameter */ + gp_XYZ pvec = dir.XYZ() ^ edge2; + + /* if determinant is near zero, ray lies in plane of triangle */ + double det = edge1 * pvec; + + if (det > -EPSILON && det < EPSILON) + return false; + + /* calculate U parameter and test bounds */ + double u = ( tvec * pvec ) / det; + //if (u < 0.0 || u > 1.0) + if (u < -EPSILON || u > 1.0 + EPSILON) + return false; + + /* prepare to test V parameter */ + gp_XYZ qvec = tvec ^ edge1; + + /* calculate V parameter and test bounds */ + double v = (dir.XYZ() * qvec) / det; + //if ( v < 0.0 || u + v > 1.0 ) + if ( v < -EPSILON || u + v > 1.0 + EPSILON) + return false; + + /* calculate t, ray intersects triangle */ + t = (edge2 * qvec) / det; + + //return true; + return t > 0.; +} + +//================================================================================ +/*! + * \brief Perform smooth of _LayerEdge's based on EDGE's + * \retval bool - true if node has been moved + */ +//================================================================================ + +bool _LayerEdge::SmoothOnEdge(Handle(Geom_Surface)& surface, + const TopoDS_Face& F, + SMESH_MesherHelper& helper) +{ + ASSERT( IsOnEdge() ); + + SMDS_MeshNode* tgtNode = const_cast( _nodes.back() ); + SMESH_TNodeXYZ oldPos( tgtNode ); + double dist01, distNewOld; + + SMESH_TNodeXYZ p0( _2neibors->tgtNode(0)); + SMESH_TNodeXYZ p1( _2neibors->tgtNode(1)); + dist01 = p0.Distance( _2neibors->tgtNode(1) ); + + gp_Pnt newPos = p0 * _2neibors->_wgt[0] + p1 * _2neibors->_wgt[1]; + double lenDelta = 0; + if ( _curvature ) + { + //lenDelta = _curvature->lenDelta( _len ); + lenDelta = _curvature->lenDeltaByDist( dist01 ); + newPos.ChangeCoord() += _normal * lenDelta; + } + + distNewOld = newPos.Distance( oldPos ); + + if ( F.IsNull() ) + { + if ( _2neibors->_plnNorm ) + { + // put newPos on the plane defined by source node and _plnNorm + gp_XYZ new2src = SMESH_TNodeXYZ( _nodes[0] ) - newPos.XYZ(); + double new2srcProj = (*_2neibors->_plnNorm) * new2src; + newPos.ChangeCoord() += (*_2neibors->_plnNorm) * new2srcProj; + } + tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() ); + _pos.back() = newPos.XYZ(); + } + else + { + tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() ); + gp_XY uv( Precision::Infinite(), 0 ); + helper.CheckNodeUV( F, tgtNode, uv, 1e-10, /*force=*/true ); + _pos.back().SetCoord( uv.X(), uv.Y(), 0 ); + + newPos = surface->Value( uv.X(), uv.Y() ); + tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() ); + } + + // commented for IPAL0052478 + // if ( _curvature && lenDelta < 0 ) + // { + // gp_Pnt prevPos( _pos[ _pos.size()-2 ]); + // _len -= prevPos.Distance( oldPos ); + // _len += prevPos.Distance( newPos ); + // } + bool moved = distNewOld > dist01/50; + //if ( moved ) + dumpMove( tgtNode ); // debug + + return moved; +} + +//================================================================================ +/*! + * \brief Perform laplacian smooth in 3D of nodes inflated from FACE + * \retval bool - true if _tgtNode has been moved + */ +//================================================================================ + +int _LayerEdge::Smooth(const int step, const bool isConcaveFace, const bool findBest ) +{ + if ( _simplices.size() < 2 ) + return 0; // _LayerEdge inflated along EDGE or FACE + + const gp_XYZ& curPos ( _pos.back() ); + const gp_XYZ& prevPos( _pos[ _pos.size()-2 ]); + + // quality metrics (orientation) of tetras around _tgtNode + int nbOkBefore = 0; + double vol, minVolBefore = 1e100; + for ( size_t i = 0; i < _simplices.size(); ++i ) + { + nbOkBefore += _simplices[i].IsForward( _nodes[0], &curPos, vol ); + minVolBefore = Min( minVolBefore, vol ); + } + int nbBad = _simplices.size() - nbOkBefore; + + // compute new position for the last _pos using different _funs + gp_XYZ newPos; + for ( int iFun = -1; iFun < theNbSmooFuns; ++iFun ) + { + if ( iFun < 0 ) + newPos = (this->*_smooFunction)(); // fun chosen by ChooseSmooFunction() + else if ( _funs[ iFun ] == _smooFunction ) + continue; // _smooFunction again + else if ( step > 0 ) + newPos = (this->*_funs[ iFun ])(); // try other smoothing fun + else + break; // let "easy" functions improve elements around distorted ones + + if ( _curvature ) + { + double delta = _curvature->lenDelta( _len ); + if ( delta > 0 ) + newPos += _normal * delta; + else + { + double segLen = _normal * ( newPos - prevPos ); + if ( segLen + delta > 0 ) + newPos += _normal * delta; + } + // double segLenChange = _normal * ( curPos - newPos ); + // newPos += 0.5 * _normal * segLenChange; + } + + int nbOkAfter = 0; + double minVolAfter = 1e100; + for ( size_t i = 0; i < _simplices.size(); ++i ) + { + nbOkAfter += _simplices[i].IsForward( _nodes[0], &newPos, vol ); + minVolAfter = Min( minVolAfter, vol ); + } + // get worse? + if ( nbOkAfter < nbOkBefore ) + continue; + if (( isConcaveFace || findBest ) && + ( nbOkAfter == nbOkBefore ) && + //( iFun > -1 || nbOkAfter < _simplices.size() ) && + ( minVolAfter <= minVolBefore )) + continue; + + SMDS_MeshNode* n = const_cast< SMDS_MeshNode* >( _nodes.back() ); + + // commented for IPAL0052478 + // _len -= prevPos.Distance(SMESH_TNodeXYZ( n )); + // _len += prevPos.Distance(newPos); + + n->setXYZ( newPos.X(), newPos.Y(), newPos.Z()); + _pos.back() = newPos; + dumpMoveComm( n, _funNames[ iFun < 0 ? smooFunID() : iFun ]); + + nbBad = _simplices.size() - nbOkAfter; + + if ( iFun > -1 ) + { + //_smooFunction = _funs[ iFun ]; + // cout << "# " << _funNames[ iFun ] << "\t N:" << _nodes.back()->GetID() + // << "\t nbBad: " << _simplices.size() - nbOkAfter + // << " minVol: " << minVolAfter + // << " " << newPos.X() << " " << newPos.Y() << " " << newPos.Z() + // << endl; + minVolBefore = minVolAfter; + nbOkBefore = nbOkAfter; + continue; // look for a better function + } + + if ( !findBest ) + break; + + } // loop on smoothing functions + + return nbBad; +} + +//================================================================================ +/*! + * \brief Chooses a smoothing technic giving a position most close to an initial one. + * For a correct result, _simplices must contain nodes lying on geometry. + */ +//================================================================================ + +void _LayerEdge::ChooseSmooFunction( const set< TGeomID >& concaveVertices, + const TNode2Edge& n2eMap) +{ + if ( _smooFunction ) return; + + // use smoothNefPolygon() near concaveVertices + if ( !concaveVertices.empty() ) + { + for ( size_t i = 0; i < _simplices.size(); ++i ) + { + if ( concaveVertices.count( _simplices[i]._nPrev->getshapeId() )) + { + _smooFunction = _funs[ FUN_NEFPOLY ]; + + // set FUN_CENTROIDAL to neighbor edges + TNode2Edge::const_iterator n2e; + for ( i = 0; i < _simplices.size(); ++i ) + { + if (( _simplices[i]._nPrev->GetPosition()->GetDim() == 2 ) && + (( n2e = n2eMap.find( _simplices[i]._nPrev )) != n2eMap.end() )) + { + n2e->second->_smooFunction = _funs[ FUN_CENTROIDAL ]; + } + } + return; + } + } + //} + + // this coice is done only if ( !concaveVertices.empty() ) for Grids/smesh/bugs_19/X1 + // where the nodes are smoothed too far along a sphere thus creating + // inverted _simplices + double dist[theNbSmooFuns]; + //double coef[theNbSmooFuns] = { 1., 1.2, 1.4, 1.4 }; + double coef[theNbSmooFuns] = { 1., 1., 1., 1. }; + + double minDist = Precision::Infinite(); + gp_Pnt p = SMESH_TNodeXYZ( _nodes[0] ); + for ( int i = 0; i < FUN_NEFPOLY; ++i ) + { + gp_Pnt newP = (this->*_funs[i])(); + dist[i] = p.SquareDistance( newP ); + if ( dist[i]*coef[i] < minDist ) + { + _smooFunction = _funs[i]; + minDist = dist[i]*coef[i]; + } + } + } + else + { + _smooFunction = _funs[ FUN_LAPLACIAN ]; + } + // int minDim = 3; + // for ( size_t i = 0; i < _simplices.size(); ++i ) + // minDim = Min( minDim, _simplices[i]._nPrev->GetPosition()->GetDim() ); + // if ( minDim == 0 ) + // _smooFunction = _funs[ FUN_CENTROIDAL ]; + // else if ( minDim == 1 ) + // _smooFunction = _funs[ FUN_CENTROIDAL ]; + + + // int iMin; + // for ( int i = 0; i < FUN_NB; ++i ) + // { + // //cout << dist[i] << " "; + // if ( _smooFunction == _funs[i] ) { + // iMin = i; + // //debugMsg( fNames[i] ); + // break; + // } + // } + // cout << _funNames[ iMin ] << "\t N:" << _nodes.back()->GetID() << endl; +} + +//================================================================================ +/*! + * \brief Returns a name of _SmooFunction + */ +//================================================================================ + +int _LayerEdge::smooFunID( _LayerEdge::PSmooFun fun) const +{ + if ( !fun ) + fun = _smooFunction; + for ( int i = 0; i < theNbSmooFuns; ++i ) + if ( fun == _funs[i] ) + return i; + + return theNbSmooFuns; +} + +//================================================================================ +/*! + * \brief Computes a new node position using Laplacian smoothing + */ +//================================================================================ + +gp_XYZ _LayerEdge::smoothLaplacian() +{ + gp_XYZ newPos (0,0,0); + for ( size_t i = 0; i < _simplices.size(); ++i ) + newPos += SMESH_TNodeXYZ( _simplices[i]._nPrev ); + newPos /= _simplices.size(); + + return newPos; +} + +//================================================================================ +/*! + * \brief Computes a new node position using angular-based smoothing + */ +//================================================================================ + +gp_XYZ _LayerEdge::smoothAngular() +{ + vector< gp_Vec > edgeDir; edgeDir. reserve( _simplices.size() + 1); + vector< double > edgeSize; edgeSize.reserve( _simplices.size() ); + vector< gp_XYZ > points; points. reserve( _simplices.size() ); + + gp_XYZ pPrev = SMESH_TNodeXYZ( _simplices.back()._nPrev ); + gp_XYZ pN( 0,0,0 ); + for ( size_t i = 0; i < _simplices.size(); ++i ) + { + gp_XYZ p = SMESH_TNodeXYZ( _simplices[i]._nPrev ); + edgeDir.push_back( p - pPrev ); + edgeSize.push_back( edgeDir.back().Magnitude() ); + //double edgeSize = edgeDir.back().Magnitude(); + if ( edgeSize.back() < numeric_limits::min() ) + { + edgeDir.pop_back(); + edgeSize.pop_back(); + } + else + { + edgeDir.back() /= edgeSize.back(); + points.push_back( p ); + pN += p; + } + pPrev = p; + } + edgeDir.push_back ( edgeDir[0] ); + edgeSize.push_back( edgeSize[0] ); + pN /= points.size(); + + gp_XYZ newPos(0,0,0); + //gp_XYZ pN = SMESH_TNodeXYZ( _nodes.back() ); + double sumSize = 0; + for ( size_t i = 0; i < points.size(); ++i ) + { + gp_Vec toN( pN - points[i]); + double toNLen = toN.Magnitude(); + if ( toNLen < numeric_limits::min() ) + { + newPos += pN; + continue; + } + gp_Vec bisec = edgeDir[i] + edgeDir[i+1]; + double bisecLen = bisec.SquareMagnitude(); + if ( bisecLen < numeric_limits::min() ) + { + gp_Vec norm = edgeDir[i] ^ toN; + bisec = norm ^ edgeDir[i]; + bisecLen = bisec.SquareMagnitude(); + } + bisecLen = Sqrt( bisecLen ); + bisec /= bisecLen; + +#if 1 + //bisecLen = 1.; + gp_XYZ pNew = ( points[i] + bisec.XYZ() * toNLen ) * bisecLen; + sumSize += bisecLen; +#else + gp_XYZ pNew = ( points[i] + bisec.XYZ() * toNLen ) * ( edgeSize[i] + edgeSize[i+1] ); + sumSize += ( edgeSize[i] + edgeSize[i+1] ); +#endif + newPos += pNew; + } + newPos /= sumSize; + + return newPos; +} + +//================================================================================ +/*! + * \brief Computes a new node position using weigthed node positions + */ +//================================================================================ + +gp_XYZ _LayerEdge::smoothLengthWeighted() +{ + vector< double > edgeSize; edgeSize.reserve( _simplices.size() + 1); + vector< gp_XYZ > points; points. reserve( _simplices.size() ); + + gp_XYZ pPrev = SMESH_TNodeXYZ( _simplices.back()._nPrev ); + for ( size_t i = 0; i < _simplices.size(); ++i ) + { + gp_XYZ p = SMESH_TNodeXYZ( _simplices[i]._nPrev ); + edgeSize.push_back( ( p - pPrev ).Modulus() ); + if ( edgeSize.back() < numeric_limits::min() ) + { + edgeSize.pop_back(); + } + else + { + points.push_back( p ); + } + pPrev = p; + } + edgeSize.push_back( edgeSize[0] ); + + gp_XYZ newPos(0,0,0); + double sumSize = 0; + for ( size_t i = 0; i < points.size(); ++i ) + { + newPos += points[i] * ( edgeSize[i] + edgeSize[i+1] ); + sumSize += edgeSize[i] + edgeSize[i+1]; + } + newPos /= sumSize; + return newPos; +} + +//================================================================================ +/*! + * \brief Computes a new node position using angular-based smoothing + */ +//================================================================================ + +gp_XYZ _LayerEdge::smoothCentroidal() +{ + gp_XYZ newPos(0,0,0); + gp_XYZ pN = SMESH_TNodeXYZ( _nodes.back() ); + double sumSize = 0; + for ( size_t i = 0; i < _simplices.size(); ++i ) + { + gp_XYZ p1 = SMESH_TNodeXYZ( _simplices[i]._nPrev ); + gp_XYZ p2 = SMESH_TNodeXYZ( _simplices[i]._nNext ); + gp_XYZ gc = ( pN + p1 + p2 ) / 3.; + double size = (( p1 - pN ) ^ ( p2 - pN )).Modulus(); + + sumSize += size; + newPos += gc * size; + } + newPos /= sumSize; + + return newPos; +} + +//================================================================================ +/*! + * \brief Computes a new node position located inside a Nef polygon + */ +//================================================================================ + +gp_XYZ _LayerEdge::smoothNefPolygon() +{ + gp_XYZ newPos(0,0,0); + + // get a plane to seach a solution on + + vector< gp_XYZ > vecs( _simplices.size() + 1 ); + size_t i; + const double tol = numeric_limits::min(); + gp_XYZ center(0,0,0); + for ( i = 0; i < _simplices.size(); ++i ) + { + vecs[i] = ( SMESH_TNodeXYZ( _simplices[i]._nNext ) - + SMESH_TNodeXYZ( _simplices[i]._nPrev )); + center += SMESH_TNodeXYZ( _simplices[i]._nPrev ); + } + vecs.back() = vecs[0]; + center /= _simplices.size(); + + gp_XYZ zAxis(0,0,0); + for ( i = 0; i < _simplices.size(); ++i ) + zAxis += vecs[i] ^ vecs[i+1]; + + gp_XYZ yAxis; + for ( i = 0; i < _simplices.size(); ++i ) + { + yAxis = vecs[i]; + if ( yAxis.SquareModulus() > tol ) + break; + } + gp_XYZ xAxis = yAxis ^ zAxis; + // SMESH_TNodeXYZ p0( _simplices[0]._nPrev ); + // const double tol = 1e-6 * ( p0.Distance( _simplices[1]._nPrev ) + + // p0.Distance( _simplices[2]._nPrev )); + // gp_XYZ center = smoothLaplacian(); + // gp_XYZ xAxis, yAxis, zAxis; + // for ( i = 0; i < _simplices.size(); ++i ) + // { + // xAxis = SMESH_TNodeXYZ( _simplices[i]._nPrev ) - center; + // if ( xAxis.SquareModulus() > tol*tol ) + // break; + // } + // for ( i = 1; i < _simplices.size(); ++i ) + // { + // yAxis = SMESH_TNodeXYZ( _simplices[i]._nPrev ) - center; + // zAxis = xAxis ^ yAxis; + // if ( zAxis.SquareModulus() > tol*tol ) + // break; + // } + // if ( i == _simplices.size() ) return newPos; + + yAxis = zAxis ^ xAxis; + xAxis /= xAxis.Modulus(); + yAxis /= yAxis.Modulus(); + + // get half-planes of _simplices + + vector< _halfPlane > halfPlns( _simplices.size() ); + int nbHP = 0; + for ( size_t i = 0; i < _simplices.size(); ++i ) + { + gp_XYZ OP1 = SMESH_TNodeXYZ( _simplices[i]._nPrev ) - center; + gp_XYZ OP2 = SMESH_TNodeXYZ( _simplices[i]._nNext ) - center; + gp_XY p1( OP1 * xAxis, OP1 * yAxis ); + gp_XY p2( OP2 * xAxis, OP2 * yAxis ); + gp_XY vec12 = p2 - p1; + double dist12 = vec12.Modulus(); + if ( dist12 < tol ) + continue; + vec12 /= dist12; + halfPlns[ nbHP ]._pos = p1; + halfPlns[ nbHP ]._dir = vec12; + halfPlns[ nbHP ]._inNorm.SetCoord( -vec12.Y(), vec12.X() ); + ++nbHP; + } + + // intersect boundaries of half-planes, define state of intersection points + // in relation to all half-planes and calculate internal point of a 2D polygon + + double sumLen = 0; + gp_XY newPos2D (0,0); + + enum { UNDEF = -1, NOT_OUT, IS_OUT, NO_INT }; + typedef std::pair< gp_XY, int > TIntPntState; // coord and isOut state + TIntPntState undefIPS( gp_XY(1e100,1e100), UNDEF ); + + vector< vector< TIntPntState > > allIntPnts( nbHP ); + for ( int iHP1 = 0; iHP1 < nbHP; ++iHP1 ) + { + vector< TIntPntState > & intPnts1 = allIntPnts[ iHP1 ]; + if ( intPnts1.empty() ) intPnts1.resize( nbHP, undefIPS ); + + int iPrev = SMESH_MesherHelper::WrapIndex( iHP1 - 1, nbHP ); + int iNext = SMESH_MesherHelper::WrapIndex( iHP1 + 1, nbHP ); + + int nbNotOut = 0; + const gp_XY* segEnds[2] = { 0, 0 }; // NOT_OUT points + + for ( int iHP2 = 0; iHP2 < nbHP; ++iHP2 ) + { + if ( iHP1 == iHP2 ) continue; + + TIntPntState & ips1 = intPnts1[ iHP2 ]; + if ( ips1.second == UNDEF ) + { + // find an intersection point of boundaries of iHP1 and iHP2 + + if ( iHP2 == iPrev ) // intersection with neighbors is known + ips1.first = halfPlns[ iHP1 ]._pos; + else if ( iHP2 == iNext ) + ips1.first = halfPlns[ iHP2 ]._pos; + else if ( !halfPlns[ iHP1 ].FindInterestion( halfPlns[ iHP2 ], ips1.first )) + ips1.second = NO_INT; + + // classify the found intersection point + if ( ips1.second != NO_INT ) + { + ips1.second = NOT_OUT; + for ( int i = 0; i < nbHP && ips1.second == NOT_OUT; ++i ) + if ( i != iHP1 && i != iHP2 && + halfPlns[ i ].IsOut( ips1.first, tol )) + ips1.second = IS_OUT; + } + vector< TIntPntState > & intPnts2 = allIntPnts[ iHP2 ]; + if ( intPnts2.empty() ) intPnts2.resize( nbHP, undefIPS ); + TIntPntState & ips2 = intPnts2[ iHP1 ]; + ips2 = ips1; + } + if ( ips1.second == NOT_OUT ) + { + ++nbNotOut; + segEnds[ bool(segEnds[0]) ] = & ips1.first; + } + } + + // find a NOT_OUT segment of boundary which is located between + // two NOT_OUT int points + + if ( nbNotOut < 2 ) + continue; // no such a segment + + if ( nbNotOut > 2 ) + { + // sort points along the boundary + map< double, TIntPntState* > ipsByParam; + for ( int iHP2 = 0; iHP2 < nbHP; ++iHP2 ) + { + TIntPntState & ips1 = intPnts1[ iHP2 ]; + if ( ips1.second != NO_INT ) + { + gp_XY op = ips1.first - halfPlns[ iHP1 ]._pos; + double param = op * halfPlns[ iHP1 ]._dir; + ipsByParam.insert( make_pair( param, & ips1 )); + } + } + // look for two neighboring NOT_OUT points + nbNotOut = 0; + map< double, TIntPntState* >::iterator u2ips = ipsByParam.begin(); + for ( ; u2ips != ipsByParam.end(); ++u2ips ) + { + TIntPntState & ips1 = *(u2ips->second); + if ( ips1.second == NOT_OUT ) + segEnds[ bool( nbNotOut++ ) ] = & ips1.first; + else if ( nbNotOut >= 2 ) + break; + else + nbNotOut = 0; + } + } + + if ( nbNotOut >= 2 ) + { + double len = ( *segEnds[0] - *segEnds[1] ).Modulus(); + sumLen += len; + + newPos2D += 0.5 * len * ( *segEnds[0] + *segEnds[1] ); + } + } + + if ( sumLen > 0 ) + { + newPos2D /= sumLen; + newPos = center + xAxis * newPos2D.X() + yAxis * newPos2D.Y(); + } + else + { + newPos = center; + } + + return newPos; +} + +//================================================================================ +/*! + * \brief Add a new segment to _LayerEdge during inflation + */ +//================================================================================ + +void _LayerEdge::SetNewLength( double len, _EdgesOnShape& eos, SMESH_MesherHelper& helper ) +{ + if ( _len - len > -1e-6 ) + { + //_pos.push_back( _pos.back() ); + return; + } + + SMDS_MeshNode* n = const_cast< SMDS_MeshNode*>( _nodes.back() ); + gp_XYZ oldXYZ = SMESH_TNodeXYZ( n ); + gp_XYZ newXYZ; + if ( eos._hyp.IsOffsetMethod() ) + { + newXYZ = oldXYZ; + gp_Vec faceNorm; + SMDS_ElemIteratorPtr faceIt = _nodes[0]->GetInverseElementIterator( SMDSAbs_Face ); + while ( faceIt->more() ) + { + const SMDS_MeshElement* face = faceIt->next(); + if ( !eos.GetNormal( face, faceNorm )) + continue; + + // translate plane of a face + gp_XYZ baryCenter = oldXYZ + faceNorm.XYZ() * ( len - _len ); + + // find point of intersection of the face plane located at baryCenter + // and _normal located at newXYZ + double d = -( faceNorm.XYZ() * baryCenter ); // d of plane equation ax+by+cz+d=0 + double dot = ( faceNorm.XYZ() * _normal ); + if ( dot < std::numeric_limits::min() ) + dot = ( len - _len ) * 1e-3; + double step = -( faceNorm.XYZ() * newXYZ + d ) / dot; + newXYZ += step * _normal; + } + } + else + { + newXYZ = oldXYZ + _normal * ( len - _len ) * _lenFactor; + } + n->setXYZ( newXYZ.X(), newXYZ.Y(), newXYZ.Z() ); + + _pos.push_back( newXYZ ); + _len = len; + + if ( !eos._sWOL.IsNull() ) + { + double distXYZ[4]; + if ( eos.SWOLType() == TopAbs_EDGE ) + { + double u = Precision::Infinite(); // to force projection w/o distance check + helper.CheckNodeU( TopoDS::Edge( eos._sWOL ), n, u, 1e-10, /*force=*/true, distXYZ ); + _pos.back().SetCoord( u, 0, 0 ); + if ( _nodes.size() > 1 ) + { + SMDS_EdgePosition* pos = static_cast( n->GetPosition() ); + pos->SetUParameter( u ); + } + } + else // TopAbs_FACE + { + gp_XY uv( Precision::Infinite(), 0 ); + helper.CheckNodeUV( TopoDS::Face( eos._sWOL ), n, uv, 1e-10, /*force=*/true, distXYZ ); + _pos.back().SetCoord( uv.X(), uv.Y(), 0 ); + if ( _nodes.size() > 1 ) + { + SMDS_FacePosition* pos = static_cast( n->GetPosition() ); + pos->SetUParameter( uv.X() ); + pos->SetVParameter( uv.Y() ); + } + } + n->setXYZ( distXYZ[1], distXYZ[2], distXYZ[3]); + } + dumpMove( n ); //debug +} + +//================================================================================ +/*! + * \brief Remove last inflation step + */ +//================================================================================ + +void _LayerEdge::InvalidateStep( int curStep, const _EdgesOnShape& eos, bool restoreLength ) +{ + if ( _pos.size() > curStep ) + { + if ( restoreLength ) + _len -= ( _pos[ curStep-1 ] - _pos.back() ).Modulus(); + + _pos.resize( curStep ); + gp_Pnt nXYZ = _pos.back(); + SMDS_MeshNode* n = const_cast< SMDS_MeshNode*>( _nodes.back() ); + if ( !eos._sWOL.IsNull() ) + { + TopLoc_Location loc; + if ( eos.SWOLType() == TopAbs_EDGE ) + { + SMDS_EdgePosition* pos = static_cast( n->GetPosition() ); + pos->SetUParameter( nXYZ.X() ); + double f,l; + Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge( eos._sWOL ), loc, f,l); + nXYZ = curve->Value( nXYZ.X() ).Transformed( loc ); + } + else + { + SMDS_FacePosition* pos = static_cast( n->GetPosition() ); + pos->SetUParameter( nXYZ.X() ); + pos->SetVParameter( nXYZ.Y() ); + Handle(Geom_Surface) surface = BRep_Tool::Surface( TopoDS::Face(eos._sWOL), loc ); + nXYZ = surface->Value( nXYZ.X(), nXYZ.Y() ).Transformed( loc ); + } + } + n->setXYZ( nXYZ.X(), nXYZ.Y(), nXYZ.Z() ); + dumpMove( n ); + } +} + +//================================================================================ +/*! + * \brief Create layers of prisms + */ +//================================================================================ + +bool _ViscousBuilder::refine(_SolidData& data) +{ + SMESH_MesherHelper helper( *_mesh ); + helper.SetSubShape( data._solid ); + helper.SetElementsOnShape(false); + + Handle(Geom_Curve) curve; + Handle(Geom_Surface) surface; + TopoDS_Edge geomEdge; + TopoDS_Face geomFace; + TopoDS_Shape prevSWOL; + TopLoc_Location loc; + double f,l, u; + gp_XY uv; + bool isOnEdge; + TGeomID prevBaseId = -1; + TNode2Edge* n2eMap = 0; + TNode2Edge::iterator n2e; + + // Create intermediate nodes on each _LayerEdge + + for ( size_t iS = 0; iS < data._edgesOnShape.size(); ++iS ) + { + _EdgesOnShape& eos = data._edgesOnShape[iS]; + if ( eos._edges.empty() ) continue; + + if ( eos._edges[0]->_nodes.size() < 2 ) + continue; // on _noShrinkShapes + + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + _LayerEdge& edge = *eos._edges[i]; + + // get accumulated length of segments + vector< double > segLen( edge._pos.size() ); + segLen[0] = 0.0; + for ( size_t j = 1; j < edge._pos.size(); ++j ) + segLen[j] = segLen[j-1] + (edge._pos[j-1] - edge._pos[j] ).Modulus(); + + // allocate memory for new nodes if it is not yet refined + const SMDS_MeshNode* tgtNode = edge._nodes.back(); + if ( edge._nodes.size() == 2 ) + { + edge._nodes.resize( eos._hyp.GetNumberLayers() + 1, 0 ); + edge._nodes[1] = 0; + edge._nodes.back() = tgtNode; + } + // get data of a shrink shape + if ( !eos._sWOL.IsNull() && eos._sWOL != prevSWOL ) + { + isOnEdge = ( eos.SWOLType() == TopAbs_EDGE ); + if ( isOnEdge ) + { + geomEdge = TopoDS::Edge( eos._sWOL ); + curve = BRep_Tool::Curve( geomEdge, loc, f,l); + } + else + { + geomFace = TopoDS::Face( eos._sWOL ); + surface = BRep_Tool::Surface( geomFace, loc ); + } + prevSWOL = eos._sWOL; + } + // restore shapePos of the last node by already treated _LayerEdge of another _SolidData + const TGeomID baseShapeId = edge._nodes[0]->getshapeId(); + if ( baseShapeId != prevBaseId ) + { + map< TGeomID, TNode2Edge* >::iterator s2ne = data._s2neMap.find( baseShapeId ); + n2eMap = ( s2ne == data._s2neMap.end() ) ? 0 : n2eMap = s2ne->second; + prevBaseId = baseShapeId; + } + _LayerEdge* edgeOnSameNode = 0; + if ( n2eMap && (( n2e = n2eMap->find( edge._nodes[0] )) != n2eMap->end() )) + { + edgeOnSameNode = n2e->second; + const gp_XYZ& otherTgtPos = edgeOnSameNode->_pos.back(); + SMDS_PositionPtr lastPos = tgtNode->GetPosition(); + if ( isOnEdge ) + { + SMDS_EdgePosition* epos = static_cast( lastPos ); + epos->SetUParameter( otherTgtPos.X() ); + } + else + { + SMDS_FacePosition* fpos = static_cast( lastPos ); + fpos->SetUParameter( otherTgtPos.X() ); + fpos->SetVParameter( otherTgtPos.Y() ); + } + } + // calculate height of the first layer + double h0; + const double T = segLen.back(); //data._hyp.GetTotalThickness(); + const double f = eos._hyp.GetStretchFactor(); + const int N = eos._hyp.GetNumberLayers(); + const double fPowN = pow( f, N ); + if ( fPowN - 1 <= numeric_limits::min() ) + h0 = T / N; + else + h0 = T * ( f - 1 )/( fPowN - 1 ); + + const double zeroLen = std::numeric_limits::min(); + + // create intermediate nodes + double hSum = 0, hi = h0/f; + size_t iSeg = 1; + for ( size_t iStep = 1; iStep < edge._nodes.size(); ++iStep ) + { + // compute an intermediate position + hi *= f; + hSum += hi; + while ( hSum > segLen[iSeg] && iSeg < segLen.size()-1) + ++iSeg; + int iPrevSeg = iSeg-1; + while ( fabs( segLen[iPrevSeg] - segLen[iSeg]) <= zeroLen && iPrevSeg > 0 ) + --iPrevSeg; + double r = ( segLen[iSeg] - hSum ) / ( segLen[iSeg] - segLen[iPrevSeg] ); + gp_Pnt pos = r * edge._pos[iPrevSeg] + (1-r) * edge._pos[iSeg]; + + SMDS_MeshNode*& node = const_cast< SMDS_MeshNode*& >( edge._nodes[ iStep ]); + if ( !eos._sWOL.IsNull() ) + { + // compute XYZ by parameters + if ( isOnEdge ) + { + u = pos.X(); + if ( !node ) + pos = curve->Value( u ).Transformed(loc); + } + else + { + uv.SetCoord( pos.X(), pos.Y() ); + if ( !node ) + pos = surface->Value( pos.X(), pos.Y() ).Transformed(loc); + } + } + // create or update the node + if ( !node ) + { + node = helper.AddNode( pos.X(), pos.Y(), pos.Z()); + if ( !eos._sWOL.IsNull() ) + { + if ( isOnEdge ) + getMeshDS()->SetNodeOnEdge( node, geomEdge, u ); + else + getMeshDS()->SetNodeOnFace( node, geomFace, uv.X(), uv.Y() ); + } + else + { + getMeshDS()->SetNodeInVolume( node, helper.GetSubShapeID() ); + } + } + else + { + if ( !eos._sWOL.IsNull() ) + { + // make average pos from new and current parameters + if ( isOnEdge ) + { + u = 0.5 * ( u + helper.GetNodeU( geomEdge, node )); + pos = curve->Value( u ).Transformed(loc); + + SMDS_EdgePosition* epos = static_cast( node->GetPosition() ); + epos->SetUParameter( u ); + } + else + { + uv = 0.5 * ( uv + helper.GetNodeUV( geomFace, node )); + pos = surface->Value( uv.X(), uv.Y()).Transformed(loc); + + SMDS_FacePosition* fpos = static_cast( node->GetPosition() ); + fpos->SetUParameter( uv.X() ); + fpos->SetVParameter( uv.Y() ); + } + } + node->setXYZ( pos.X(), pos.Y(), pos.Z() ); + } + } // loop on edge._nodes + + if ( !eos._sWOL.IsNull() ) // prepare for shrink() + { + if ( isOnEdge ) + edge._pos.back().SetCoord( u, 0,0); + else + edge._pos.back().SetCoord( uv.X(), uv.Y() ,0); + + if ( edgeOnSameNode ) + edgeOnSameNode->_pos.back() = edge._pos.back(); + } + + } // loop on eos._edges to create nodes + + + if ( !getMeshDS()->IsEmbeddedMode() ) + // Log node movement + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + SMESH_TNodeXYZ p ( eos._edges[i]->_nodes.back() ); + getMeshDS()->MoveNode( p._node, p.X(), p.Y(), p.Z() ); + } + } + + + // Create volumes + + helper.SetElementsOnShape(true); + + vector< vector* > nnVec; + set< vector* > nnSet; + set< int > degenEdgeInd; + vector degenVols; + + TopExp_Explorer exp( data._solid, TopAbs_FACE ); + for ( ; exp.More(); exp.Next() ) + { + const TGeomID faceID = getMeshDS()->ShapeToIndex( exp.Current() ); + if ( data._ignoreFaceIds.count( faceID )) + continue; + const bool isReversedFace = data._reversedFaceIds.count( faceID ); + SMESHDS_SubMesh* fSubM = getMeshDS()->MeshElements( exp.Current() ); + SMDS_ElemIteratorPtr fIt = fSubM->GetElements(); + while ( fIt->more() ) + { + const SMDS_MeshElement* face = fIt->next(); + const int nbNodes = face->NbCornerNodes(); + nnVec.resize( nbNodes ); + nnSet.clear(); + degenEdgeInd.clear(); + int nbZ = 0; + SMDS_NodeIteratorPtr nIt = face->nodeIterator(); + for ( int iN = 0; iN < nbNodes; ++iN ) + { + const SMDS_MeshNode* n = nIt->next(); + const int i = isReversedFace ? nbNodes-1-iN : iN; + nnVec[ i ] = & data._n2eMap[ n ]->_nodes; + if ( nnVec[ i ]->size() < 2 ) + degenEdgeInd.insert( iN ); + else + nbZ = nnVec[ i ]->size(); + + if ( helper.HasDegeneratedEdges() ) + nnSet.insert( nnVec[ i ]); + } + if ( nbZ == 0 ) + continue; + if ( 0 < nnSet.size() && nnSet.size() < 3 ) + continue; + + switch ( nbNodes ) + { + case 3: + switch ( degenEdgeInd.size() ) + { + case 0: // PENTA + { + for ( int iZ = 1; iZ < nbZ; ++iZ ) + helper.AddVolume( (*nnVec[0])[iZ-1], (*nnVec[1])[iZ-1], (*nnVec[2])[iZ-1], + (*nnVec[0])[iZ], (*nnVec[1])[iZ], (*nnVec[2])[iZ]); + break; + } + case 1: // PYRAM + { + int i2 = *degenEdgeInd.begin(); + int i0 = helper.WrapIndex( i2 - 1, nbNodes ); + int i1 = helper.WrapIndex( i2 + 1, nbNodes ); + for ( int iZ = 1; iZ < nbZ; ++iZ ) + helper.AddVolume( (*nnVec[i0])[iZ-1], (*nnVec[i1])[iZ-1], + (*nnVec[i1])[iZ], (*nnVec[i0])[iZ], (*nnVec[i2])[0]); + break; + } + case 2: // TETRA + { + int i3 = !degenEdgeInd.count(0) ? 0 : !degenEdgeInd.count(1) ? 1 : 2; + for ( int iZ = 1; iZ < nbZ; ++iZ ) + helper.AddVolume( (*nnVec[0])[iZ-1], (*nnVec[1])[iZ-1], (*nnVec[2])[iZ-1], + (*nnVec[i3])[iZ]); + break; + } + } + break; + + case 4: + switch ( degenEdgeInd.size() ) + { + case 0: // HEX + { + for ( int iZ = 1; iZ < nbZ; ++iZ ) + helper.AddVolume( (*nnVec[0])[iZ-1], (*nnVec[1])[iZ-1], + (*nnVec[2])[iZ-1], (*nnVec[3])[iZ-1], + (*nnVec[0])[iZ], (*nnVec[1])[iZ], + (*nnVec[2])[iZ], (*nnVec[3])[iZ]); + break; + } + case 2: // PENTA? + { + int i2 = *degenEdgeInd.begin(); + int i3 = *degenEdgeInd.rbegin(); + bool ok = ( i3 - i2 == 1 ); + if ( i2 == 0 && i3 == 3 ) { i2 = 3; i3 = 0; ok = true; } + int i0 = helper.WrapIndex( i3 + 1, nbNodes ); + int i1 = helper.WrapIndex( i0 + 1, nbNodes ); + for ( int iZ = 1; iZ < nbZ; ++iZ ) + { + const SMDS_MeshElement* vol = + helper.AddVolume( (*nnVec[i3])[0], (*nnVec[i0])[iZ], (*nnVec[i0])[iZ-1], + (*nnVec[i2])[0], (*nnVec[i1])[iZ], (*nnVec[i1])[iZ-1]); + if ( !ok && vol ) + degenVols.push_back( vol ); + } + break; + } + case 3: // degen HEX + { + const SMDS_MeshNode* nn[8]; + for ( int iZ = 1; iZ < nbZ; ++iZ ) + { + const SMDS_MeshElement* vol = + helper.AddVolume( nnVec[0]->size() > 1 ? (*nnVec[0])[iZ-1] : (*nnVec[0])[0], + nnVec[1]->size() > 1 ? (*nnVec[1])[iZ-1] : (*nnVec[1])[0], + nnVec[2]->size() > 1 ? (*nnVec[2])[iZ-1] : (*nnVec[2])[0], + nnVec[3]->size() > 1 ? (*nnVec[3])[iZ-1] : (*nnVec[3])[0], + nnVec[0]->size() > 1 ? (*nnVec[0])[iZ] : (*nnVec[0])[0], + nnVec[1]->size() > 1 ? (*nnVec[1])[iZ] : (*nnVec[1])[0], + nnVec[2]->size() > 1 ? (*nnVec[2])[iZ] : (*nnVec[2])[0], + nnVec[3]->size() > 1 ? (*nnVec[3])[iZ] : (*nnVec[3])[0]); + degenVols.push_back( vol ); + } + } + break; + } + break; + + default: + return error("Not supported type of element", data._index); + + } // switch ( nbNodes ) + } // while ( fIt->more() ) + } // loop on FACEs + + if ( !degenVols.empty() ) + { + SMESH_ComputeErrorPtr& err = _mesh->GetSubMesh( data._solid )->GetComputeError(); + if ( !err || err->IsOK() ) + { + err.reset( new SMESH_ComputeError( COMPERR_WARNING, + "Degenerated volumes created" )); + err->myBadElements.insert( err->myBadElements.end(), + degenVols.begin(),degenVols.end() ); + } + } + + return true; +} + +//================================================================================ +/*! + * \brief Shrink 2D mesh on faces to let space for inflated layers + */ +//================================================================================ + +bool _ViscousBuilder::shrink() +{ + // make map of (ids of FACEs to shrink mesh on) to (_SolidData containing _LayerEdge's + // inflated along FACE or EDGE) + map< TGeomID, _SolidData* > f2sdMap; + for ( size_t i = 0 ; i < _sdVec.size(); ++i ) + { + _SolidData& data = _sdVec[i]; + TopTools_MapOfShape FFMap; + map< TGeomID, TopoDS_Shape >::iterator s2s = data._shrinkShape2Shape.begin(); + for (; s2s != data._shrinkShape2Shape.end(); ++s2s ) + if ( s2s->second.ShapeType() == TopAbs_FACE ) + { + f2sdMap.insert( make_pair( getMeshDS()->ShapeToIndex( s2s->second ), &data )); + + if ( FFMap.Add( (*s2s).second )) + // Put mesh faces on the shrinked FACE to the proxy sub-mesh to avoid + // usage of mesh faces made in addBoundaryElements() by the 3D algo or + // by StdMeshers_QuadToTriaAdaptor + if ( SMESHDS_SubMesh* smDS = getMeshDS()->MeshElements( s2s->second )) + { + SMESH_ProxyMesh::SubMesh* proxySub = + data._proxyMesh->getFaceSubM( TopoDS::Face( s2s->second ), /*create=*/true); + SMDS_ElemIteratorPtr fIt = smDS->GetElements(); + while ( fIt->more() ) + proxySub->AddElement( fIt->next() ); + // as a result 3D algo will use elements from proxySub and not from smDS + } + } + } + + SMESH_MesherHelper helper( *_mesh ); + helper.ToFixNodeParameters( true ); + + // EDGE's to shrink + map< TGeomID, _Shrinker1D > e2shrMap; + vector< _EdgesOnShape* > subEOS; + vector< _LayerEdge* > lEdges; + + // loop on FACES to srink mesh on + map< TGeomID, _SolidData* >::iterator f2sd = f2sdMap.begin(); + for ( ; f2sd != f2sdMap.end(); ++f2sd ) + { + _SolidData& data = *f2sd->second; + const TopoDS_Face& F = TopoDS::Face( getMeshDS()->IndexToShape( f2sd->first )); + SMESH_subMesh* sm = _mesh->GetSubMesh( F ); + SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); + + Handle(Geom_Surface) surface = BRep_Tool::Surface(F); + + helper.SetSubShape(F); + + // =========================== + // Prepare data for shrinking + // =========================== + + // Collect nodes to smooth, as src nodes are not yet replaced by tgt ones + // and thus all nodes on a FACE connected to 2d elements are to be smoothed + vector < const SMDS_MeshNode* > smoothNodes; + { + SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); + while ( nIt->more() ) + { + const SMDS_MeshNode* n = nIt->next(); + if ( n->NbInverseElements( SMDSAbs_Face ) > 0 ) + smoothNodes.push_back( n ); + } + } + // Find out face orientation + double refSign = 1; + const set ignoreShapes; + bool isOkUV; + if ( !smoothNodes.empty() ) + { + vector<_Simplex> simplices; + _Simplex::GetSimplices( smoothNodes[0], simplices, ignoreShapes ); + helper.GetNodeUV( F, simplices[0]._nPrev, 0, &isOkUV ); // fix UV of silpmex nodes + helper.GetNodeUV( F, simplices[0]._nNext, 0, &isOkUV ); + gp_XY uv = helper.GetNodeUV( F, smoothNodes[0], 0, &isOkUV ); + if ( !simplices[0].IsForward(uv, smoothNodes[0], F, helper,refSign) ) + refSign = -1; + } + + // Find _LayerEdge's inflated along F + subEOS.clear(); + lEdges.clear(); + { + SMESH_subMeshIteratorPtr subIt = sm->getDependsOnIterator(/*includeSelf=*/false, + /*complexFirst=*/true); //!!! + while ( subIt->more() ) + { + const TGeomID subID = subIt->next()->GetId(); + if ( data._noShrinkShapes.count( subID )) + continue; + _EdgesOnShape* eos = data.GetShapeEdges( subID ); + if ( !eos || eos->_sWOL.IsNull() ) continue; + + subEOS.push_back( eos ); + + for ( size_t i = 0; i < eos->_edges.size(); ++i ) + { + lEdges.push_back( eos->_edges[ i ] ); + prepareEdgeToShrink( *eos->_edges[ i ], *eos, helper, smDS ); + } + } + } + + dumpFunction(SMESH_Comment("beforeShrinkFace")<first); // debug + SMDS_ElemIteratorPtr fIt = smDS->GetElements(); + while ( fIt->more() ) + if ( const SMDS_MeshElement* f = fIt->next() ) + dumpChangeNodes( f ); + dumpFunctionEnd(); + + // Replace source nodes by target nodes in mesh faces to shrink + dumpFunction(SMESH_Comment("replNodesOnFace")<first); // debug + const SMDS_MeshNode* nodes[20]; + for ( size_t iS = 0; iS < subEOS.size(); ++iS ) + { + _EdgesOnShape& eos = * subEOS[ iS ]; + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + _LayerEdge& edge = *eos._edges[i]; + const SMDS_MeshNode* srcNode = edge._nodes[0]; + const SMDS_MeshNode* tgtNode = edge._nodes.back(); + SMDS_ElemIteratorPtr fIt = srcNode->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + if ( !smDS->Contains( f )) + continue; + SMDS_NodeIteratorPtr nIt = f->nodeIterator(); + for ( int iN = 0; nIt->more(); ++iN ) + { + const SMDS_MeshNode* n = nIt->next(); + nodes[iN] = ( n == srcNode ? tgtNode : n ); + } + helper.GetMeshDS()->ChangeElementNodes( f, nodes, f->NbNodes() ); + dumpChangeNodes( f ); + } + } + } + dumpFunctionEnd(); + + // find out if a FACE is concave + const bool isConcaveFace = isConcave( F, helper ); + + // Create _SmoothNode's on face F + vector< _SmoothNode > nodesToSmooth( smoothNodes.size() ); + { + dumpFunction(SMESH_Comment("fixUVOnFace")<first); // debug + const bool sortSimplices = isConcaveFace; + for ( size_t i = 0; i < smoothNodes.size(); ++i ) + { + const SMDS_MeshNode* n = smoothNodes[i]; + nodesToSmooth[ i ]._node = n; + // src nodes must be replaced by tgt nodes to have tgt nodes in _simplices + _Simplex::GetSimplices( n, nodesToSmooth[ i ]._simplices, ignoreShapes, 0, sortSimplices); + // fix up incorrect uv of nodes on the FACE + helper.GetNodeUV( F, n, 0, &isOkUV); + dumpMove( n ); + } + dumpFunctionEnd(); + } + //if ( nodesToSmooth.empty() ) continue; + + // Find EDGE's to shrink and set simpices to LayerEdge's + set< _Shrinker1D* > eShri1D; + { + for ( size_t iS = 0; iS < subEOS.size(); ++iS ) + { + _EdgesOnShape& eos = * subEOS[ iS ]; + if ( eos.SWOLType() == TopAbs_EDGE ) + { + SMESH_subMesh* edgeSM = _mesh->GetSubMesh( eos._sWOL ); + _Shrinker1D& srinker = e2shrMap[ edgeSM->GetId() ]; + eShri1D.insert( & srinker ); + srinker.AddEdge( eos._edges[0], eos, helper ); + VISCOUS_3D::ToClearSubWithMain( edgeSM, data._solid ); + // restore params of nodes on EGDE if the EDGE has been already + // srinked while srinking other FACE + srinker.RestoreParams(); + } + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + _LayerEdge& edge = * eos._edges[i]; + _Simplex::GetSimplices( /*tgtNode=*/edge._nodes.back(), edge._simplices, ignoreShapes ); + } + } + } + + bool toFixTria = false; // to improve quality of trias by diagonal swap + if ( isConcaveFace ) + { + const bool hasTria = _mesh->NbTriangles(), hasQuad = _mesh->NbQuadrangles(); + if ( hasTria != hasQuad ) { + toFixTria = hasTria; + } + else { + set nbNodesSet; + SMDS_ElemIteratorPtr fIt = smDS->GetElements(); + while ( fIt->more() && nbNodesSet.size() < 2 ) + nbNodesSet.insert( fIt->next()->NbCornerNodes() ); + toFixTria = ( *nbNodesSet.begin() == 3 ); + } + } + + // ================== + // Perform shrinking + // ================== + + bool shrinked = true; + int badNb, shriStep=0, smooStep=0; + _SmoothNode::SmoothType smoothType + = isConcaveFace ? _SmoothNode::ANGULAR : _SmoothNode::LAPLACIAN; + while ( shrinked ) + { + shriStep++; + // Move boundary nodes (actually just set new UV) + // ----------------------------------------------- + dumpFunction(SMESH_Comment("moveBoundaryOnF")<first<<"_st"<SetNewLength2d( surface, F, eos, helper ); + } + } + dumpFunctionEnd(); + + // Move nodes on EDGE's + // (XYZ is set as soon as a needed length reached in SetNewLength2d()) + set< _Shrinker1D* >::iterator shr = eShri1D.begin(); + for ( ; shr != eShri1D.end(); ++shr ) + (*shr)->Compute( /*set3D=*/false, helper ); + + // Smoothing in 2D + // ----------------- + int nbNoImpSteps = 0; + bool moved = true; + badNb = 1; + while (( nbNoImpSteps < 5 && badNb > 0) && moved) + { + dumpFunction(SMESH_Comment("shrinkFace")<first<<"_st"<<++smooStep); // debug + + int oldBadNb = badNb; + badNb = 0; + moved = false; + // '% 5' minimizes NB FUNCTIONS on viscous_layers_00/B2 case + _SmoothNode::SmoothType smooTy = ( smooStep % 5 ) ? smoothType : _SmoothNode::LAPLACIAN; + for ( size_t i = 0; i < nodesToSmooth.size(); ++i ) + { + moved |= nodesToSmooth[i].Smooth( badNb, surface, helper, refSign, + smooTy, /*set3D=*/isConcaveFace); + } + if ( badNb < oldBadNb ) + nbNoImpSteps = 0; + else + nbNoImpSteps++; + + dumpFunctionEnd(); + } + if ( badNb > 0 ) + return error(SMESH_Comment("Can't shrink 2D mesh on face ") << f2sd->first ); + if ( shriStep > 200 ) + return error(SMESH_Comment("Infinite loop at shrinking 2D mesh on face ") << f2sd->first ); + + // Fix narrow triangles by swapping diagonals + // --------------------------------------- + if ( toFixTria ) + { + set usedNodes; + fixBadFaces( F, helper, /*is2D=*/true, shriStep, & usedNodes); // swap diagonals + + // update working data + set::iterator n; + for ( size_t i = 0; i < nodesToSmooth.size() && !usedNodes.empty(); ++i ) + { + n = usedNodes.find( nodesToSmooth[ i ]._node ); + if ( n != usedNodes.end()) + { + _Simplex::GetSimplices( nodesToSmooth[ i ]._node, + nodesToSmooth[ i ]._simplices, + ignoreShapes, NULL, + /*sortSimplices=*/ smoothType == _SmoothNode::ANGULAR ); + usedNodes.erase( n ); + } + } + for ( size_t i = 0; i < lEdges.size() && !usedNodes.empty(); ++i ) + { + n = usedNodes.find( /*tgtNode=*/ lEdges[i]->_nodes.back() ); + if ( n != usedNodes.end()) + { + _Simplex::GetSimplices( lEdges[i]->_nodes.back(), + lEdges[i]->_simplices, + ignoreShapes ); + usedNodes.erase( n ); + } + } + } + // TODO: check effect of this additional smooth + // additional laplacian smooth to increase allowed shrink step + // for ( int st = 1; st; --st ) + // { + // dumpFunction(SMESH_Comment("shrinkFace")<first<<"_st"<<++smooStep); // debug + // for ( size_t i = 0; i < nodesToSmooth.size(); ++i ) + // { + // nodesToSmooth[i].Smooth( badNb,surface,helper,refSign, + // _SmoothNode::LAPLACIAN,/*set3D=*/false); + // } + // } + } // while ( shrinked ) + + // No wrongly shaped faces remain; final smooth. Set node XYZ. + bool isStructuredFixed = false; + if ( SMESH_2D_Algo* algo = dynamic_cast( sm->GetAlgo() )) + isStructuredFixed = algo->FixInternalNodes( *data._proxyMesh, F ); + if ( !isStructuredFixed ) + { + if ( isConcaveFace ) // fix narrow faces by swapping diagonals + fixBadFaces( F, helper, /*is2D=*/false, ++shriStep ); + + for ( int st = 3; st; --st ) + { + switch( st ) { + case 1: smoothType = _SmoothNode::LAPLACIAN; break; + case 2: smoothType = _SmoothNode::LAPLACIAN; break; + case 3: smoothType = _SmoothNode::ANGULAR; break; + } + dumpFunction(SMESH_Comment("shrinkFace")<first<<"_st"<<++smooStep); // debug + for ( size_t i = 0; i < nodesToSmooth.size(); ++i ) + { + nodesToSmooth[i].Smooth( badNb,surface,helper,refSign, + smoothType,/*set3D=*/st==1 ); + } + dumpFunctionEnd(); + } + } + // Set an event listener to clear FACE sub-mesh together with SOLID sub-mesh + VISCOUS_3D::ToClearSubWithMain( sm, data._solid ); + + if ( !getMeshDS()->IsEmbeddedMode() ) + // Log node movement + for ( size_t i = 0; i < nodesToSmooth.size(); ++i ) + { + SMESH_TNodeXYZ p ( nodesToSmooth[i]._node ); + getMeshDS()->MoveNode( nodesToSmooth[i]._node, p.X(), p.Y(), p.Z() ); + } + + } // loop on FACES to srink mesh on + + + // Replace source nodes by target nodes in shrinked mesh edges + + map< int, _Shrinker1D >::iterator e2shr = e2shrMap.begin(); + for ( ; e2shr != e2shrMap.end(); ++e2shr ) + e2shr->second.SwapSrcTgtNodes( getMeshDS() ); + + return true; +} + +//================================================================================ +/*! + * \brief Computes 2d shrink direction and finds nodes limiting shrinking + */ +//================================================================================ + +bool _ViscousBuilder::prepareEdgeToShrink( _LayerEdge& edge, + _EdgesOnShape& eos, + SMESH_MesherHelper& helper, + const SMESHDS_SubMesh* faceSubMesh) +{ + const SMDS_MeshNode* srcNode = edge._nodes[0]; + const SMDS_MeshNode* tgtNode = edge._nodes.back(); + + if ( eos.SWOLType() == TopAbs_FACE ) + { + gp_XY srcUV ( edge._pos[0].X(), edge._pos[0].Y() ); //helper.GetNodeUV( F, srcNode ); + gp_XY tgtUV = edge.LastUV( TopoDS::Face( eos._sWOL ), eos ); //helper.GetNodeUV( F, tgtNode ); + gp_Vec2d uvDir( srcUV, tgtUV ); + double uvLen = uvDir.Magnitude(); + uvDir /= uvLen; + edge._normal.SetCoord( uvDir.X(),uvDir.Y(), 0 ); + edge._len = uvLen; + + edge._pos.resize(1); + edge._pos[0].SetCoord( tgtUV.X(), tgtUV.Y(), 0 ); + + // set UV of source node to target node + SMDS_FacePosition* pos = static_cast( tgtNode->GetPosition() ); + pos->SetUParameter( srcUV.X() ); + pos->SetVParameter( srcUV.Y() ); + } + else // _sWOL is TopAbs_EDGE + { + const TopoDS_Edge& E = TopoDS::Edge( eos._sWOL ); + SMESHDS_SubMesh* edgeSM = getMeshDS()->MeshElements( E ); + if ( !edgeSM || edgeSM->NbElements() == 0 ) + return error(SMESH_Comment("Not meshed EDGE ") << getMeshDS()->ShapeToIndex( E )); + + const SMDS_MeshNode* n2 = 0; + SMDS_ElemIteratorPtr eIt = srcNode->GetInverseElementIterator(SMDSAbs_Edge); + while ( eIt->more() && !n2 ) + { + const SMDS_MeshElement* e = eIt->next(); + if ( !edgeSM->Contains(e)) continue; + n2 = e->GetNode( 0 ); + if ( n2 == srcNode ) n2 = e->GetNode( 1 ); + } + if ( !n2 ) + return error(SMESH_Comment("Wrongly meshed EDGE ") << getMeshDS()->ShapeToIndex( E )); + + double uSrc = helper.GetNodeU( E, srcNode, n2 ); + double uTgt = helper.GetNodeU( E, tgtNode, srcNode ); + double u2 = helper.GetNodeU( E, n2, srcNode ); + + edge._pos.clear(); + + if ( fabs( uSrc-uTgt ) < 0.99 * fabs( uSrc-u2 )) + { + // tgtNode is located so that it does not make faces with wrong orientation + return true; + } + edge._pos.resize(1); + edge._pos[0].SetCoord( U_TGT, uTgt ); + edge._pos[0].SetCoord( U_SRC, uSrc ); + edge._pos[0].SetCoord( LEN_TGT, fabs( uSrc-uTgt )); + + edge._simplices.resize( 1 ); + edge._simplices[0]._nPrev = n2; + + // set U of source node to the target node + SMDS_EdgePosition* pos = static_cast( tgtNode->GetPosition() ); + pos->SetUParameter( uSrc ); + } + return true; +} + +//================================================================================ +/*! + * \brief Restore position of a sole node of a _LayerEdge based on _noShrinkShapes + */ +//================================================================================ + +void _ViscousBuilder::restoreNoShrink( _LayerEdge& edge ) const +{ + if ( edge._nodes.size() == 1 ) + { + edge._pos.clear(); + edge._len = 0; + + const SMDS_MeshNode* srcNode = edge._nodes[0]; + TopoDS_Shape S = SMESH_MesherHelper::GetSubShapeByNode( srcNode, getMeshDS() ); + if ( S.IsNull() ) return; + + gp_Pnt p; + + switch ( S.ShapeType() ) + { + case TopAbs_EDGE: + { + double f,l; + TopLoc_Location loc; + Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge( S ), loc, f, l ); + if ( curve.IsNull() ) return; + SMDS_EdgePosition* ePos = static_cast( srcNode->GetPosition() ); + p = curve->Value( ePos->GetUParameter() ); + break; + } + case TopAbs_VERTEX: + { + p = BRep_Tool::Pnt( TopoDS::Vertex( S )); + break; + } + default: return; + } + getMeshDS()->MoveNode( srcNode, p.X(), p.Y(), p.Z() ); + dumpMove( srcNode ); + } +} + +//================================================================================ +/*! + * \brief Try to fix triangles with high aspect ratio by swaping diagonals + */ +//================================================================================ + +void _ViscousBuilder::fixBadFaces(const TopoDS_Face& F, + SMESH_MesherHelper& helper, + const bool is2D, + const int step, + set * involvedNodes) +{ + SMESH::Controls::AspectRatio qualifier; + SMESH::Controls::TSequenceOfXYZ points(3), points1(3), points2(3); + const double maxAspectRatio = is2D ? 4. : 2; + _NodeCoordHelper xyz( F, helper, is2D ); + + // find bad triangles + + vector< const SMDS_MeshElement* > badTrias; + vector< double > badAspects; + SMESHDS_SubMesh* sm = helper.GetMeshDS()->MeshElements( F ); + SMDS_ElemIteratorPtr fIt = sm->GetElements(); + while ( fIt->more() ) + { + const SMDS_MeshElement * f = fIt->next(); + if ( f->NbCornerNodes() != 3 ) continue; + for ( int iP = 0; iP < 3; ++iP ) points(iP+1) = xyz( f->GetNode(iP)); + double aspect = qualifier.GetValue( points ); + if ( aspect > maxAspectRatio ) + { + badTrias.push_back( f ); + badAspects.push_back( aspect ); + } + } + if ( step == 1 ) + { + dumpFunction(SMESH_Comment("beforeSwapDiagonals_F")<GetElements(); + while ( fIt->more() ) + { + const SMDS_MeshElement * f = fIt->next(); + if ( f->NbCornerNodes() == 3 ) + dumpChangeNodes( f ); + } + dumpFunctionEnd(); + } + if ( badTrias.empty() ) + return; + + // find couples of faces to swap diagonal + + typedef pair < const SMDS_MeshElement* , const SMDS_MeshElement* > T2Trias; + vector< T2Trias > triaCouples; + + TIDSortedElemSet involvedFaces, emptySet; + for ( size_t iTia = 0; iTia < badTrias.size(); ++iTia ) + { + T2Trias trias [3]; + double aspRatio [3]; + int i1, i2, i3; + + if ( !involvedFaces.insert( badTrias[iTia] ).second ) + continue; + for ( int iP = 0; iP < 3; ++iP ) + points(iP+1) = xyz( badTrias[iTia]->GetNode(iP)); + + // find triangles adjacent to badTrias[iTia] with better aspect ratio after diag-swaping + int bestCouple = -1; + for ( int iSide = 0; iSide < 3; ++iSide ) + { + const SMDS_MeshNode* n1 = badTrias[iTia]->GetNode( iSide ); + const SMDS_MeshNode* n2 = badTrias[iTia]->GetNode(( iSide+1 ) % 3 ); + trias [iSide].first = badTrias[iTia]; + trias [iSide].second = SMESH_MeshAlgos::FindFaceInSet( n1, n2, emptySet, involvedFaces, + & i1, & i2 ); + if (( ! trias[iSide].second ) || + ( trias[iSide].second->NbCornerNodes() != 3 ) || + ( ! sm->Contains( trias[iSide].second ))) + continue; + + // aspect ratio of an adjacent tria + for ( int iP = 0; iP < 3; ++iP ) + points2(iP+1) = xyz( trias[iSide].second->GetNode(iP)); + double aspectInit = qualifier.GetValue( points2 ); + + // arrange nodes as after diag-swaping + if ( helper.WrapIndex( i1+1, 3 ) == i2 ) + i3 = helper.WrapIndex( i1-1, 3 ); + else + i3 = helper.WrapIndex( i1+1, 3 ); + points1 = points; + points1( 1+ iSide ) = points2( 1+ i3 ); + points2( 1+ i2 ) = points1( 1+ ( iSide+2 ) % 3 ); + + // aspect ratio after diag-swaping + aspRatio[ iSide ] = qualifier.GetValue( points1 ) + qualifier.GetValue( points2 ); + if ( aspRatio[ iSide ] > aspectInit + badAspects[ iTia ] ) + continue; + + // prevent inversion of a triangle + gp_Vec norm1 = gp_Vec( points1(1), points1(3) ) ^ gp_Vec( points1(1), points1(2) ); + gp_Vec norm2 = gp_Vec( points2(1), points2(3) ) ^ gp_Vec( points2(1), points2(2) ); + if ( norm1 * norm2 < 0. && norm1.Angle( norm2 ) > 70./180.*M_PI ) + continue; + + if ( bestCouple < 0 || aspRatio[ bestCouple ] > aspRatio[ iSide ] ) + bestCouple = iSide; + } + + if ( bestCouple >= 0 ) + { + triaCouples.push_back( trias[bestCouple] ); + involvedFaces.insert ( trias[bestCouple].second ); + } + else + { + involvedFaces.erase( badTrias[iTia] ); + } + } + if ( triaCouples.empty() ) + return; + + // swap diagonals + + SMESH_MeshEditor editor( helper.GetMesh() ); + dumpFunction(SMESH_Comment("beforeSwapDiagonals_F")<insert( triaCouples[i].first->begin_nodes(), + triaCouples[i].first->end_nodes() ); + involvedNodes->insert( triaCouples[i].second->begin_nodes(), + triaCouples[i].second->end_nodes() ); + } + + // just for debug dump resulting triangles + dumpFunction(SMESH_Comment("swapDiagonals_F")<( _nodes.back() ); + + if ( eos.SWOLType() == TopAbs_FACE ) + { + gp_XY curUV = helper.GetNodeUV( F, tgtNode ); + gp_Pnt2d tgtUV( _pos[0].X(), _pos[0].Y() ); + gp_Vec2d uvDir( _normal.X(), _normal.Y() ); + const double uvLen = tgtUV.Distance( curUV ); + const double kSafe = Max( 0.5, 1. - 0.1 * _simplices.size() ); + + // Select shrinking step such that not to make faces with wrong orientation. + double stepSize = 1e100; + for ( size_t i = 0; i < _simplices.size(); ++i ) + { + // find intersection of 2 lines: curUV-tgtUV and that connecting simplex nodes + gp_XY uvN1 = helper.GetNodeUV( F, _simplices[i]._nPrev ); + gp_XY uvN2 = helper.GetNodeUV( F, _simplices[i]._nNext ); + gp_XY dirN = uvN2 - uvN1; + double det = uvDir.Crossed( dirN ); + if ( Abs( det ) < std::numeric_limits::min() ) continue; + gp_XY dirN2Cur = curUV - uvN1; + double step = dirN.Crossed( dirN2Cur ) / det; + if ( step > 0 ) + stepSize = Min( step, stepSize ); + } + gp_Pnt2d newUV; + if ( uvLen <= stepSize ) + { + newUV = tgtUV; + _pos.clear(); + } + else if ( stepSize > 0 ) + { + newUV = curUV + uvDir.XY() * stepSize * kSafe; + } + else + { + return true; + } + SMDS_FacePosition* pos = static_cast( tgtNode->GetPosition() ); + pos->SetUParameter( newUV.X() ); + pos->SetVParameter( newUV.Y() ); + +#ifdef __myDEBUG + gp_Pnt p = surface->Value( newUV.X(), newUV.Y() ); + tgtNode->setXYZ( p.X(), p.Y(), p.Z() ); + dumpMove( tgtNode ); +#endif + } + else // _sWOL is TopAbs_EDGE + { + const TopoDS_Edge& E = TopoDS::Edge( eos._sWOL ); + const SMDS_MeshNode* n2 = _simplices[0]._nPrev; + SMDS_EdgePosition* tgtPos = static_cast( tgtNode->GetPosition() ); + + const double u2 = helper.GetNodeU( E, n2, tgtNode ); + const double uSrc = _pos[0].Coord( U_SRC ); + const double lenTgt = _pos[0].Coord( LEN_TGT ); + + double newU = _pos[0].Coord( U_TGT ); + if ( lenTgt < 0.99 * fabs( uSrc-u2 )) // n2 got out of src-tgt range + { + _pos.clear(); + } + else + { + newU = 0.1 * tgtPos->GetUParameter() + 0.9 * u2; + } + tgtPos->SetUParameter( newU ); +#ifdef __myDEBUG + gp_XY newUV = helper.GetNodeUV( F, tgtNode, _nodes[0]); + gp_Pnt p = surface->Value( newUV.X(), newUV.Y() ); + tgtNode->setXYZ( p.X(), p.Y(), p.Z() ); + dumpMove( tgtNode ); +#endif + } + return true; +} + +//================================================================================ +/*! + * \brief Perform smooth on the FACE + * \retval bool - true if the node has been moved + */ +//================================================================================ + +bool _SmoothNode::Smooth(int& badNb, + Handle(Geom_Surface)& surface, + SMESH_MesherHelper& helper, + const double refSign, + SmoothType how, + bool set3D) +{ + const TopoDS_Face& face = TopoDS::Face( helper.GetSubShape() ); + + // get uv of surrounding nodes + vector uv( _simplices.size() ); + for ( size_t i = 0; i < _simplices.size(); ++i ) + uv[i] = helper.GetNodeUV( face, _simplices[i]._nPrev, _node ); + + // compute new UV for the node + gp_XY newPos (0,0); + if ( how == TFI && _simplices.size() == 4 ) + { + gp_XY corners[4]; + for ( size_t i = 0; i < _simplices.size(); ++i ) + if ( _simplices[i]._nOpp ) + corners[i] = helper.GetNodeUV( face, _simplices[i]._nOpp, _node ); + else + throw SALOME_Exception(LOCALIZED("TFI smoothing: _Simplex::_nOpp not set!")); + + newPos = helper.calcTFI ( 0.5, 0.5, + corners[0], corners[1], corners[2], corners[3], + uv[1], uv[2], uv[3], uv[0] ); + } + else if ( how == ANGULAR ) + { + newPos = computeAngularPos( uv, helper.GetNodeUV( face, _node ), refSign ); + } + else if ( how == CENTROIDAL && _simplices.size() > 3 ) + { + // average centers of diagonals wieghted with their reciprocal lengths + if ( _simplices.size() == 4 ) + { + double w1 = 1. / ( uv[2]-uv[0] ).SquareModulus(); + double w2 = 1. / ( uv[3]-uv[1] ).SquareModulus(); + newPos = ( w1 * ( uv[2]+uv[0] ) + w2 * ( uv[3]+uv[1] )) / ( w1+w2 ) / 2; + } + else + { + double sumWeight = 0; + int nb = _simplices.size() == 4 ? 2 : _simplices.size(); + for ( int i = 0; i < nb; ++i ) + { + int iFrom = i + 2; + int iTo = i + _simplices.size() - 1; + for ( int j = iFrom; j < iTo; ++j ) + { + int i2 = SMESH_MesherHelper::WrapIndex( j, _simplices.size() ); + double w = 1. / ( uv[i]-uv[i2] ).SquareModulus(); + sumWeight += w; + newPos += w * ( uv[i]+uv[i2] ); + } + } + newPos /= 2 * sumWeight; // 2 is to get a middle between uv's + } + } + else + { + // Laplacian smooth + for ( size_t i = 0; i < _simplices.size(); ++i ) + newPos += uv[i]; + newPos /= _simplices.size(); + } + + // count quality metrics (orientation) of triangles around the node + int nbOkBefore = 0; + gp_XY tgtUV = helper.GetNodeUV( face, _node ); + for ( size_t i = 0; i < _simplices.size(); ++i ) + nbOkBefore += _simplices[i].IsForward( tgtUV, _node, face, helper, refSign ); + + int nbOkAfter = 0; + for ( size_t i = 0; i < _simplices.size(); ++i ) + nbOkAfter += _simplices[i].IsForward( newPos, _node, face, helper, refSign ); + + if ( nbOkAfter < nbOkBefore ) + { + badNb += _simplices.size() - nbOkBefore; + return false; + } + + SMDS_FacePosition* pos = static_cast( _node->GetPosition() ); + pos->SetUParameter( newPos.X() ); + pos->SetVParameter( newPos.Y() ); + +#ifdef __myDEBUG + set3D = true; +#endif + if ( set3D ) + { + gp_Pnt p = surface->Value( newPos.X(), newPos.Y() ); + const_cast< SMDS_MeshNode* >( _node )->setXYZ( p.X(), p.Y(), p.Z() ); + dumpMove( _node ); + } + + badNb += _simplices.size() - nbOkAfter; + return ( (tgtUV-newPos).SquareModulus() > 1e-10 ); +} + +//================================================================================ +/*! + * \brief Computes new UV using angle based smoothing technic + */ +//================================================================================ + +gp_XY _SmoothNode::computeAngularPos(vector& uv, + const gp_XY& uvToFix, + const double refSign) +{ + uv.push_back( uv.front() ); + + vector< gp_XY > edgeDir ( uv.size() ); + vector< double > edgeSize( uv.size() ); + for ( size_t i = 1; i < edgeDir.size(); ++i ) + { + edgeDir [i-1] = uv[i] - uv[i-1]; + edgeSize[i-1] = edgeDir[i-1].Modulus(); + if ( edgeSize[i-1] < numeric_limits::min() ) + edgeDir[i-1].SetX( 100 ); + else + edgeDir[i-1] /= edgeSize[i-1] * refSign; + } + edgeDir.back() = edgeDir.front(); + edgeSize.back() = edgeSize.front(); + + gp_XY newPos(0,0); + //int nbEdges = 0; + double sumSize = 0; + for ( size_t i = 1; i < edgeDir.size(); ++i ) + { + if ( edgeDir[i-1].X() > 1. ) continue; + int i1 = i-1; + while ( edgeDir[i].X() > 1. && ++i < edgeDir.size() ); + if ( i == edgeDir.size() ) break; + gp_XY p = uv[i]; + gp_XY norm1( -edgeDir[i1].Y(), edgeDir[i1].X() ); + gp_XY norm2( -edgeDir[i].Y(), edgeDir[i].X() ); + gp_XY bisec = norm1 + norm2; + double bisecSize = bisec.Modulus(); + if ( bisecSize < numeric_limits::min() ) + { + bisec = -edgeDir[i1] + edgeDir[i]; + bisecSize = bisec.Modulus(); + } + bisec /= bisecSize; + + gp_XY dirToN = uvToFix - p; + double distToN = dirToN.Modulus(); + if ( bisec * dirToN < 0 ) + distToN = -distToN; + + newPos += ( p + bisec * distToN ) * ( edgeSize[i1] + edgeSize[i] ); + //++nbEdges; + sumSize += edgeSize[i1] + edgeSize[i]; + } + newPos /= /*nbEdges * */sumSize; + return newPos; +} + +//================================================================================ +/*! + * \brief Delete _SolidData + */ +//================================================================================ + +_SolidData::~_SolidData() +{ + TNode2Edge::iterator n2e = _n2eMap.begin(); + for ( ; n2e != _n2eMap.end(); ++n2e ) + { + _LayerEdge* & e = n2e->second; + if ( e && e->_2neibors ) + delete e->_2neibors; + delete e; + e = NULL; + } + _n2eMap.clear(); +} +//================================================================================ +/*! + * \brief Keep a _LayerEdge inflated along the EDGE + */ +//================================================================================ + +void _Shrinker1D::AddEdge( const _LayerEdge* e, + _EdgesOnShape& eos, + SMESH_MesherHelper& helper ) +{ + // init + if ( _nodes.empty() ) + { + _edges[0] = _edges[1] = 0; + _done = false; + } + // check _LayerEdge + if ( e == _edges[0] || e == _edges[1] ) + return; + if ( eos.SWOLType() != TopAbs_EDGE ) + throw SALOME_Exception(LOCALIZED("Wrong _LayerEdge is added")); + if ( _edges[0] && !_geomEdge.IsSame( eos._sWOL )) + throw SALOME_Exception(LOCALIZED("Wrong _LayerEdge is added")); + + // store _LayerEdge + _geomEdge = TopoDS::Edge( eos._sWOL ); + double f,l; + BRep_Tool::Range( _geomEdge, f,l ); + double u = helper.GetNodeU( _geomEdge, e->_nodes[0], e->_nodes.back()); + _edges[ u < 0.5*(f+l) ? 0 : 1 ] = e; + + // Update _nodes + + const SMDS_MeshNode* tgtNode0 = _edges[0] ? _edges[0]->_nodes.back() : 0; + const SMDS_MeshNode* tgtNode1 = _edges[1] ? _edges[1]->_nodes.back() : 0; + + if ( _nodes.empty() ) + { + SMESHDS_SubMesh * eSubMesh = helper.GetMeshDS()->MeshElements( _geomEdge ); + if ( !eSubMesh || eSubMesh->NbNodes() < 1 ) + return; + TopLoc_Location loc; + Handle(Geom_Curve) C = BRep_Tool::Curve( _geomEdge, loc, f,l ); + GeomAdaptor_Curve aCurve(C, f,l); + const double totLen = GCPnts_AbscissaPoint::Length(aCurve, f, l); + + int nbExpectNodes = eSubMesh->NbNodes(); + _initU .reserve( nbExpectNodes ); + _normPar.reserve( nbExpectNodes ); + _nodes .reserve( nbExpectNodes ); + SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes(); + while ( nIt->more() ) + { + const SMDS_MeshNode* node = nIt->next(); + if ( node->NbInverseElements(SMDSAbs_Edge) == 0 || + node == tgtNode0 || node == tgtNode1 ) + continue; // refinement nodes + _nodes.push_back( node ); + _initU.push_back( helper.GetNodeU( _geomEdge, node )); + double len = GCPnts_AbscissaPoint::Length(aCurve, f, _initU.back()); + _normPar.push_back( len / totLen ); + } + } + else + { + // remove target node of the _LayerEdge from _nodes + int nbFound = 0; + for ( size_t i = 0; i < _nodes.size(); ++i ) + if ( !_nodes[i] || _nodes[i] == tgtNode0 || _nodes[i] == tgtNode1 ) + _nodes[i] = 0, nbFound++; + if ( nbFound == _nodes.size() ) + _nodes.clear(); + } +} + +//================================================================================ +/*! + * \brief Move nodes on EDGE from ends where _LayerEdge's are inflated + */ +//================================================================================ + +void _Shrinker1D::Compute(bool set3D, SMESH_MesherHelper& helper) +{ + if ( _done || _nodes.empty()) + return; + const _LayerEdge* e = _edges[0]; + if ( !e ) e = _edges[1]; + if ( !e ) return; + + _done = (( !_edges[0] || _edges[0]->_pos.empty() ) && + ( !_edges[1] || _edges[1]->_pos.empty() )); + + double f,l; + if ( set3D || _done ) + { + Handle(Geom_Curve) C = BRep_Tool::Curve(_geomEdge, f,l); + GeomAdaptor_Curve aCurve(C, f,l); + + if ( _edges[0] ) + f = helper.GetNodeU( _geomEdge, _edges[0]->_nodes.back(), _nodes[0] ); + if ( _edges[1] ) + l = helper.GetNodeU( _geomEdge, _edges[1]->_nodes.back(), _nodes.back() ); + double totLen = GCPnts_AbscissaPoint::Length( aCurve, f, l ); + + for ( size_t i = 0; i < _nodes.size(); ++i ) + { + if ( !_nodes[i] ) continue; + double len = totLen * _normPar[i]; + GCPnts_AbscissaPoint discret( aCurve, len, f ); + if ( !discret.IsDone() ) + return throw SALOME_Exception(LOCALIZED("GCPnts_AbscissaPoint failed")); + double u = discret.Parameter(); + SMDS_EdgePosition* pos = static_cast( _nodes[i]->GetPosition() ); + pos->SetUParameter( u ); + gp_Pnt p = C->Value( u ); + const_cast< SMDS_MeshNode*>( _nodes[i] )->setXYZ( p.X(), p.Y(), p.Z() ); + } + } + else + { + BRep_Tool::Range( _geomEdge, f,l ); + if ( _edges[0] ) + f = helper.GetNodeU( _geomEdge, _edges[0]->_nodes.back(), _nodes[0] ); + if ( _edges[1] ) + l = helper.GetNodeU( _geomEdge, _edges[1]->_nodes.back(), _nodes.back() ); + + for ( size_t i = 0; i < _nodes.size(); ++i ) + { + if ( !_nodes[i] ) continue; + double u = f * ( 1-_normPar[i] ) + l * _normPar[i]; + SMDS_EdgePosition* pos = static_cast( _nodes[i]->GetPosition() ); + pos->SetUParameter( u ); + } + } +} + +//================================================================================ +/*! + * \brief Restore initial parameters of nodes on EDGE + */ +//================================================================================ + +void _Shrinker1D::RestoreParams() +{ + if ( _done ) + for ( size_t i = 0; i < _nodes.size(); ++i ) + { + if ( !_nodes[i] ) continue; + SMDS_EdgePosition* pos = static_cast( _nodes[i]->GetPosition() ); + pos->SetUParameter( _initU[i] ); + } + _done = false; +} + +//================================================================================ +/*! + * \brief Replace source nodes by target nodes in shrinked mesh edges + */ +//================================================================================ + +void _Shrinker1D::SwapSrcTgtNodes( SMESHDS_Mesh* mesh ) +{ + const SMDS_MeshNode* nodes[3]; + for ( int i = 0; i < 2; ++i ) + { + if ( !_edges[i] ) continue; + + SMESHDS_SubMesh * eSubMesh = mesh->MeshElements( _geomEdge ); + if ( !eSubMesh ) return; + const SMDS_MeshNode* srcNode = _edges[i]->_nodes[0]; + const SMDS_MeshNode* tgtNode = _edges[i]->_nodes.back(); + SMDS_ElemIteratorPtr eIt = srcNode->GetInverseElementIterator(SMDSAbs_Edge); + while ( eIt->more() ) + { + const SMDS_MeshElement* e = eIt->next(); + if ( !eSubMesh->Contains( e )) + continue; + SMDS_ElemIteratorPtr nIt = e->nodesIterator(); + for ( int iN = 0; iN < e->NbNodes(); ++iN ) + { + const SMDS_MeshNode* n = static_cast( nIt->next() ); + nodes[iN] = ( n == srcNode ? tgtNode : n ); + } + mesh->ChangeElementNodes( e, nodes, e->NbNodes() ); + } + } +} + +//================================================================================ +/*! + * \brief Creates 2D and 1D elements on boundaries of new prisms + */ +//================================================================================ + +bool _ViscousBuilder::addBoundaryElements() +{ + SMESH_MesherHelper helper( *_mesh ); + + vector< const SMDS_MeshNode* > faceNodes; + + for ( size_t i = 0; i < _sdVec.size(); ++i ) + { + _SolidData& data = _sdVec[i]; + TopTools_IndexedMapOfShape geomEdges; + TopExp::MapShapes( data._solid, TopAbs_EDGE, geomEdges ); + for ( int iE = 1; iE <= geomEdges.Extent(); ++iE ) + { + const TopoDS_Edge& E = TopoDS::Edge( geomEdges(iE)); + if ( data._noShrinkShapes.count( getMeshDS()->ShapeToIndex( E ))) + continue; + + // Get _LayerEdge's based on E + + map< double, const SMDS_MeshNode* > u2nodes; + if ( !SMESH_Algo::GetSortedNodesOnEdge( getMeshDS(), E, /*ignoreMedium=*/false, u2nodes)) + continue; + + vector< _LayerEdge* > ledges; ledges.reserve( u2nodes.size() ); + TNode2Edge & n2eMap = data._n2eMap; + map< double, const SMDS_MeshNode* >::iterator u2n = u2nodes.begin(); + { + //check if 2D elements are needed on E + TNode2Edge::iterator n2e = n2eMap.find( u2n->second ); + if ( n2e == n2eMap.end() ) continue; // no layers on vertex + ledges.push_back( n2e->second ); + u2n++; + if (( n2e = n2eMap.find( u2n->second )) == n2eMap.end() ) + continue; // no layers on E + ledges.push_back( n2eMap[ u2n->second ]); + + const SMDS_MeshNode* tgtN0 = ledges[0]->_nodes.back(); + const SMDS_MeshNode* tgtN1 = ledges[1]->_nodes.back(); + int nbSharedPyram = 0; + SMDS_ElemIteratorPtr vIt = tgtN0->GetInverseElementIterator(SMDSAbs_Volume); + while ( vIt->more() ) + { + const SMDS_MeshElement* v = vIt->next(); + nbSharedPyram += int( v->GetNodeIndex( tgtN1 ) >= 0 ); + } + if ( nbSharedPyram > 1 ) + continue; // not free border of the pyramid + + faceNodes.clear(); + faceNodes.push_back( ledges[0]->_nodes[0] ); + faceNodes.push_back( ledges[1]->_nodes[0] ); + if ( ledges[0]->_nodes.size() > 1 ) faceNodes.push_back( ledges[0]->_nodes[1] ); + if ( ledges[1]->_nodes.size() > 1 ) faceNodes.push_back( ledges[1]->_nodes[1] ); + + if ( getMeshDS()->FindElement( faceNodes, SMDSAbs_Face, /*noMedium=*/true)) + continue; // faces already created + } + for ( ++u2n; u2n != u2nodes.end(); ++u2n ) + ledges.push_back( n2eMap[ u2n->second ]); + + // Find out orientation and type of face to create + + bool reverse = false, isOnFace; + + map< TGeomID, TopoDS_Shape >::iterator e2f = + data._shrinkShape2Shape.find( getMeshDS()->ShapeToIndex( E )); + TopoDS_Shape F; + if (( isOnFace = ( e2f != data._shrinkShape2Shape.end() ))) + { + F = e2f->second.Oriented( TopAbs_FORWARD ); + reverse = ( helper.GetSubShapeOri( F, E ) == TopAbs_REVERSED ); + if ( helper.GetSubShapeOri( data._solid, F ) == TopAbs_REVERSED ) + reverse = !reverse, F.Reverse(); + if ( helper.IsReversedSubMesh( TopoDS::Face(F) )) + reverse = !reverse; + } + else + { + // find FACE with layers sharing E + PShapeIteratorPtr fIt = helper.GetAncestors( E, *_mesh, TopAbs_FACE ); + while ( fIt->more() && F.IsNull() ) + { + const TopoDS_Shape* pF = fIt->next(); + if ( helper.IsSubShape( *pF, data._solid) && + !data._ignoreFaceIds.count( e2f->first )) + F = *pF; + } + } + // Find the sub-mesh to add new faces + SMESHDS_SubMesh* sm = 0; + if ( isOnFace ) + sm = getMeshDS()->MeshElements( F ); + else + sm = data._proxyMesh->getFaceSubM( TopoDS::Face(F), /*create=*/true ); + if ( !sm ) + return error("error in addBoundaryElements()", data._index); + + // Make faces + const int dj1 = reverse ? 0 : 1; + const int dj2 = reverse ? 1 : 0; + for ( size_t j = 1; j < ledges.size(); ++j ) + { + vector< const SMDS_MeshNode*>& nn1 = ledges[j-dj1]->_nodes; + vector< const SMDS_MeshNode*>& nn2 = ledges[j-dj2]->_nodes; + if ( nn1.size() == nn2.size() ) + { + if ( isOnFace ) + for ( size_t z = 1; z < nn1.size(); ++z ) + sm->AddElement( getMeshDS()->AddFace( nn1[z-1], nn2[z-1], nn2[z], nn1[z] )); + else + for ( size_t z = 1; z < nn1.size(); ++z ) + sm->AddElement( new SMDS_FaceOfNodes( nn1[z-1], nn2[z-1], nn2[z], nn1[z] )); + } + else if ( nn1.size() == 1 ) + { + if ( isOnFace ) + for ( size_t z = 1; z < nn2.size(); ++z ) + sm->AddElement( getMeshDS()->AddFace( nn1[0], nn2[z-1], nn2[z] )); + else + for ( size_t z = 1; z < nn2.size(); ++z ) + sm->AddElement( new SMDS_FaceOfNodes( nn1[0], nn2[z-1], nn2[z] )); + } + else + { + if ( isOnFace ) + for ( size_t z = 1; z < nn1.size(); ++z ) + sm->AddElement( getMeshDS()->AddFace( nn1[z-1], nn2[0], nn1[z] )); + else + for ( size_t z = 1; z < nn1.size(); ++z ) + sm->AddElement( new SMDS_FaceOfNodes( nn1[z-1], nn2[0], nn2[z] )); + } + } + + // Make edges + for ( int isFirst = 0; isFirst < 2; ++isFirst ) + { + _LayerEdge* edge = isFirst ? ledges.front() : ledges.back(); + _EdgesOnShape* eos = data.GetShapeEdges( edge ); + if ( eos && eos->SWOLType() == TopAbs_EDGE ) + { + vector< const SMDS_MeshNode*>& nn = edge->_nodes; + if ( nn.size() < 2 || nn[1]->GetInverseElementIterator( SMDSAbs_Edge )->more() ) + continue; + helper.SetSubShape( eos->_sWOL ); + helper.SetElementsOnShape( true ); + for ( size_t z = 1; z < nn.size(); ++z ) + helper.AddEdge( nn[z-1], nn[z] ); + } + } + + } // loop on EDGE's + } // loop on _SolidData's + + return true; +} diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ViscousLayers2D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ViscousLayers2D.cpp new file mode 100644 index 000000000000..3c1841e7b20d --- /dev/null +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ViscousLayers2D.cpp @@ -0,0 +1,2775 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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, or (at your option) any later version. +// +// 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_ViscousLayers2D.cxx +// Created : 23 Jul 2012 +// Author : Edward AGAPOV (eap) + +#include "StdMeshers_ViscousLayers2D.hxx" + +#include "SMDS_EdgePosition.hxx" +#include "SMDS_FaceOfNodes.hxx" +#include "SMDS_FacePosition.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMDS_SetIterator.hxx" +#include "SMESHDS_Group.hxx" +#include "SMESHDS_Hypothesis.hxx" +#include "SMESH_Algo.hxx" +#include "SMESH_ComputeError.hxx" +#include "SMESH_ControlsDef.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_Group.hxx" +#include "SMESH_HypoFilter.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_ProxyMesh.hxx" +#include "SMESH_Quadtree.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_subMeshEventListener.hxx" +#include "StdMeshers_FaceSide.hxx" + +#include "utilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef _DEBUG_ +//#define __myDEBUG +#endif + +using namespace std; + +//================================================================================ +namespace VISCOUS_2D +{ + typedef int TGeomID; + + //-------------------------------------------------------------------------------- + /*! + * \brief Proxy Mesh of FACE with viscous layers. It's needed only to + * redefine newSubmesh(). + */ + struct _ProxyMeshOfFace : public SMESH_ProxyMesh + { + //--------------------------------------------------- + // Proxy sub-mesh of an EDGE. It contains nodes in _uvPtStructVec. + struct _EdgeSubMesh : public SMESH_ProxyMesh::SubMesh + { + _EdgeSubMesh(int index=0): SubMesh(index) {} + //virtual int NbElements() const { return _elements.size()+1; } + virtual int NbNodes() const { return Max( 0, _uvPtStructVec.size()-2 ); } + void SetUVPtStructVec(UVPtStructVec& vec) { _uvPtStructVec.swap( vec ); } + }; + _ProxyMeshOfFace(const SMESH_Mesh& mesh): SMESH_ProxyMesh(mesh) {} + _EdgeSubMesh* GetEdgeSubMesh(int ID) { return (_EdgeSubMesh*) getProxySubMesh(ID); } + virtual SubMesh* newSubmesh(int index=0) const { return new _EdgeSubMesh(index); } + }; + //-------------------------------------------------------------------------------- + /*! + * \brief SMESH_subMeshEventListener used to store _ProxyMeshOfFace, computed + * by _ViscousBuilder2D, in a SMESH_subMesh of the FACE. + * This is to delete _ProxyMeshOfFace when StdMeshers_ViscousLayers2D + * hypothesis is modified + */ + struct _ProxyMeshHolder : public SMESH_subMeshEventListener + { + _ProxyMeshHolder( const TopoDS_Face& face, + SMESH_ProxyMesh::Ptr& mesh) + : SMESH_subMeshEventListener( /*deletable=*/true, Name() ) + { + SMESH_subMesh* faceSM = mesh->GetMesh()->GetSubMesh( face ); + faceSM->SetEventListener( this, new _Data( mesh ), faceSM ); + } + // Finds a proxy mesh of face + static SMESH_ProxyMesh::Ptr FindProxyMeshOfFace( const TopoDS_Shape& face, + SMESH_Mesh& mesh ) + { + SMESH_ProxyMesh::Ptr proxy; + SMESH_subMesh* faceSM = mesh.GetSubMesh( face ); + if ( EventListenerData* ld = faceSM->GetEventListenerData( Name() )) + proxy = static_cast< _Data* >( ld )->_mesh; + return proxy; + } + // Treat events + void ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* subMesh, + EventListenerData* data, + const SMESH_Hypothesis* /*hyp*/) + { + if ( event == SMESH_subMesh::CLEAN && eventType == SMESH_subMesh::COMPUTE_EVENT) + ((_Data*) data)->_mesh.reset(); + } + private: + // holder of a proxy mesh + struct _Data : public SMESH_subMeshEventListenerData + { + SMESH_ProxyMesh::Ptr _mesh; + _Data( SMESH_ProxyMesh::Ptr& mesh ) + :SMESH_subMeshEventListenerData( /*isDeletable=*/true), _mesh( mesh ) + {} + }; + // Returns identifier string + static const char* Name() { return "VISCOUS_2D::_ProxyMeshHolder"; } + }; + + struct _PolyLine; + //-------------------------------------------------------------------------------- + /*! + * \brief Segment connecting inner ends of two _LayerEdge's. + */ + struct _Segment + { + const gp_XY* _uv[2]; // poiter to _LayerEdge::_uvIn + int _indexInLine; // position in _PolyLine + + _Segment() {} + _Segment(const gp_XY& p1, const gp_XY& p2):_indexInLine(-1) { _uv[0] = &p1; _uv[1] = &p2; } + const gp_XY& p1() const { return *_uv[0]; } + const gp_XY& p2() const { return *_uv[1]; } + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Tree of _Segment's used for a faster search of _Segment's. + */ + struct _SegmentTree : public SMESH_Quadtree + { + typedef boost::shared_ptr< _SegmentTree > Ptr; + + _SegmentTree( const vector< _Segment >& segments ); + void GetSegmentsNear( const _Segment& seg, vector< const _Segment* >& found ); + void GetSegmentsNear( const gp_Ax2d& ray, vector< const _Segment* >& found ); + protected: + _SegmentTree() {} + _SegmentTree* newChild() const { return new _SegmentTree; } + void buildChildrenData(); + Bnd_B2d* buildRootBox(); + private: + static int maxNbSegInLeaf() { return 5; } + struct _SegBox + { + const _Segment* _seg; + bool _iMin[2]; + void Set( const _Segment& seg ) + { + _seg = &seg; + _iMin[0] = ( seg._uv[1]->X() < seg._uv[0]->X() ); + _iMin[1] = ( seg._uv[1]->Y() < seg._uv[0]->Y() ); + } + bool IsOut( const _Segment& seg ) const; + bool IsOut( const gp_Ax2d& ray ) const; + }; + vector< _SegBox > _segments; + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Edge normal to FACE boundary, connecting a point on EDGE (_uvOut) + * and a point of a layer internal boundary (_uvIn) + */ + struct _LayerEdge + { + gp_XY _uvOut; // UV on the FACE boundary + gp_XY _uvIn; // UV inside the FACE + double _length2D; // distance between _uvOut and _uvIn + + bool _isBlocked;// is more inflation possible or not + + gp_XY _normal2D; // to curve + double _len2dTo3dRatio; // to pass 2D <--> 3D + gp_Ax2d _ray; // a ray starting at _uvOut + + vector _uvRefined; // divisions by layers + + bool SetNewLength( const double length ); + +#ifdef _DEBUG_ + int _ID; +#endif + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Poly line composed of _Segment's of one EDGE. + * It's used to detect intersection of inflated layers by intersecting + * _Segment's in 2D. + */ + struct _PolyLine + { + StdMeshers_FaceSide* _wire; + int _edgeInd; // index of my EDGE in _wire + bool _advancable; // true if there is a viscous layer on my EDGE + bool _isStraight2D;// pcurve type + _PolyLine* _leftLine; // lines of neighbour EDGE's + _PolyLine* _rightLine; + int _firstPntInd; // index in vector of _wire + int _lastPntInd; + int _index; // index in _ViscousBuilder2D::_polyLineVec + + vector< _LayerEdge > _lEdges; /* _lEdges[0] is usually is not treated + as it is equal to the last one of the _leftLine */ + vector< _Segment > _segments; // segments connecting _uvIn's of _lEdges + _SegmentTree::Ptr _segTree; + + vector< _PolyLine* > _reachableLines; // lines able to interfere with my layer + + vector< const SMDS_MeshNode* > _leftNodes; // nodes built from a left VERTEX + vector< const SMDS_MeshNode* > _rightNodes; // nodes built from a right VERTEX + + typedef vector< _Segment >::iterator TSegIterator; + typedef vector< _LayerEdge >::iterator TEdgeIterator; + + TIDSortedElemSet _newFaces; // faces generated from this line + + bool IsCommonEdgeShared( const _PolyLine& other ); + size_t FirstLEdge() const + { + return ( _leftLine->_advancable && _lEdges.size() > 2 ) ? 1 : 0; + } + bool IsAdjacent( const _Segment& seg, const _LayerEdge* LE=0 ) const + { + if ( LE /*&& seg._indexInLine < _lEdges.size()*/ ) + return ( seg._uv[0] == & LE->_uvIn || + seg._uv[1] == & LE->_uvIn ); + return ( & seg == &_leftLine->_segments.back() || + & seg == &_rightLine->_segments[0] ); + } + bool IsConcave() const; + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Intersector of _Segment's + */ + struct _SegmentIntersection + { + gp_XY _vec1, _vec2; // Vec( _seg.p1(), _seg.p2() ) + gp_XY _vec21; // Vec( _seg2.p1(), _seg1.p1() ) + double _D; // _vec1.Crossed( _vec2 ) + double _param1, _param2; // intersection param on _seg1 and _seg2 + + bool Compute(const _Segment& seg1, const _Segment& seg2, bool seg2IsRay = false ) + { + // !!! If seg2IsRay, returns true at any _param2 !!! + const double eps = 1e-10; + _vec1 = seg1.p2() - seg1.p1(); + _vec2 = seg2.p2() - seg2.p1(); + _vec21 = seg1.p1() - seg2.p1(); + _D = _vec1.Crossed(_vec2); + if ( fabs(_D) < std::numeric_limits::min()) + return false; + _param1 = _vec2.Crossed(_vec21) / _D; + if (_param1 < -eps || _param1 > 1 + eps ) + return false; + _param2 = _vec1.Crossed(_vec21) / _D; + return seg2IsRay || ( _param2 > -eps && _param2 < 1 + eps ); + } + bool Compute( const _Segment& seg1, const gp_Ax2d& ray ) + { + gp_XY segEnd = ray.Location().XY() + ray.Direction().XY(); + _Segment seg2( ray.Location().XY(), segEnd ); + return Compute( seg1, seg2, true ); + } + //gp_XY GetPoint() { return _seg1.p1() + _param1 * _vec1; } + }; + //-------------------------------------------------------------------------------- + + typedef map< const SMDS_MeshNode*, _LayerEdge*, TIDCompare > TNode2Edge; + typedef StdMeshers_ViscousLayers2D THypVL; + + //-------------------------------------------------------------------------------- + /*! + * \brief Builder of viscous layers + */ + class _ViscousBuilder2D + { + public: + _ViscousBuilder2D(SMESH_Mesh& theMesh, + const TopoDS_Face& theFace, + vector< const THypVL* > & theHyp, + vector< TopoDS_Shape > & theHypShapes); + SMESH_ComputeErrorPtr GetError() const { return _error; } + // does it's job + SMESH_ProxyMesh::Ptr Compute(); + + private: + + friend class ::StdMeshers_ViscousLayers2D; + + bool findEdgesWithLayers(); + bool makePolyLines(); + bool inflate(); + bool fixCollisions(); + bool refine(); + bool shrink(); + bool improve(); + bool toShrinkForAdjacent( const TopoDS_Face& adjFace, + const TopoDS_Edge& E, + const TopoDS_Vertex& V); + void setLenRatio( _LayerEdge& LE, const gp_Pnt& pOut ); + void setLayerEdgeData( _LayerEdge& lEdge, + const double u, + Handle(Geom2d_Curve)& pcurve, + Handle(Geom_Curve)& curve, + const gp_Pnt pOut, + const bool reverse, + GeomAPI_ProjectPointOnSurf* faceProj); + void adjustCommonEdge( _PolyLine& LL, _PolyLine& LR ); + void calcLayersHeight(const double totalThick, + vector& heights, + const THypVL* hyp); + bool removeMeshFaces(const TopoDS_Shape& face); + + const THypVL* getLineHypothesis(int iPL); + double getLineThickness (int iPL); + + bool error( const string& text ); + SMESHDS_Mesh* getMeshDS() { return _mesh->GetMeshDS(); } + _ProxyMeshOfFace* getProxyMesh(); + + // debug + //void makeGroupOfLE(); + + private: + + // input data + SMESH_Mesh* _mesh; + TopoDS_Face _face; + vector< const THypVL* > _hyps; + vector< TopoDS_Shape > _hypShapes; + + // result data + SMESH_ProxyMesh::Ptr _proxyMesh; + SMESH_ComputeErrorPtr _error; + + // working data + Handle(Geom_Surface) _surface; + SMESH_MesherHelper _helper; + TSideVector _faceSideVec; // wires (StdMeshers_FaceSide) of _face + vector<_PolyLine> _polyLineVec; // fronts to advance + vector< const THypVL* > _hypOfEdge; // a hyp per an EDGE of _faceSideVec + bool _is2DIsotropic; // is same U and V resoulution of _face + vector _clearedFaces; // FACEs whose mesh was removed by shrink() + + //double _fPowN; // to compute thickness of layers + double _maxThickness; // max possible layers thickness + + // sub-shapes of _face + set _ignoreShapeIds; // ids of EDGEs w/o layers + set _noShrinkVert; // ids of VERTEXes that are extremities + // of EDGEs along which _LayerEdge can't be inflated because no viscous layers + // defined on neighbour FACEs sharing an EDGE. Nonetheless _LayerEdge's + // are inflated along such EDGEs but then such _LayerEdge's are turned into + // a node on VERTEX, i.e. all nodes on a _LayerEdge are melded into one node. + + int _nbLE; // for DEBUG + }; + + //================================================================================ + /*! + * \brief Returns StdMeshers_ViscousLayers2D for the FACE + */ + bool findHyps(SMESH_Mesh& theMesh, + const TopoDS_Face& theFace, + vector< const StdMeshers_ViscousLayers2D* > & theHyps, + vector< TopoDS_Shape > & theAssignedTo) + { + theHyps.clear(); + theAssignedTo.clear(); + SMESH_HypoFilter hypFilter + ( SMESH_HypoFilter::HasName( StdMeshers_ViscousLayers2D::GetHypType() )); + list< const SMESHDS_Hypothesis * > hypList; + list< TopoDS_Shape > hypShapes; + int nbHyps = theMesh.GetHypotheses + ( theFace, hypFilter, hypList, /*ancestors=*/true, &hypShapes ); + if ( nbHyps ) + { + theHyps.reserve( nbHyps ); + theAssignedTo.reserve( nbHyps ); + list< const SMESHDS_Hypothesis * >::iterator hyp = hypList.begin(); + list< TopoDS_Shape >::iterator shape = hypShapes.begin(); + for ( ; hyp != hypList.end(); ++hyp, ++shape ) + { + theHyps.push_back( static_cast< const StdMeshers_ViscousLayers2D* > ( *hyp )); + theAssignedTo.push_back( *shape ); + } + } + return nbHyps; + } + + //================================================================================ + /*! + * \brief Returns ids of EDGEs not to create Viscous Layers on + * \param [in] theHyp - the hypothesis, holding edges either to ignore or not to. + * \param [in] theFace - the FACE whose EDGEs are checked. + * \param [in] theMesh - the mesh. + * \param [in,out] theEdgeIds - container returning EDGEs to ignore. + * \return int - number of found EDGEs of the FACE. + */ + //================================================================================ + + int getEdgesToIgnore( const StdMeshers_ViscousLayers2D* theHyp, + const TopoDS_Shape& theFace, + const SMESHDS_Mesh* theMesh, + set< int > & theEdgeIds) + { + int nbEdgesToIgnore = 0; + vector ids = theHyp->GetBndShapes(); + if ( theHyp->IsToIgnoreShapes() ) // EDGEs to ignore are given + { + for ( size_t i = 0; i < ids.size(); ++i ) + { + const TopoDS_Shape& E = theMesh->IndexToShape( ids[i] ); + if ( !E.IsNull() && + E.ShapeType() == TopAbs_EDGE && + SMESH_MesherHelper::IsSubShape( E, theFace )) + { + theEdgeIds.insert( ids[i] ); + ++nbEdgesToIgnore; + } + } + } + else // EDGEs to make the Viscous Layers on are given + { + TopExp_Explorer E( theFace, TopAbs_EDGE ); + for ( ; E.More(); E.Next(), ++nbEdgesToIgnore ) + theEdgeIds.insert( theMesh->ShapeToIndex( E.Current() )); + + for ( size_t i = 0; i < ids.size(); ++i ) + nbEdgesToIgnore -= theEdgeIds.erase( ids[i] ); + } + return nbEdgesToIgnore; + } + +} // namespace VISCOUS_2D + +//================================================================================ +// StdMeshers_ViscousLayers hypothesis +// +StdMeshers_ViscousLayers2D::StdMeshers_ViscousLayers2D(int hypId, int studyId, SMESH_Gen* gen) + :StdMeshers_ViscousLayers(hypId, studyId, gen) +{ + _name = StdMeshers_ViscousLayers2D::GetHypType(); + _param_algo_dim = -2; // auxiliary hyp used by 2D algos +} +// -------------------------------------------------------------------------------- +bool StdMeshers_ViscousLayers2D::SetParametersByMesh(const SMESH_Mesh* theMesh, + const TopoDS_Shape& theShape) +{ + // TODO ??? + return false; +} +// -------------------------------------------------------------------------------- +SMESH_ProxyMesh::Ptr +StdMeshers_ViscousLayers2D::Compute(SMESH_Mesh& theMesh, + const TopoDS_Face& theFace) +{ + SMESH_ProxyMesh::Ptr pm; + + vector< const StdMeshers_ViscousLayers2D* > hyps; + vector< TopoDS_Shape > hypShapes; + if ( VISCOUS_2D::findHyps( theMesh, theFace, hyps, hypShapes )) + { + VISCOUS_2D::_ViscousBuilder2D builder( theMesh, theFace, hyps, hypShapes ); + pm = builder.Compute(); + SMESH_ComputeErrorPtr error = builder.GetError(); + if ( error && !error->IsOK() ) + theMesh.GetSubMesh( theFace )->GetComputeError() = error; + else if ( !pm ) + pm.reset( new SMESH_ProxyMesh( theMesh )); + if ( getenv("__ONLY__VL2D__")) + pm.reset(); + } + else + { + pm.reset( new SMESH_ProxyMesh( theMesh )); + } + return pm; +} +// -------------------------------------------------------------------------------- +SMESH_ComputeErrorPtr +StdMeshers_ViscousLayers2D::CheckHypothesis(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + SMESH_Hypothesis::Hypothesis_Status& theStatus) +{ + SMESH_ComputeErrorPtr error = SMESH_ComputeError::New(COMPERR_OK); + theStatus = SMESH_Hypothesis::HYP_OK; + + TopExp_Explorer exp( theShape, TopAbs_FACE ); + for ( ; exp.More() && theStatus == SMESH_Hypothesis::HYP_OK; exp.Next() ) + { + const TopoDS_Face& face = TopoDS::Face( exp.Current() ); + vector< const StdMeshers_ViscousLayers2D* > hyps; + vector< TopoDS_Shape > hypShapes; + if ( VISCOUS_2D::findHyps( theMesh, face, hyps, hypShapes )) + { + VISCOUS_2D::_ViscousBuilder2D builder( theMesh, face, hyps, hypShapes ); + builder._faceSideVec = + StdMeshers_FaceSide::GetFaceWires( face, theMesh, true, error, + SMESH_ProxyMesh::Ptr(), + /*theCheckVertexNodes=*/false); + if ( error->IsOK() && !builder.findEdgesWithLayers()) + { + error = builder.GetError(); + if ( error && !error->IsOK() ) + theStatus = SMESH_Hypothesis::HYP_INCOMPAT_HYPS; + } + } + } + return error; +} +// -------------------------------------------------------------------------------- +void StdMeshers_ViscousLayers2D::RestoreListeners() const +{ + StudyContextStruct* sc = _gen->GetStudyContext( _studyId ); + std::map < int, SMESH_Mesh * >::iterator i_smesh = sc->mapMesh.begin(); + for ( ; i_smesh != sc->mapMesh.end(); ++i_smesh ) + { + SMESH_Mesh* smesh = i_smesh->second; + if ( !smesh || + !smesh->HasShapeToMesh() || + !smesh->GetMeshDS() || + !smesh->GetMeshDS()->IsUsedHypothesis( this )) + continue; + + // set event listeners to EDGE's of FACE where this hyp is used + TopoDS_Shape shape = i_smesh->second->GetShapeToMesh(); + for ( TopExp_Explorer face( shape, TopAbs_FACE); face.More(); face.Next() ) + if ( SMESH_Algo* algo = _gen->GetAlgo( *smesh, face.Current() )) + { + const std::list & usedHyps = + algo->GetUsedHypothesis( *smesh, face.Current(), /*ignoreAuxiliary=*/false ); + if ( std::find( usedHyps.begin(), usedHyps.end(), this ) != usedHyps.end() ) + for ( TopExp_Explorer edge( face.Current(), TopAbs_EDGE); edge.More(); edge.Next() ) + VISCOUS_3D::ToClearSubWithMain( smesh->GetSubMesh( edge.Current() ), face.Current() ); + } + } +} +// END StdMeshers_ViscousLayers2D hypothesis +//================================================================================ + +using namespace VISCOUS_2D; + +//================================================================================ +/*! + * \brief Constructor of _ViscousBuilder2D + */ +//================================================================================ + +_ViscousBuilder2D::_ViscousBuilder2D(SMESH_Mesh& theMesh, + const TopoDS_Face& theFace, + vector< const THypVL* > & theHyps, + vector< TopoDS_Shape > & theAssignedTo): + _mesh( &theMesh ), _face( theFace ), _helper( theMesh ) +{ + _hyps.swap( theHyps ); + _hypShapes.swap( theAssignedTo ); + + _helper.SetSubShape( _face ); + _helper.SetElementsOnShape( true ); + + _face.Orientation( TopAbs_FORWARD ); // 2D logic works only in this case + _surface = BRep_Tool::Surface( _face ); + + _error = SMESH_ComputeError::New(COMPERR_OK); + + _nbLE = 0; +} + +//================================================================================ +/*! + * \brief Stores error description and returns false + */ +//================================================================================ + +bool _ViscousBuilder2D::error(const string& text ) +{ + _error->myName = COMPERR_ALGO_FAILED; + _error->myComment = string("Viscous layers builder 2D: ") + text; + if ( SMESH_subMesh* sm = _mesh->GetSubMesh( _face ) ) + { + SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); + if ( smError && smError->myAlgo ) + _error->myAlgo = smError->myAlgo; + smError = _error; + } +#ifdef _DEBUG_ + cout << "_ViscousBuilder2D::error " << text << endl; +#endif + return false; +} + +//================================================================================ +/*! + * \brief Does its job + */ +//================================================================================ + +SMESH_ProxyMesh::Ptr _ViscousBuilder2D::Compute() +{ + _faceSideVec = StdMeshers_FaceSide::GetFaceWires( _face, *_mesh, true, _error); + + if ( !_error->IsOK() ) + return _proxyMesh; + + if ( !findEdgesWithLayers() ) // analysis of a shape + return _proxyMesh; + + if ( ! makePolyLines() ) // creation of fronts + return _proxyMesh; + + if ( ! inflate() ) // advance fronts + return _proxyMesh; + + // remove elements and nodes from _face + removeMeshFaces( _face ); + + if ( !shrink() ) // shrink segments on edges w/o layers + return _proxyMesh; + + if ( ! refine() ) // make faces + return _proxyMesh; + + //improve(); + + return _proxyMesh; +} + +//================================================================================ +/*! + * \brief Finds EDGE's to make viscous layers on. + */ +//================================================================================ + +bool _ViscousBuilder2D::findEdgesWithLayers() +{ + // collect all EDGEs to ignore defined by _hyps + typedef std::pair< set, const THypVL* > TEdgesOfHyp; + vector< TEdgesOfHyp > ignoreEdgesOfHyp( _hyps.size() ); + for ( size_t i = 0; i < _hyps.size(); ++i ) + { + ignoreEdgesOfHyp[i].second = _hyps[i]; + getEdgesToIgnore( _hyps[i], _face, getMeshDS(), ignoreEdgesOfHyp[i].first ); + } + + // get all shared EDGEs + TopTools_MapOfShape sharedEdges; + TopTools_IndexedMapOfShape hypFaces; // faces with VL hyps + for ( size_t i = 0; i < _hypShapes.size(); ++i ) + TopExp::MapShapes( _hypShapes[i], TopAbs_FACE, hypFaces ); + TopTools_IndexedDataMapOfShapeListOfShape facesOfEdgeMap; + for ( int iF = 1; iF <= hypFaces.Extent(); ++iF ) + TopExp::MapShapesAndAncestors( hypFaces(iF), TopAbs_EDGE, TopAbs_FACE, facesOfEdgeMap); + for ( int iE = 1; iE <= facesOfEdgeMap.Extent(); ++iE ) + if ( facesOfEdgeMap( iE ).Extent() > 1 ) + sharedEdges.Add( facesOfEdgeMap.FindKey( iE )); + + // fill _hypOfEdge + if ( _hyps.size() > 1 ) + { + // check if two hypotheses define different parameters for the same EDGE + for ( size_t iWire = 0; iWire < _faceSideVec.size(); ++iWire ) + { + StdMeshers_FaceSidePtr wire = _faceSideVec[ iWire ]; + for ( int iE = 0; iE < wire->NbEdges(); ++iE ) + { + const THypVL* hyp = 0; + const TGeomID edgeID = wire->EdgeID( iE ); + if ( !sharedEdges.Contains( wire->Edge( iE ))) + { + for ( size_t i = 0; i < ignoreEdgesOfHyp.size(); ++i ) + if ( ! ignoreEdgesOfHyp[i].first.count( edgeID )) + { + if ( hyp ) + return error(SMESH_Comment("Several hypotheses define " + "Viscous Layers on the edge #") << edgeID ); + hyp = ignoreEdgesOfHyp[i].second; + } + } + _hypOfEdge.push_back( hyp ); + if ( !hyp ) + _ignoreShapeIds.insert( edgeID ); + } + // check if two hypotheses define different number of viscous layers for + // adjacent EDGEs + const THypVL *hyp, *prevHyp = _hypOfEdge.back(); + size_t iH = _hypOfEdge.size() - wire->NbEdges(); + for ( ; iH < _hypOfEdge.size(); ++iH ) + { + hyp = _hypOfEdge[ iH ]; + if ( hyp && prevHyp && + hyp->GetNumberLayers() != prevHyp->GetNumberLayers() ) + { + return error("Two hypotheses define different number of " + "viscous layers on adjacent edges"); + } + prevHyp = hyp; + } + } + } + else if ( _hyps.size() == 1 ) + { + _ignoreShapeIds.swap( ignoreEdgesOfHyp[0].first ); + } + + // check all EDGEs of the _face to fill _ignoreShapeIds and _noShrinkVert + + int totalNbEdges = 0; + for ( size_t iWire = 0; iWire < _faceSideVec.size(); ++iWire ) + { + StdMeshers_FaceSidePtr wire = _faceSideVec[ iWire ]; + totalNbEdges += wire->NbEdges(); + for ( int iE = 0; iE < wire->NbEdges(); ++iE ) + { + if ( sharedEdges.Contains( wire->Edge( iE ))) + { + // ignore internal EDGEs (shared by several FACEs) + const TGeomID edgeID = wire->EdgeID( iE ); + _ignoreShapeIds.insert( edgeID ); + + // check if ends of an EDGE are to be added to _noShrinkVert + const TopTools_ListOfShape& faceList = facesOfEdgeMap.FindFromKey( wire->Edge( iE )); + TopTools_ListIteratorOfListOfShape faceIt( faceList ); + for ( ; faceIt.More(); faceIt.Next() ) + { + const TopoDS_Shape& neighbourFace = faceIt.Value(); + if ( neighbourFace.IsSame( _face )) continue; + SMESH_Algo* algo = _mesh->GetGen()->GetAlgo( *_mesh, neighbourFace ); + if ( !algo ) continue; + + const StdMeshers_ViscousLayers2D* viscHyp = 0; + const list & allHyps = + algo->GetUsedHypothesis(*_mesh, neighbourFace, /*noAuxiliary=*/false); + list< const SMESHDS_Hypothesis *>::const_iterator hyp = allHyps.begin(); + for ( ; hyp != allHyps.end() && !viscHyp; ++hyp ) + viscHyp = dynamic_cast( *hyp ); + + // set neighbourIgnoreEdges; + // if (viscHyp) + // getEdgesToIgnore( viscHyp, neighbourFace, getMeshDS(), neighbourIgnoreEdges ); + + for ( int iV = 0; iV < 2; ++iV ) + { + TopoDS_Vertex vertex = iV ? wire->LastVertex(iE) : wire->FirstVertex(iE); + if ( !viscHyp ) + _noShrinkVert.insert( getMeshDS()->ShapeToIndex( vertex )); + else + { + PShapeIteratorPtr edgeIt = _helper.GetAncestors( vertex, *_mesh, TopAbs_EDGE ); + while ( const TopoDS_Shape* edge = edgeIt->next() ) + if ( !edge->IsSame( wire->Edge( iE )) && + _helper.IsSubShape( *edge, neighbourFace )) + { + const TGeomID neighbourID = getMeshDS()->ShapeToIndex( *edge ); + bool hasVL = !sharedEdges.Contains( *edge ); + if ( hasVL ) + { + hasVL = false; + for ( hyp = allHyps.begin(); hyp != allHyps.end() && !hasVL; ++hyp ) + if ( viscHyp = dynamic_cast( *hyp )) + hasVL = viscHyp->IsShapeWithLayers( neighbourID ); + } + if ( !hasVL ) + { + _noShrinkVert.insert( getMeshDS()->ShapeToIndex( vertex )); + break; + } + } + } + } + } + } + } + } + + int nbMyEdgesIgnored = _ignoreShapeIds.size(); + + // add VERTEXes w/o layers to _ignoreShapeIds (this is used by toShrinkForAdjacent()) + // for ( size_t iWire = 0; iWire < _faceSideVec.size(); ++iWire ) + // { + // StdMeshers_FaceSidePtr wire = _faceSideVec[ iWire ]; + // for ( int iE = 0; iE < wire->NbEdges(); ++iE ) + // { + // TGeomID edge1 = wire->EdgeID( iE ); + // TGeomID edge2 = wire->EdgeID( iE+1 ); + // if ( _ignoreShapeIds.count( edge1 ) && _ignoreShapeIds.count( edge2 )) + // _ignoreShapeIds.insert( getMeshDS()->ShapeToIndex( wire->LastVertex( iE ))); + // } + // } + + return ( nbMyEdgesIgnored < totalNbEdges ); +} + +//================================================================================ +/*! + * \brief Create the inner front of the viscous layers and prepare data for inflation + */ +//================================================================================ + +bool _ViscousBuilder2D::makePolyLines() +{ + // Create _PolyLines and _LayerEdge's + + // count total nb of EDGEs to allocate _polyLineVec + int nbEdges = 0; + for ( size_t iWire = 0; iWire < _faceSideVec.size(); ++iWire ) + { + StdMeshers_FaceSidePtr wire = _faceSideVec[ iWire ]; + nbEdges += wire->NbEdges(); + if ( wire->GetUVPtStruct().empty() && wire->NbPoints() > 0 ) + return error("Invalid node parameters on some EDGE"); + } + _polyLineVec.resize( nbEdges ); + + // check if 2D normal should be computed by 3D one by means of projection + GeomAPI_ProjectPointOnSurf* faceProj = 0; + TopLoc_Location loc; + { + _LayerEdge tmpLE; + const UVPtStruct& uv = _faceSideVec[0]->GetUVPtStruct()[0]; + gp_Pnt p = SMESH_TNodeXYZ( uv.node ); + tmpLE._uvOut.SetCoord( uv.u, uv.v ); + tmpLE._normal2D.SetCoord( 1., 0. ); + setLenRatio( tmpLE, p ); + const double r1 = tmpLE._len2dTo3dRatio; + tmpLE._normal2D.SetCoord( 0., 1. ); + setLenRatio( tmpLE, p ); + const double r2 = tmpLE._len2dTo3dRatio; + // projection is needed if two _len2dTo3dRatio's differ too much + const double maxR = Max( r2, r1 ); + if ( Abs( r2-r1 )/maxR > 0.2*maxR ) + faceProj = & _helper.GetProjector( _face, loc ); + } + _is2DIsotropic = !faceProj; + + // Assign data to _PolyLine's + // --------------------------- + + size_t iPoLine = 0; + for ( size_t iWire = 0; iWire < _faceSideVec.size(); ++iWire ) + { + StdMeshers_FaceSidePtr wire = _faceSideVec[ iWire ]; + const vector& points = wire->GetUVPtStruct(); + int iPnt = 0; + for ( int iE = 0; iE < wire->NbEdges(); ++iE ) + { + _PolyLine& L = _polyLineVec[ iPoLine++ ]; + L._index = iPoLine-1; + L._wire = wire.get(); + L._edgeInd = iE; + L._advancable = !_ignoreShapeIds.count( wire->EdgeID( iE )); + + int iRight = iPoLine - (( iE+1 < wire->NbEdges() ) ? 0 : wire->NbEdges() ); + L._rightLine = &_polyLineVec[ iRight ]; + _polyLineVec[ iRight ]._leftLine = &L; + + L._firstPntInd = iPnt; + double lastNormPar = wire->LastParameter( iE ) - 1e-10; + while ( points[ iPnt ].normParam < lastNormPar ) + ++iPnt; + L._lastPntInd = iPnt; + L._lEdges.resize( Max( 3, L._lastPntInd - L._firstPntInd + 1 )); // 3 edges minimum + + // TODO: add more _LayerEdge's to strongly curved EDGEs + // in order not to miss collisions + + double u; gp_Pnt p; + Handle(Geom_Curve) curve = BRep_Tool::Curve( L._wire->Edge( iE ), loc, u, u ); + Handle(Geom2d_Curve) pcurve = L._wire->Curve2d( L._edgeInd ); + const bool reverse = (( L._wire->Edge( iE ).Orientation() == TopAbs_REVERSED ) ^ + (_face.Orientation() == TopAbs_REVERSED )); + for ( int i = L._firstPntInd; i <= L._lastPntInd; ++i ) + { + _LayerEdge& lEdge = L._lEdges[ i - L._firstPntInd ]; + u = ( i == L._firstPntInd ? wire->FirstU(iE) : points[ i ].param ); + p = SMESH_TNodeXYZ( points[ i ].node ); + setLayerEdgeData( lEdge, u, pcurve, curve, p, reverse, faceProj ); + setLenRatio( lEdge, p ); + } + if ( L._lastPntInd - L._firstPntInd + 1 < 3 ) // add 3-d _LayerEdge in the middle + { + L._lEdges[2] = L._lEdges[1]; + u = 0.5 * ( wire->FirstU(iE) + wire->LastU(iE) ); + if ( !curve.IsNull() ) + p = curve->Value( u ); + else + p = 0.5 * ( SMESH_TNodeXYZ( points[ L._firstPntInd ].node ) + + SMESH_TNodeXYZ( points[ L._lastPntInd ].node )); + setLayerEdgeData( L._lEdges[1], u, pcurve, curve, p, reverse, faceProj ); + setLenRatio( L._lEdges[1], p ); + } + } + } + + // Fill _PolyLine's with _segments + // -------------------------------- + + double maxLen2dTo3dRatio = 0; + for ( iPoLine = 0; iPoLine < _polyLineVec.size(); ++iPoLine ) + { + _PolyLine& L = _polyLineVec[ iPoLine ]; + L._segments.resize( L._lEdges.size() - 1 ); + for ( size_t i = 1; i < L._lEdges.size(); ++i ) + { + _Segment & S = L._segments[i-1]; + S._uv[0] = & L._lEdges[i-1]._uvIn; + S._uv[1] = & L._lEdges[i ]._uvIn; + S._indexInLine = i-1; + if ( maxLen2dTo3dRatio < L._lEdges[i]._len2dTo3dRatio ) + maxLen2dTo3dRatio = L._lEdges[i]._len2dTo3dRatio; + } + // // connect _PolyLine's with segments, the 1st _LayerEdge of every _PolyLine + // // becomes not connected to any segment + // if ( L._leftLine->_advancable ) + // L._segments[0]._uv[0] = & L._leftLine->_lEdges.back()._uvIn; + + L._segTree.reset( new _SegmentTree( L._segments )); + } + + // Evaluate max possible _thickness if required layers thickness seems too high + // ---------------------------------------------------------------------------- + + _maxThickness = _hyps[0]->GetTotalThickness(); + for ( size_t iH = 1; iH < _hyps.size(); ++iH ) + _maxThickness = Max( _maxThickness, _hyps[iH]->GetTotalThickness() ); + + _SegmentTree::box_type faceBndBox2D; + for ( iPoLine = 0; iPoLine < _polyLineVec.size(); ++iPoLine ) + faceBndBox2D.Add( *_polyLineVec[ iPoLine]._segTree->getBox() ); + const double boxTol = 1e-3 * sqrt( faceBndBox2D.SquareExtent() ); + + if ( _maxThickness * maxLen2dTo3dRatio > sqrt( faceBndBox2D.SquareExtent() ) / 10 ) + { + vector< const _Segment* > foundSegs; + double maxPossibleThick = 0; + _SegmentIntersection intersection; + for ( size_t iL1 = 0; iL1 < _polyLineVec.size(); ++iL1 ) + { + _PolyLine& L1 = _polyLineVec[ iL1 ]; + _SegmentTree::box_type boxL1 = * L1._segTree->getBox(); + boxL1.Enlarge( boxTol ); + // consider case of a circle as well! + for ( size_t iL2 = iL1; iL2 < _polyLineVec.size(); ++iL2 ) + { + _PolyLine& L2 = _polyLineVec[ iL2 ]; + _SegmentTree::box_type boxL2 = * L2._segTree->getBox(); + boxL2.Enlarge( boxTol ); + if ( boxL1.IsOut( boxL2 )) + continue; + for ( size_t iLE = 1; iLE < L1._lEdges.size(); ++iLE ) + { + foundSegs.clear(); + L2._segTree->GetSegmentsNear( L1._lEdges[iLE]._ray, foundSegs ); + for ( size_t i = 0; i < foundSegs.size(); ++i ) + if ( intersection.Compute( *foundSegs[i], L1._lEdges[iLE]._ray )) + { + double distToL2 = intersection._param2 / L1._lEdges[iLE]._len2dTo3dRatio; + double psblThick = distToL2 / ( 1 + L1._advancable + L2._advancable ); + maxPossibleThick = Max( psblThick, maxPossibleThick ); + } + } + } + } + if ( maxPossibleThick > 0. ) + _maxThickness = Min( _maxThickness, maxPossibleThick ); + } + + // Adjust _LayerEdge's at _PolyLine's extremities + // ----------------------------------------------- + + for ( iPoLine = 0; iPoLine < _polyLineVec.size(); ++iPoLine ) + { + _PolyLine& LL = _polyLineVec[ iPoLine ]; + _PolyLine& LR = *LL._rightLine; + adjustCommonEdge( LL, LR ); + } + // recreate _segments if some _LayerEdge's have been removed by adjustCommonEdge() + for ( iPoLine = 0; iPoLine < _polyLineVec.size(); ++iPoLine ) + { + _PolyLine& L = _polyLineVec[ iPoLine ]; + // if ( L._segments.size() == L._lEdges.size() - 1 ) + // continue; + L._segments.resize( L._lEdges.size() - 1 ); + for ( size_t i = 1; i < L._lEdges.size(); ++i ) + { + _Segment & S = L._segments[i-1]; + S._uv[0] = & L._lEdges[i-1]._uvIn; + S._uv[1] = & L._lEdges[i ]._uvIn; + S._indexInLine = i-1; + } + L._segTree.reset( new _SegmentTree( L._segments )); + } + // connect _PolyLine's with segments, the 1st _LayerEdge of every _PolyLine + // becomes not connected to any segment + for ( iPoLine = 0; iPoLine < _polyLineVec.size(); ++iPoLine ) + { + _PolyLine& L = _polyLineVec[ iPoLine ]; + if ( L._leftLine->_advancable ) + L._segments[0]._uv[0] = & L._leftLine->_lEdges.back()._uvIn; + } + + // Fill _reachableLines. + // ---------------------- + + // compute bnd boxes taking into account the layers total thickness + vector< _SegmentTree::box_type > lineBoxes( _polyLineVec.size() ); + for ( iPoLine = 0; iPoLine < _polyLineVec.size(); ++iPoLine ) + { + lineBoxes[ iPoLine ] = *_polyLineVec[ iPoLine ]._segTree->getBox(); + lineBoxes[ iPoLine ].Enlarge( maxLen2dTo3dRatio * getLineThickness( iPoLine ) * + ( _polyLineVec[ iPoLine ]._advancable ? 2. : 1.2 )); + } + // _reachableLines + for ( iPoLine = 0; iPoLine < _polyLineVec.size(); ++iPoLine ) + { + _PolyLine& L1 = _polyLineVec[ iPoLine ]; + const double thick1 = getLineThickness( iPoLine ); + for ( size_t iL2 = 0; iL2 < _polyLineVec.size(); ++iL2 ) + { + _PolyLine& L2 = _polyLineVec[ iL2 ]; + if ( iPoLine == iL2 || lineBoxes[ iPoLine ].IsOut( lineBoxes[ iL2 ])) + continue; + if ( !L1._advancable && ( L1._leftLine == &L2 || L1._rightLine == &L2 )) + continue; + // check reachability by _LayerEdge's + int iDelta = 1; //Max( 1, L1._lEdges.size() / 100 ); + for ( size_t iLE = 1; iLE < L1._lEdges.size(); iLE += iDelta ) + { + _LayerEdge& LE = L1._lEdges[iLE]; + if ( !lineBoxes[ iL2 ].IsOut ( LE._uvOut, + LE._uvOut + LE._normal2D * thick1 * LE._len2dTo3dRatio )) + { + L1._reachableLines.push_back( & L2 ); + break; + } + } + } + // add self to _reachableLines + Geom2dAdaptor_Curve pcurve( L1._wire->Curve2d( L1._edgeInd )); + L1._isStraight2D = ( pcurve.GetType() == GeomAbs_Line ); + if ( !L1._isStraight2D ) + { + // TODO: check carefully + L1._reachableLines.push_back( & L1 ); + } + } + + return true; +} + +//================================================================================ +/*! + * \brief adjust common _LayerEdge of two adjacent _PolyLine's + * \param LL - left _PolyLine + * \param LR - right _PolyLine + */ +//================================================================================ + +void _ViscousBuilder2D::adjustCommonEdge( _PolyLine& LL, _PolyLine& LR ) +{ + int nbAdvancableL = LL._advancable + LR._advancable; + if ( nbAdvancableL == 0 ) + return; + + _LayerEdge& EL = LL._lEdges.back(); + _LayerEdge& ER = LR._lEdges.front(); + gp_XY normL = EL._normal2D; + gp_XY normR = ER._normal2D; + gp_XY tangL ( normL.Y(), -normL.X() ); + + // set common direction to a VERTEX _LayerEdge shared by two _PolyLine's + gp_XY normCommon = ( normL * int( LL._advancable ) + + normR * int( LR._advancable )).Normalized(); + EL._normal2D = normCommon; + EL._ray.SetLocation ( EL._uvOut ); + EL._ray.SetDirection( EL._normal2D ); + if ( nbAdvancableL == 1 ) { // _normal2D is true normal (not average) + EL._isBlocked = true; // prevent intersecting with _Segments of _advancable line + EL._length2D = 0; + } + // update _LayerEdge::_len2dTo3dRatio according to a new direction + const vector& points = LL._wire->GetUVPtStruct(); + setLenRatio( EL, SMESH_TNodeXYZ( points[ LL._lastPntInd ].node )); + + ER = EL; + + const double dotNormTang = normR * tangL; + const bool largeAngle = Abs( dotNormTang ) > 0.2; + if ( largeAngle ) // not 180 degrees + { + // recompute _len2dTo3dRatio to take into account angle between EDGEs + gp_Vec2d oldNorm( LL._advancable ? normL : normR ); + double angleFactor = 1. / Max( 0.3, Cos( oldNorm.Angle( normCommon ))); + EL._len2dTo3dRatio *= angleFactor; + ER._len2dTo3dRatio = EL._len2dTo3dRatio; + + gp_XY normAvg = ( normL + normR ).Normalized(); // average normal at VERTEX + + if ( dotNormTang < 0. ) // ---------------------------- CONVEX ANGLE + { + // Remove _LayerEdge's intersecting the normAvg to avoid collisions + // during inflate(). + // + // find max length of the VERTEX-based _LayerEdge whose direction is normAvg + double maxLen2D = _maxThickness * EL._len2dTo3dRatio; + const gp_XY& pCommOut = ER._uvOut; + gp_XY pCommIn = pCommOut + normAvg * maxLen2D; + _Segment segCommon( pCommOut, pCommIn ); + _SegmentIntersection intersection; + vector< const _Segment* > foundSegs; + for ( size_t iL1 = 0; iL1 < _polyLineVec.size(); ++iL1 ) + { + _PolyLine& L1 = _polyLineVec[ iL1 ]; + const _SegmentTree::box_type* boxL1 = L1._segTree->getBox(); + if ( boxL1->IsOut ( pCommOut, pCommIn )) + continue; + for ( size_t iLE = 1; iLE < L1._lEdges.size(); ++iLE ) + { + foundSegs.clear(); + L1._segTree->GetSegmentsNear( segCommon, foundSegs ); + for ( size_t i = 0; i < foundSegs.size(); ++i ) + if ( intersection.Compute( *foundSegs[i], segCommon ) && + intersection._param2 > 1e-10 ) + { + double len2D = intersection._param2 * maxLen2D / ( 2 + L1._advancable ); + if ( len2D < maxLen2D ) { + maxLen2D = len2D; + pCommIn = pCommOut + normAvg * maxLen2D; // here length of segCommon changes + } + } + } + } + + // remove _LayerEdge's intersecting segCommon + for ( int isR = 0; isR < 2; ++isR ) // loop on [ LL, LR ] + { + _PolyLine& L = isR ? LR : LL; + _PolyLine::TEdgeIterator eIt = isR ? L._lEdges.begin()+1 : L._lEdges.end()-2; + int dIt = isR ? +1 : -1; + if ( nbAdvancableL == 1 && L._advancable && normL * normR > -0.01 ) + continue; // obtuse internal angle + // at least 3 _LayerEdge's should remain in a _PolyLine + if ( L._lEdges.size() < 4 ) continue; + size_t iLE = 1; + _SegmentIntersection lastIntersection; + for ( ; iLE < L._lEdges.size(); ++iLE, eIt += dIt ) + { + gp_XY uvIn = eIt->_uvOut + eIt->_normal2D * _maxThickness * eIt->_len2dTo3dRatio; + _Segment segOfEdge( eIt->_uvOut, uvIn ); + if ( !intersection.Compute( segCommon, segOfEdge )) + break; + lastIntersection._param1 = intersection._param1; + lastIntersection._param2 = intersection._param2; + } + if ( iLE >= L._lEdges.size() - 1 ) + { + // all _LayerEdge's intersect the segCommon, limit inflation + // of remaining 3 _LayerEdge's + vector< _LayerEdge > newEdgeVec( Min( 3, L._lEdges.size() )); + newEdgeVec.front() = L._lEdges.front(); + newEdgeVec.back() = L._lEdges.back(); + if ( newEdgeVec.size() == 3 ) + { + newEdgeVec[1] = L._lEdges[ isR ? (L._lEdges.size() - 2) : 1 ]; + newEdgeVec[1]._len2dTo3dRatio *= lastIntersection._param2; + } + L._lEdges.swap( newEdgeVec ); + if ( !isR ) std::swap( lastIntersection._param1 , lastIntersection._param2 ); + L._lEdges.front()._len2dTo3dRatio *= lastIntersection._param1; // ?? + L._lEdges.back ()._len2dTo3dRatio *= lastIntersection._param2; + } + else if ( iLE != 1 ) + { + // eIt points to the _LayerEdge not intersecting with segCommon + if ( isR ) + LR._lEdges.erase( LR._lEdges.begin()+1, eIt ); + else + LL._lEdges.erase( eIt, --LL._lEdges.end() ); + // eIt = isR ? L._lEdges.begin()+1 : L._lEdges.end()-2; + // for ( size_t i = 1; i < iLE; ++i, eIt += dIt ) + // eIt->_isBlocked = true; + } + } + } + else // ------------------------------------------ CONCAVE ANGLE + { + if ( nbAdvancableL == 1 ) + { + // make that the _LayerEdge at VERTEX is not shared by LL and LR: + // different normals is a sign that they are not shared + _LayerEdge& notSharedEdge = LL._advancable ? LR._lEdges[0] : LL._lEdges.back(); + _LayerEdge& sharedEdge = LR._advancable ? LR._lEdges[0] : LL._lEdges.back(); + + notSharedEdge._normal2D.SetCoord( 0.,0. ); + sharedEdge._normal2D = normAvg; + sharedEdge._isBlocked = false; + notSharedEdge._isBlocked = true; + } + } + } +} + +//================================================================================ +/*! + * \brief initialize data of a _LayerEdge + */ +//================================================================================ + +void _ViscousBuilder2D::setLayerEdgeData( _LayerEdge& lEdge, + const double u, + Handle(Geom2d_Curve)& pcurve, + Handle(Geom_Curve)& curve, + const gp_Pnt pOut, + const bool reverse, + GeomAPI_ProjectPointOnSurf* faceProj) +{ + gp_Pnt2d uv; + if ( faceProj && !curve.IsNull() ) + { + uv = pcurve->Value( u ); + gp_Vec tangent; gp_Pnt p; gp_Vec du, dv; + curve->D1( u, p, tangent ); + if ( reverse ) + tangent.Reverse(); + _surface->D1( uv.X(), uv.Y(), p, du, dv ); + gp_Vec faceNorm = du ^ dv; + gp_Vec normal = faceNorm ^ tangent; + normal.Normalize(); + p = pOut.XYZ() + normal.XYZ() * /*1e-2 * */_hyps[0]->GetTotalThickness() / _hyps[0]->GetNumberLayers(); + faceProj->Perform( p ); + if ( !faceProj->IsDone() || faceProj->NbPoints() < 1 ) + return setLayerEdgeData( lEdge, u, pcurve, curve, p, reverse, NULL ); + Quantity_Parameter U,V; + faceProj->LowerDistanceParameters(U,V); + lEdge._normal2D.SetCoord( U - uv.X(), V - uv.Y() ); + lEdge._normal2D.Normalize(); + } + else + { + gp_Vec2d tangent; + pcurve->D1( u, uv, tangent ); + tangent.Normalize(); + if ( reverse ) + tangent.Reverse(); + lEdge._normal2D.SetCoord( -tangent.Y(), tangent.X() ); + } + lEdge._uvOut = lEdge._uvIn = uv.XY(); + lEdge._ray.SetLocation ( lEdge._uvOut ); + lEdge._ray.SetDirection( lEdge._normal2D ); + lEdge._isBlocked = false; + lEdge._length2D = 0; +#ifdef _DEBUG_ + lEdge._ID = _nbLE++; +#endif +} + +//================================================================================ +/*! + * \brief Compute and set _LayerEdge::_len2dTo3dRatio + */ +//================================================================================ + +void _ViscousBuilder2D::setLenRatio( _LayerEdge& LE, const gp_Pnt& pOut ) +{ + const double probeLen2d = 1e-3; + + gp_Pnt2d p2d = LE._uvOut + LE._normal2D * probeLen2d; + gp_Pnt p3d = _surface->Value( p2d.X(), p2d.Y() ); + double len3d = p3d.Distance( pOut ); + if ( len3d < std::numeric_limits::min() ) + LE._len2dTo3dRatio = std::numeric_limits::min(); + else + LE._len2dTo3dRatio = probeLen2d / len3d; +} + +//================================================================================ +/*! + * \brief Increase length of _LayerEdge's to reach the required thickness of layers + */ +//================================================================================ + +bool _ViscousBuilder2D::inflate() +{ + // Limit size of inflation step by geometry size found by + // itersecting _LayerEdge's with _Segment's + double minSize = _maxThickness, maxSize = 0; + vector< const _Segment* > foundSegs; + _SegmentIntersection intersection; + for ( size_t iL1 = 0; iL1 < _polyLineVec.size(); ++iL1 ) + { + _PolyLine& L1 = _polyLineVec[ iL1 ]; + for ( size_t iL2 = 0; iL2 < L1._reachableLines.size(); ++iL2 ) + { + _PolyLine& L2 = * L1._reachableLines[ iL2 ]; + for ( size_t iLE = 1; iLE < L1._lEdges.size(); ++iLE ) + { + foundSegs.clear(); + L2._segTree->GetSegmentsNear( L1._lEdges[iLE]._ray, foundSegs ); + for ( size_t i = 0; i < foundSegs.size(); ++i ) + if ( ! L1.IsAdjacent( *foundSegs[i], & L1._lEdges[iLE] ) && + intersection.Compute( *foundSegs[i], L1._lEdges[iLE]._ray )) + { + double distToL2 = intersection._param2 / L1._lEdges[iLE]._len2dTo3dRatio; + double size = distToL2 / ( 1 + L1._advancable + L2._advancable ); + if ( 1e-10 < size && size < minSize ) + minSize = size; + if ( size > maxSize ) + maxSize = size; + } + } + } + } + if ( minSize > maxSize ) // no collisions possible + maxSize = _maxThickness; +#ifdef __myDEBUG + cout << "-- minSize = " << minSize << ", maxSize = " << maxSize << endl; +#endif + + double curThick = 0, stepSize = minSize; + int nbSteps = 0; + if ( maxSize > _maxThickness ) + maxSize = _maxThickness; + while ( curThick < maxSize ) + { + curThick += stepSize * 1.25; + if ( curThick > _maxThickness ) + curThick = _maxThickness; + + // Elongate _LayerEdge's + for ( size_t iL = 0; iL < _polyLineVec.size(); ++iL ) + { + _PolyLine& L = _polyLineVec[ iL ]; + if ( !L._advancable ) continue; + const double lineThick = Min( curThick, getLineThickness( iL )); + bool lenChange = false; + for ( size_t iLE = L.FirstLEdge(); iLE < L._lEdges.size(); ++iLE ) + lenChange |= L._lEdges[iLE].SetNewLength( lineThick ); + // for ( int k=0; k_advancable &&*/ L.IsCommonEdgeShared( *L._leftLine ) ) { + L._lEdges[0] = L._leftLine->_lEdges.back(); + } + if ( !L._rightLine->_advancable && L.IsCommonEdgeShared( *L._rightLine ) ) { + L._lEdges.back() = L._rightLine->_lEdges[0]; + } + + _SegmentIntersection intersection; + for ( int isR = 0; ( isR < 2 && L._lEdges.size() > 2 ); ++isR ) + { + int nbRemove = 0, deltaIt = isR ? -1 : +1; + _PolyLine::TEdgeIterator eIt = isR ? L._lEdges.end()-1 : L._lEdges.begin(); + if ( eIt->_length2D == 0 ) continue; + _Segment seg1( eIt->_uvOut, eIt->_uvIn ); + for ( eIt += deltaIt; nbRemove < L._lEdges.size()-1; eIt += deltaIt ) + { + _Segment seg2( eIt->_uvOut, eIt->_uvIn ); + if ( !intersection.Compute( seg1, seg2 )) + break; + ++nbRemove; + } + if ( nbRemove > 0 ) { + if ( nbRemove == L._lEdges.size()-1 ) // 1st and last _LayerEdge's intersect + { + --nbRemove; + _LayerEdge& L0 = L._lEdges.front(); + _LayerEdge& L1 = L._lEdges.back(); + L0._length2D *= intersection._param1 * 0.5; + L1._length2D *= intersection._param2 * 0.5; + L0._uvIn = L0._uvOut + L0._normal2D * L0._length2D; + L1._uvIn = L1._uvOut + L1._normal2D * L1._length2D; + if ( L.IsCommonEdgeShared( *L._leftLine )) + L._leftLine->_lEdges.back() = L0; + } + if ( isR ) + L._lEdges.erase( L._lEdges.end()-nbRemove-1, + L._lEdges.end()-nbRemove ); + else + L._lEdges.erase( L._lEdges.begin()+1, + L._lEdges.begin()+1+nbRemove ); + } + } + } + return true; +} + +//================================================================================ +/*! + * \brief Remove intersection of _PolyLine's + */ +//================================================================================ + +bool _ViscousBuilder2D::fixCollisions() +{ + // look for intersections of _Segment's by intersecting _LayerEdge's with + // _Segment's + vector< const _Segment* > foundSegs; + _SegmentIntersection intersection; + + list< pair< _LayerEdge*, double > > edgeLenLimitList; + list< _LayerEdge* > blockedEdgesList; + + for ( size_t iL1 = 0; iL1 < _polyLineVec.size(); ++iL1 ) + { + _PolyLine& L1 = _polyLineVec[ iL1 ]; + //if ( !L1._advancable ) continue; + for ( size_t iL2 = 0; iL2 < L1._reachableLines.size(); ++iL2 ) + { + _PolyLine& L2 = * L1._reachableLines[ iL2 ]; + for ( size_t iLE = L1.FirstLEdge(); iLE < L1._lEdges.size(); ++iLE ) + { + _LayerEdge& LE1 = L1._lEdges[iLE]; + if ( LE1._isBlocked ) continue; + foundSegs.clear(); + L2._segTree->GetSegmentsNear( LE1._ray, foundSegs ); + for ( size_t i = 0; i < foundSegs.size(); ++i ) + { + if ( ! L1.IsAdjacent( *foundSegs[i], &LE1 ) && + intersection.Compute( *foundSegs[i], LE1._ray )) + { + const double dist2DToL2 = intersection._param2; + double newLen2D = dist2DToL2 / 2; + if ( newLen2D < 1.1 * LE1._length2D ) // collision! + { + if ( newLen2D > 0 || !L1._advancable ) + { + blockedEdgesList.push_back( &LE1 ); + if ( L1._advancable && newLen2D > 0 ) + { + edgeLenLimitList.push_back( make_pair( &LE1, newLen2D )); + blockedEdgesList.push_back( &L2._lEdges[ foundSegs[i]->_indexInLine ]); + blockedEdgesList.push_back( &L2._lEdges[ foundSegs[i]->_indexInLine + 1 ]); + } + else // here dist2DToL2 < 0 and LE1._length2D == 0 + { + _LayerEdge* LE2[2] = { & L2._lEdges[ foundSegs[i]->_indexInLine ], + & L2._lEdges[ foundSegs[i]->_indexInLine + 1 ] }; + _Segment outSeg2( LE2[0]->_uvOut, LE2[1]->_uvOut ); + intersection.Compute( outSeg2, LE1._ray ); + newLen2D = intersection._param2 / 2; + if ( newLen2D > 0 ) + { + edgeLenLimitList.push_back( make_pair( LE2[0], newLen2D )); + edgeLenLimitList.push_back( make_pair( LE2[1], newLen2D )); + } + } + } + } + } + } + } + } + } + + // limit length of _LayerEdge's that are extrema of _PolyLine's + // to avoid intersection of these _LayerEdge's + for ( size_t iL1 = 0; iL1 < _polyLineVec.size(); ++iL1 ) + { + _PolyLine& L = _polyLineVec[ iL1 ]; + if ( L._lEdges.size() < 4 ) // all intermediate _LayerEdge's intersect with extremum ones + { + _LayerEdge& LEL = L._leftLine->_lEdges.back(); + _LayerEdge& LER = L._lEdges.back(); + _Segment segL( LEL._uvOut, LEL._uvIn ); + _Segment segR( LER._uvOut, LER._uvIn ); + double newLen2DL, newLen2DR; + if ( intersection.Compute( segL, LER._ray )) + { + newLen2DR = intersection._param2 / 2; + newLen2DL = LEL._length2D * intersection._param1 / 2; + } + else if ( intersection.Compute( segR, LEL._ray )) + { + newLen2DL = intersection._param2 / 2; + newLen2DR = LER._length2D * intersection._param1 / 2; + } + else + { + continue; + } + if ( newLen2DL > 0 && newLen2DR > 0 ) + { + if ( newLen2DL < 1.1 * LEL._length2D ) + edgeLenLimitList.push_back( make_pair( &LEL, newLen2DL )); + if ( newLen2DR < 1.1 * LER._length2D ) + edgeLenLimitList.push_back( make_pair( &LER, newLen2DR )); + } + } + } + + // set limited length to _LayerEdge's + list< pair< _LayerEdge*, double > >::iterator edge2Len = edgeLenLimitList.begin(); + for ( ; edge2Len != edgeLenLimitList.end(); ++edge2Len ) + { + _LayerEdge* LE = edge2Len->first; + if ( LE->_length2D > edge2Len->second ) + { + LE->_isBlocked = false; + LE->SetNewLength( edge2Len->second / LE->_len2dTo3dRatio ); + } + LE->_isBlocked = true; + } + + // block inflation of _LayerEdge's + list< _LayerEdge* >::iterator edge = blockedEdgesList.begin(); + for ( ; edge != blockedEdgesList.end(); ++edge ) + (*edge)->_isBlocked = true; + + // find a not blocked _LayerEdge + for ( size_t iL = 0; iL < _polyLineVec.size(); ++iL ) + { + _PolyLine& L = _polyLineVec[ iL ]; + if ( !L._advancable ) continue; + for ( size_t iLE = L.FirstLEdge(); iLE < L._lEdges.size(); ++iLE ) + if ( !L._lEdges[ iLE ]._isBlocked ) + return false; + } + + return true; +} + +//================================================================================ +/*! + * \brief Create new edges and shrink edges existing on a non-advancable _PolyLine + * adjacent to an advancable one. + */ +//================================================================================ + +bool _ViscousBuilder2D::shrink() +{ + gp_Pnt2d uv; //gp_Vec2d tangent; + _SegmentIntersection intersection; + double sign; + + for ( size_t iL1 = 0; iL1 < _polyLineVec.size(); ++iL1 ) + { + _PolyLine& L = _polyLineVec[ iL1 ]; // line with no layers + if ( L._advancable ) + continue; + const int nbAdvancable = ( L._rightLine->_advancable + L._leftLine->_advancable ); + if ( nbAdvancable == 0 ) + continue; + + const TopoDS_Vertex& V1 = L._wire->FirstVertex( L._edgeInd ); + const TopoDS_Vertex& V2 = L._wire->LastVertex ( L._edgeInd ); + const int v1ID = getMeshDS()->ShapeToIndex( V1 ); + const int v2ID = getMeshDS()->ShapeToIndex( V2 ); + const bool isShrinkableL = ! _noShrinkVert.count( v1ID ) && L._leftLine->_advancable; + const bool isShrinkableR = ! _noShrinkVert.count( v2ID ) && L._rightLine->_advancable; + if ( !isShrinkableL && !isShrinkableR ) + continue; + + const TopoDS_Edge& E = L._wire->Edge ( L._edgeInd ); + const int edgeID = L._wire->EdgeID ( L._edgeInd ); + const double edgeLen = L._wire->EdgeLength ( L._edgeInd ); + Handle(Geom2d_Curve) pcurve = L._wire->Curve2d ( L._edgeInd ); + const bool edgeReversed = ( E.Orientation() == TopAbs_REVERSED ); + + SMESH_MesherHelper helper( *_mesh ); // to create nodes and edges on E + helper.SetSubShape( E ); + helper.SetElementsOnShape( true ); + + // Check a FACE adjacent to _face by E + bool existingNodesFound = false; + TopoDS_Face adjFace; + PShapeIteratorPtr faceIt = _helper.GetAncestors( E, *_mesh, TopAbs_FACE ); + while ( const TopoDS_Shape* f = faceIt->next() ) + if ( !_face.IsSame( *f )) + { + adjFace = TopoDS::Face( *f ); + SMESH_ProxyMesh::Ptr pm = _ProxyMeshHolder::FindProxyMeshOfFace( adjFace, *_mesh ); + if ( !pm || pm->NbProxySubMeshes() == 0 /*|| !pm->GetProxySubMesh( E )*/) + { + // There are no viscous layers on an adjacent FACE, clear it's 2D mesh + removeMeshFaces( adjFace ); + // if ( removeMeshFaces( adjFace )) + // _clearedFaces.push_back( adjFace ); // to re-compute after all + } + else + { + // There are viscous layers on the adjacent FACE; shrink must be already done; + // + // copy layer nodes + // + const vector& points = L._wire->GetUVPtStruct(); + int iPFrom = L._firstPntInd, iPTo = L._lastPntInd; + if ( isShrinkableL ) + { + const THypVL* hyp = getLineHypothesis( L._leftLine->_index ); + vector& uvVec = L._lEdges.front()._uvRefined; + for ( int i = 0; i < hyp->GetNumberLayers(); ++i ) { + const UVPtStruct& uvPt = points[ iPFrom + i + 1 ]; + L._leftNodes.push_back( uvPt.node ); + uvVec.push_back ( pcurve->Value( uvPt.param ).XY() ); + } + iPFrom += hyp->GetNumberLayers(); + } + if ( isShrinkableR ) + { + const THypVL* hyp = getLineHypothesis( L._rightLine->_index ); + vector& uvVec = L._lEdges.back()._uvRefined; + for ( int i = 0; i < hyp->GetNumberLayers(); ++i ) { + const UVPtStruct& uvPt = points[ iPTo - i - 1 ]; + L._rightNodes.push_back( uvPt.node ); + uvVec.push_back ( pcurve->Value( uvPt.param ).XY() ); + } + iPTo -= hyp->GetNumberLayers(); + } + // make proxy sub-mesh data of present nodes + // + UVPtStructVec nodeDataVec( & points[ iPFrom ], & points[ iPTo + 1 ]); + + double normSize = nodeDataVec.back().normParam - nodeDataVec.front().normParam; + for ( int iP = nodeDataVec.size()-1; iP >= 0 ; --iP ) + nodeDataVec[iP].normParam = + ( nodeDataVec[iP].normParam - nodeDataVec[0].normParam ) / normSize; + + const SMDS_MeshNode* n = nodeDataVec.front().node; + if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX ) + nodeDataVec.front().param = L._wire->FirstU( L._edgeInd ); + n = nodeDataVec.back().node; + if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX ) + nodeDataVec.back().param = L._wire->LastU( L._edgeInd ); + + _ProxyMeshOfFace::_EdgeSubMesh* myEdgeSM = getProxyMesh()->GetEdgeSubMesh( edgeID ); + myEdgeSM->SetUVPtStructVec( nodeDataVec ); + + existingNodesFound = true; + break; + } + } // loop on FACEs sharing E + + // Commented as a case with a seam EDGE (issue 0052461) is hard to support + // because SMESH_ProxyMesh can't hold different sub-meshes for two + // 2D representations of the seam. But such a case is not a real practice one. + // Check if L is an already shrinked seam + // if ( adjFace.IsNull() && _helper.IsRealSeam( edgeID )) + // { + // for ( int iL2 = iL1-1; iL2 > -1; --iL2 ) + // { + // _PolyLine& L2 = _polyLineVec[ iL2 ]; + // if ( edgeID == L2._wire->EdgeID( L2._edgeInd )) + // { + // // copy layer nodes + // const int seamPar = _helper.GetPeriodicIndex(); + // vector& uvVec = L._lEdges.front()._uvRefined; + // if ( isShrinkableL ) + // { + // L._leftNodes = L2._rightNodes; + // uvVec = L2._lEdges.back()._uvRefined; + // } + // if ( isShrinkableR ) + // { + // L._rightNodes = L2._leftNodes; + // uvVec = L2._lEdges.front()._uvRefined; + // } + // for ( size_t i = 0; i < uvVec.size(); ++i ) + // { + // gp_XY & uv = uvVec[i]; + // uv.SetCoord( seamPar, _helper.GetOtherParam( uv.Coord( seamPar ))); + // } + + // existingNodesFound = true; + // break; + // } + // } + // } + + if ( existingNodesFound ) + continue; // nothing more to do in this case + + double u1 = L._wire->FirstU( L._edgeInd ), uf = u1; + double u2 = L._wire->LastU ( L._edgeInd ), ul = u2; + + // a ratio to pass 2D <--> 1D + const double len1D = 1e-3; + const double len2D = pcurve->Value(uf).Distance( pcurve->Value(uf+len1D)); + double len1dTo2dRatio = len1D / len2D; + + // create a vector of proxy nodes + const vector& points = L._wire->GetUVPtStruct(); + UVPtStructVec nodeDataVec( & points[ L._firstPntInd ], + & points[ L._lastPntInd + 1 ]); + nodeDataVec.front().param = u1; // U on vertex is correct on only one of shared edges + nodeDataVec.back ().param = u2; + nodeDataVec.front().normParam = 0; + nodeDataVec.back ().normParam = 1; + + // Get length of existing segments (from an edge start to a node) and their nodes + vector< double > segLengths( nodeDataVec.size() - 1 ); + BRepAdaptor_Curve curve( E ); + for ( size_t iP = 1; iP < nodeDataVec.size(); ++iP ) + { + const double len = GCPnts_AbscissaPoint::Length( curve, uf, nodeDataVec[iP].param ); + segLengths[ iP-1 ] = len; + } + + // Move first and last parameters on EDGE (U of n1) according to layers' thickness + // and create nodes of layers on EDGE ( -x-x-x ) + + // Before + // n1 n2 n3 n4 + // x-----x-----x-----x----- + // | e1 e2 e3 e4 + + // After + // n1 n2 n3 + // x-x-x-x-----x-----x---- + // | | | | e1 e2 e3 + + int isRShrinkedForAdjacent; + UVPtStructVec nodeDataForAdjacent; + for ( int isR = 0; isR < 2; ++isR ) + { + _PolyLine* L2 = isR ? L._rightLine : L._leftLine; // line with layers + if ( !L2->_advancable && + !toShrinkForAdjacent( adjFace, E, L._wire->FirstVertex( L._edgeInd + isR ))) + continue; + if ( isR ? !isShrinkableR : !isShrinkableL ) + continue; + + double & u = isR ? u2 : u1; // param to move + double u0 = isR ? ul : uf; // init value of the param to move + int iPEnd = isR ? nodeDataVec.size() - 1 : 0; + + _LayerEdge& nearLE = isR ? L._lEdges.back() : L._lEdges.front(); + _LayerEdge& farLE = isR ? L._lEdges.front() : L._lEdges.back(); + + // try to find length of advancement along L by intersecting L with + // an adjacent _Segment of L2 + + double& length2D = nearLE._length2D; + double length1D = 0; + sign = ( isR ^ edgeReversed ) ? -1. : 1.; + + bool isConvex = false; + if ( L2->_advancable ) + { + const uvPtStruct& tang2P1 = points[ isR ? L2->_firstPntInd : L2->_lastPntInd ]; + const uvPtStruct& tang2P2 = points[ isR ? L2->_firstPntInd+1 : L2->_lastPntInd-1 ]; + gp_XY seg2Dir( tang2P2.u - tang2P1.u, + tang2P2.v - tang2P1.v ); + int iFSeg2 = isR ? 0 : L2->_segments.size() - 1; + int iLSeg2 = isR ? 1 : L2->_segments.size() - 2; + gp_XY uvLSeg2In = L2->_lEdges[ iLSeg2 ]._uvIn; + Handle(Geom2d_Line) seg2Line = new Geom2d_Line( uvLSeg2In, seg2Dir ); + + Geom2dAdaptor_Curve edgeCurve( pcurve, Min( uf, ul ), Max( uf, ul )); + Geom2dAdaptor_Curve seg2Curve( seg2Line ); + Geom2dInt_GInter curveInt( edgeCurve, seg2Curve, 1e-7, 1e-7 ); + isConvex = ( curveInt.IsDone() && !curveInt.IsEmpty() ); + if ( isConvex ) { + /* convex VERTEX */ + length1D = Abs( u - curveInt.Point( 1 ).ParamOnFirst() ); + double maxDist2d = 2 * L2->_lEdges[ iLSeg2 ]._length2D; + isConvex = ( length1D < maxDist2d * len1dTo2dRatio ); + /* |L seg2 + * | o---o--- + * | / | + * |/ | L2 + * x------x--- */ + } + if ( !isConvex ) { /* concave VERTEX */ /* o-----o--- + * \ | + * \ | L2 + * x--x--- + * / + * L / */ + length2D = L2->_lEdges[ iFSeg2 ]._length2D; + //if ( L2->_advancable ) continue; + } + } + else // L2 is advancable but in the face adjacent by L + { + length2D = farLE._length2D; + if ( length2D == 0 ) { + _LayerEdge& neighborLE = + ( isR ? L._leftLine->_lEdges.back() : L._rightLine->_lEdges.front() ); + length2D = neighborLE._length2D; + if ( length2D == 0 ) + length2D = _maxThickness * nearLE._len2dTo3dRatio; + } + } + + // move u to the internal boundary of layers + // u --> u + // x-x-x-x-----x-----x---- + double maxLen3D = Min( _maxThickness, edgeLen / ( 1 + nbAdvancable )); + double maxLen2D = maxLen3D * nearLE._len2dTo3dRatio; + if ( !length2D ) length2D = length1D / len1dTo2dRatio; + if ( Abs( length2D ) > maxLen2D ) + length2D = maxLen2D; + nearLE._uvIn = nearLE._uvOut + nearLE._normal2D * length2D; + + u += length2D * len1dTo2dRatio * sign; + nodeDataVec[ iPEnd ].param = u; + + gp_Pnt2d newUV = pcurve->Value( u ); + nodeDataVec[ iPEnd ].u = newUV.X(); + nodeDataVec[ iPEnd ].v = newUV.Y(); + + // compute params of layers on L + vector heights; + const THypVL* hyp = getLineHypothesis( L2->_index ); + calcLayersHeight( u - u0, heights, hyp ); + // + vector< double > params( heights.size() ); + for ( size_t i = 0; i < params.size(); ++i ) + params[ i ] = u0 + heights[ i ]; + + // create nodes of layers and edges between them + // x-x-x-x--- + vector< const SMDS_MeshNode* >& layersNode = isR ? L._rightNodes : L._leftNodes; + vector& nodeUV = ( isR ? L._lEdges.back() : L._lEdges[0] )._uvRefined; + nodeUV.resize ( hyp->GetNumberLayers() ); + layersNode.resize( hyp->GetNumberLayers() ); + const SMDS_MeshNode* vertexNode = nodeDataVec[ iPEnd ].node; + const SMDS_MeshNode * prevNode = vertexNode; + for ( size_t i = 0; i < params.size(); ++i ) + { + const gp_Pnt p = curve.Value( params[i] ); + layersNode[ i ] = helper.AddNode( p.X(), p.Y(), p.Z(), /*id=*/0, params[i] ); + nodeUV [ i ] = pcurve->Value( params[i] ).XY(); + helper.AddEdge( prevNode, layersNode[ i ] ); + prevNode = layersNode[ i ]; + } + + // store data of layer nodes made for adjacent FACE + if ( !L2->_advancable ) + { + isRShrinkedForAdjacent = isR; + nodeDataForAdjacent.resize( hyp->GetNumberLayers() ); + + size_t iFrw = 0, iRev = nodeDataForAdjacent.size()-1, *i = isR ? &iRev : &iFrw; + nodeDataForAdjacent[ *i ] = points[ isR ? L._lastPntInd : L._firstPntInd ]; + nodeDataForAdjacent[ *i ].param = u0; + nodeDataForAdjacent[ *i ].normParam = isR; + for ( ++iFrw, --iRev; iFrw < layersNode.size(); ++iFrw, --iRev ) + { + nodeDataForAdjacent[ *i ].node = layersNode[ iFrw - 1 ]; + nodeDataForAdjacent[ *i ].u = nodeUV [ iFrw - 1 ].X(); + nodeDataForAdjacent[ *i ].v = nodeUV [ iFrw - 1 ].Y(); + nodeDataForAdjacent[ *i ].param = params [ iFrw - 1 ]; + } + } + // replace a node on vertex by a node of last (most internal) layer + // in a segment on E + SMDS_ElemIteratorPtr segIt = vertexNode->GetInverseElementIterator( SMDSAbs_Edge ); + const SMDS_MeshNode* segNodes[3]; + while ( segIt->more() ) + { + const SMDS_MeshElement* segment = segIt->next(); + if ( segment->getshapeId() != edgeID ) continue; + + const int nbNodes = segment->NbNodes(); + for ( int i = 0; i < nbNodes; ++i ) + { + const SMDS_MeshNode* n = segment->GetNode( i ); + segNodes[ i ] = ( n == vertexNode ? layersNode.back() : n ); + } + getMeshDS()->ChangeElementNodes( segment, segNodes, nbNodes ); + break; + } + nodeDataVec[ iPEnd ].node = layersNode.back(); + + } // loop on the extremities of L + + // Shrink edges to fit in between the layers at EDGE ends + + double newLength = GCPnts_AbscissaPoint::Length( curve, u1, u2 ); + double lenRatio = newLength / edgeLen * ( edgeReversed ? -1. : 1. ); + for ( size_t iP = 1; iP < nodeDataVec.size()-1; ++iP ) + { + const SMDS_MeshNode* oldNode = nodeDataVec[iP].node; + + GCPnts_AbscissaPoint discret( curve, segLengths[iP-1] * lenRatio, u1 ); + if ( !discret.IsDone() ) + throw SALOME_Exception(LOCALIZED("GCPnts_AbscissaPoint failed")); + + nodeDataVec[iP].param = discret.Parameter(); + if ( oldNode->GetPosition()->GetTypeOfPosition() != SMDS_TOP_EDGE ) + throw SALOME_Exception(SMESH_Comment("ViscousBuilder2D: not SMDS_TOP_EDGE node position: ") + << oldNode->GetPosition()->GetTypeOfPosition() + << " of node " << oldNode->GetID()); + SMDS_EdgePosition* pos = static_cast( oldNode->GetPosition() ); + pos->SetUParameter( nodeDataVec[iP].param ); + + gp_Pnt newP = curve.Value( nodeDataVec[iP].param ); + getMeshDS()->MoveNode( oldNode, newP.X(), newP.Y(), newP.Z() ); + + gp_Pnt2d newUV = pcurve->Value( nodeDataVec[iP].param ).XY(); + nodeDataVec[iP].u = newUV.X(); + nodeDataVec[iP].v = newUV.Y(); + nodeDataVec[iP].normParam = segLengths[iP-1] / edgeLen; + // nodeDataVec[iP].x = segLengths[iP-1] / edgeLen; + // nodeDataVec[iP].y = segLengths[iP-1] / edgeLen; + } + + // Add nodeDataForAdjacent to nodeDataVec + + if ( !nodeDataForAdjacent.empty() ) + { + const double par1 = isRShrinkedForAdjacent ? u2 : uf; + const double par2 = isRShrinkedForAdjacent ? ul : u1; + const double shrinkLen = GCPnts_AbscissaPoint::Length( curve, par1, par2 ); + + // compute new normParam for nodeDataVec + for ( size_t iP = 0; iP < nodeDataVec.size()-1; ++iP ) + nodeDataVec[iP+1].normParam = segLengths[iP] / ( edgeLen + shrinkLen ); + double normDelta = 1 - nodeDataVec.back().normParam; + if ( !isRShrinkedForAdjacent ) + for ( size_t iP = 0; iP < nodeDataVec.size(); ++iP ) + nodeDataVec[iP].normParam += normDelta; + + // compute new normParam for nodeDataForAdjacent + const double deltaR = isRShrinkedForAdjacent ? nodeDataVec.back().normParam : 0; + for ( size_t iP = !isRShrinkedForAdjacent; iP < nodeDataForAdjacent.size(); ++iP ) + { + double lenFromPar1 = + GCPnts_AbscissaPoint::Length( curve, par1, nodeDataForAdjacent[iP].param ); + nodeDataForAdjacent[iP].normParam = deltaR + normDelta * lenFromPar1 / shrinkLen; + } + // concatenate nodeDataVec and nodeDataForAdjacent + nodeDataVec.insert(( isRShrinkedForAdjacent ? nodeDataVec.end() : nodeDataVec.begin() ), + nodeDataForAdjacent.begin(), nodeDataForAdjacent.end() ); + } + + // Extend nodeDataVec by a node located at the end of not shared _LayerEdge + /* n - to add to nodeDataVec + * o-----o--- + * |\ | + * | o---o--- + * | |x--x--- L2 + * | / + * |/ L + * x + * / */ + for ( int isR = 0; isR < 2; ++isR ) + { + _PolyLine& L2 = *( isR ? L._rightLine : L._leftLine ); // line with layers + if ( ! L2._advancable || L.IsCommonEdgeShared( L2 ) ) + continue; + vector< const SMDS_MeshNode* >& layerNodes2 = isR ? L2._leftNodes : L2._rightNodes; + _LayerEdge& LE2 = isR ? L2._lEdges.front() : L2._lEdges.back(); + if ( layerNodes2.empty() ) + { + // refine the not shared _LayerEdge + vector layersHeight; + calcLayersHeight( LE2._length2D, layersHeight, getLineHypothesis( L2._index )); + + vector& nodeUV2 = LE2._uvRefined; + nodeUV2.resize ( layersHeight.size() ); + layerNodes2.resize( layersHeight.size() ); + for ( size_t i = 0; i < layersHeight.size(); ++i ) + { + gp_XY uv = LE2._uvOut + LE2._normal2D * layersHeight[i]; + gp_Pnt p = _surface->Value( uv.X(), uv.Y() ); + nodeUV2 [ i ] = uv; + layerNodes2[ i ] = _helper.AddNode( p.X(), p.Y(), p.Z(), /*id=*/0, uv.X(), uv.Y() ); + } + } + UVPtStruct ptOfNode; + ptOfNode.u = LE2._uvRefined.back().X(); + ptOfNode.v = LE2._uvRefined.back().Y(); + ptOfNode.node = layerNodes2.back(); + ptOfNode.param = isR ? ul : uf; + ptOfNode.normParam = isR ? 1 : 0; + + nodeDataVec.insert(( isR ? nodeDataVec.end() : nodeDataVec.begin() ), ptOfNode ); + + // recompute normParam of nodes in nodeDataVec + newLength = GCPnts_AbscissaPoint::Length( curve, + nodeDataVec.front().param, + nodeDataVec.back().param); + for ( size_t iP = 1; iP < nodeDataVec.size(); ++iP ) + { + const double len = GCPnts_AbscissaPoint::Length( curve, + nodeDataVec.front().param, + nodeDataVec[iP].param ); + nodeDataVec[iP].normParam = len / newLength; + } + } + + // create a proxy sub-mesh containing the moved nodes + _ProxyMeshOfFace::_EdgeSubMesh* edgeSM = getProxyMesh()->GetEdgeSubMesh( edgeID ); + edgeSM->SetUVPtStructVec( nodeDataVec ); + + // set a sub-mesh event listener to remove just created edges when + // "ViscousLayers2D" hypothesis is modified + VISCOUS_3D::ToClearSubWithMain( _mesh->GetSubMesh( E ), _face ); + + } // loop on _polyLineVec + + return true; +} + +//================================================================================ +/*! + * \brief Returns true if there will be a shrinked mesh on EDGE E of FACE adjFace + * near VERTEX V + */ +//================================================================================ + +bool _ViscousBuilder2D::toShrinkForAdjacent( const TopoDS_Face& adjFace, + const TopoDS_Edge& E, + const TopoDS_Vertex& V) +{ + if ( _noShrinkVert.count( getMeshDS()->ShapeToIndex( V )) || adjFace.IsNull() ) + return false; + + vector< const StdMeshers_ViscousLayers2D* > hyps; + vector< TopoDS_Shape > hypShapes; + if ( VISCOUS_2D::findHyps( *_mesh, adjFace, hyps, hypShapes )) + { + VISCOUS_2D::_ViscousBuilder2D builder( *_mesh, adjFace, hyps, hypShapes ); + builder._faceSideVec = StdMeshers_FaceSide::GetFaceWires( adjFace, *_mesh, true, _error ); + builder.findEdgesWithLayers(); + + PShapeIteratorPtr edgeIt = _helper.GetAncestors( V, *_mesh, TopAbs_EDGE ); + while ( const TopoDS_Shape* edgeAtV = edgeIt->next() ) + { + if ( !edgeAtV->IsSame( E ) && + _helper.IsSubShape( *edgeAtV, adjFace ) && + !builder._ignoreShapeIds.count( getMeshDS()->ShapeToIndex( *edgeAtV ))) + { + return true; + } + } + } + return false; +} + +//================================================================================ +/*! + * \brief Make faces + */ +//================================================================================ + +bool _ViscousBuilder2D::refine() +{ + // find out orientation of faces to create + bool isReverse = + ( _helper.GetSubShapeOri( _mesh->GetShapeToMesh(), _face ) == TopAbs_REVERSED ); + + // store a proxyMesh in a sub-mesh + // make faces on each _PolyLine + vector< double > layersHeight; + double prevLen2D = -1; + for ( size_t iL = 0; iL < _polyLineVec.size(); ++iL ) + { + _PolyLine& L = _polyLineVec[ iL ]; + if ( !L._advancable ) continue; + + // replace an inactive (1st) _LayerEdge with an active one of a neighbour _PolyLine + //size_t iLE = 0, nbLE = L._lEdges.size(); + const bool leftEdgeShared = L.IsCommonEdgeShared( *L._leftLine ); + const bool rightEdgeShared = L.IsCommonEdgeShared( *L._rightLine ); + if ( /*!L._leftLine->_advancable &&*/ leftEdgeShared ) + { + L._lEdges[0] = L._leftLine->_lEdges.back(); + //iLE += int( !L._leftLine->_advancable ); + } + if ( !L._rightLine->_advancable && rightEdgeShared ) + { + L._lEdges.back() = L._rightLine->_lEdges[0]; + //--nbLE; + } + + // limit length of neighbour _LayerEdge's to avoid sharp change of layers thickness + + vector< double > segLen( L._lEdges.size() ); + segLen[0] = 0.0; + + // check if length modification is usefull: look for _LayerEdge's + // with length limited due to collisions + bool lenLimited = false; + for ( size_t iLE = 1; ( iLE < L._lEdges.size()-1 && !lenLimited ); ++iLE ) + lenLimited = L._lEdges[ iLE ]._isBlocked; + + if ( lenLimited ) + { + for ( size_t i = 1; i < segLen.size(); ++i ) + { + // accumulate length of segments + double sLen = (L._lEdges[i-1]._uvOut - L._lEdges[i]._uvOut ).Modulus(); + segLen[i] = segLen[i-1] + sLen; + } + const double totSegLen = segLen.back(); + // normalize the accumulated length + for ( size_t iS = 1; iS < segLen.size(); ++iS ) + segLen[iS] /= totSegLen; + + for ( int isR = 0; isR < 2; ++isR ) + { + size_t iF = 0, iL = L._lEdges.size()-1; + size_t *i = isR ? &iL : &iF; + _LayerEdge* prevLE = & L._lEdges[ *i ]; + double weight = 0; + for ( ++iF, --iL; iF < L._lEdges.size()-1; ++iF, --iL ) + { + _LayerEdge& LE = L._lEdges[*i]; + if ( prevLE->_length2D > 0 ) + { + gp_XY tangent ( LE._normal2D.Y(), -LE._normal2D.X() ); + weight += Abs( tangent * ( prevLE->_uvIn - LE._uvIn )) / totSegLen; + // gp_XY prevTang( LE._uvOut - prevLE->_uvOut ); + // gp_XY prevNorm( -prevTang.Y(), prevTang.X() ); + gp_XY prevNorm = LE._normal2D; + double prevProj = prevNorm * ( prevLE->_uvIn - prevLE->_uvOut ); + if ( prevProj > 0 ) { + prevProj /= prevNorm.Modulus(); + if ( LE._length2D < prevProj ) + weight += 0.75 * ( 1 - weight ); // length decrease is more preferable + LE._length2D = weight * LE._length2D + ( 1 - weight ) * prevProj; + LE._uvIn = LE._uvOut + LE._normal2D * LE._length2D; + } + } + prevLE = & LE; + } + } + } + // DEBUG: to see _uvRefined. cout can be redirected to hide NETGEN output + // cerr << "import smesh" << endl << "mesh = smesh.Mesh()"<< endl; + + const vector& points = L._wire->GetUVPtStruct(); + + // analyse extremities of the _PolyLine to find existing nodes + const TopoDS_Vertex& V1 = L._wire->FirstVertex( L._edgeInd ); + const TopoDS_Vertex& V2 = L._wire->LastVertex ( L._edgeInd ); + const int v1ID = getMeshDS()->ShapeToIndex( V1 ); + const int v2ID = getMeshDS()->ShapeToIndex( V2 ); + const bool isShrinkableL = ! _noShrinkVert.count( v1ID ); + const bool isShrinkableR = ! _noShrinkVert.count( v2ID ); + + bool hasLeftNode = ( !L._leftLine->_rightNodes.empty() && leftEdgeShared ); + bool hasRightNode = ( !L._rightLine->_leftNodes.empty() && rightEdgeShared ); + bool hasOwnLeftNode = ( !L._leftNodes.empty() ); + bool hasOwnRightNode = ( !L._rightNodes.empty() ); + bool isClosedEdge = ( points[ L._firstPntInd ].node == points[ L._lastPntInd ].node ); + const size_t + nbN = L._lastPntInd - L._firstPntInd + 1, + iN0 = ( hasLeftNode || hasOwnLeftNode || isClosedEdge || !isShrinkableL ), + iNE = nbN - ( hasRightNode || hasOwnRightNode || !isShrinkableR ); + + // update _uvIn of end _LayerEdge's by existing nodes + const SMDS_MeshNode *nL = 0, *nR = 0; + if ( hasOwnLeftNode ) nL = L._leftNodes.back(); + else if ( hasLeftNode ) nL = L._leftLine->_rightNodes.back(); + if ( hasOwnRightNode ) nR = L._rightNodes.back(); + else if ( hasRightNode ) nR = L._rightLine->_leftNodes.back(); + if ( nL ) + L._lEdges[0]._uvIn = _helper.GetNodeUV( _face, nL, points[ L._firstPntInd + 1 ].node ); + if ( nR ) + L._lEdges.back()._uvIn = _helper.GetNodeUV( _face, nR, points[ L._lastPntInd - 1 ].node ); + + // compute normalized [0;1] node parameters of nodes on a _PolyLine + vector< double > normPar( nbN ); + const double + normF = L._wire->FirstParameter( L._edgeInd ), + normL = L._wire->LastParameter ( L._edgeInd ), + normDist = normL - normF; + for ( int i = L._firstPntInd; i <= L._lastPntInd; ++i ) + normPar[ i - L._firstPntInd ] = ( points[i].normParam - normF ) / normDist; + + // Calculate UV of most inner nodes + + vector< gp_XY > innerUV( nbN ); + + // check if innerUV should be interpolated between _LayerEdge::_uvIn's + const size_t nbLE = L._lEdges.size(); + bool needInterpol = ( nbN != nbLE ); + if ( !needInterpol ) + { + // more check: compare length of inner and outer end segments + double lenIn, lenOut; + for ( int isR = 0; isR < 2 && !needInterpol; ++isR ) + { + const _Segment& segIn = isR ? L._segments.back() : L._segments[0]; + const gp_XY& uvIn1 = segIn.p1(); + const gp_XY& uvIn2 = segIn.p2(); + const gp_XY& uvOut1 = L._lEdges[ isR ? nbLE-1 : 0 ]._uvOut; + const gp_XY& uvOut2 = L._lEdges[ isR ? nbLE-2 : 1 ]._uvOut; + if ( _is2DIsotropic ) + { + lenIn = ( uvIn1 - uvIn2 ).Modulus(); + lenOut = ( uvOut1 - uvOut2 ).Modulus(); + } + else + { + lenIn = _surface->Value( uvIn1.X(), uvIn1.Y() ) + .Distance( _surface->Value( uvIn2.X(), uvIn2.Y() )); + lenOut = _surface->Value( uvOut1.X(), uvOut1.Y() ) + .Distance( _surface->Value( uvOut2.X(), uvOut2.Y() )); + } + needInterpol = ( lenIn < 0.66 * lenOut ); + } + } + + if ( needInterpol ) + { + // compute normalized accumulated length of inner segments + size_t iS; + if ( _is2DIsotropic ) + for ( iS = 1; iS < segLen.size(); ++iS ) + { + double sLen = ( L._lEdges[iS-1]._uvIn - L._lEdges[iS]._uvIn ).Modulus(); + segLen[iS] = segLen[iS-1] + sLen; + } + else + for ( iS = 1; iS < segLen.size(); ++iS ) + { + const gp_XY& uv1 = L._lEdges[iS-1]._uvIn; + const gp_XY& uv2 = L._lEdges[iS ]._uvIn; + gp_Pnt p1 = _surface->Value( uv1.X(), uv1.Y() ); + gp_Pnt p2 = _surface->Value( uv2.X(), uv2.Y() ); + double sLen = p1.Distance( p2 ); + segLen[iS] = segLen[iS-1] + sLen; + } + // normalize the accumulated length + for ( iS = 1; iS < segLen.size(); ++iS ) + segLen[iS] /= segLen.back(); + + // calculate UV of most inner nodes according to the normalized node parameters + iS = 0; + for ( size_t i = 0; i < innerUV.size(); ++i ) + { + while ( normPar[i] > segLen[iS+1] ) + ++iS; + double r = ( normPar[i] - segLen[iS] ) / ( segLen[iS+1] - segLen[iS] ); + innerUV[ i ] = r * L._lEdges[iS+1]._uvIn + (1-r) * L._lEdges[iS]._uvIn; + } + } + else // ! needInterpol + { + for ( size_t i = 0; i < nbLE; ++i ) + innerUV[ i ] = L._lEdges[i]._uvIn; + } + + // normalized height of layers + const THypVL* hyp = getLineHypothesis( iL ); + calcLayersHeight( 1., layersHeight, hyp); + + // Create layers of faces + + // nodes to create 1 layer of faces + vector< const SMDS_MeshNode* > outerNodes( nbN ); + vector< const SMDS_MeshNode* > innerNodes( nbN ); + + // initialize outerNodes by nodes of the L._wire + for ( int i = L._firstPntInd; i <= L._lastPntInd; ++i ) + outerNodes[ i-L._firstPntInd ] = points[i].node; + + L._leftNodes .reserve( hyp->GetNumberLayers() ); + L._rightNodes.reserve( hyp->GetNumberLayers() ); + int cur = 0, prev = -1; // to take into account orientation of _face + if ( isReverse ) std::swap( cur, prev ); + for ( int iF = 0; iF < hyp->GetNumberLayers(); ++iF ) // loop on layers of faces + { + // create innerNodes of a current layer + for ( size_t i = iN0; i < iNE; ++i ) + { + gp_XY uvOut = points[ L._firstPntInd + i ].UV(); + gp_XY& uvIn = innerUV[ i ]; + gp_XY uv = layersHeight[ iF ] * uvIn + ( 1.-layersHeight[ iF ]) * uvOut; + gp_Pnt p = _surface->Value( uv.X(), uv.Y() ); + innerNodes[i] = _helper.AddNode( p.X(), p.Y(), p.Z(), /*id=*/0, uv.X(), uv.Y() ); + } + // use nodes created for adjacent _PolyLine's + if ( hasOwnLeftNode ) innerNodes.front() = L._leftNodes [ iF ]; + else if ( hasLeftNode ) innerNodes.front() = L._leftLine->_rightNodes[ iF ]; + if ( hasOwnRightNode ) innerNodes.back() = L._rightNodes[ iF ]; + else if ( hasRightNode ) innerNodes.back() = L._rightLine->_leftNodes[ iF ]; + if ( isClosedEdge ) innerNodes.front() = innerNodes.back(); // circle + if ( !isShrinkableL ) innerNodes.front() = outerNodes.front(); + if ( !isShrinkableR ) innerNodes.back() = outerNodes.back(); + if ( !hasOwnLeftNode ) L._leftNodes.push_back( innerNodes.front() ); + if ( !hasOwnRightNode ) L._rightNodes.push_back( innerNodes.back() ); + + // create faces + for ( size_t i = 1; i < innerNodes.size(); ++i ) + if ( SMDS_MeshElement* f = _helper.AddFace( outerNodes[ i+prev ], outerNodes[ i+cur ], + innerNodes[ i+cur ], innerNodes[ i+prev ])) + L._newFaces.insert( L._newFaces.end(), f ); + + outerNodes.swap( innerNodes ); + } + + // faces between not shared _LayerEdge's (at concave VERTEX) + for ( int isR = 0; isR < 2; ++isR ) + { + if ( isR ? rightEdgeShared : leftEdgeShared ) + continue; + vector< const SMDS_MeshNode* > & + lNodes = (isR ? L._rightNodes : L._leftLine->_rightNodes ), + rNodes = (isR ? L._rightLine->_leftNodes : L._leftNodes ); + if ( lNodes.empty() || rNodes.empty() || lNodes.size() != rNodes.size() ) + continue; + + for ( size_t i = 1; i < lNodes.size(); ++i ) + _helper.AddFace( lNodes[ i+prev ], rNodes[ i+prev ], + rNodes[ i+cur ], lNodes[ i+cur ]); + + const UVPtStruct& ptOnVertex = points[ isR ? L._lastPntInd : L._firstPntInd ]; + if ( isReverse ) + _helper.AddFace( ptOnVertex.node, lNodes[ 0 ], rNodes[ 0 ]); + else + _helper.AddFace( ptOnVertex.node, rNodes[ 0 ], lNodes[ 0 ]); + } + + // Fill the _ProxyMeshOfFace + + UVPtStructVec nodeDataVec( outerNodes.size() ); // outerNodes swapped with innerNodes + for ( size_t i = 0; i < outerNodes.size(); ++i ) + { + gp_XY uv = _helper.GetNodeUV( _face, outerNodes[i] ); + nodeDataVec[i].u = uv.X(); + nodeDataVec[i].v = uv.Y(); + nodeDataVec[i].node = outerNodes[i]; + nodeDataVec[i].param = points [i + L._firstPntInd].param; + nodeDataVec[i].normParam = normPar[i]; + nodeDataVec[i].x = normPar[i]; + nodeDataVec[i].y = normPar[i]; + } + nodeDataVec.front().param = L._wire->FirstU( L._edgeInd ); + nodeDataVec.back() .param = L._wire->LastU ( L._edgeInd ); + + _ProxyMeshOfFace::_EdgeSubMesh* edgeSM + = getProxyMesh()->GetEdgeSubMesh( L._wire->EdgeID( L._edgeInd )); + edgeSM->SetUVPtStructVec( nodeDataVec ); + + } // loop on _PolyLine's + + // re-compute FACEs whose mesh was removed by shrink() + for ( size_t i = 0; i < _clearedFaces.size(); ++i ) + { + SMESH_subMesh* sm = _mesh->GetSubMesh( _clearedFaces[i] ); + if ( sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE ) + sm->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + } + + return true; +} + +//================================================================================ +/*! + * \brief Improve quality of the created mesh elements + */ +//================================================================================ + +bool _ViscousBuilder2D::improve() +{ + if ( !_proxyMesh ) + return false; + + // fixed nodes on EDGE's + std::set fixedNodes; + for ( size_t iWire = 0; iWire < _faceSideVec.size(); ++iWire ) + { + StdMeshers_FaceSidePtr wire = _faceSideVec[ iWire ]; + const vector& points = wire->GetUVPtStruct(); + for ( size_t i = 0; i < points.size(); ++i ) + fixedNodes.insert( fixedNodes.end(), points[i].node ); + } + // fixed proxy nodes + for ( size_t iL = 0; iL < _polyLineVec.size(); ++iL ) + { + _PolyLine& L = _polyLineVec[ iL ]; + const TopoDS_Edge& E = L._wire->Edge( L._edgeInd ); + if ( const SMESH_ProxyMesh::SubMesh* sm = _proxyMesh->GetProxySubMesh( E )) + { + const UVPtStructVec& points = sm->GetUVPtStructVec(); + for ( size_t i = 0; i < points.size(); ++i ) + fixedNodes.insert( fixedNodes.end(), points[i].node ); + } + for ( size_t i = 0; i < L._rightNodes.size(); ++i ) + fixedNodes.insert( fixedNodes.end(), L._rightNodes[i] ); + } + + // smoothing + SMESH_MeshEditor editor( _mesh ); + for ( size_t iL = 0; iL < _polyLineVec.size(); ++iL ) + { + _PolyLine& L = _polyLineVec[ iL ]; + if ( L._isStraight2D ) continue; + // SMESH_MeshEditor::SmoothMethod how = + // L._isStraight2D ? SMESH_MeshEditor::LAPLACIAN : SMESH_MeshEditor::CENTROIDAL; + //editor.Smooth( L._newFaces, fixedNodes, how, /*nbIt = */3 ); + //editor.Smooth( L._newFaces, fixedNodes, SMESH_MeshEditor::LAPLACIAN, /*nbIt = */1 ); + editor.Smooth( L._newFaces, fixedNodes, SMESH_MeshEditor::CENTROIDAL, /*nbIt = */3 ); + } + return true; +} + +//================================================================================ +/*! + * \brief Remove elements and nodes from a face + */ +//================================================================================ + +bool _ViscousBuilder2D::removeMeshFaces(const TopoDS_Shape& face) +{ + // we don't use SMESH_subMesh::ComputeStateEngine() because of a listener + // which clears EDGEs together with _face. + bool thereWereElems = false; + SMESH_subMesh* sm = _mesh->GetSubMesh( face ); + if ( SMESHDS_SubMesh* smDS = sm->GetSubMeshDS() ) + { + SMDS_ElemIteratorPtr eIt = smDS->GetElements(); + thereWereElems = eIt->more(); + while ( eIt->more() ) getMeshDS()->RemoveFreeElement( eIt->next(), smDS ); + SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); + while ( nIt->more() ) getMeshDS()->RemoveFreeNode( nIt->next(), smDS ); + } + sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + + return thereWereElems; +} + +//================================================================================ +/*! + * \brief Returns a hypothesis for a _PolyLine + */ +//================================================================================ + +const StdMeshers_ViscousLayers2D* _ViscousBuilder2D::getLineHypothesis(int iPL) +{ + return iPL < (int)_hypOfEdge.size() ? _hypOfEdge[ iPL ] : _hyps[0]; +} + +//================================================================================ +/*! + * \brief Returns a layers thickness for a _PolyLine + */ +//================================================================================ + +double _ViscousBuilder2D::getLineThickness(int iPL) +{ + if ( const StdMeshers_ViscousLayers2D* h = getLineHypothesis( iPL )) + return Min( _maxThickness, h->GetTotalThickness() ); + return _maxThickness; +} + +//================================================================================ +/*! + * \brief Creates a _ProxyMeshOfFace and store it in a sub-mesh of FACE + */ +//================================================================================ + +_ProxyMeshOfFace* _ViscousBuilder2D::getProxyMesh() +{ + if ( _proxyMesh.get() ) + return (_ProxyMeshOfFace*) _proxyMesh.get(); + + _ProxyMeshOfFace* proxyMeshOfFace = new _ProxyMeshOfFace( *_mesh ); + _proxyMesh.reset( proxyMeshOfFace ); + new _ProxyMeshHolder( _face, _proxyMesh ); + + return proxyMeshOfFace; +} + +//================================================================================ +/*! + * \brief Calculate height of layers for the given thickness. Height is measured + * from the outer boundary + */ +//================================================================================ + +void _ViscousBuilder2D::calcLayersHeight(const double totalThick, + vector& heights, + const THypVL* hyp) +{ + const double fPowN = pow( hyp->GetStretchFactor(), hyp->GetNumberLayers() ); + heights.resize( hyp->GetNumberLayers() ); + double h0; + if ( fPowN - 1 <= numeric_limits::min() ) + h0 = totalThick / hyp->GetNumberLayers(); + else + h0 = totalThick * ( hyp->GetStretchFactor() - 1 )/( fPowN - 1 ); + + double hSum = 0, hi = h0; + for ( int i = 0; i < hyp->GetNumberLayers(); ++i ) + { + hSum += hi; + heights[ i ] = hSum; + hi *= hyp->GetStretchFactor(); + } +} + +//================================================================================ +/*! + * \brief Elongate this _LayerEdge + */ +//================================================================================ + +bool _LayerEdge::SetNewLength( const double length3D ) +{ + if ( _isBlocked ) return false; + + //_uvInPrev = _uvIn; + _length2D = length3D * _len2dTo3dRatio; + _uvIn = _uvOut + _normal2D * _length2D; + return true; +} + +//================================================================================ +/*! + * \brief Return true if _LayerEdge at a common VERTEX between EDGEs with + * and w/o layer is common to the both _PolyLine's. If this is true, nodes + * of this _LayerEdge are inflated along a _PolyLine w/o layer, else the nodes + * are inflated along _normal2D of _LayerEdge of EDGE with layer + */ +//================================================================================ + +bool _PolyLine::IsCommonEdgeShared( const _PolyLine& other ) +{ + const double tol = 1e-30; + + if ( & other == _leftLine ) + return _lEdges[0]._normal2D.IsEqual( _leftLine->_lEdges.back()._normal2D, tol ); + + if ( & other == _rightLine ) + return _lEdges.back()._normal2D.IsEqual( _rightLine->_lEdges[0]._normal2D, tol ); + + return false; +} + +//================================================================================ +/*! + * \brief Return \c true if the EDGE of this _PolyLine is concave + */ +//================================================================================ + +bool _PolyLine::IsConcave() const +{ + if ( _lEdges.size() < 2 ) + return false; + + gp_Vec2d v1( _lEdges[0]._uvOut, _lEdges[1]._uvOut ); + gp_Vec2d v2( _lEdges[0]._uvOut, _lEdges[2]._uvOut ); + const double size2 = v2.Magnitude(); + + return ( v1 ^ v2 ) / size2 < -1e-3 * size2; +} + +//================================================================================ +/*! + * \brief Constructor of SegmentTree + */ +//================================================================================ + +_SegmentTree::_SegmentTree( const vector< _Segment >& segments ): + SMESH_Quadtree() +{ + _segments.resize( segments.size() ); + for ( size_t i = 0; i < segments.size(); ++i ) + _segments[i].Set( segments[i] ); + + compute(); +} + +//================================================================================ +/*! + * \brief Return the maximal bnd box + */ +//================================================================================ + +_SegmentTree::box_type* _SegmentTree::buildRootBox() +{ + _SegmentTree::box_type* box = new _SegmentTree::box_type; + for ( size_t i = 0; i < _segments.size(); ++i ) + { + box->Add( *_segments[i]._seg->_uv[0] ); + box->Add( *_segments[i]._seg->_uv[1] ); + } + return box; +} + +//================================================================================ +/*! + * \brief Redistrubute _segments among children + */ +//================================================================================ + +void _SegmentTree::buildChildrenData() +{ + for ( int i = 0; i < _segments.size(); ++i ) + for (int j = 0; j < nbChildren(); j++) + if ( !myChildren[j]->getBox()->IsOut( *_segments[i]._seg->_uv[0], + *_segments[i]._seg->_uv[1] )) + ((_SegmentTree*)myChildren[j])->_segments.push_back( _segments[i]); + + SMESHUtils::FreeVector( _segments ); // = _elements.clear() + free memory + + for (int j = 0; j < nbChildren(); j++) + { + _SegmentTree* child = static_cast<_SegmentTree*>( myChildren[j]); + child->myIsLeaf = ( child->_segments.size() <= maxNbSegInLeaf() ); + } +} + +//================================================================================ +/*! + * \brief Return elements which can include the point + */ +//================================================================================ + +void _SegmentTree::GetSegmentsNear( const _Segment& seg, + vector< const _Segment* >& found ) +{ + if ( getBox()->IsOut( *seg._uv[0], *seg._uv[1] )) + return; + + if ( isLeaf() ) + { + for ( int i = 0; i < _segments.size(); ++i ) + if ( !_segments[i].IsOut( seg )) + found.push_back( _segments[i]._seg ); + } + else + { + for (int i = 0; i < nbChildren(); i++) + ((_SegmentTree*) myChildren[i])->GetSegmentsNear( seg, found ); + } +} + + +//================================================================================ +/*! + * \brief Return segments intersecting a ray + */ +//================================================================================ + +void _SegmentTree::GetSegmentsNear( const gp_Ax2d& ray, + vector< const _Segment* >& found ) +{ + if ( getBox()->IsOut( ray )) + return; + + if ( isLeaf() ) + { + for ( int i = 0; i < _segments.size(); ++i ) + if ( !_segments[i].IsOut( ray )) + found.push_back( _segments[i]._seg ); + } + else + { + for (int i = 0; i < nbChildren(); i++) + ((_SegmentTree*) myChildren[i])->GetSegmentsNear( ray, found ); + } +} + +//================================================================================ +/*! + * \brief Classify a _Segment + */ +//================================================================================ + +bool _SegmentTree::_SegBox::IsOut( const _Segment& seg ) const +{ + const double eps = std::numeric_limits::min(); + for ( int iC = 0; iC < 2; ++iC ) + { + if ( seg._uv[0]->Coord(iC+1) < _seg->_uv[ _iMin[iC]]->Coord(iC+1)+eps && + seg._uv[1]->Coord(iC+1) < _seg->_uv[ _iMin[iC]]->Coord(iC+1)+eps ) + return true; + if ( seg._uv[0]->Coord(iC+1) > _seg->_uv[ 1-_iMin[iC]]->Coord(iC+1)-eps && + seg._uv[1]->Coord(iC+1) > _seg->_uv[ 1-_iMin[iC]]->Coord(iC+1)-eps ) + return true; + } + return false; +} + +//================================================================================ +/*! + * \brief Classify a ray + */ +//================================================================================ + +bool _SegmentTree::_SegBox::IsOut( const gp_Ax2d& ray ) const +{ + double distBoxCenter2Ray = + ray.Direction().XY() ^ ( ray.Location().XY() - 0.5 * (*_seg->_uv[0] + *_seg->_uv[1])); + + double boxSectionDiam = + Abs( ray.Direction().X() ) * ( _seg->_uv[1-_iMin[1]]->Y() - _seg->_uv[_iMin[1]]->Y() ) + + Abs( ray.Direction().Y() ) * ( _seg->_uv[1-_iMin[0]]->X() - _seg->_uv[_iMin[0]]->X() ); + + return Abs( distBoxCenter2Ray ) > 0.5 * boxSectionDiam; +}