From ea825222ec6cabe30833fb5e3deff17a73f3d5cd Mon Sep 17 00:00:00 2001 From: vsr Date: Mon, 15 Nov 2010 06:52:35 +0000 Subject: [PATCH] Merge from PHASE_25_BR 14/11/2010 --- doc/salome/gui/SMESH/images/a-clipping2.png | Bin 21116 -> 17327 bytes .../gui/SMESH/images/advanced_mesh_infos.png | Bin 24892 -> 28432 bytes doc/salome/gui/SMESH/images/bnd_box.png | Bin 0 -> 17441 bytes .../gui/SMESH/images/bnd_box_preview.png | Bin 0 -> 56083 bytes doc/salome/gui/SMESH/images/elem_info.png | Bin 0 -> 907 bytes doc/salome/gui/SMESH/images/eleminfo1.png | Bin 18764 -> 19088 bytes doc/salome/gui/SMESH/images/eleminfo2.png | Bin 33198 -> 36810 bytes doc/salome/gui/SMESH/images/formula5.png | Bin 0 -> 5184 bytes .../gui/SMESH/images/hexotic_parameters.png | Bin 21710 -> 23172 bytes .../gui/SMESH/images/hyp_source_edges.png | Bin 0 -> 13394 bytes .../gui/SMESH/images/hyp_source_faces.png | Bin 0 -> 13297 bytes doc/salome/gui/SMESH/images/image42.png | Bin 0 -> 857 bytes doc/salome/gui/SMESH/images/image43.png | Bin 0 -> 965 bytes doc/salome/gui/SMESH/images/image49.png | Bin 861 -> 988 bytes doc/salome/gui/SMESH/images/image79.jpg | Bin 49431 -> 57934 bytes doc/salome/gui/SMESH/images/image99.gif | Bin 10733 -> 15691 bytes .../SMESH/images/max_element_length_2d.png | Bin 0 -> 17544 bytes .../SMESH/images/max_element_length_3d.png | Bin 0 -> 17960 bytes doc/salome/gui/SMESH/images/min_distance.png | Bin 0 -> 22662 bytes .../gui/SMESH/images/min_distance_preview.png | Bin 0 -> 116380 bytes .../SMESH/input/about_quality_controls.doc | 22 +- doc/salome/gui/SMESH/input/area.doc | 3 +- doc/salome/gui/SMESH/input/aspect_ratio.doc | 12 +- .../gui/SMESH/input/aspect_ratio_3d.doc | 4 +- .../gui/SMESH/input/basic_meshing_algos.doc | 1 + doc/salome/gui/SMESH/input/clipping.doc | 13 +- doc/salome/gui/SMESH/input/index.doc | 9 +- doc/salome/gui/SMESH/input/length_2d.doc | 4 +- .../gui/SMESH/input/max_element_length_2d.doc | 29 + .../gui/SMESH/input/max_element_length_3d.doc | 30 + doc/salome/gui/SMESH/input/measurements.doc | 71 + doc/salome/gui/SMESH/input/mesh_infos.doc | 89 +- doc/salome/gui/SMESH/input/minimum_angle.doc | 3 +- .../gui/SMESH/input/modifying_meshes.doc | 1 - .../SMESH/input/selection_filter_library.doc | 10 + doc/salome/gui/SMESH/input/skew.doc | 3 +- .../gui/SMESH/input/smeshpy_interface.doc | 1 + doc/salome/gui/SMESH/input/taper.doc | 4 +- .../SMESH/input/tui_defining_hypotheses.doc | 60 +- doc/salome/gui/SMESH/input/tui_filters.doc | 40 + .../gui/SMESH/input/tui_grouping_elements.doc | 2 +- .../gui/SMESH/input/tui_measurements.doc | 84 ++ .../gui/SMESH/input/tui_quality_controls.doc | 66 + .../gui/SMESH/input/use_existing_algos.doc | 58 + doc/salome/gui/SMESH/input/volume.doc | 4 +- doc/salome/gui/SMESH/input/warping.doc | 4 +- idl/Makefile.am | 6 +- idl/SMESH_BasicHypothesis.idl | 55 + idl/SMESH_Filter.idl | 19 + idl/SMESH_Gen.idl | 4 +- idl/SMESH_Group.idl | 5 - idl/SMESH_Measurements.idl | 61 + idl/SMESH_Mesh.idl | 7 + resources/Makefile.am | 7 +- resources/SalomeApp.xml | 4 + resources/StdMeshers.xml | 26 +- resources/advanced_mesh_info.png | Bin 973 -> 988 bytes resources/mesh_bounding_box.png | Bin 0 -> 3449 bytes resources/mesh_elem_info.png | Bin 0 -> 907 bytes resources/mesh_max_element_length_2d.png | Bin 0 -> 857 bytes resources/mesh_max_element_length_3d.png | Bin 0 -> 965 bytes resources/mesh_min_dist.png | Bin 0 -> 3360 bytes src/Controls/SMESHControls.cxx | 2 + src/Controls/SMESH_Controls.cxx | 446 +++++- src/Controls/SMESH_ControlsDef.hxx | 27 + src/OBJECT/Makefile.am | 7 +- src/OBJECT/SMESH_Actor.cxx | 174 +-- src/OBJECT/SMESH_Actor.h | 18 +- src/OBJECT/SMESH_ActorDef.h | 15 +- src/OBJECT/SMESH_DeviceActor.cxx | 22 +- src/OBJECT/SMESH_DeviceActor.h | 6 +- src/OBJECT/SMESH_PreviewActorsCollection.cxx | 1 - src/OBJECT/SMESH_ScalarBarActor.cxx | 923 ++++++++++++ src/OBJECT/SMESH_ScalarBarActor.h | 246 +++ src/SMDS/SMDS_MeshElement.hxx | 2 +- src/SMESH/SMESH_Algo.hxx | 9 +- src/SMESH/SMESH_Group.cxx | 2 +- src/SMESH/SMESH_Group.hxx | 1 - src/SMESH/SMESH_HypoFilter.hxx | 2 + src/SMESH/SMESH_Hypothesis.cxx | 18 + src/SMESH/SMESH_Hypothesis.hxx | 5 + src/SMESH/SMESH_Mesh.cxx | 26 +- src/SMESH/SMESH_Mesh.hxx | 23 +- src/SMESH/SMESH_MesherHelper.cxx | 33 +- src/SMESH/SMESH_MesherHelper.hxx | 9 +- src/SMESH/SMESH_subMesh.cxx | 7 +- src/SMESHDS/SMESHDS_Group.cxx | 2 +- src/SMESHDS/SMESHDS_Group.hxx | 2 +- src/SMESHDS/SMESHDS_GroupBase.hxx | 2 +- src/SMESHDS/SMESHDS_GroupOnGeom.cxx | 2 +- src/SMESHDS/SMESHDS_GroupOnGeom.hxx | 2 +- src/SMESHDS/SMESHDS_Mesh.cxx | 34 + src/SMESHDS/SMESHDS_Mesh.hxx | 9 +- src/SMESHFiltersSelection/SMESH_Type.h | 5 + .../SMESH_TypeFilter.cxx | 31 + src/SMESHGUI/Makefile.am | 15 +- src/SMESHGUI/SMESHGUI.cxx | 1074 +++++++++---- src/SMESHGUI/SMESHGUI.h | 36 + src/SMESHGUI/SMESHGUI_ClippingDlg.cxx | 792 ++++++---- src/SMESHGUI/SMESHGUI_ClippingDlg.h | 116 +- src/SMESHGUI/SMESHGUI_FilterDlg.cxx | 20 +- src/SMESHGUI/SMESHGUI_Measurements.cxx | 1231 +++++++++++++++ src/SMESHGUI/SMESHGUI_Measurements.h | 172 +++ src/SMESHGUI/SMESHGUI_MeshInfo.cxx | 1335 +++++++++++++++++ src/SMESHGUI/SMESHGUI_MeshInfo.h | 220 +++ src/SMESHGUI/SMESHGUI_MeshOp.cxx | 5 +- src/SMESHGUI/SMESHGUI_MeshUtils.cxx | 11 + src/SMESHGUI/SMESHGUI_MeshUtils.h | 3 + .../SMESHGUI_Preferences_ScalarBarDlg.cxx | 110 +- .../SMESHGUI_Preferences_ScalarBarDlg.h | 10 + src/SMESHGUI/SMESHGUI_Selection.cxx | 45 +- src/SMESHGUI/SMESHGUI_Selection.h | 3 + src/SMESHGUI/SMESHGUI_Utils.cxx | 14 + src/SMESHGUI/SMESHGUI_Utils.h | 3 + src/SMESHGUI/SMESHGUI_VTKUtils.cxx | 108 ++ src/SMESHGUI/SMESHGUI_VTKUtils.h | 10 + src/SMESHGUI/SMESH_images.ts | 18 +- src/SMESHGUI/SMESH_msg_en.ts | 570 ++++++- src/SMESH_I/Makefile.am | 4 +- src/SMESH_I/SMESH_2smeshpy.cxx | 15 + src/SMESH_I/SMESH_DumpPython.cxx | 12 + src/SMESH_I/SMESH_Filter_i.cxx | 90 ++ src/SMESH_I/SMESH_Filter_i.hxx | 49 +- src/SMESH_I/SMESH_Gen_i.cxx | 179 ++- src/SMESH_I/SMESH_Gen_i.hxx | 5 +- src/SMESH_I/SMESH_Hypothesis_i.cxx | 13 + src/SMESH_I/SMESH_Hypothesis_i.hxx | 3 +- src/SMESH_I/SMESH_Measurements_i.cxx | 259 ++++ src/SMESH_I/SMESH_Measurements_i.hxx | 63 + src/SMESH_I/SMESH_MeshEditor_i.cxx | 7 +- src/SMESH_I/SMESH_Mesh_i.cxx | 67 +- src/SMESH_I/SMESH_Mesh_i.hxx | 6 +- src/SMESH_I/SMESH_PythonDump.hxx | 4 + src/SMESH_I/SMESH_subMesh_i.cxx | 10 + src/SMESH_I/SMESH_subMesh_i.hxx | 13 +- src/SMESH_SWIG/SMESH_BelongToGeom.py | 1 + src/SMESH_SWIG/SMESH_GroupLyingOnGeom.py | 1 + src/SMESH_SWIG/SMESH_controls.py | 12 + src/SMESH_SWIG/smeshDC.py | 371 ++++- src/StdMeshers/Makefile.am | 10 +- .../StdMeshers_CompositeSegment_1D.hxx | 1 - src/StdMeshers/StdMeshers_ImportSource.cxx | 443 ++++++ src/StdMeshers/StdMeshers_ImportSource.hxx | 97 ++ src/StdMeshers/StdMeshers_Import_1D.cxx | 959 ++++++++++++ src/StdMeshers/StdMeshers_Import_1D.hxx | 81 + src/StdMeshers/StdMeshers_Import_1D2D.cxx | 642 ++++++++ src/StdMeshers/StdMeshers_Import_1D2D.hxx | 60 + .../StdMeshers_QuadToTriaAdaptor.cxx | 24 +- .../StdMeshers_QuadToTriaAdaptor.hxx | 20 +- .../StdMeshersGUI_ObjectReferenceParamWdg.cxx | 70 +- .../StdMeshersGUI_ObjectReferenceParamWdg.h | 24 +- .../StdMeshersGUI_StdHypothesisCreator.cxx | 137 +- src/StdMeshersGUI/StdMeshers_images.ts | 8 + src/StdMeshersGUI/StdMeshers_msg_en.ts | 32 + src/StdMeshers_I/Makefile.am | 12 +- .../StdMeshers_Deflection1D_i.cxx | 1 - .../StdMeshers_ImportSource1D_i.cxx | 280 ++++ .../StdMeshers_ImportSource1D_i.hxx | 74 + .../StdMeshers_ImportSource2D_i.cxx | 280 ++++ .../StdMeshers_ImportSource2D_i.hxx | 74 + src/StdMeshers_I/StdMeshers_Import_1D2D_i.cxx | 67 + src/StdMeshers_I/StdMeshers_Import_1D2D_i.hxx | 53 + src/StdMeshers_I/StdMeshers_Import_1D_i.cxx | 85 ++ src/StdMeshers_I/StdMeshers_Import_1D_i.hxx | 54 + .../StdMeshers_ProjectionSource1D_i.hxx | 1 - .../StdMeshers_RadialQuadrangle_1D2D_i.cxx | 1 - .../StdMeshers_RadialQuadrangle_1D2D_i.hxx | 2 - src/StdMeshers_I/StdMeshers_Regular_1D_i.cxx | 1 - src/StdMeshers_I/StdMeshers_Regular_1D_i.hxx | 1 - src/StdMeshers_I/StdMeshers_i.cxx | 12 + 170 files changed, 12555 insertions(+), 1090 deletions(-) create mode 100644 doc/salome/gui/SMESH/images/bnd_box.png create mode 100644 doc/salome/gui/SMESH/images/bnd_box_preview.png create mode 100644 doc/salome/gui/SMESH/images/elem_info.png create mode 100644 doc/salome/gui/SMESH/images/formula5.png create mode 100644 doc/salome/gui/SMESH/images/hyp_source_edges.png create mode 100644 doc/salome/gui/SMESH/images/hyp_source_faces.png create mode 100755 doc/salome/gui/SMESH/images/image42.png create mode 100755 doc/salome/gui/SMESH/images/image43.png create mode 100755 doc/salome/gui/SMESH/images/max_element_length_2d.png create mode 100755 doc/salome/gui/SMESH/images/max_element_length_3d.png create mode 100644 doc/salome/gui/SMESH/images/min_distance.png create mode 100644 doc/salome/gui/SMESH/images/min_distance_preview.png create mode 100644 doc/salome/gui/SMESH/input/max_element_length_2d.doc create mode 100644 doc/salome/gui/SMESH/input/max_element_length_3d.doc create mode 100644 doc/salome/gui/SMESH/input/measurements.doc create mode 100644 doc/salome/gui/SMESH/input/tui_measurements.doc create mode 100644 doc/salome/gui/SMESH/input/use_existing_algos.doc create mode 100644 idl/SMESH_Measurements.idl create mode 100755 resources/mesh_bounding_box.png create mode 100644 resources/mesh_elem_info.png create mode 100755 resources/mesh_max_element_length_2d.png create mode 100755 resources/mesh_max_element_length_3d.png create mode 100755 resources/mesh_min_dist.png create mode 100644 src/OBJECT/SMESH_ScalarBarActor.cxx create mode 100644 src/OBJECT/SMESH_ScalarBarActor.h create mode 100644 src/SMESHGUI/SMESHGUI_Measurements.cxx create mode 100644 src/SMESHGUI/SMESHGUI_Measurements.h create mode 100644 src/SMESHGUI/SMESHGUI_MeshInfo.cxx create mode 100644 src/SMESHGUI/SMESHGUI_MeshInfo.h create mode 100644 src/SMESH_I/SMESH_Measurements_i.cxx create mode 100644 src/SMESH_I/SMESH_Measurements_i.hxx create mode 100644 src/StdMeshers/StdMeshers_ImportSource.cxx create mode 100644 src/StdMeshers/StdMeshers_ImportSource.hxx create mode 100644 src/StdMeshers/StdMeshers_Import_1D.cxx create mode 100644 src/StdMeshers/StdMeshers_Import_1D.hxx create mode 100644 src/StdMeshers/StdMeshers_Import_1D2D.cxx create mode 100644 src/StdMeshers/StdMeshers_Import_1D2D.hxx create mode 100644 src/StdMeshers_I/StdMeshers_ImportSource1D_i.cxx create mode 100644 src/StdMeshers_I/StdMeshers_ImportSource1D_i.hxx create mode 100644 src/StdMeshers_I/StdMeshers_ImportSource2D_i.cxx create mode 100644 src/StdMeshers_I/StdMeshers_ImportSource2D_i.hxx create mode 100644 src/StdMeshers_I/StdMeshers_Import_1D2D_i.cxx create mode 100644 src/StdMeshers_I/StdMeshers_Import_1D2D_i.hxx create mode 100644 src/StdMeshers_I/StdMeshers_Import_1D_i.cxx create mode 100644 src/StdMeshers_I/StdMeshers_Import_1D_i.hxx diff --git a/doc/salome/gui/SMESH/images/a-clipping2.png b/doc/salome/gui/SMESH/images/a-clipping2.png index bfac4cea53acd9b713925ea20e3e34e0edf45f19..9d1249c68694fb6d24d18e92d9246522b8648574 100755 GIT binary patch literal 17327 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

b@R{rFI3w-&fUGRNK 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

kbrQWH`@(8qoV4DC6`=dUT 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 diff --git a/doc/salome/gui/SMESH/images/bnd_box.png b/doc/salome/gui/SMESH/images/bnd_box.png new file mode 100644 index 0000000000000000000000000000000000000000..6761a76ff1eaa5729b6a473af5cf6772a65a2f72 GIT binary patch literal 17441 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/bnd_box_preview.png b/doc/salome/gui/SMESH/images/bnd_box_preview.png new file mode 100644 index 0000000000000000000000000000000000000000..902101cf35a053647287e8906d6a5d67fc169964 GIT binary patch literal 56083 zcmdpdg*5nMx$u; zWJzZSB2smLF^x=l!rYrNGEyoOO&j~YUPVVK>EdBM92|VoeslYV7jU)nq{<93s#g<) z-XyYb3%F9HMaP^-NvY5^&+VK98E{0{z;v>SI5?N&g{%Bv8VozFSfcMiI#oUxL0%Y> z=E>+$NhO6Uu*~P`Df#g7j5(Y2o{Aq6F~n;X#%fZT1eyBQX5AGesgGND>B3hce@zJr!}3#lKPn z9$8YhstTOKDDU+*;mm(?YOwZ!$t_tjQgqGlHbA~iQoe=sg<JBGfBVsU8;sm zDiMPwG)kIQ>TRW0nAbmSS6Ns~(XZc%i;1VptiaHmKnbsCa6DpON}2tr() zO=C%4Oa^8T?`OlAGxfE6r5=1%_X)vSOD>Gee5UzVn%DUw$DYj$kSN6MKqg!;gGz%o zJFRu;@&}R7-mS9+G(&YLe;EG4XxHllj0S&=l7;U@KBguXRI==g7!!mqKcqnQDN|pi zBum`=d2rSv2}1}{XQ;kf3)F-J-;D8-N^d}6D!Q3QQZ>KlBs+Z7sL8=uDAtbuO{#Vj zClv>o6Q3aRH#^aWnWY(2{a+xA9_-Z2U?;wB+hwW)s!AJwGe(=j@RNvysD|7#RdH1# zvx7%_jauJH!c=L)aVCSU$=?RQyPbMVfV_)&s}@cVTA|Ve9@YN9)NkyV>C ziY)RD!^S7Dcl2-T+o0@VYb?3w+!OV;+R_ll!!=dGclqRwd{E(Ib;j3_sN9pHTvgxv zvM1PRj#1`26&Q`uo`_a2aM?wVlC)wo4nf}dnO`f8cz#)vKD4q-A(jEcx5}yiRmOKY zL~4AO15Z|i5kepvu0+0ImVa?RY3Bnl(KAZ6#r$mc|k?kH0=aOb-X}|RX{*E}tcXw+Hu=?BEfP~{KUo9+T0RrI zB1u)L=u1X{k6mFi9W5!C4y4IzvjZhI{%xHrhc640Lz!Hn;-I?K`IEH8Ee%>5mGV5K zVx~Gw$jL8%mw|n%n?YsrU54>Kcp};vA9=k(X4Di-+U(9=bG=B9S-SX5e*EkUxJL`w zuLv$UwPYPGJ!Xh19GWR5jT z7*RB*kvP?rfUB~sETP|GmAh19e-l_*&HEn`qO#wE3J2sA%QH1$nh zL{w4`PvSmNAvf~+cj>rHKSMGq{J33>J7|8ZP>2@C-t=2E7zp>_@p zBTe0zR8`XYnyq>_NopjY-={>NvhnLJeX@8qYy&;TdkQ?uURoRK_+b`ql`{6)>eD;5 zKMj8T_|!_}+|#eA3Qxqxh9BQKNIA2USDV+Qyz%+Y!UQucOv%_(G+~>rG{Tbnb!|O6 zqCRN{RHqbZdOE!2EVPiYd2ZyItY&1QN4BP~?*`H$!&G^ew9(%wj>CtzDt0s%Y%uQa zzSyU-#-JzP5l-9}bV;S*OH37w#tGLwZg}?+adzXz%iOsqDc{@RSBj6RG=3qp1kIOV z>meo>bM!YH?~|mjPI>c@kd9n`SQDsxx$#C+Z6L8wX1lSkA7zq-s}Vb(7~fEdDwncL z%~<&PPX$pra{M~(X_b2elZ=aiPq$+p+z!Fqtf>|3sZ^h^Ci#`{48$P2~q1# z#r!AokP(4zr6hr~tlshjHbwn;H_FfX9pGOgN~8A-r%$4L87psTc*N0Y*exydpS`C` zTX_TJ9@k0Y`BU^Av7ELqLAA&E9zQB0Km8q69$+&FDNHHeobg9d-P~|dC{Oyvo%$<` z3s?AORlLJXR;-&q6W1e#SPb?_eqH+Prhj2ts*~vK-Z)ybA#t?6x)USa3juJ|be%}T zH$_bB@8!YDL5aKri_VT7JyxoD`-&Szmb{!g3a1xzVRm2mQZeu)2mIo@Mk-8?)wMG7 zcxGi8Fi zO|hjkQm;%Iccy+!>Oqf9xMVHg3mS%8xlP(N5srp6?{j7r5*g9O?Z0tnLq0<>=$&Vf zgICa0?6iv)>03vO#N%Z z^{<)KH1VSXG|e8PNbxUsX^!=Dt-q4Xm_cvuj`#WS(vlPJzO~PYR|yxlo!n3>!(viu z-sEiH{i|a86sO~ud$ljl$=mE{uKmhQ%S)= z_G1yyZK@)h#|Y>eAxXgwD11cUen0hTB%m^*C^{GcwYJhPT%Y*KJaqEb;?srq)=G@vg#cnNj0i+M`;yeD?OTbbq~I<2@XaGT6?aIQGI?VO_A#z8zdda+q=a(rU(C=Ww4Sj zPu@y|lEmB3T0Dc*ek74|THR~;b~^a1-jvOm8Dsv>pKHPJx!}cAW5MtvS^4PjLJ@5~e?=gr6zhY2V4-R6IeY1P+Pj$m1rmw}zxa4y-kAr0lyDRV(U6{=A~ z-@$JJb?T;t9vP5WDOq1Djru19nERtFj+INVd<&6I#8br$9c=J>7M6Cavx}3*2lj0` zZ616%Sq57XlR5)C_8w=oZbaZigYEVe55QWB1!zUaJyT1`vKVm<4|7L-vDH<6htm{@ zT}py7px>#W5OoygqpHr0)YCT;lM`2Rr~52bnXuPib+#nEMtF6<=?_D?y_}`-w6rMk zjCvou7_`;0YE_eB(W*LdE@D4#Jr1onZn>0F(EY|gHv1AqXZgEU5hl7R|2YO0LECnO z!&)2Mg@wS5sSww;WesvzAtfC*RsGz}JFMV)}=8N|@8`>2NStz%~3rOBLJB8n^u7IR5zRP_g74bX3P zGK!_vUEH!52MA103bsoZ)$=W0HfukmK7=LjnQ~_goMB#B+y8r4*;*h}kGjAqES~pk zg*f12+xz=nzF`YPso>RO&uz3 z91cHpdL#TPzDaxyY0U1(8kT!CLC-hgT`E!39`x8CTrovQw^2>ul7>K!GN_#PX9&Jl zz{rgh!wVACS5_oql`bw)fl>C$QMoDWbhu1z2@I^&uNZomPzf2v5eM|Hp%vs=Ve`ki zGH59etT>!jWRe-61$1GdmYW(B?D>`Xc=w2L`+aG%xu?^L9IgDId+&qv76WNmNCSoX zsmo2+$`HBNn9TpA^ljyOK-QEc(TT3NmRL{T6+(YVjZzFQ;N2!RAUF#w�MNla{1Y|k9qTx$1T7x+UKTDlGaag9r1EvuX_HTS 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/eleminfo1.png b/doc/salome/gui/SMESH/images/eleminfo1.png index a93a622f1d44046971ac167d2f52e5ff7cfefed3..4d12b54b1279934a85b3277a9e47b437f4b2e313 100755 GIT binary patch literal 19088 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 LRrvzh2mb#LB6Je| diff --git a/doc/salome/gui/SMESH/images/eleminfo2.png b/doc/salome/gui/SMESH/images/eleminfo2.png index c417b6d25f37a6a14349ba792d770376fee7f1b0..26cfae3651dabdc316df9acb76f1f47c05314fe8 100755 GIT binary patch literal 36810 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 z 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 literal 33198 zcmb@u1yq%7+bz04B&5Nhkw!%6loAk7x{(f%E=lPQNkycj1nHFSkWlIF5EKxU?mX9e z-|yewf6n{uv&Y`&jIqX27mH^->v`_`n)8}-UWO?tNaJ23yM{m@a39M^svr<3#s~ze zIVL*1qRY1Khd|s$JeGW@=Jx*g>`UFZqZb%k{lBl2;oQf(|2XNIKgz2Gl||H7vYKk# z@yW{?`VP11Es|X7{n5-fG?G-Z6W->Axf8o~{4{%RX<>~t60qP#{E*pNUp zj6yU2kU;!PxB?F1DT8OoLrfaB`y7b3>RXiP@P-<-u$niU?3gq^Iv&v(i(`H#jSR)2 z2{hxTWeg-p9SluCAbuO5cGjVgvt7BdZ!bLJ>e2sd;~t8lv=}`a-W@JN}Pl&3223^ZT2`_}j%~DmG)&BtQiMA1?7`D_nnLHZ2?^f{gp;52T{$?n zb@zyrr@S<~<@Qr(Pdadn@ZEw3>~KX_d-wZ!9eYHC0;n~}(pl(1Uv z@><(BBFv1ykAbb?ZH7$We1j&)#)>4Fa~u343ej{g@8bJpV=Hg}V03q}3GmFZh!GKp z)|GwIzF%~<*(Hrg&-*znx}(tRd&Zd_7PQ7uC`+qxsH|b3JES~r;Hd23r8;e8-Pvxo z#=-qM*E{=W!U_lR?3#(j?W|h_?gzil8A`~r)4|7jPc%Qy{J1xGc(wJqX7Yiej@kG2=e5t*W zg*bVDQuX3?Ic8}6RUwuUO4Yp8cp?#Q!m;r`on87XD&+MTucP{}6W{7je`09^Il- zM{>Ra%UvZS0kr1J1Kd99N&JQiAL^(l zut-+W>3^c8U7k5j58&mW`a0OG38u1nqx(1dUZ(QcN?PYO8c-KxN99)^SB0-p>rV)X zv7lzxT=9CZ_BDZ0eV6M?WGgC9x3FmuQSGC{2wSWIP(2E!z1>^}Tn!v=wKie{YH%%u~MZ3(uZT4>u{EUv+Xu95Cifm9E*WxfN!0R_3j{ z<#%cpFGZJHQr^w`zN^|OPfj{8rx2IG6|QEwedv4JY_#l6=XQ4y{f{`o(YhI}@+idc z`!_YGIJy;OE;f;mOTUP?}vl^Gk23AZB-I#9QGvIM=NZzlAUfjtUmoWWk z*?xy`?7ff1xPi-u=d{FF+$Ox&@-|l9 z3C%K9OYU2DF3eNpX$JSXdI?d*PBU7}q%FS<{Np1)T3JG(q$hWRiD;lbBBf0JN&Ec_ zi#=MI;ORsn)t$T>eha_)lSx~2it`D_mc&O_NtA?x*9IMqYI8DWiX)p3n=iDSiLp_d zHGS_;wG0s_d0`fu72E0<$OV6k4C_v4DzGiEN)BEu@y6+F*J@N~omae(tSyvcW@n6Y z{Vmx=GTnanz;W^V634Hf^c#n(&zLqYepEdURdC^~X>KJfi@7uSN-rRu8SjOMhn9wj z_*f9zK)VU+Gx;fheMfV*wJvFTrCwp%TGY39E~)a=@7!h4WLW#2qQ+)YByCn#cf=N8$k>AxP3?GV`ieE@LkWRaLRXzQnc5Z8zci!=3Z9g)s z%su4;=V*B(4W;iapBmf!lV()i$C-of6xyQq=s{I4p> zCvHM6If51y3GYe;aSzW%7(HHT# z6F_GPG9kkGdRKgh(?tS)+R}{rp*t*`uikLbv|IC-(<;czKbmRckD%nMqN(RF|6Nn| zHUf+0dBMY#P!pG~+lKatIuGZro#=NGjIj>YSW8ST^Zf=U$$8c9-&5?ZPxt56#m*(R zukXPruMQc~E#`h~)Kl>I@_(A5Nz;uGQ^h==KXhUmVF(jp_c$@3cxF6-D-yLAh2p>ca=xKvtaA zEgzh&0U8O8rAE>(U%!6;R_#+s8Gw%0COUV95sXLrit>Sr7-K97g4cE;G+p`O>U@c4 z@!9+hTWXu?+TG=$F9`(38f4sr;T^`I9mbewsAyNO8u`q4hf31Y)6*MnEwqw3FZUz{ z44O#MeRo4uND&EoohfC!jS)_BGhA6sEig0`vzpv<*6(_eo1mMIc_w1b+MWB-2>A z|Hk-1JE6FYdSA+WhxLOZ?LX7$b_S{}aY`(4h7k|*)QsCh3E}UnljTfQqTW5DWfc{H ziulx?Rm)sG2JFZ{wWH(e{rmSCz;_c}ytejXTMX8rB1)j*twvtFZevE}M++Q2T#KnDd z>3vS~E;NHxla`qo^UqYJgoeh==NDFt$V+q`i-u6P)U)G7WEIMYxoUEMwdY(+h#V#j zW5Iqk{{un(H81TFZw~9B2eE4u&%DCs2yuNycH}Vge6khf)y{9Oppz387~rTzYaib% ze}Il)FcJ?vwiw96a^_riObN?p#v&H)Q4U}`QQa4=M+vw>R`;MNib6#EF)XYqGE-7H zXHJn9M=~Z(Ih8)*m>imsRa6`d65^PHQB4^E$g=QP&GPj z`#oAdc=AC~SDx$iIl;9+0!%bPyTF*0=@|jX?Q{HjK5d`3p#_8sn}K()i!l?3Gpo&_ zp`si z-ewf zPjFI&Uiyz(X=FlCL--aJvU(nU4>?+j7FEh96ieo{As{40!N9<1+|HY)q#+8cNmgQR zUuX^39##}JY74{)jg0I#+Fl|gBt%J+i(}^E;^OeR@I1RX-Gq%~K3#Q>*KRK2-8~&t z1T7t1nb)bym!B`x)YJ?Y+r!+}i>hxEV3t~rvQP-SUr$U-Jc6?yEHM!M@{AM87^{8* zNseM#upHy(xkiuL1MlOXw;B%TJecp^4QOl>Zn`+JsxTi!t+t!*gcEYu`SG~nY^VEZ z)8{f=r`pzNr7vawn4L&`O?7eq^tZP*Z+9QtbNpc{GB1;eM72w!DG8UKD|dT3JA=>T z&Td%^XX8Hb{J~zovwP#YnOWE9@%h;1%%)DYjcG~qwqP|I;$ZZkWa4v0$nWkV15Rvg z?3?G#+#U%BF$viewZ}W~%Ps=4j@Ei_ZH)g&D z+nGENpDx`H3NXe0&hTIXO&kVgaoF0Rn{z91k8mpyT2q_Bh-KijTj=dhcHC zr-lY03Q=#0Xll{UHw>}}L|j~)Zf#M~J@$cPyl-tK!Z zaD|*aS&;GpO_tI2L2(#d1(V(EUVhgNit3`QEHo~&zV?eNr{9;CgCDqV+_rbSty%0{ zhlhXyl6+HXUXw|*lO#}_W^rkWChp1ly=CQ0DI-ADiAt;Z&I7;~%ph^y1~+9oMjk&g zU)3Ci?`xw4HBP^X-rd)GRb?~1D0+Du-Di>;{^=7Zaz9@SLXD;p&Uf?(j0x_T?rMia zi)fvp(27JZRKYa>F#7N){3gOzZ+>H_vR)%sT*9+ds>*%JpJM1 zNPjB=+Ff3pBYcHD4i+N$<`4*Oiy^cWLFXan_2C@+>UsG1fg&Bgv%O)(1P&8)6%~~= zry1nQuAhcpK}9Wf_$+n(`gMd7!@$ek6{Cd~Kl9N~H%{wd0@*bSnpEooP2O_;C6X_SlJZK&&Y_5eUsIR6-fgUdu9TN&^wc2v_XEgIP1ma{$0ZfaqIcaPSC{U%*c%3x+i-7n(=?oO=0v?l-olOfr z>5L+uj+qrYgg<4!Cd9001u!lq%yM9oP#~!7sGU{^{HAS9Oag2SY(8g7N3+w~qxCVR z+I?Y{Q-P%js||V2Dp~B9fnZA_e_t(t;lI)ArH}FYZLQS!W4Uy(UjZF%$9I#n;Kcs? z@nfOD#(;*OzeeLH?ypADO=V8T9|9wP5p29fxz2Naz5P!}^s4wxH&g3~@#G_s%~VBe z{+7DEy}g*WHrW~akr8|{zr!Nhr}A<_DypdRmA=K_iRDQ4N}EYLSfI(4Ii195dQIUy zzaJb4ATs@My>a`ikH|wKBO25Y3~`pY#g^79WE`4o)SOP3DpXku&37-c5npUb-H4)mkX^0d?Jd%mA{^4wBNrGHgo4mw7)IVGcJqPT2;chp2SCQo&d*U0 zsi~AF39SQ zfKHBpxKoi`P|EACHsF(n1F`s;fwsGL(LurRh@{Pf(cphGf0ZKV5yx+c+rUclaQDxl z2**whRoU6dB??|G_czOUTK;@>AmfU@#o?<~uZS>Z>is=QFA?;>m?_7NAG+%|?vOiK zisz}p!=D2d(0TU#@_!TlxAE~3P=sr0NSZHB3i@2~50v-4^`_p)&@wy6sY9X_f9d1ndA%06g@qK-acViJm_eho}OMMah^4gf+a2+(4?iQqT)X^q;mb{ zP2==SvB*ze4yQ`m+TTX6_>LB6(s6TNKR?|M(V`9hq#Kr=e!IeIyjW@$-p}6YG*@Dy z^P-kQA_Vsl@JuD<>!If&8g#aLKQsNMjGRX-_cmsAGWD#itlkSd-c(jrj(PHNqQW9p znPY9|_+7u%t`dQGPr_}$^yL9Ll%P0@j;oVWo2#n}xrY{ICmmUjH|6pjWBUE0MK4H@ zTjuQ@)f$`qbCF-Gl!J&>y8gffI@KJ;|Ix_54@Nc%O0ObGyO~sCoy*{m7O*TKE8V~(F>bb)LQ z^v3(tAwY&e9&ml&qrY#{HFcqt8boilvE3+R=@?1a7B7{SBqNlDsi@db=5rg$!THI4 zKw28LR3wGENpt?=`}gkQ-lNokCSKAc*~&~ab}8?V_mmL!FcX{ql)j1jM_~2N1!DmH zOSTU){cAW^6#60^n5DY=`@4eo$&c^?Mu_ZGiAOKR@-K?z_X*2_g02!pF)Z|pUP{)x z{2{w*-DoaptuNQunO}}97baa~{NGNLp-SVD^BRu*e(D(_ZkeGh-M;qvRg)+Iw9&&k zisK|@YKkv_8Md~zYTc-MVr9T*JJTX|>9;ywP2Cwm70?w;?Pv;Jc*lC9fpkkc!g{(+ z-lQ4o>Dju$Wt%U`m4WeUwz-RyX&FVum2Z3?X#lx55%W<$2B5FuBqQ8aoaR|xT@79C zO(t*Xw3MCa$)pmNmXb97vOu#snaR|bDiB^;%8o-SgeEd40{rd$W1B~wWPYtE0pFMY z1eBZgp(1Xw=|}kcqaGa}8?DA?NtKkVSmb292cfKE*e_tX8^rDFFzlWovuB30lhyp>ji=^P0D`y`n9W5)ppUqL{JfUzeRnigxwKJ z!ooJ=#gv*ZTP+W5MWOTATb;bJK306iB>%Mxs59R6$K;6g(o%w7zkaO_eZ*!|cpnOl z9Q7?CHv7|I3XaPPJrf272A(&iRaS+(IC@->qwipEJ$dpZU5y2WqzUfV_n&&il`n7T z%nx7q`Xa1nN(rxCy*g91Pd;YSdUo}Q`%IPFZjOSSSH#Pze~qVr!{flZP^TWR(O|P^ za17ezQsd)md;5Q|%Or73Yl%#{A|IKJ_W>tv*|Qi%HbNOPm|-e8?xGL*DL4^Or?Q@SRBTS4QMjB>}B zZa3e|lyCJfK9UHF7s58*uXL9Lp-6?iUyj!M?;rUS7<;ECO7Q@ ziiZk#&@{1x5s0U1{_kqQ|NZ^W+R+oWv5sCHNI$nwn`yCPk305e4M>I`DCOk|K%Hj( zOQZhh^V;44kE-M&DIN{Y=T@L4BYAm32D)N9w9pcu7^6jDTCW!O=&L=u&R`-ggNvIK zs;a6=Sj~n9H^JtMZ7M1J`SBT`LB>O3hn@`*G#os!=B9Idk?n@o6WRFt9hC;f84_K1 zT8-|`62aN(49n=v?Y3Xqt>c9Cf!H0)2Zs#J7=Gne&Poft6 zf4f`pvv6Jm2^k+&ABo^I=HfHYM|S5(VtKIL(XZ(fEJM$kSMuuBwb;YK&Izsc&nr42 zInU(2VE43r!xOm5Ak*JtG2to?It$1s08PKGoz|yt$@#1$2Xb%kZH`lGUTj_ilEN5~ z<_iQPf=uAr1DD^vy7#*p>krwD+c9y-1#vbTcJX$0cX_75UPZL6rVmb(d12H!{|S~S z=QDB|Fb9tNIqtIFztU>l82*Vos_5kz*N+zh@Mt<-CO4kh`0`&_fCxOYNF#|58gn%Q zPzI2))W0dUanCA;uISo1PKWAw&B&=meQye1ynYLPAi{j1x&*rWzZLC`!?QC_WDhGH zMb$d=Q5H%EUXZw7f-uLwh;9Op)y;Ne4#13%TE~?|DACBe7I&$aHy8yVj7KdH!C@Eq z5ZJ4}qYrLKG)3p9=yyin-rm_dI9T2YDY>?CKq=}ignVCYj)HODjDS{|@l`mYMo`J3 zG08SMS3PCM`t#A{g#vc zb>#N$B>7a1tN4}VRoBE)zCua_9UWa{z9J@vfyFP2%Bd0swz1J{)qSXk{wW?k_UtBZ> za-0e58h$i!+^bM5NBcS*Bot&#oZ{h0T|2j`AFOA>q!GK)?1j`;fT?KvU?5i;duPQv zl$IRAG~=&}453HdsPf4?kJQxO_PID!>YO)8(mvcOG(^L>=9`&G=XrYa!u0<}d?!jB z0;KA*+f^%lY((aFUZ(Wjqxo^Hyk1=*fE2+6i@XUf{}RD}>@vECta*LqCS&|@3~is} zXmttCM5xv|?OXQ>88u^2mY#I>VIkAji3J3z{_2JY!L$M zj3N8)8n{^%QZBEssMrs^g9Qc6We=C~KX%yv?79DEuaryaSoxE%ZF|x}7rxWBK3QOv zx&J6^LXM~04jl!J;93yK;MyRA2XlaufP}foF=_^5E_EI(>>%-t>?TEIAB_R8Fc4TW z8ori6g9qqwuVvbyhJ7iICMruL635IC!+fpO&R|rgrAv2*SUlD1ZD{XXcS&6yENH(X z=kE{_?|7PzNWOpfF4)`a)Z+ZxuZjw8tzA;MKcfW6jH>e1;Y`$yFCYB8( zzR)?s$fxCIqjk6d^-nr!X(Wva;n7Z{j`~i9-tFv&qt4wWC_Egyx_`)2_WR082*y|Z zt%GSh$LZajotU(==m)Nw;Er66ollH7J=~O_C(3vn%NVLn8H7hEIPxn2w%K7%L}(ER z;=d<2nm)5Xfr83wJ)yKB$$DKVB{e3L0UqF2#XQM^2b2SGW8>cHy2g{W0#t^NHVvD+=6#<80nP=M^%FjfZoaPYXK=l+^{Pbv?&hK7dQ`TqF&$KL;` z5N^9CWHZH$)GQ|_CqqL+TN2C7?3edQgja%MzvmJAGfq-?pyQIY#~uEez6I_a`ZUt7)hFKm7jtE|o?!PR zyU3fXTWil=-q?uB&CMm-N7C3|!#O4`z9(jMI^EBq3G(^ZR$dN1JSIe&-kjWMr?7K5v6$@Hwa*dj?a4 zjSU}8qsDtl@GlZqTU+ZMt$BXHZL{0H7O1PG6$%nsMs6?hLXwJ~QDCna6;@bI{P>lPh7J=$i|>3z`Fxz}vw zn?a9OVwUvuZ0I9Qm1A5wxfv!&rug*{ zEg{R@yYiN@(@mrQ*`MUG8XH;TM-gL*Ynz*+LKqqu`5o`Bd>$Xy%v7+nWKl>HiPWoi z8J!U2MGY; z5-j($_4T9XZ7;@hZJugrA?q_}VhAO;5qo=1PQQk(f-2g6y4f6!9d=7DDlZ>4`~6~| z6~InD4-czmDmXcDUu;MFwDk2Un4Bi@Sd}`iD4c=25+I(Dt4a|VQ@7+C<+h(Rnjq}K z3&M2BT*={>PW1@|2jYI1W~FKO%|fjvR4=bnaaKZ!r^W3P4km+>mE~WzN2~4ucDJ;M z?Y+#z|NZ;-78on+UQA}S7=3;Hi7K09sT6R- z4VOA2$)<;fhsz9GQ5$x?-JO}K2A8NK{MPz)e44C-|A)xyE-j5Ao%Jz?$IzUu_+J{Y z41)^nDcD>al=wtpfzyoFhgh-$xdZ>L^Tvww8ycC0y!R){GFu*SN6M&t|BzAtF6rfF z&j-_P^@2xvjORx%B*RRYoRQk-&bxMKN+^Ex=zk%^dW}n}J?pg_0ru)hOiDVL8=k~- zGCf}5)ksJam=GRffluD3s6QuNs6X%?q#Ru8?$aTP|F!JVV@*^hc01QWr_4A=Dp3Ib zxO&UZYs?1c&Ye31VUk;0TMM=ZKIc61MuaZ!9l&n$Tw-g9C`tl8a{b zWVX}T#wOCh`#1=4k}qizdqcH)`}?Eof%+*}r9gtACz%ibo=#ODNc9CJO|N>B`5b?$ zOOI4lRhfgQ=6&=X18LeJ3-kI|k;Cc$P3-jPYG!o060@P5U9{KffyGC^9(--5jeiNGYzvzI7iBVLerWh1mL2J&%fb-jk3~ z=JWhHV`nsV^!j+o_!^1R*Z%(Tgd`+LGAgDLfElLGO2QN~*0Jqur>}cEVaMm^Qm0!%Qxc{K>neRxWWYT5=2z}hA z>suR~QWQOJw}J0U2}kUT%R4MDD+5;S9m$)mkn*ZXr~1V{7bhp&o7=BtYEI>od4rUg z;iib0nwl0(7t}$vEb{oMs<^JC@qlb&zBwASQS83HzS6R?)|3aX+*0K)U%oVqXdN57 z`R?62W>!}2H4kEu<5xEkFX=%dy{yEUp8A370P?ymg#rGePVyP^GxnNKOu;hm{?eO94YAq z1`=KAY=l;-y1EhDOI=I9C(F0?_S!d_FQfS8+$1(dz>otHRs(+RGtNZibJ&FTmb8qF z!S%B>4iZ)=)pPFHh*IZujhSX2>c@{ChlYiHPaR9n7ny>qi<15%P&$etPkj~+{dsVZ zFa(d%UyY^X$Jbb^-{eF@{xLBG2*?YR40Ztmpa750jLs=6!~qe+eDV{+cyW?=h8V2! zGWcG$Ixa4}plEn{c@dJ4eLMdQR`_Swh!Gp{F}Ge%GAueQbvjf}OlTE3BaK?9hjdI# z7)WOmzPJ5SCvL;V$$I5lxyY1GozoqFX{7FOUpYxzlO^uOZWEnUgxKzKuhs8qxOBg# zDzWwIoLWIDTH7bd|5RDo@yWD%pwdcnZ*}kr>~6B392^`-^wHJTg)P(C$WB5`9FUbo zUsG4tHaklRdKTHRd|*sc&-17RgjwJF)>{Uiey~aw_kInNsiI`}JR}ykj9v~kum`ol z4^%0n^cApM25}E0m;GQ@Axj7Hu)%Xaq{GHW_Rr#5{(ddpsaUhVtRV1Cy^_1 z%Iwjjt4OW(^6YpQky?Bs!-ljQ6iHt9_mGcE=nZxIJyAAObi(VXOZ#a}M(O-in%XN6 zl((fgP5p=B;;5SA14A)&?~>K3>&*vg-8?*&fY@*g-rpBV^FGPz3>{T6sEeZE;2;G2 z3aqZ?1Bp`Cgc9E*I*vdkc9P!M>qwt=hy+;E>RjW4`vy%B>IE7`+lw8#i5VYh_V4i} zCMRRVuF$P>%In--3xCwu4|SnP`FSpzUKcx9r-30MOVAmYR#c2k^4$w~9Qvzghpul* zq|eG$R#Ia&_01c9VAMz?MQlM5AOn0ps61uLvJz|Bwww$MSCOG3NF)V{&t7sBbg4L} zt!=Nb%Z_tAGd0aXZp(Z3pceelFz)W@88J_L*Gk`iw1`^E-GgQ zcUHzv#(Vef?K2wLIQ=m}o}D49HhOH#)Jw)}M#Qc*?a=k$cfljoGta!h(1Shx@bush zl4K$V1U^c18xpBJ03~VJG3*OO11fB1lj=#!-MrLK-UV}4!0+VC8cbK&NXW=w*12v* zMMU6$&QY{)PAVrZXZFsqeQJQ{^%)Bb%c6c(_^VfKpt{&Ew4kJB(q>%@Qj}3uNYXbW zc@@6M5u&4`qZAf(U&@1Hys(&+POjKci!d4Qt7vGqZ{PMsg57;#E=PdiYpw5DQkr%3uNeiqme+QUeg_P`Yn zQL`T^`{YSXVqzGe@Y}awINiXUtvoXKkfaL?eUl$J0Y` zpY~cf*wOsuMaaM0aJSuFzU{Sw5(v8(Se@r%p&{UwzJ{#NJ!b*;J@ZJOz#IT)*n{68 zmemRThyzxPw%2$PN4Epn=YgU3mg>z|pC=Rv$fjNP9c3U-;GNJr(w?tgU}$O@*4VE zk)&Mc2=*60WUOcFZUArinN5Imuh#-ck7KOrPp~fDTY?YCP`yCI(rxl2h2X|Sy(=4% z&cNwrNJmpa1f#a~oX>g!0jtGx=PMJ$Hy{>PB=r)IhQss7p1pHnanT=c@w$!Ouc42~ zEeZHr%M*pN^lnK_r`cOrTwHt$?n_Ss$CbO9#gb2-l4@$ie-zm7(4w{>7AK3I>>(7r zyLYeaG3LvI#sSCn{%hJ%u>>mfz`|FbQuRW%F&5rJ3`0P#{^1t(uo5{y(o(zHHnKaO z&2d_zST_ukJ*2Zzu=-I^Q3o1cIu@lR$SNox8+&9p=rx@*n8FjeoO*L!hkCYuuqr{| zFEnVLTTK{+u+|4cM<}Afxa8<&W@bnv93Q_`ZENA9(*xS%V3~<@O>J!kP(6N^-z1vv zVq$!u{(SE3#f7~rVPTQi`UwEk&CSi8kBNy15;^UwOSyF=At4yBNnweZj$E8X>C7(` z=(p!tHiI~aZc;R*0O^E=#zvsMctEd?j*jft(@5&7F!RbGkv(}{Vf`+}poc13nERxY zge&g?B5c;*+k$Wq!;JUuN7dHVeR}hT=m5Z~6nuwIaLX);3gp2BIsKKBHc`@i@eO!_ z)msd7^iOO}M_`m|+1s<9{)knKU>Rm$V~Ym*5e1+g#nCx2R;2TEzRByUsp-c-4zA7# zC>Iley*$PckbMrtV`*xt;U(AZ_I6&G9e6$9WU=1469&JSArUeGy~8&W6S+LKPjI2i z%gy>ZJ4vQ%9O$rdae1^fW}$Gv2bVtX%Bu1{cVAvyY=ey#kzcY|voG9)PbD;PlCb{a z&wEWZwNfztHoSFpDXiw38e5yb?&ee-_jY!6W}QqPcOY|svJKv8i5;ONh+uqbJbZk7 z)~BD)U>CGOiwhlz-QERQu|SDS%gYOtHJ&~Vqmz!Zr#=VRX7xVXmJTpI(bCaDf_pnS z<@Nvqg<55()75r-7PDc%Vy!1XU4_~-JaIq1o5QdLQCtKZ^2*n*UwICyAzcst|{Ok;gRRN~zaqr$4Lnd^F#U-2HZY#o>ves#ki(Q^YiytG@9q65lJeBRi}*wM)5d5waFLO@OAwlBoXJM~{r&9^H}r~5 z85kMY^yp~d;~>$dlbqqaKIXQy;MdA2adNnc579lhmoI5(X;Bpv6c{_mk(ts0jfeN+ z*Z(ll(u%Jqb-_h(aBu*#IY5mi=;KEQWS|Z)GrS5YMff=wSHjwwHGX6-PQB9S(i;gG zz@WL;JadITj|faUBU(XpdDtagmMk(KwrGgz?kRpg_c+#(DiFQ?o&gwq!|6sn(Eh<(vmOCah!_C{DYc&DL^hT{w0H!ci(7VE6FC4hAT0{WtxHNt z86WTbBxBndF_oMte9FZf_XHUy2MH%HFK>n@=Hy!hGHx3;pU-)H6WUSxqb(!A@(j=l zVZGSDc!9+7+ME^$B|`@H5in55Q(9HT0^mXuY7C1Dp;pkK?o~Db6)66`9x4JEvIQ}% zT-g*6la%xd_=gF6d#N;Ru}Tu};cWTZ5{LY66I}xX4w_7HPiie#;p!n<-=?M}o;6a( zK9o@tL6AQ8)<(N?O&GI^0qG&xWOB0i%k59)c&W=DZDf28;_D#QAl7(kZ(a)`;Wj5g zx?f1i5qcQiogvKw0Mv%#%?luV2C%L8QnqJZ=UYF2 z{+xS(m3Oz?t!$%yv*|OeZ$AdvcMx<;h$QDT-udx$=F{s=BuPgS(7!n<8PYD(tb!}x zxj(9jlqD=J^E-9=o#H-bXN%JljrKoGx-BeB33*2`eSIo)91;Z79jMfBRGfWd3D{eM zgM)4>DXs&xj%G-tCFisKF*OP04<-$8kncS?vGin1YvM#ql$l^a{Odzm@4zwA^@0I` zfoeO0$m%yBDP|OOQ#TxY#ANBffPP~#())7YBOC$wj!GbF|2gOG!by0q@f@? zY%e}4#`W?dR-pz4Eet8&E7H=^8yyw6-9l zYS7dmMGnO&fzOUgyUH3XOwwP|!0QH(%rVk_Acfo8UDWHWIj=csU=!RY?1xPbKkI~& zW%;%@RhS&MB&>nY0H*^VWp5!VZ~61yq1@f|l4hh}BO@rzQH%VJ;^f z-4!U;$kPPgf`!oa($Ud@BJv%S2J^WF0ZvX%05p7{bU&7tQ4#v?zZkCHxIqKbN(2X} z$CedFkkbU5AUjt~5xfDJ`BBn(!KSscyKzqtzFMrj7m}cKXduIPJIVhc_}X*dgWGBh z2N^2{+tPWA<2j2jM>gMgyNOa12of(=RhtifxH+f-v(zIglk)NiG3eU9efwrj)?z{JVAELK@4i#o}pB;+^&6l(n2xO?h zf=Sc_YYvRY{dgq){~FtUelv_8dg^OI;%4BJ_D0wiK%4|AS%U4GoJ;QvX3A8L690Kq-%I|G$gKI9s`J3 z8*omfyaTB(Il*N}53T+&&^ga9gT*LDPh>QjuP*h+0CtPf=it`KNz&rtVsOtoigfa; zIZ5jnBO5oIQi#1)bPaUdBk1*;`!{k-%YUC4AF%()8070rc)U-YE&L2L&}RrO=Sqf} z`TxoS08=vr?TDwUpgW1zCcjcH85{=~%E`xm9{`woDf2z|Us&lZnGk8{rE`_%_4CyTUGqrAnVmeq{?L2E<;x;6$9SV6$)34ZAArr8s&y z5bheiqjmr}mlN4XrKhKp`6xk4SmSY6Ja$e*OkC?s4V5Bf-sh6i#l?mHDiEB)Ow;anM~mTX3(%;m^?+_J4eAfr$X!KYMwUHOB(I)o zCepzBLLh(L(9l3YNSNX9-dUh48&u>#m@z@3W3!J>U~q67FsuK-VNFIjkR%4yJIo6( zc3nZ>Q;W32zykm#Z{(v4IWHVKT3UkZ*R#sx$NzPI6U23N+i?=6N7|v{Cup%ghXEd# z!?B%fuoxPVRDbgE%{~2w1ju`Fbdq@Ntr9}Ga`D^dd~-iw$=5g(L(z*PI+KX9xVxI4 zAYVs1I}Xk7(*lj61hC2P-no;f-Y}I~Opg3!9Ize}Dl46fjMWRgqel1Sh1ol`pfTn1 zQdLuH2QT;QocsE{P7)K4N{}1EgB5zj4lohANQQlS=DiLnp=Ks2pRd2lgT4+r6H~@N zntEWqt`BBn++}4gRL=gB#J!BXezw;^#u6OsEL;#=@>kMwbjiQJGNGlC_cpnythBTR)2vEPZ~T9?;mQx=*}At z8s&M8GyzBS5Pa(3*jQpraJYPLyE>L3fw2rx(>b3@ zuh?wHi_Oc6=-T@F@^O8SNN1SXxC-6<+qc(?g`gkbUmXlUssdopM&?*R<63Ap--H}c zd+Fg(4t*|HCrSN_pVwdsg^XPQx&I8};ZuOE>OWvs_4M{eLiFq%tRf6!pP?n~>1^+L{`B8}RF*KIY^&+EDP@ z`wBdGz;)}^EvO58F6SrCnSCL}CR|P;kbJNLYsAsjb-af3f&A-t?>Z5sn))w;rpF<5 zpS$~Uy{^E$2`7bE4+&6`4@9yVf!@*~iC9!r6baPS`3#ajPa|q+29Ixdekggusrnbo z4ZO75oXh;cGJWCa6GAEzT>gTHqfE#*-7sU%z3qy~arYAm`7&t^#b^wr>z<<;So>$~ zSLpFShy`QH67%3sJW11kZJies*HkOlEgl;u$DD-4h~Zc3?X#79&fa6u@B5phxL>>6 z^1y5JwCS*MGTvh&v9{A%aWR3KDHZ>DZ{dz(dj!W=qW$gX5gcI-|9F0?e)|GABCs4M z=+%)P8+1ev@yZ_g%qgp)LIlNPY9>mKk?ZK*XXr4&-u~W=4S?$_p5Y7bIP|s%1Z;x< zIY#0khc&DI0jkdv|zh1A;nWF`}}wnST7}mGI>2 zB$ZdiGZxA`yk|7Z#5EZ~U-$uUZR4ThX(cUv^ta?``TL{3K< z{`?mAq1(jRI3_hU3bOcFSy_;bN0WWW+6ps9K^#cm8;Yki+$Ll>gt1S=lxrX$qIQ2r zg$MATp7#R8EOFmfb)g8+-M)>08D6B|+6R0C4qyU`3sU%6TU$exT~PbUdQgn43(0QX z*ATbHj&u=%7DjayG2{6C~DiBg)$yH-%@9fkbNp0G- zv8IB-%|YnKe$UhrBWVPvx$=E}!HgX%Fp@w(OicHK(DoOsA2$dD1W}L|B|dpN`A(!W zg7gYVg4O_Ts|5^Sy4GkhfWm8iI zl-r>HX5b-E#ejKb1P7y|ib00msWvt?Rw?JF$y~!rZ4>jvyXg$_=VNk}1!^qtyPBG+ z>gsW=F5EZo>&hTtmO2&$raL@5alp+a5y&xdG+)RkL_~EfQD-lIQ96h8#dilNjE!Ci zNf=&UR;dM}mgW8N2__ue_z;GmfnAgYvzw61REB{irLlnlF*#b5AOQgl47; zW{a>|eBQCMnp)!NgolQ*Kb8J1RB@5gR+Y-;7=0B1R1K+d>DIou>T&S!!^Qyfdnx?Fp&I^ zgKb3|AkNXk%fN-T+01zI@TzU5gZo8J<(%p>r6N%gz%*9RN^?Y#D(B$?V0>(`b|p0c zsst#hYz@Q3c_yJ5W!jd&n%j^-?Y<6o$FWk{BX}8U=;js_Ani-{y;T&%(a(4T1h>Ii z@Qw^9*O;wM&aV_BA?n-!-G`vxL+8A0;1I5#3`yTlbzHT&FjvpEtD8MX) zSv0@$axUnq_m%^zD)2c@g_R3UE&M}Q;e)wBt=rk!x?QWQ0L=!sNheN5Lsiu~*a=^| zxh;ps)RYF7he1?SRE7CEBr+t8jEpMG`l*a?fcg9Y zLl_7XIO`z1DNgu+h4W)^Q5?a{&aUKC4=G=6`vox-mbeNS>5r8qmXrj8iyp!KyobbS z8h9QS0%j75;ww+4pwOv0jwEF_{G{XH82oT-v$@N#tcBD28U8DQud}l$5DxqTd=^NU z!r|sTp8!*~iYF1_{-5c17|zV7?0x?>?%jbA3xk=*|JB=>hf~?MZU53lN(dz)L+Nf3 zMX?H*lCh%PC>a(qOOm0aGNdAv2$7*AAtcg7#L{3M77;?3X+ko-`*{!B_I&U2^nK6s zZrk_Xf7rC{WUXsB&*Rwl-?3lA)mKxJ=4(%IWydASaY)dEHFYk?MB*waWw@*tG(O$*#HSq@a!E@|_xX*N9k?bPh5@`kAmc?Yb#ReRe2|GmwKFTZ z&?-1fFKD(jPF?W-`qwi1Sy?&~D2ZMIZaJ2lqwzE%n&!S1O|-d#!vZYf#LCEn<8*^j z%unB7tSiDqL{A|q^d#ZH4}j`}Kp6lO3zDWYK0um{#9U3?OUvM?03%b8+?*VB2*Irn zo;;zYndGoTNQb?tj=BHLqo1_um`rwe!f~N_z!oPaExk86BsyB4xTK`8w3HPpNe|>O z0A~v?b)##>T0EQ7JfVt+={kZ9FX5TOP}4Gc?2Y=l9g&gzz%<%1q|~qmArSbjYf)4o zqaozXY*sPM5dzgQaYwJ>4<`W^QLmGdf`Slk?OmFh%2R(^qU>(Kop?gM9=lxDb|(>*>9-Obx?VR-m+a(*ZojZ(Y4?edK8 z?_RLOFmxv>DY*!nEGw0ekD3Md%wA*T`B1UR5CSHHj~qX~6E_6)qOgz!cfsBJ_vdjV zM@K!C0|y)-Ks%CWV9j9nD*e!i=9w5N3;Cr8umSmul_L8A#mgRG>{iI1t;hFh?fMHY z(^FHfBgv_W{mt8+v`@#m=ehq-Oq2A6AwjQBR0p9aWu#H2PjN5f7$f)yk`Dp~u_k&q z+c`QGW2w9X+XV1b`|?sfD98O}nXa8!YLnRx3K z3x!RDr!QDQR?AjgQSneRN4cPryu5s#Yv(*H$eAu}ikQ3W6MB1bV}20!6@n3<^C-c-i~4Q3E(DiPxw2guT zS_~VG+eYHKZ<6LS`1^Ip2aPQL)mJP8*RNlHSzljo9@W)fY*|-d-;O;i5OT|`*|Uj> zmiqh5_bXRX2oLu+aN-^F%N-HXySaTn1vU-)T+kO-hN>uCbVorwD8R?)0Jp@Kn{HMh zY;Z@1TcK-w+*>D7iUo3(cXvC;q!OG1ZeCvhSFd)Zuhd|?S!kShB%$KEDe4vT;pX5C z#8E^%iaP3QT;p6zmIMN-(XY#Tm=l6n41xo>xlfL{QW0^glxJ_!^@pPz^XH$zcoTFH z^+A`uyo(nv5@VK>xG20)9!qo=HX3o1JN0j(e=kYf_4>!wo}DEthD-fS#?w2tR&$DN zN}YD$E7*(SZkBi^bRJC@+O%d_YxD=T2kz`fi4(is>uR07EH^jyWDM}|b93+CzyAuB zMQq#L-0=NN@4|NRZU)zyfOB`DFFP~yGLB%%{ri_B4?Ww3PVN|TORDM4wziN4#GV}M zz1r#(2_=P7pqtnH`JUy!*q?`}3g{5{a zCPqh%(XAW@F)$j}Osjm=?=}@Dvuq+5TX9!r_sx8bk8s{Msl2MKO(Zo>+SVWVHUtJOZioSjp1@;qU!d_ET4(jf`dn%}i+?(!ZWRybjl7>#S z*GCTkm8hsFi2_2283K6(-2MgOY%q^%YIEMde}C)^4y)qCz~=VUcf@H(jyq-lpo||? z8_6lc*tsM;;Vaj!`2&SNuh(ryr_Y9-*Y1V&#e1aB`kPVHQx1BW!nqBx3MZC;&6GR( zku4@BMs1MpScVHy-Q8W5U;q@E#Zm>FhxHHzHRXR1;SSfY#!gqYy z^Dq|Z80?_=8i7?R0r)UHgsJ|-upgpmC<(q)bux>PMsU#~Z(^sDbL$G$+lIxX1kGUx zq|J-MZm@vy#<0P&iLMSzqC5AZTY>bbk|=6sX7>J>SFKgl8bbb(P$e8%s4`ekqZC@n z22;Ai*B@3v{#eI?y;He1nt~83)gb5D+uKVWA21>-#45{K>$jbwz7S}5q`|Bd+EC6_ zm7Gt@?IYGHP7NE7{Y=jDOZ*YHcu^Z+5>5kGGZ8?FP5Ak!jS?GD7m!KFmzWU`#tlgA zz-*Rb$0$Ik3(gL(`Nsf-pbA(RFE8HwSFr(8-4Y8SiVYIelr!3lM4WdX`ed~}ew+c5 zdas#TMtEssjC4PJKrd&5W-rg;#boj)V8K#*r={CkapV$GQsxs66^-T>m}@r_=D9UP z8uQmmI*YOzr3Lh@)8y~}`SGxW76HB>vy>q4G*iIB%=!uLMb-MUY+^F!{ zEXzqKx+lj6F8~|E)Y?T!o^572CWcFcbmuO~@{oYnj-w%hxU2+>?#i?&A3|sj__#R~ zdVs!X%1QbuN5+TkVm~;Rp|TdWo7wrBb&Hr_D zZudZE;p2mg1O;2_*SIm(0R+K2T`0Ik=UBlwLo}BI4Y9?$QVe~pGfdmz>6vFJq+KCe zHF;|m7L=DTol^~%5pHZ0)QhpM8!i+z^Id7iZ)U1(rap!4D2zhN&v#~`jV!DN20Yka z$y^o8p9)(*qBmauw5-W~vSR>t`l+e$cGAyxcXRX8 zPbtQ#8-g|-gD;)$4#(9uZ3Qcrkw1QqY0`#D=j)qw8Ei}S9msGi;ir-HfgD6}IXQlu zIdxmxyFJo^mT(e*_i~d{fWHH-TVztzGOesGGDKRo6@%LtI8pcXI)QhA>6ys-b4gA} z0ejKhEQoO*-XdV@TZL__GZJ3Lm_aqg2v?xwGld41kVghPzd&S zQK%HCdZ_4zpzq(mOCxNB6c*UC8}oghGN<9}kRS`@mT;}Pj}P8|Q~>?sLwB4n~mI(;PBzfCU6NHu58kmmy%M5 zQ<$UJm*d<*tNv~|upA>uLSQI~n_BepB{v_R^-*Dyit9?xWZe9r2|#vtf`BySAL(LhFumhShF#?fb)2L$DhuFOT`6yBLRERHddlvQRQ8snAy{H=C^Yo{nwN!v%Wat8pY+%;_)U<>Vx!Fg}Tgd43H=+(pAQU=4`=l&@i zB+`~aV@6C6Iju3cB3j0!>V45`*46pLeqSzsbPlRz4NP;8-;0ePx?TgA}#X@I8q1{ z7I?*EH5QbAp-c9gsgw&f0yGBN&JL*&Z$<5xm#!`c+V~HhowES|fUehA*Sp8ZhwvPJ z*e?apQljccpT^VV+!ES&JmVjmj_RI+c4t#18gIgG0WZQ2DwMf}D%zTzn3(AA;ua;4 zx)VkpR?vH!H3E@|#1?w^rq@m)yH$O=)P(d)^!OxM2$N!yvmvh&n;7LznR8`hn_q(0 z*att(Dugqj3CzpOv;B11Hgww*Gldp{v!0SCX;D}U} zrs%s(Yjhzj!)qedAja59a1d56f?3&p#yw4fztH9S!AQFx34mAG+nWX=fY7**mI>7d z`)COx)2>$H*ymOujB6S_J-z`0XOwLl_Yz)STZN^yLny|i+`4q272b0Dgux-eobU5} z1fgXR1rnvfCE%d#*yr`(T$ z_mgQ^!j9dBjsf#LkIzJVOwdn3W$v)|#CXM{EU%!@Pz{tzWTFn}s4!IXE%K}a(RE?u zzJ|idrDL)w{9d*-dqZjUxyXG95yRD+23J$h?UYLJos$!cS=2l$-w!`rH8*YlgFv$$ z5wW93j)+jh9|~vtMScIzwMYm$4cm79e-|U0?H>;Q%>w)jVe(df{-Lpe2z0?Fu(ovp zVI;Tu&*%9~TwK*f5LVQ1(SnUtxb;>XSiyMH)KrQsM;VK70$OO39D6=kS1$(?Q82>K zs=<}7rKSdu>Naj!F|j8;6Ib45=?bA<o4EK4#!jl-!zn#Sc7Jj{@BP6Ra^@i-=``&&@Zr}!(9Gn`WHRg{BryI=L6QN; zWP$WpvYR7hGi~I7X11fW19LrKA9j`#O%Lq`w=61;Hb6j(^ZUFr2m}PI&xw>x6FOKZ zHN1=g%A7+L_J`I24&#XP8I9^Wt`Q=Djn4Q)|BBH%jqK4An2Uy#y8Xv{HEq-HlRaXyS z3jS_s;67_cv)vmL54V)^n<5l-!gDlM6wFL-qk3*n$s~tH*g3G+CZ#(?&02EWkiBvB z)tvRZT->JlC!;WovlC6?%Ij|-FI@yABYLfY$<#+v_H%6P@He z&jn|&y4Ros?t+_7xNGc`L3fdqIp;K5X>rFJO1_FLA^|E1BM%JCP6RUS?Jt?sUVC(M zrG$iuOu?W}e(~~)310k2lz_nz2FDzRY7G|V-s!0ciEb;D%cK|co5zuu?=zvlZyzrT zKkZaK^hdoAd`+5Rc(YL>LoGK@60DJviws;O)O6n`XpKXtBB9RN+1TR2VN^jD+A!1^ zwp&pY{4RMBwaU%>nduV=2#^gv!#ec{5}uftXg9%M*g=hfzknHMI_Fu5$oai@O0 zE?9!YC1)a~87mpT_-eyC(T%IA#3KE zyOQrFQd#w4X>-wlQRS~SAd$EZHpym>OGV^XzK8NzcF@pO!!bB(pC@n+mD6?CaP__& zPz+8QbjTq8n+pyd^L9}xN*>D4oH67Uw@tbGtMQ=30edAShH?tW1ST*d}~Hc z0jYxH_bVtUc=z{@9EfJmc5vDc7l3vCg3mZ z+?<>oL_w2@Bo>*~trdvzijj9iKsHi^0^+nEdwrK6CZ3oI^ae-=0aInYv#DH{wo8D+ zl_kR3!Q^nAYAgTqU;gt<|EaOg|7S1xf9Dm*r4g^KQ2$}8j;hEVwQbP<{QQS7R$mP3 zeE@lcD*Xc*T_*t^dT@@F>=`36uLv_R!keGu8>a##2|zNfqqViQNInll?~Z1NXmf~c$SjmbON>}RK|+am{}>9v?|D>Nh%pDs7?RVg z<`%yDmrVCebgxMC7#M01g0NZEH!xNA<150H{eq6Mew+Ec_VfG4v*FD^BesB9L5b9P zKqf@#iKqc|i)Y}?zNoF`!9*_PmRS@~lX!U6(0oM1NcEM|J}?jr1h{8d3F-^nogSed zi2Vx!L^l^NtAR}hhZ%ylj)f8s6l9^;1B%ifn+F>wUpT6MX3l#Sfr7t_=56Od5mQU#_0xmXxFo;{-@&eqLorIkrWX7 zv;zZ!I1nJyDDb^xOT&f%2PUTv?S99tP{ksgM)#(QSFcEzB|AHNCYU>nh?2YvQ1%p=tZDFFakv`V5XAUbX!RXPbj(vN(G2k2KpZQ3?0c#2&+5!H`*smZNVVC6= zwyZI2#ZwSqEsR0-2yjC4SPE%GE%Y(41Re>U)922eYxR#}VHce<)0uOIT(bST5R zh+p2A=X&ez6gJo|c#AKQ(tPI388%MNQs_PEA#bY==GwfDiL6x&+w&i*sgN|LkcwXP z9W!d)hy)4fh8K4SWfm8AHO@|N+{|S1Yw1XRBcomTo%>)|F5P%&CE|%t;pO&B2?_`x z=_H77Ssn`m8IJeLF8B4>dv`@0?!m6LQY;ZkS^`KJNvXH5rh^CJ*kJrX&GQtrX|csh zp-^qD92~Tv;;N|~L*PtbZF1=A&P~Tp>6YIjJoRrF4Ta#MUZ0Vko`md?r#j0aA&5k?mf#+2#XeL#OYat5F=Hqj@&MJb)WxCxDFY3JU6< zGxq!j-jM}xSS)mg++j}?I9~t=5$g}ry6SMyj}JCk8`3KAk;xAix%tqy?)<}(6vPEg zMOPZ2;$Y!dlB9PxG;WV3gYT$Ei!kB_-g2dV91fy6%H^Wvz+V<))IasE>-i{c?QS*4 z3210P`MOCMH@V`ljef1z_SrUE7a%#7-P)&S01htyu)xsX7z8~sIEU%6SrnN?!nP^5 zZQE=L^%se5u$VzTFNOfre=tO!+`(c(NEXPlTt_V$KRd zhvaoMH4E`EU{l~N-g0~Q;N~hfv0NW0qEE&1(ZijZ{&^US#4HN;{KGfEs)CT{)93T> z89ym`fIfkx(_LqlmGD#%eL4Ec7$sj}04o%?1*Yv1OHHAgqMQN1$Op?|Nys}cy2m{y zO|3YPdq3oKLw-*;yp@}~1RCp0t696bd$}{A*JfiiM#dD0H`oaWoUSy|A$2{(+7 z+d)!5;AuX5qx-z`061w}qHG)6QCpqH9YU2m*x@o0BPATv7A*5S#%8DAy?Yw-_7HS{ zo)O&{3*Bsr;SNNTbP_ul(vVbLU8QgOj2efPS`SPL(CrnE9zFU6>scoh z`T7%^MQrp?GGv0Nz=yp!T^9)LxbU%~Y2{UU?q%i;R!Q7Ri@Aa3-oQGwqjBTfwHI)d z)z#E+9mX#`jjL%41EH_l+Tt)W+k+3A43Vq# zqiYncAh4^t?&S87I)jg$ovIkSFbVZ&_0p(23H6tY>T7xWDDyK~3*Ad^amsIQ)b1|c zGohojMp3rVPD*{3wl>LkLD9c3<(ybkm|R!s`EI}SB}(B|Nf?S09pNe)U3uxJYsXJ> zW?3J82FM4;FSgvs{c}4=-W8d;2bv1hk4)dd4cAgwpG^i#0A805f|>Md+Y}rcdJd4} zVlj|iD1l}{qQ(V+0lIC+7XsqiRhp8aph}lzKFZ3v8LjK!|@`F z1_E^tJ{|qz`3;B&${dsXCGtX|Gq7T+FdyT}5TntWJ~ULN$JW2+&M?m2`D!uZUjAQd z=DKB1{&y%#s{QPx3m0m%;;ldtLPzRp%1NzQzHBi!x9IkpUR}$GaHslqn>}D-;?mN=C=XOZhopj_vH-iYWL$*+<}dn^e-J9iQ%=03PZ#F{ry>Z%m!&9c1$FF zm0_OCIu<)v&q}?2;=TZV0_`0S1kU~UQtIM%FLxNbu$lV`rVv@;NhbPa9|3yiQ_nHw zK)hVCe6hqM!;;;d;-W4D2j9m1a*o2f71#3(+ie(Ch2)qu8#aVs2vCIreXpvf_7KJG ztQ|1LlQ@+oFGG`7S>ZDb>4}e*mu+w>a+3g8Js<>C#s3|;h zg;!Wu5Bow;QP*}xY@=(Whm zyCWwdT@*D0l{-~dW%1uY>(APU@)3*EUO1hY*)iyj93ibM&@b=lpWSOvKoK(=g%)iD z>-27vliokJj?{n89ZldC64J%U(_pIx;s|`cmMoPBE!npMicqa}Js~B_IX=$Z4nEQ*ZliRmrL8dRAr*|~5#|oDz=@Ew6VehAl*csg z=YV$*HLt6ytHSe6YylC|M*bo(Y0V{bI&w#q)rc3r@!6NNhC^3JdpbeY%fLR|TWXoc znPZ}hns*o`ES7oj3~Sb|)k+S5aA*Q$8?{%xxl-39PUhvXv{N^#VYd0R`^(i_RT;rW^{`YU+Y8UV2m&i30TO59o{_)inGGj_64Vs!v z$iM{T>3M%-S^dxP%|m*&x;kt3piII7d|*;|*MSMHu=}+&ioY~7^$x#7zym`+DYve* zcTbYJtV6Nj7RS?YEAeEKOz#nU6sxRcBvUKl?$1yE40c|S_`idlF8X%*+|K`r@L8z) zyq#{F7J)qJxG#Ape?A~wcHzOn>YE8(B#H#MG8gikNWwHlo>fGZE5F<$+=~G>(MCb7 zxzQ*+Fz#62G4dgII6mHan#jSltOLs+Y|CA0s+V! zYr?f4w1>Y=nlF|Juy!#eu-PU!Q#bn(o;~yM(9u7p3Utf&Iz)eq;8b-$@MOaCzj$QG zE2{x3J;=%u#bb%06@6$e1-@+`WB9e_-m6BnLv!u$ugGWASm$c2xKrbv+u&*&X%a0} ze=cEP${l^*+<^bFe7Qm4{;?Aj334G7HE~$bNaJ~Rjd~iGJTbgBulDLbPl3?QEy5Iv zTNTOcodEhMYVzy3vC0F0qt+Pm1aU}5uyc;>e)1f~YA2ST&?NGxk94Z_rXBk-Iw-=g zXwV6-0qY`IXxkF(F`yp;RT6eU+y@YX2yWIS{WTw(=AMS*WC@iJ!QyY}y`2!PRc?O7 z21>kDlEWMq*VY-$&M;a{=W{5AZHK}f5$D?_59U!~MJN|gTfYIIv*oCp8|j{aB`n2R zrcRT`H;}l<*KGASeeTxV1242hm5=Lm6VY_g=qucbG7om&X~-Qkl2qj2rO`y=YsJJZ zi*0iAM8?ecM$wj=`LYMKC&-LyYHI2pjNr+%d$faCRWMQ)$(7+dq;b0$iDrcukNZ;p zyV-nes5+qzYf*Jw2A&F{UJzm(Asiu4s;H`F!QG^El3;TNl=|F-8LU*R`QVezaF*u_vO)?H4Xm0zB8i&tn^@alO?PjP|Bc@)sHS; zfETo$5gll8=Z>;}`89jYfT!j8(?{KM{PcnIhkGjvb9&v1Ck2lIj4gwTT(Y9~6QT5e zi7@{PZT`pCjcy#(jZFQRdiB!4(8l(Hz^UtXs^-2dCkLZ4#50~R;wYxR0Pr|=?E3CB zFfz+&CwKK(WEQaHj~4g$IApw>on?|f)FZi!{=uO#+TByc+1|eI??2)&rG?>j@2@p; z=&^ImPB1Ti4qDc~a;z!)(DJ{(5n2&cKUw-Bl9#+1J9J5|`{nY14UG!|4zi#b9rO2u zen(MoJfx178BKbQXlRzcYV54yZn&B6a2Hc@zJfDbPx}5madGtXLfUls6N%ndDLi#+ zDd|V?Y>*ePU(d%-0On_o96Lg6ihwLl`JD{m>zBr!GCeq=+)Uk>4w(iUbgirp1N~pB z#kwlGPM4&Equdc+w{1b?ImM07Qs3WpF2Y?%z+4b$9hglI4B<%rWWGE1Qr@V^A=SX# zDc8@OSRWD*!V6#pHn;k>Kr0}d4)xFXyDspZXl|3T?&FPFC(rscd4NpffNq({TA`uQ zFQd%^ioNuC+vfx%oS4x0+t-qk8BUzy#^Cu4nSBc&GFJ$n$V$NK>z)NBS+)a+)sbMgFXpagcs_~Y%pU_xlw0pYx`ojA(@WErARqf%j6U1i>IH^?Cpwx zwL((?kg5!}98y#nmqJeMPCN~~2;6X0dJWkK@#pfeSQ63UWO|53}i^iLL)eWCke`=+#q?=+wnX_-`5Tqwd-}M7lJO& z&Y;wK_LU(B!Ud6+B=+y-iJ`|c&(@2buJecV*=aU2zBEG8_yQI<()3;pxsf$mWf2!G z(isLxwn{pk?%pRgdb=;Epq<%p*`^s;cm7T|_@1y>hA(A&nvNdF z$Odg>+MZTk+Mp80DQnz48Sq_5YBA$>HSVsI{<0Vcoi>g3>3g(tp|1^XC!HQtn0+-f zVaU)rJ~!97+f?vBdF-M3wYwy?-`naHe)OBo9NB|rbZvrlT28LcjCxH;0XQxf%$F2uU#R7obzT53puwuZ~Ln0iwS+ZU#+PB z#_K|9_$}$(PFmxgZEXd*eip%56?gCwd9=&m?U{9s*>YUJzrQE7u5d0^@Z-@U?*%pz zuawnxnSUowN6s6v{WQ{ILyrg%{A3BO8L2 z(FdeA^Z9!bZ$MaF`tO&rRO!uR?Zs{$V&S-A^7ogcT3hS>`j3a zzRY%J%S8EOiJ=+e)gzwRjcc!Rb61#3il?yR$&j&oH~vVrn&DjCtG>Nw5Lv;jIwmj5JmDU~^t$HI zoGtA1@DeYnE)jXLh@n>*f62ULA!zR`E&4K>goEHX`K$W=@IQns9~O~y<=_|YbCK(- z7xP|LmovXs4r&O`wQOv;qI-LD)sFbEPN`u+lU~G{!RaZv%QtrH{P!Q)+2=n76Oa@a z^NXa428Nh=nlSfoJWr=klL{EdUV`FSv>#4KQ+zE$y)9Q6w~gSrVD6XUwNLebi+#{+ zOLydzRh*#>hb@(BeoTMgM%iQ=)@=LZGf^QA#F|`FWY5r{e!ZOfV04Pw>(`t*5uR#R*QB*c7yEtDLU+F?=J{xAyDp$rKhqm+#Z%sZ3#yzyws z*9|ygBk!f~Ud%S9yqty)BSuym5GYXr+HOTON_?7KxY#eI%$|O4nCv@``Q&Izn+Q?c znPVBGN@fphV-|)y-}br}#GcK3+KUgh1)K;WmZ5=6<1Nwn=IHFBv%{bVEbKkU+e{M1=fJbYv5 z!;;{00ruxg#ro;bLLqiz^BEZ#*jTt%T+Ohf(#Ni~wQ{FmQbsl#xi23wQoGAbwY?|y zgPz4!$}53QDQJetHN#GhwtpXPP9v%g^yEP!I5L%xu&}VAg1W+N4MTq5JA#}Ex+&2w z1|hC_;_4G(XNi32o zrlO)S!qID$5BdS>hH?CssOeJBHf&tQ6Z422$1;q#!aXv-upkt0*~}^-{j+6Sn%ha9 z`DSa6)=oR)QFP;fE9U0r_V@S4?>6O&23C!)9(u&LHUvZVmNzyMO2*>U4b7$-?Nj=s z{rA6xg_PP%(RH7v)oHDk4{7bhPev7h+zj+C{-bkDmUvXrPRNd|q$<>0feCYkhlRDZ zw{vwp@q{qz-akw`xmAQ!iLtNsL+q-3fKVYx1=CqgtB=Sg*cdmYfdem6ZbO($b>49~ zHdKs8-rX(Cz00`85J(Q-gD?ZONMuR=U%(MvcoPq2{*!6RQW_ael1@7a^Mh#8Z_nmE zL)8+K)O>j@z-rDO$3tG@RK?-fYLH$gv2VaQhILBscJ@xW`5fj;uqS))afZb($s5DK z7W`W2ZX2_ z0{$Ij&6J_t9cDWjavUbOLA+TShPbECsazm`l2?Zj)|mm1C}oLke|1eI{@`oQ15Lc| z-qb!wdadY3(%jkYNsA=?DYgBI;5x7im>85=Q+kh#<%O6|TsbKV0!UsjYn_hu%;QTP zu2BY(%{=kW8yp25RksOt0Yl$M7v<@(Md$WM3P6zM`RDQJaLJ-QYO>-;McV{>IJ7B# zh_p23hGoK0B8?SbNjpcgm1GVJxKq96iAR{toax0l~psJns{e{pd>ZX?ev| znme_5pp2Qn9Dh8cay~pHBtFp*2|-`3EUDP595LJ5*1NV=^j`-D{gX#<~H*vZ+c^=eV#)#zzW=uXel($d(SI-feZQn0R??9l$g z#7}c)=Ri+R3XA=AuU-*ZppML0#)5ub5+X_>9p%OLzd9yjt|w!J zQ{`E-H+`_My1g)A%c(vzzPTzTt!TE0)oJQLw6!5Xw++kTJO#Xs@n$!pl0D81U}!iB zc@5N~D)iyj@(S#Yu!aD)xY*7o&f5T9OHIG5Rj97|rf?jnJ0&UMu@}=pL#f zm@=7(?q96upZ0XYe9<b5 z4NIYxS$bamfu|_#)k7dWaM^9`xd8 z$azy3^mK$3MR+c>xcE{T`@UcJORt~)MDCp0!S}${&F|*1*F&N7+xmCa4v-QRMw9NN zuY+Fpm=QU|e#Ajx86$3X2M$*Bs2CC7$#H#O67%VG6_Ij+{@saHn#9j0eUBtf>VhY_ zT`Dy#&GEW6oXtKZjKqdDqpsA*LmuZ~$&nyfL`mPPj=7P>>Y>rue3>T%j@h3z#Ahn{ zmAwK&zeg%kx5SRuCnrx8yB;SI+^m#E8GbR`r)~4d#0LPaRh-L;9z#a_5cvzjbkxff7EKNNg#{b?DLC zCKR?QeASBi9=htaa-<#MV7Iol+~A*Xv%Jp^Smc-_8^%5loBH@=F9&2QM1x~pA} zD+;r>8T?&7$e5X(v5QRIFsQM@xtmYps6p2KSnqNDaTj=6N}@A>j>m_GW7X`Jhw>%< zwUX*)IFlGJwl2f@p4IBE3s}u42n`KA@w_P~v^f4M6w<2LJjb6T{7U$Ac@RyN^3KsW zY0=ix-t{{n`(_+sZd}jRjegzA@?)Z=D+F`UwDXn9m$c;In}U5`$kp5lgeV~2#~{J<%#Gg&vQu2WX|*KhI=JUF+)+UkG&Ku z86SIy(^LoOFKQqa1JmPTihX!|OdLvuAz-*?Zz))L+KrZTK*-Zq|Lud9#CuI|(Bn7O z^0oQn6E=p7UJ0S(r+O{B+-?{-Kfx%Qg}tHnT|Bq}4iZ%fG27WLL++Pm)>ZO_T*__!Q&1M8akAJ*4 z7;Gqq=d&arXlz;(#)N9f<3byoJH62%{_CqO{*Vs8OKgB?kfG2z%Do(Mx8stcX4V9p ztZ!_q4eF-BFf;RyW*?+E_kIwKlxfn#8OOY_?&;g6UlllYf78x=Xs(Ca$l{HBS|S6X z-yg3rgZ38$tVcM-ZZbh@9>Z|^0xlzW7`r$EaecSViPUKvH<&UR7Ryj>bj_8#xZQwf zFxCnSJjC;5{SB*gOW_fW1!qd@pV&bqin z71ZC$cYH{1wAnftWt`+VQRuL;H!fP7i&-`rG)KExt=_b21&KSD_>8H_G&dA*h*ht2 zD*FnwZ7C0Tn4j1cnbp9{x003Nhy2<_TT(A}%A+|sZX~2pLOI3vvHmVJ>wfCbOJuOk z$)6Q~WkoEtLR|-N6>Xv`AbXyd77mdW1+pfel|yc6iPuiFNp8Isf6d&%ZpQMD zT({I@dvrt%U8D~2q68K5?3D1}P;+jjpurpi0xwo*`mU({+#3hu z%~E`*yzDz3>Oo+|pfOtE#zM%8B{z8MTH}2<`-b!|!>)uuwUE6CYwwSZKR@}fGCr>9 zoxGU9WRzFipf|2sh0a0hO;6y$ z;Bv%PdhcB=p~YsY65^GLkA7qaPF-U2I4%{p|o(H#f_{V^l;U>{Bk3XC-Mfmk+-%E~@j`(7;yc z=gfelf%o8tEaQP*TSZMn2>SM7JW}r9;|nZ^kfhwx?hDzwW{_Z%vIvePRI8T4x%4IR z3Vgz7PhNE4LvF88>;r0IDrbp--lEyMtecbc_l5n-4XNLBLyvFcV>ta&-Qj%Ats2H1 zzobx{!P*b_&R|AI7s|7Xn?xTG4SnU-USwo7d?yK8>W?ygicz?mxo^){Y{c*)MG0A8 z)5i;RN4q;NB^bq&KIip&fdT4d7-B;2Bp_4hLFFJqUP>1+t`&OuULY?;YD1^4Dr1=e7$i*MBDXH8wmAo(CRfe&Ub&FBJ%kf-*gqN+4eoDl9nz=bO~ z+XsBHt~Am@%=Zz7DguZ&Eiqis1Ae3Wcy5A3=o>#a*kc_!j{lL?tJguKu1(m04I9>_ zP9T!-a~0!0K7$J O09f1T&Rb3U$o~SkVZ?I) literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/hexotic_parameters.png b/doc/salome/gui/SMESH/images/hexotic_parameters.png index c06ff3bb2ecb0a5ee2f3ed61570aa8a481d7d9de..5f4bb3df5e8f7ada557f671ecb1a37fa7f0eae30 100644 GIT binary patch literal 23172 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

Ro91sV62BNF+gcmRQ`l zS(+i?ONiQ!47%_wWF0GjN#t%+BsM%~v9FCr-=Io|^{4$Hvwq@CD~K7&#JKx2Jhxz!Jn3&36fX!j8HQiy=cDBZ=2w8w z;GWpoT_wu!^6_;)tS>2H!CccUP%3)6s$0$9$|6ULOA$Yip|R^O0n7wEj0p z!~Ad$w#(}i6%j!dhuooD*<4@06B%h&*iaqR?7y=PT|8ZZpkGrdc85|9xsOyY8g8CR zo~yQysiJhIc2&SbvQYM%Hb2QiNB3sdD`m&KV{kC#*!>1tB(8oDc-FgYt+b0iW;S4XF_s}rEyvfZSfitEW(`8K#mk^2RtHXqG^ z8sXs*_xv*~8K6LiG98u^puNCyk|WTlB_rzB%JN}e-ZM6Shg5^mb3JLAJSI?+wJeX z0TM0ikK_K<2Osuf-GaqJx4C^*Y%=ZJphk8!_v$v*qXF_4(P@^x?yYp@<>STxSXIj0bZg zA|fntuOGI0)cRg1HO#ve*gp@ywY9P7VO|&_>Xr=V73xJr-RtOX|90GGXu%<3FHpaV zq`cBn%u-M#t11)>9)W~W9j|G9TzWQv-`(;bZ>Vz0BdZ0v!WHGL9Chw~Fsh`-)c zbtS91C~Aq0!w>bbLcZ5U(YC(~W4C_EgYi|G!tz0ZiWkjFw!C+G8iqCFx^dHVg z!}! zQCnl!A$shrd9ftN*1~=Sxm`=4%7`GM|9O;OsS)zI3!gS-gbZ3Bhy;C47UC00c literal 21710 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 diff --git a/doc/salome/gui/SMESH/images/hyp_source_edges.png b/doc/salome/gui/SMESH/images/hyp_source_edges.png new file mode 100644 index 0000000000000000000000000000000000000000..2305e178bd6c84cfe60d537a90741ec483eb22f3 GIT binary patch literal 13394 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�WkOa`S`f@*wXh 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/image42.png b/doc/salome/gui/SMESH/images/image42.png new file mode 100755 index 0000000000000000000000000000000000000000..d0120fa1ede5f2785da08336bfa85689607c8d9d GIT binary patch literal 857 zcmV-f1E&0mP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ;&q+i>;4wDVIRNfJ{J{9CArAN&bQyOcrGSfFQDgb#hQa*=6x!u9?Xpr*tB5 zoSvR;+pekFgWa0!dJ%HSgD+Kw$LIavy(f$@d`pvjWBdMrVqsyySeAulS(M9VaaO?m z{JaT*fP;ermX?-;9Yql-n(7KSFi|09cwi_FZ- z0A%eT2pAh1!}C0KuVAjgg6m^F`zZH+t6+s;ut*dCR0;WL{S7VE`Te*P2kE0 z(_5%+zE6PSD<~Ynj(~S9SYBSHbgPGKHe0AxtM`B%phm0JVqjpv z%+1Xi*L49p9mg@iqii;79LM=e&!7Ke9LF)Uv$FFDTS zcX!v^cypL%UhgQl2iHYNCPQ5l~JTAv;ngsYg4RqYY jGXlRHliGjF1^9OWjdNV6x1YOp00000NkvXXu0mjfRrhtP literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/image43.png b/doc/salome/gui/SMESH/images/image43.png new file mode 100755 index 0000000000000000000000000000000000000000..7b6b895a1d83a5d1393a3af60c2a8fbe4a7c0433 GIT binary patch literal 965 zcmV;$13LVPP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZq>)?Vof(C zC13~yM`(&}M6`?8O1r2b5?W%XNEbp2VxZt!QX&$v4B03F#ejC@!laF5bcQ5;kQp+R z(#*Vj-+OcKJucqIq$PIcfy@7LIsDJp|6ET*_&+TN;CbF-kF&G0S(LfCIqzu%larIu zYPIlvpVie>FL#(zS63JLe4cu}&I5TzzyShu0U#J4L{NP6uBNxQmqw!jFp&GN$h*6{ z7-RVJ*QJ<5!1H1h0c+#4zkh~Wt%flM;7w0N9xM5QyeI$M{RZd2xeh^UBJsPm!iysV z{PshcBgc>OTHnJpU_A#gH8myO-Q9Se$KM-YWMl^kQ_@?v&Ju{>!VhyadhZ((jScwB>l2U524i>pin4KsZ>y^iPnlh15gJxasW{jv9q&- zbB^s_zRgNHtYoF$pi-$|ttAXKQ50a>oeaAGs?{o=&zHG$=_{OrD_6#{UX@B?T)P$@ zYlZ9Azr#7l`1m-+v~kYz@!97)3IQ<2aQb9~2ux3pptVkjM;IL)<>t*bZru2hnVFM_ zIFwR^VTf}U=WIIRj# zn0~*Pp`oFfEW_BbjdPO7#SsKL>(#`>XNWj1Uw$2>nwh^+O{}$~96%uxc3obPKYqH0 zF%GR;Xzde4ai2WT!#Rhw24f=nj*U~kvqThyEG~YUt?TCIW+_`eLDOzqe19LMngl^i zDB_Y0k&LjpFKF#^R=lwkGA!2b>aM@J*Ey`lN)00000NkvXXu0mjfoe{Pk literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/image49.png b/doc/salome/gui/SMESH/images/image49.png index 74926d24450a3e5b4ca4e9466d88538874a38df9..6e5b3176bc67ae89e0b55398dff8f90a58084dae 100755 GIT binary patch literal 988 zcmV<210(#2P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igi8 z69ouD!UQn@00Ue}L_t(I%dM1MXj^3%$A9N^tu$S;m6~Op7gE=PlYtqVUUW{%TAh>0 zDvN6`EW2juLyw&{NJ2(!gswzy=WNd6q`cFX1vS@05jTdx1IWRC#1E44hx+Rc+ zr;dD71hE=N2bm;QCjnxZ$4X(X_~u%?XoQQG&R*S^vMo< zJ{yD%7?@U?$omP7y^(2ARrRZ-3g_qNQFR+tw^`I}vWCO+kqLki;QYpoYeru=T0vRa z1ukDY%kY;MQIuaOl9+73aY6&|1+tooscYoToSUx$dbaKB zhaY?w>T-Yd?GtQXrG)=dJQo20kQ z-UU_zJ;gW-JW_m5NRsqpI&If~aYC$3rtFeMRb*D2!5dl*0Q-vVjutP^uHpyNz-e{ zoe03eIsc!brrG-X`lhBP)2+O`yl6BUjYe03ns(aQ*x1m}keVlyO-xLlIeiL1RaKSE zWWii!)9b4jq=hB)rd>)uyMP8QdK1+c!R+JlUo* zTgmqAr_R2&_uQvie_d+l0auppFKRJ>tcp`vPss<$fYT!t&%?eQpzGCn@;^Z5ip zSR$W;n=YMVYQ_DYPypx~SnLMWxnAP%$PFL>J9BJU_crYC(W znbF@J@9&O3x%WO462c(?Kt)uVKRyj<%OKW+V#qC(0OXbez)V8@&>Qb)`PAE|XBFg^ zl;;`@0Qh43mZt_qtW#DE#5(0zr|k5IIi86pXVtBJb7cX^6r8DNb%HyDmq~cb8XBH!Ykv*^=*aN8$_|EB6=msw=$r>GNL~uH{-TP!W9v>- z*oWom1k+ZBeCh{VND{|hW8@`^5M+yoHh6aZ;U0VT~?o78k?5Uon nO~xlzDEqVcCqKUb{4wzZCeiR|q-K9=00000NkvXXu0mjfJ-v_Y diff --git a/doc/salome/gui/SMESH/images/image79.jpg b/doc/salome/gui/SMESH/images/image79.jpg index 6d164167fb70656b96bdf17c574eb4ed3765009c..0efc736950fdfe0da08551e01812327ecde6a5f0 100755 GIT binary patch literal 57934 zcmb@t2Ut@!SL79t=hH58?X5F)*UqJVS(2?7F2l@e+aI;b=O zX$dtzkkAAKLNB2l{(bKL&%OKZdv>{Jvc6|MPu8qi-#asF)>qy+8$bIEVA9hDX#=RJ zr~ta>Kfu`};1PiO!i9ev=Y{6{xJY~PA`Q*OtCufdqNTq|PfvH1j*j6P3lqaN=4*6x zOdL$itZeM;?DUMBTpVm%ENtv-|7e7Y`urZ6i&rjQyu!vn$H4YqE@$5W%(PUa7g(sN zgaH?rsi>K$&e{Qj007m+b8Y{j@c&h)E}ZLl=`!t=t90iTFie08RMgZLXsG|8^?B`( z^XmW_=8G&sw;x<$HF|Mb*n{oP>!dHVA`h#+vl|bQMdj=~!>?TB;N;@w5fhh?ym3=r zK~YKh?!8BvTG~3gAiby0OiazpEiCOF9G#q9psrrtKE8hb0fBGcMnp!vi;hW7`H+fC z`H>U{91 znE@JrL)=%_uuV$-8DOk8>`%Ju$&=wTz}!CQ3{ZhQ0}S06+xRF;Y9$Yx0d$j&m%*ga z#4X1o$=o{n@EFO@7yggRGWrUt96e#P8QeMay&;i_p{6?qV5IB~D$- z7BjVb*l!Y=*NQ{Ao(fI2@P;)H*8P$CB$^DmD^XusSn_PY#HEqP*aQ|dVx8sy+AD4i zissfVt-fDGm3IBr{k7D~{K^8U>}+P1F%Xe@QS4R8+>by0vjhJhOs-J6gNkFhGXPE$ z_J4G0-Rx+NtEF`S=m3=EbbUXor>}eTUoymq<3^$}?7n8@d2K`0mTYxECW*jHlwU<$ zH|zV=j)E4e)JHBB9S7#g=M}U!-Jz7ciBO-Sx zXSO$38Ra&Wg**l>XWxGP>0P<3r8jel4$bv>9j0#s#S)^sYM@So+eW_@$mw2pg9XEO zTX&0PCSkHI99xL>Qf3|s%PsR=O8&LW63Qj}oOi61p|roBUwl$>`7`zFsm&GFn>W5r zn$_#wP-!+d(qh+&U^BXZ@xLSgW?36K`ZxVpe$2UPd*FNq$k!cBYd;a3@7*!ddddCY zdKSAHCO=IjCca8ssb^yR&2Y|^;e(W?0b~o03#ebsi%8Y4X8<2V8lQzIk8i>Sy}46S zYHk>Nq3UTaB-E71I#??`v;K8{NA(kZoWuFxqSbr1CMr@ARF6Y6}@eV`0ms6Dkbj@x_#5Now(! z(KEnXu+OLqB-A8DsGPAPhck{MrQzNl5(7&@5YYJHGfx!vGvW5b^=;e zX8ba z)!qQjAE?VHK|P`f6i{l26@kL3yQLF2%odWkerk`=>-2o#dQ~@R0>9gE^>iy{I@>Ha zSaft(Y}M zGxoe=Fy#s2rfwWOW+pN6ufhtT8Q#%ft+^J#bdB%iDX8R!+>TMde4u)r5&gf8tIOAw zQOYgXtgWnc(+Gtz3hCmFSU3l?yh0Y|pQ?^WFr&j?NXE<9A!O9rFTcm)*UERi*%u=QG^LS=z8#HM>41)a7Z1nOkTwzV;#%< zOUsNs~{HorHFI^RDH%mQ9+;8G0TNx#w0R z#a4Tj)BjGkRsgB2Ip6 zfAd`?QC!^63Rp~}VO1HAbA+2bh3+t!14hw`dQvwd)DU^Y$O-+-7B~!+U%h1Ciz`E{ zyD2n7w8xy9!ina{rA`}~F?64XUQ^vW;P5^nq9$FW)){JNQDBm71~xsJ@=%UJC>DC$ zjNY;cbv@beIk4WbR1Dmy3(XR5E|{)e$-?+za^@UIrt>{cX%7VLKTm0Wot~Ik<(YC& z%uz^)_bB~inRl;4`qB+k^Y0J%^5yYpX4MqIPi0Tnch+nKFCU0#whm$hsr`Ldr1%vS z8o#P~l|p^@Ic0=yL)^4jBv>^jY@n(i%#zYA?fybC#?Tv#P@WydoC%(X1c_rkCv0o| zs6u9l>#1p75-_!BOL~1V*0?@pK10WjzJI_KKIwLZ+QZ~RtFk=lS#>v@Z}#!|-4Mm=%V)a1eah(x>8W^!ih&NNKz9N|M#D0zSH=we z7$Vw!lSU*($4oW?rxmt_tP64xp$Jm#kBZksi7}KAPE`$>2W!YV4qoJbVG zHP4^_+2xmtc}CSVR?BZ|Ozy7@L3ogWI(|_I)GVC0z2#PPLf*Z0;p(l>ABnz>^^sFk zn5Lh-A~m^_Jvik^aBN-A#*<%}Lk;&hw5f(um6gS-XDj{U^lxkd6OYmEsMX3a z=Cv+^`D?J9#&!YKs4jvD_6w>F>h}ejX{wP)$hbqQ2O8`_Q*qdW@qg6O{E! zO1LTQqQT0Mw7TOO@MBD_*V~aVe0)*al@JC&32F#>yAK z`%30lQhu^Tg}=(&$anH$G2`1Nr6L!l24J!-(p1UJ*LcPE$$OM2Zd@NB);Hz4Xu)%T z=pzow4Byk0*eNobD8(l#g@mq!l?tc}Ug1_O0jD08*22#KZs$ z=d0h8?;QPoW7gX38?2Z)bAgdhrk)}B!d=MG8Q}Y~LChNXzJMw@b?Kd(j6+SDK1FM! zXv5yFT9zP#BGvNxR`u#p!+#*f9^lFS@v}Mn=Ag0_4aPu>@}yxfB%6jw&y+Xz z3TLpMaKudSHVe*<9Ps*+mqD{`w?tU7p-tMz;jXoGpf~x0^QDo-6#^cG24m16i1BSk z`qMrEwN2D9Qe6N$xVt(|l2gN`lR{(`wc?oQQo+d&!+YfLqJd-Cu!c*;vmvG-au#^^ zoh&_u7I@YU1O3qYliqr+3wQFFlYU;`ugGuV`y(K+sS$U~Tn6#)ZEF~d^d4ZboXS#q zRGp?-mA%Ef_-+ma2Lc_NlYHCHXDZRonOW-I%fM?Xim?R`z8q|~pR&}E3GN*CLWqsx zpGONmraRQ6=yPf~hJ8vFv%RV9=oDkm`Exe9_}4JO7aOgzyU{Y8R?PnLS-r?jXz7e8 zKGA>x+;7}bb&c80i4&yx8_e)|IaHiH6Ae_=nO!{tNb1u9`4`ird$zu_Rq0m!>=xA> z;9HbzFDbxYcbJ|Znb9kQ>113^wTvTg&ws^GP8ZLuFxTh*zA5(qWupB%|L;($!x~St z?quiq8t#XEMHT;x7yQ_f&B#3N+|~sAt4K|SIciKa*b+oKEX(9(6w`D6kVVIoqxslSW2MO%1HXIH<`;^sh3@xBD#S$S==`onbeXhU7Lc^l|YkK z8{|!O+GV}e_OilqZHOH-URDlT2t||_2Cc+O6xVc`SxSZ(52|_ulubMF+kcOTvbusC z@BK&!Rtq7GubDl@s}Hb$OrOQVG%;pUQOP3SNW3J>CI3zpgohzAXKwW(W;9s8Z2W-E zYACP977Hu&Kk7z1Y-d3JxQm8gp*O{sRo>_9kAXVgk;{*UZ<}>8MjzF-!@Zt82=PDS zYWlc5I#zQVTie?wqWh?a@<}?Ai{&B1GS4AwA^Q7^oA$1CwpxvWgcI43jV;J}%rB4O z>Xn;CvdzF`+?o$8cSK=v$FxT6(#BqCGkGJjjypQza#5~KItXsQeIb7C)5T94Z8h}YnplqC)@m)LgGZUX$Z2WK;$Dg5} zEbPyEZh`1yS|u{3dQy7DYSjALOT@y7w8NSga@Xu%*YU-#&>D5W=)8mjgZO{J?A~|N zM1qRy{2qx9omS~OPHEG2cS-XuOnL0fSO4Odvdow)Z-fVJoH{RJw&OyaHcU`91WQT* zyyc`;t#ErTD=peP6+Ob+MVBx3)Bkzprdl(FE%~7{26-2_>BETpI_a776#(mq}#hD7!zDi}&gP1&7BBfV<434h0NwWs#&iqx0 zZn7`(4|-NTaxJn&C|PnntQvD-37yjy0~TVE;d-6=CUY@Uw|o28#?+tt_`U5(=iwA& z6e8~xkR-hk7oqrR%Z^Jah0A!C+J>Gcr-|#Vz>fLR(W=t%Z!a>GXK3=lqFeR4nHeV^ z)kUE^6)}IMMPo?#b~&}FCzFOg3Vk(}h7DUF;Czx;O5b+gug1lzi!UEn2l$dZmczJ? zA-{vx0`;le?b~Y8d^vusOsInSwxLk*c{wpWS0AS45aAXrSEHK)x6;-uNjYZlH)|uQ zz0JkX7?d_wl;B%3R=*rY^7y-%vfI579a$@#n1m5lEceFr6;%HgEMSw0{LR1ul9hwU z`Kj`h%uEEWt0LTs&G-sjAAS3QZ!ho%+$ujdoYK z;ar2o%LIdgd)W7SqG?7|wK;l`Ixe{Z@FuiLI&u{9T0}dA3m*g~_ht2GhU71wGDSTZ zRd7jO-vFmPtRLR^i#~LBzLVBGx={NNXZ>KQGgGd?;Ap#p zXUY;7_cT4f$@Z!>bd9%-zShwGR>IxfEc=G$_;nlIFweaOVJYzww&XyU)1`{vJl7 z3z8Qdkb=UOvL&+$2-RwfGzBh?NN|gtVjmDfA;c4;)a6%p;MIlPM~=Nz(PFQ>m4BNy z8QL<0STrY~29vwrKGgYuB%x0(w>6AJp#A)8=xgg>3$2+(2_f40PNPyUc@0Mt*sGDZ zwn!xMK%is7C5l#4uiWSRC&krRvOXs5U4QCH%8P<^oIJxze_MSrIl?(%Nsid(EdX{% zF!o$VxK&6mIdIb5>C((i*~g@1U`}BJ$7`Qw?<%Y>3rYmRQ5h{UM8Af`;q6vJQTx%g zH-!g0FzcrV!}85`QWR@h%X*{+8-c*(?&*|TVOIy`FjQ0s6S428daYz9X>Tii;KkV< z3pY77ahx5vc2KG_wCUyOH!DjEO>U^+rh;P&9HK_^J_HHH?YO3Z1;iuiJd+rbgpwfh-G7^2 zkWg|)F!S``P6o<`3PBG4*MZ$Pypzhf+N!wJ)NZ*@GBA+cdKf8+CE1(^;-Jx;qX z4HRyzUjg#!HwW&7tSzC+6IpM^E!*WO&NQXOSi&3|)`GlodvGac*E0Y|u+iqzwm|lU zmZUES3HydI{8!HaZN0ONcddc16I7gE=S8>+$2g_tN>L}?v|{sb8KQyVgYRydwNV&M zj@f;F=UiLm>1=&BYk19-vjPhH+F9mC0tW6g8Om8PGiH2!u9;dRx~YGYK9TPD@xg%e zY#ngNkm+Ec-9~x1Al4YdwJzgx#ZCTajH+i7&Cf=6hh(|!o0SO{DMQxB(>`f2$4?z! zkOY~!Ht*WZq6|3T~O9X{x3GVW#kxa6SkH*KsK8xE2| zB0|$ZwmR4>^)rCthx+^yJ^hw)BYiQr+a!iCZCf5&E20sOP#3XXwz*N?w3*XZZ!Fnb zrJ%uvsfIrJs_s}{+v-$fF3h_x$}y;G#GI|*u_e>mVfzLf#-Qp~I{k-G^tz(yX{l9T z7&Lc!3er{NvR7yZN>v|?hN*Pj(|2Qj=U^WD&QB5k)zBKCon-!hqY$BqbH{`!rgoY1zy&zLg87uY{1XELZd_xiIZDiti;`=jTz$rB3Rl~o z8S*<1qM4NkANdE>=P7=@`*dTMttT*KLSyufq_6H*^yIcSF7-_|r zVKk^$>&)SX7=z zd>9bTyJ=u}*mMR+J9og|6z^NfaT~A?o16;DF0P)05H#-UbNzXeNOzEFF&uo?VMsp+ zH4YQFiATw&4y_Yu1qi$zOMUd9D!T+R<}!WJ%`X25km&0oJdv=j0;gUJT%FXH4`r(z z+)&_M69h4%m7F@&EFs>S@AcVSgfQm)^y*qY?Hv-AJ1+3+7}k(yV#J$AHgZhs$tN=r z(tm;O>t6y)Ju@QEC0LYne#y4I8Fao-AVF>9t{$J~n>N zkh9BYuXLQ?gkQvRM2n3#WGiNPrii#tRf@7m#;-LwF79rvZiNQgBGd+QVb#9dmK7O) zG1!v;U!~n~g}$JUjJKAlQ87MiJml`#prGD09`k&>xVK__08huQnEMmR-&3(JA0BxL z)4ex>L*_MD{e3sIhHVXpIe4SfofP+-h+uz3cQ3iQ1@AU0y3!X(si|a=`Pixkt>`IB z<(P>AbEi4v0b@6Zcq_N_&e3`wMpkGDzM;5Ym1 ztAV9$ntS@b_|t2R*``pW&Yi-H)DqXxHMPvKjpc%}U~7eeEWV`f0BPeqh32MP5( zTx^+lK3ZH)%|$-|Zb8Ni%F=E~kC|?=@UPh?d&ehH|9(d>lx$o&nAtPiObg%Tml|lm zyXOzD+hZutTf@1^oxR>-={%$#|N0Kv8dUtdIY_nlq2@8)aF~ByNQKXlY~M;~07R?{ z?|FhxMTJ5%^fO`WmhS!w!={y!WwoZ9z8M}5nBH~wv`Snps~2VY#p`=ZcR=i>U;UP5 znY(7>6lh^`T9bolKK|A^&*R61`$x+Mip5b3i5D%17T|{5!nYETvO*CBEhIq^2okCTz zt$5JK)VN3`xd%*%4h54pxay^x>h6VYZEENvj%-_6-@Vv+{G$|?V$%Q_b9OH^{I;cW zVb%WIy>FXA#4ra-ms+C%;7pEab}&6o^|p4&>SDK?^qXGU?HeC!L?5JwCgHt{ch%fC zjL8KRF{(3yz4j!|#%$cWP=J%&9kGJWVulHbmLY~IQY?NB%%Pny4`RyEJNAeD;BhJ_ z=z`9kT>rzdZyDEMdn^|9U=(iivPL`6gJHNJFMYA5)=RqTdh*32&3A)0JvRN5`5(fP zWb%sqduC=c zXzYehL+es&k=Ks&rHhW0&x*t(nz1z#1j?U7-?0jNn_cf_1Mr)Yjx)d&wPqBiGaj0I zP|;2oP|mxH3GdkjcBb+FDv5`QCR@okAmqy;B>{KPdwWMAE0TCPMvz&nu*Y3NmiZji zrnRf>BuAyb7rh*)#L(xZSi)sp6C2^7U&~w>cP!ak1lxxWs=Myvgf_Kn5nr@kdQ+~5 z+0r%FRlfgV{IwWf44JMApOW`*tBoK@voAQg!|s!t3sEu|V#D%@Tq~9x=)lm_VnY)A zkCAW2jBd3d z=#k6vY1(QJbw^3gn%`&PbdQk>xo^Pa^{kV4FO9vEf$*IW%RSs|1{h|o^Z2ySJUC+e zVw0|)>Upf*vr-~MG~oo9S7aITrt_9dMpJ`!RxUR>k@ZgtS9NXjtm6cGUwfKm9Iij7 zxe2*!gAmfAixv&~FtwIcLWFS!Y9`MZ%0IE`ZLrop19awDl21C?J;0(MKN>iFE^&qE zSC3S-Hy4QjI`}sgWHDKm>S)cct&|;2`e1e{)p)%2b26GKDyY=Gpb6WIUn|F;ye!za z4Dr_$e~xC}`ADsTgu!4iL|IvX=NNIe8c=Y@W=~6EtqnDZ4OM&^BmQn9~f`Edi zo3w+$+ ziw@P^JWE^KvBY$%`s$HvB zIm|3g-qHo*U>qz8dEGu@3vE*1!k*+<8Y#gnKIzRo9nrWNL5)r7m25_GOOhK=2whpd zDf4+%BT^p5Yy1dX~m!?ML~A0W(;tW!0p-4Mtg)izt|?>h!+ZXDjx zBom8Y1m#0HgrS&DsW4z?D*duAj#0KRSu39U%cYTQl4+1xxvFF8WiAar2(%Bgu_2#* zB$K&t@QZcTWKj}n?$2`h#n)*1$*@-uIU%30pi&TZ;kBf&zX8*9Nz z>T#o{qv}?s6WhX2+rOS_!-V`Q%|gRFSBB*?;kjDJqzb(4m9`RC4uh)E?*T^Q1Ja4a zQ*vQNp$lPfm=sIV4sz4pKsfPfu~*d%i`NRdz1A)y8fRxY0t@Bj%R@Qd&pD@_!vUI{H`JwFE1-N<;wF1c{B_zB3NBdUN=SF z$iK1&f{(fsiY)o)zVhGOu+5a3M8jpe+E1^KAikrqV@X zn!l?uY~3TKwEK1ms6!u^e(8hTAA}jqkh=!w{fi#4cZY~#H%_F^-NkXrj0IV|wEzm< zn_++o2oIxBIeNH-Pu2%9upEU?10rHO7rYCR=sj;J})l#&%|j!LzLQ;@HQ6yEQImyuUUqad+Wz% z0O#oZh}=5A@KF`}m)kemFulL7rZWMmZ>bG?Hu;JX*a$J(6BtZ^^O#S|Nz$U7+&SH< z;$Ct09wdLiDIiThdlFizo`9ECFl3%O@ZB)n^r!AQqKuN!ka5*GkgX-%H%3Y88WRtMsO?Y|!Q_9(+&ko!*hbBb)V!oHSK>{5C` z=jl1U3Gd(9`G>2*Rnw_LANeHJ)%@`$2LYsJ_pN<{`VrCLvYkVB$02Ep!rFRlJtuQF z<*& zhV+j;iOjl9g1;*|Dwwo38QUzynk@Mf(n?{0p0*J413$xB$g4C-d*H&iB2N|zNJ;jy zH+@bMp@SJ&sh>DtvnQhFT|Avf-kg^4*evBvKDD<>P*>AODZ;c5@A^#@c?>+>;&T)I zozar0eMBUvz@6c1I6@whPd}}PxmZjT15OtoDI=Cprfp%n%_-_J!wZ|&YXUal3Vy9A z#vj{en{9t65`w+bot}^hEAJnRRBt0b{7M16+)j%bdaw80aus630=)<5cpYul`XLQat zQ(;)V!FoHiLF+FPdx_UCVNVPe@OJq_Lu;~wH|@{|lZQ;z0yW=k(bwKoxcFtW;Si{% zyKd1wrG4;Au|fHk-So_&eHYQlz_@A)mdam$H}j<2?HA;btO2Q>Q`VyM%aoF%Qt!aE zAj`>S>x~fkJxQl=p1ubr`&nrCu4S-k^G5ZMob`Hv!NfiFhbkD&@td=3=Qzu`DARdt0yta3WL!cRX;sF2ToC;OQprX0yTU^kg zir0vcRZxlT1z&JLl8AVVcO`wkIC&sDcKoWAbY+~*4KFjD=9(HTxe(>ZUx++%PA?{| z+&K5Kx%+;{7c|u(H;kI#crY9RY+B?@HeY<59WZ3{{t$HrxHIB+>|=u@Os7okehBRN zLs8qsb?-F>&FEV;$8oCyKNAm%y_-#%#AF&nygXzo!e$|jtE=O?w789aNG!zvBBmW@ zq1hvntvpfy+k*rkK|&$RvQe*EhALbY!^jb?N2zE_?X)t2OM^y~TlREt4R2E|!b=`v z%r)31yP=w^+NkX>>hR^ODf+F#J{g> ztILO`6y~1NF#h;6XbIFPqPKZDvTPPJd@LQz4OJ_9qE&D|5tXH4p5fQrh<@SvRX94Y z4${psZMrtR#wrel=I+gKHDElwcZ7km;fd+Q`)({vGfZ8eEyvd>Kja z@X@Gz=6NvgScGC5g|1-oFZppPqNS^FVp8iQJ*de4wPS)9Zq39P>Zh-q_1giIrqAVn z-0{I9TM;uX6p3pyNI<+3BuCj;x*|_y4Vk)RzIZ{UnnzG0?H$>)T2)!h`cuZz?|W6N zX!9&AY^XfDJJj5FeTfwGDcCGX2{*rp$Y4&X>UrryF5BW~4DF0QjO6C{UcDiEu@|N3lKEYOC(>QfSXKBr%w;G}K1PhTdr| zj4y)5gkfguMg-PxC37PWC%bj$S+8V>YGvAsj?P;8B?zAZAO=GqF<|R535}TWQjlzx z5A-%u=P6hcpUP`Ir*n83=iFR5d>V&rC(J>wkk8N$nEZzTOK^+jkA$X>IEXsWG z?RfJJAL>{KEX8Uv+a&!F$h+7Dbpwmkq!*^z3%){%ZsCKHmyebrH-PenO6}@GBNgIf zLYZdCF2JJNw4QoFHe#8zJVG4R z+Ajp;MT!)ge~WDaElBQjz5iL*R59oGt!optUKB6~=53|1S%J8tQDMf}V@B^*Slaf| z%bby;3K=Tq%o2%xS&rs&SThTuczQ2N?GK8+m)>A7NNpolJjXU$=vrPt7!+C{->@_J zJX(UPoW{6=-qPEs%p*XiM!IybRV}zqe%1e2f}{^Z919g`eObW~$EVbYpY|H`6Ea;UUZ5Qrbxm;Dk zzJ3P4NUO7ttnUaiADBIE95hm$p2aP%oPIFOg!je3sGx(EyJ9KBsNCdq(_s=+6IokDB`5oO7*=9v2l& zr<}~JNV(dw?u4bVa%-`fiu^B9cu^bOl&(meyZy#1HIUk?)eOav=tkF0v#LLYS@M26 z@R4;5wiamwFC7Qb4|a)yq$Z{`%QqXU@1?%%uwq&erLk)&f@9KV=mM1XP2RQjGr!RB*T=!+DDfNzW8-3l^5#u;yJY+b+^vMU; zN7`BVZ5<(>*+z|b`*+kooHM4l-6xcy>?3j$O)|eGf4k|X^O7smNs?}jgVHoy8;d^Q ztTLYweC}RUh0dJ;40+-`LZ!*2GZw&+%Iyz)Iv%xD4LQI@DZlT>%6HZKN`fJq@YYxA zywl=e_{%Fiat);kXvJGv#Q|?jTD3iVtD;9fN%TK@BNRZle&?>+3++Nd){6|L*p@88 zl+#v5?Q(IX)McfoASs)k6H{!%X)CYBRdvCGC}Xm10%8n|#Ot*V;&|a^Po$jfrOJyO z^kUOvI&!A#I{zl;U-K_ZJTN6&1ZT9yHQmme%1M7tv8tt{)C3@n47rv>pf9H!zFq{S z{IFciBk9YLeDg|OIV}snC`J9=cHeM<7NqcGXXklUiT(y$GQ5A$gMIzQ7gK|R1$ZDZ zlxx?|Hfkz(QQTXI$Mj9;hFMXEOw9R~9dZ1xJw$AV;G5Y4)SUK6ut~7{;%J5AZ5M(D z!Tv4x%)X~8{(kT`Pg*U9Kaa4wbOp;Tmjtf{YnPHVm@*%spphVh*MKCe2Vs>o6nEO| z^%5^TM*xZ>vy_AUh}G0Mag{SoaU0n9S`;ByT}k8o{=s6rf@9PyvbC@o z(=%fQUSr4lk=T(qqXbLHnt-g=FW|!!ohx7^RE(s_o#$AHL0X? zYsmHoPvY^LCd3|p&Z@?&FwO}(ot94p~C9GPdtxY)b`}hsStU+ zg74nw*DWh-VTSi}G><>+#r^mF+EZCE-`uS}eKL^+1j}yvMeXX_K5ZqB7GFx?jKbvl zJaFA`=pi`bN(+9x;mu=dv^Fnw=aLYvKLap@b@P!cPNFbjClYw5I{l2*a;SWLQ%xNb zw>9%{v@nu%`G%-LgY}T9DPK4(4f9Xo`XZiQI#Zl}5C!EI@)S(Iw`}mX>I33Z&iY;; zTp(WQ43H8$w1ia}yJx-DypYw7O+#);4^G`*5RD#QurT+ez0Ra_J?4m&gjj>j@k`Bd z#-LG7D{x!wAPQb>^ydOl~P1#Oa{w$^TDwl@Zz1<^l z;lXPj<;BdkYk=?-1(&^=3!pkC=?BA{@1=BA|314hT6*za(a>tE`QOpf0nI>jo>Uj3 z%pWGxUHT1R@10P+wO#d3l?UlxCjGrWA@Hhepjgq`h!+5uA@1tC^jMbv-Kkq-N{1|Ve;w6Wh9aF*IFY)1FG|WnDTa)+qWQz+%^v3PtVz9@;K>-24+ujle4S- zu17s9)++6hTX@Z33?09CkS<1<+X+b+{un!L0ahrZSWaK}4F?C^PnzuDuW8L2Kk%}^ zYFS>T#f}d)OtlPwrG6gNbg{+aLC#1ib3kHWx}ETg>!9{xn$VDYRR!uU zD1oC=mDcQNwLtNf4O0}iX_ zRc1a_-4=Q{0|lEobKZ%5+b8b`AO6_)GvTg}Mx^Pf+(9(y5CfxVF!`4sSWhn7xB2av zZa*mO7R4sG*M6!^S!k}Q3)eAJe&yt2bb0V;*U&=iJ&?+-Wnr?fG3bW-U%chA*Fwp{ z#|XtN#YwAXv32yMRlkgWm!mhnVYEv&;0tk82|U|-&L~vp7;55d*f2@nqq8gYw)uH} z*Gm1H=KF)!f{kmPKbYt+L+eFfyRHL*UrQ-Ewx}HqR#PaLf)+t)R_>|i6uWW^j<=_D z^S@<=+z992t9kgFd%}A33J2b+b7ax3if!pKSLvT4pVe{{ale@&<*oKffCY6g#?!aa z+GfV7cUo^0lWc9PWEKS@mBJcBY=6W;QCHR!RKT#1TitMbfmA>FPJQ`aZVO>__~7{D zWV^jHBn>Dr;S6~vT1PsDmL4d!eQ!t|+sn$|_dU9fQ_X}(HJk1~WqKzuEaTTLmM^#Q z=4pddT{MSTcy-qHvz`ULIf9?uVmb>bEuQ6 zh&eN>qPjP1+J5_Z;&9R9l%k<~7?L`EPWRnOWcydr?|6a=XSB5V|t)5ce0}A$`Rmu4on3QCAI!KZ2b!stC-rl5)?hlanXFa}u zmq6(#>?9Pr`{C|Ijptz&*R9Jm7T%ge)!**e%za8aAvh4;CTrWpn-ZxPp;RJd$tlX)6_HyxmLxc{Vb@ls_=>>viUE zs`6UPQIrpyvyFLb@?Jq?_Fm<8YB(>$bbCQ8_HWi!9W`Qlvio|Vx~Djv>{zhy568JPLH(T1s;qE` zXhI8WSy3ID#48f|r9w0nmOo^AAZy>IQuifNIt;ufxxTLwN>6gXt2C>&VZV#%1>J{<5{xmzBTo0UdjDd7W(%DG1gh*)Q?OIMXMnp!em~KFrDXihqmSo1 z{C>g=|Ix}BU`Oc5__>*rR%v4~1%~<|gnQ}9cXi_bX`JZchITFTNB%x3sARZDjUBxn zO8)b3-b7=KD^a${vQYq)&M7fQ^-b_TpmYSAaf%T!c!pm+)$#M&Z0p>&VaJzks6Oy3 z`H@z8M>nG;^I)A?l*-tpXofE)Lg~7ribZ;qvhYURz&l^1quq^T(NKZGN#EE~Z6AJh zcHBCLT+tL2y&XT6@+tWX@e1!9s(z+x*DT5kaKJbu?jcWr&bsK~leNT8w?y~mUj7N- zo|W%~Db>Ai^Vd02{TBO9&nLQ`7wo;_mFPB>`jk!!|B3A`A|y4tC92qvKRVvU;OSzm zO#C#|J#kz7w4JQ;P93h&Zf3*r>9`L{lJc#ujo0CVlsTUzT^PbRMX#Xl}zZXZ= zuFVU6w%LjCa9niR4;5}P-{l1vlcpV@3m$acymz`3hw6UJ>*mpXr7@HB`!c1&`q*xo zMdFr{RxOElHy4Wvk6&ySz4NAP%(@3OGiiSRrE_9!p$n2&R7FBla{$&R?X&Uc%%D+8IyZYi>61Vv4grECd4i8D9X2eo#RhY{Fo#o2CWA#`v)Ha-%uauO5o{96jSuGsQsXg?WqFY=@kXB zH(UZ<)m6=$Q`-;ssfbg*S3C08hmoELSsnZ1!@!_E&Hob;#hpwDcwbfqvKM~Lbn&VX zH_(zOdH@Y8K2Vum`4gBOPom8o5|5EU4~v9Dicaw@@JfhPfEf!P_8W(6`fIv|W~Hb$ zvm$MUG~iljj^nPSM$S|KBYRxivkFz!4{JfP(G>ySpF0V3?_LsBR~b^+mAjd~-6W2-3XYj;OVQ zK)?$VZ%~kK=^DsS84g&TuhgQiX@Ze!E{(Bpw84*@+y1QIZG_2Tv7)EMK_4~NwR_j< z=g$Bx6Wxf#HQc%%oS3IPRp0eE(Q>;7mv-%U6>Az0WZCPKy>AFnC$>2GC|BHW!^LJP zds(CGMtguR85`J1myn9j$3f)QAG$m7dh3RCu8Mw0ul|bJ6M;Q`8`L;VOgw$ zNNl_vw12h`{@@#il3U>u;qy8EhN{juC;cC_;-laWPZyNQ)m09k+^8EZNH>nER1k=i zG)y*{UG%do4I1agNcOTg^n6}Ms;qA#?ekw{o(yY?Jn&-=dEGHGB|GZ5WWS{+mrTQt zlK2+0FBU>{SBqWhnDgSR-S6OFiynX6ULt>Du^6vL8%i^<7(XzjpxhHjG~E7icqFLy z*Am?odtDm_R>%g-8q6Kmw7;n;AjG)wdf9#-eZ(@{$_`DvIE1oM_|DxE6M@Kj5yiDy zrI)wAA zJ#5i93!%MC(MALlUdn1r2rA62x{_VSnofEK#K+}#fKYnVo--{}sgWP0PLcKN>~IOU^PA)4)r**v}`A*9a~S!QFjMu z7fB$J%?^1bdVVhRIarhHh78I-(bC!i&WDt-IsOb8Hu>OZGe@X2KHCwzEjJ@6>27vF z>fMtuPqk%D{zh?7URz5^W6Y9%L5DBB_kujrPml{oRRM5%`BxTkcQIN;wVb5?u?C;=XMZwEpDP)NFTOlAAmIdn0?5{+ zKhU&7zBj~ui<6u7E{LOuTB zJwJGH-+@y(RMkx`49W4WeJ`}^`-!B?NO6y$t97Xm!+=lS=2o>>9r1JTrHRGj&yo7F zbOq;cvcDF`q_?uOw_Yez%bxPF${h?H%D$hjv1{l`8M2K4e6AGBE- z^tZbT**iS=G_JGcm+=p;%c}koo!sZ=QaEdushaj4X4Y139TLFip}z+s*2Wof4ON*J z44Uq1Msuu@lU@Ovna3NY9xy^&x-yZhx$L%a8N(6NeZ#R%l9iJiXrky~_6?@#*0uM( zzHoWCa#_ZBp;heAAdT*Me1B3erQ^k#TFYA-cjj?Ql6BmujYmhv?F!*z7Q1xtcWON6 zrsF0ek@m~%zJ}RC_2~-XxNQZcsKJa~ zASDm|)Lq5iOB-L_ZBF@nml%V5(oVGa)26C8kReO^+~kK@_>#)xHGUP-Ap>;N_nkcd z@FuK_CyN|wStes-P-8Q^qw||# zzw`L_Ol>bql-xM3l7e^NJYsfN&Kyq0i-jz^1InnD#*UccyG zn)ii2B7fbCaO>t>R(>=41K9-cE*-s7NI#y7nEq^yEtsUN)6noTYc<}e57~5$jke;+ z2bDS^J&it_e&fQ{q5i5+HYec?L`C_C#t$-h8GbVHF}f^Wb399=LpdVHQplrjWrZSd z6(#>VWUQtk3@4pGZb4IZ4vSy@$MPF(os_|mG889JZ5l92ZPC~U%LK|cbHFl}HkXvE z66#A>CG}=Rj)(jc$h0u-5KeSW7uo2^XpwJ&xug!<-2FmV#ME+_He2|sw;e-_iJDZ) zDgK)%#5=P=cLgJ+u+JOW1}o{KkUMk8WgaBm#zrrb%DW7??9i3Ia&h|AI_npuAB+%8V#8>UebC70x{W5AW|o z*E^YA+N>KTW3!!Q7KP_3KCS{))wLEQOI@gVq{~@E0 zD%A7yeqku;!sjI31Sg|1J^C3J69-#~N*{_!^)o0AVXLcanH8$uud3c?Z*NJm3SGh% z;;QKOO$E`Gpfd%PU}4-c}xj4RfN$fJesIsCrA1^dzsYnq4)eINNimm5^w z{yrg=n&0{@AH%1_-cf38xucAe;ddS4xJo@Za>jO4T*$t~NKD-2;<5>K448X6a-K+N za!HL1IcAM&7`r~`Y^m&QV~#5ps4Z%mDw5cK&A|9Fm#|p<$$E3bsz2}CBU3~geJ1%I zS7MMTx!_+5i)DUWb_M5X=j3|3^;6>77X_qVgM-zdJ?)gkK;uCnbo2c`(d;q3+ST$o zUHIwSG#?Gc?iBV6yI}S8u*?(erb+|}*mro4Kkkjb0dphO8$5UQn$bjQzU`PZqb6S; ztPUo)uozJ0o2Yku)cuow=w!Mt^ZWE>$_OYm#M2;01hUcpv%LA$tL7)13vv%|RqW02 zeg4y|vdg^w)_7=2KRL4c={JeACC{s`=WeiT z;C$Qe*}_{53V0c|X>*hQA|jpq^-xVxu3x&~=n!yd znX_-!>_g2IeDV~#dsLe)aJCy9G-(;)JC0?z)C*YM_6nlz!Ik~(*Gt8;X&I1e{?GjG z>Td8MAQ&3z@P~-FJY~dAYlvHld?Sxa(TaLyk+T~KOUDSkooVW@wiM*s+f!fp@{L+E zneUe%?nxGAzE2(E;BXNLRa;7fgjd>m=hAtL0%84e*dN3H8}`xv9;~O8Fa2THv#%>6%{Mp4I^QSyE$&SGG0imili=bwm)n(a zKNjq;Th<%)^Kf)BYONG+3(t0zH~Cd2|CdLvcB@3lug>>$PS)~%4&da3=7ZnYY}+BC zCbd3qRkRgPjt=)O&Tj`^7TfXm8dE6!CV+CA{QTeSq(&vb*)8e!kU@V$ni72kS^@?8 zg$D=u-w+PC>jaf~e6_H%_%8(QfHrq|dunbXez+-b@rXG_B;+sTKQAsdf_K%RLpwbi zVus@B8Wxk+ehJ2Q1f-%vb$c^GN_cS;WUdPmIao5`5hE3?w#Q*=EssW1l5hOBS^h}oZ^yG>SG~&p=G5jMqnC~Cd+m>{z%`O}IvM=M-YocY zOeq-Rija@ypFjFc;dpe1?xTZ1U`Y4X6P)74Uj6pI6L)1!#8cqz8@i+WPTbUL!mcv2 z_v}^W@~i2C?C1qL`}7x^a@h(mWA%T4==tk`&rQ$LuL|11GDS?BK{E)nq9tnTVSZ(~M4) z@P1*ljzX___u?Pq7ZbL*|L{D6d^ZBMtmGIwZuc|39@_Rqy%hvdHzoaY4k6k?7UpTR z!lR3YUBiRV>gtkcuIY5&$V-j8?P<@}Y&Kx%N{$C?c+du)WL_`17kNIvW+l^y8~WTQ z0USoE?_SRe#nG#iMm3_uJ6at7k|r*cXuw2DzYgqu{r;v`595;Y__VPAC#{P&r_pZ| zKH);D#feRlB-=wBwjsLH!CmCjSxQ8Tpuos>7GB9}luStJ=fnI4%Cu zmW?ykSOQL3BbTa|kpE-#>n=G*9Y`!a36W(K>;SzS!@_ES1{)Cc{;lLfXrYZE$G)a~4=d#uFU{9Y#4+Nh~tE#!$7tMAO7+@-)( z5J%sX>xL$!%x~t+OWZ4=gdQ0>*?aawd&XS}`VtL9>z3jo+snc?Lw*d0N(X-su-5U4 zZ3XJarWk1>z_e}S69yl#`SzBdb;^%0TQ>POMO)K}yWhW+?A*X`rU;9Uypg>$nPRnB z0|?)l|6OsZ*NNj{Fx{nIcP%;qH-GCx@DNOTc>*EYeY+$*1llczepD|vqaF{2q#1D& zJaU^iTfTjs`Qnbo64!^VD3s$)zW#E!x1@vxe=9C*UFS04)zRrhJASKi*cdm*W`60f z=jGs(==cv$$S=h6bk8uf`_GvT25{A;dedL!yY(lRC9-?zVaf*#G}ct9KrPF&lBxXA z<-v@rny;?$s`4X==}mQpE9NiDf|m-+U7?;q9=a(y_kS@0%h;z4yP3tUAnX9WRttYJ zm!8H+WsT8BGS$xkfxL9l9tCOGy5V*nSy=S5Rfl8endiwB+8xmF<*svbsYc5$vGnA)nHXjiEIwni=jJ170*YJq`l0-@IhBAvncLLYlXdI&&4b@=@wCb2We^uPp(K4H^%GwM*3|6d`f{-a0VetD zrDa9nu4g|Bul@$D?x~BcbM+`(y8_WFchlpOSmp>bqIztYj9m}YrhPK-xCa#k?Zb2y0D(0P}ny&QZMZJklzo!kvfQW@>Kzu=|6C!N;wo!Qg_3V;(rQYPB-o7 zK_xG~ql}C%aL^O4`>>JBJCJ2DBP3P^B>|$^;#v1>x`m&QGw1$ z@zJ4F$Cc#Ok&>`X8lXwGyaHy@h{OSnd&r-vkt zT6fa?a=347kiQuZ7)}ZL<|=`-FAg?J?cgOjL0%S_dHGg#m(Dasv-zM9(aXHtR^YVi zo~NtRG9}wD#`DzPIjri}vr2&!%_qe{6(GsiCiT#^hzVf3+x%VbD=PUEU|Hs_@tVF6 zmD)UAn#_6cmxhzgn1R2)aR%^GUl$!JUwx{VtK&-#68?i=!9#_HHG8e}aF z=-^%Jl`wr=RbZ>f)J7 zrbiq?S?vEHLYnT{-y`AkU(_?TCMs0w*OLz(H{F}n_`kyhC4M~!eET$gRgrA_o;IEv z0E`#yal3RoLT-zM->@1DHb+-$lJk!gO^iC*Q#(4q zoj~f#D?x$OYDjtG-g)%wdyXQe1OBaA}@mLaY^x5`G?w-b6;FG%TN|uH}*C*-D%7Evo zOQ#nQQh11r`o=4DxpID_Z-pzpl9&8kG?dJQUX4=KYc*@@ zb|B%Gp(_>maJ|mL%#RkkH#HrKtcWX^V8-AV8 zp7!BZzGDV$E~GN+(sakyjj*&*PGrmS5HTNXh{{(B)9nlYQGznQ&9IFqN)AkG3!2S3 z*qhyLYvXQL8LR~baL+Fa-t4yWy_glW#~uYTVMvuE$~{WumYyH)YNYuG%JBOqz%EYq ziAXEU0kB2=s>j?POr;4m)gTpQ%0Y451_RBquWKrOX}f&3)N{s1p43y1$~l z74QYtfE?I+C_d>aNka7HEvKw>iLcLx8U7cU{oOL&g|=XR7T# z%`Bm{>9o@w*_g-a1B&zD1``%6Ls1Sp5a=-4(!mof$EO4khx!8D-JpwRKiX0A6jl}Fv z4$zPDodbJvpSQJO4539hdtk?TZ#WzaYKZNV3C^qfGtB`MSnT-mP|Ef+H^7gwmfKLB z?c(EmZ?0T-hh9_B4;)k=k5OLp%a zMNr9LxO}#!7PP328vqJ$eD9mSU@K=1L9;wQCvu^@i6$K)UvS@N)14(Q%xG6MdkdJd zH19D=Zj_Ij8YM?o#&QD}gHXRBWk~uFs^b45<}B|U>%$;`!7&t3SoWZDaUNE5O$&qD zmDJ^0ay+w6JLk0XrAbX&b)YI+W=K%m(BCgt3^3dXYPtw^LV5dlwOR1$-;H|<$HN1M zv(}Hgyb7-5W%d&B1A{O)wUH0~QckOE)Yc|TXV!uR1np2bkuv5N9dvb^d+7B;8kWoz z@kXn0P$F=Sb5xu>HdFD-(V??z6GXAseTyUXD(v`9~tCt|BHS1PzX(qI5I zs(D!dI_M%^%#{cQ3Z`qD34Tq)Z%A90Zjfj&y}x?$>wV(81QT06YC@#6%OoWUM@NGi z#hjSF%?qM=RB?-^|Ka)cMu90yvd0etjliKh*KzNrc~H%bJaDdjDA2LxSfT|3>}8Z+ zN+tht&LVMj2AvUOa^BG!Bse5ZHX+Y_>|^-7U5EW0ai`{Zs}XKELgUK>Ja(P8)NeRB z5WEOVzDMe}G`6AQ@3nd~Cjm`$hJX9Pfu;DA7V~RDOuo~W7`x>dF-r>268`ZLoNCYV zIBDLvzhsbjLH#*c+6D6b#-LkZ#E25Y9#=A3`l=pKormW;u76i>Yq(5Yb8c=4oPx4Q zoCt8-^vHZum-GMOD5!g_`v;QMIbwBEh<@piWRQV0;n^$IEoKCv7Go};E(p`JMK9Ca z1mc-j*1Ur}SL=6+R2@rM@_DLur#q)OBA-ReY5xBWdKiD$T_gMl(Fanp#Wz^R=~5^e zo}B=7G#?=&i2jFd9muU6<<et=>uyyXyG{=U=z1GABQ$BAhB!u{4xAs* zg#C#m8=%bn^%Y*?y;9$Mz=V}aJM2q<7HhdxEkhesJ+*o=5_s-bWE0+ZM@XIHB?glj z;ov`sETZ=vsDF6x2Q@LI5Y~<|0^OnoS*r*sel^9Y=d(A}rd#{|9xCywg@%n>eeMXG6Qj$;mq- zkVdiMqaush1Cu7ZqVK|^@alJm83aFL5OghxO~r#XgxWh4ajqFf%JAfskr~SFNe~6&gp{N2j78 z^_#Kx3iJE~Rvyj5I2imFAd6q0)Lv#A_c5ykg%Z`T>hcGCp@89NkHNF?=XkOXT#t+= z`=$oUV$A=B8+=UG`ScjF4})U*j|h;0wlnVemg`XrzKe&=PjYptWJl~Oad#zc zvpzVsuYd6??}5ZubVmCNm+Pm=5Iw+@!UWKDBF;vzgqMH zRePOWGoCB~y{ylhFk^`Yqwe)caNhBElp{Tzgd~Z?cIWTU7*ru@z#4k$u*?-MF|Dg;{1y43InYH7bKEVp4Chm zGwqT-=$o58aE>|T6XsoJ2Xwz;>=-)L&SsS`gb|<~^wy^w6eWBfowTmWM(FGFZl+dj zPcPrsdr{yPwP@i=079;(xr@Gi&@pXS7f!|J^9n>ICP}3>GRY3snqwjWt?U&aUnF=w z!O%xQ*~s_O=jPy&MwLasOLnXQsS)A=;)M&9!*WS|1q_GLev-0*!?vlTlEV$Nmctz| z|Eqg|O+%);kL#khPOU)@BC%k(V`7nU?#_zPnPBj`>GTD;?t!nW=9k>$I&JjXRZS~OEb$D{l^iY(ZU7Z?>1E8ememMvUO-826bv~|+WOe;{p!_VJ~~02ObUtD3dXIB*ski$mu`TM*5N*` zgO$>|@v&XhqlH=?Yd5Z!O6{-k5!lM7U-{jf>ce7G!UZh?q&8Fbx3P$wXNdzU8Tu5A zatlxRXaz~I}oYd+6* z*MfNqoNBteapW90yX#>(y10Z*?br%vYJrTMHAJ=)f*YH_j!k^chiemEjaw6t13e(( zmJ|K#w&hHZCZ7L9SdyNI=A($8@Kyb&jGy~^3e@{Lh_5WL4r7t;APDs+x%{TumZfe< zy|}QAc(`VGa*P8F47O$>v+PdG49+M2CVoWVTi9JP z=p_$SkFcyW19CM`(-HrpffD*-(PY;vRy81!O^RXk*{lYGgQgdmyC8|W*VDQ!DyJ6{6A3v>Y0@-vAZ zf-Zt$SaX;~T9Y?m$wg+q@@6y_is8|cAjiW+Vc4i+n+2PCqxRBSIohESKs7WN)*iw1 zu+mN9uV$MSrC3trM~)Y?YlvlXu@QP)e%CqKxSEu-|MMZ1QL!szDDc2l^6AecNVFnUM_{IS5=Gs}p7Bh_#g-CA9(`+G z=(NP!)=#P`^qYFO+Ic_vJa;ay17aOJ*iPj804|K7)_9(Ss7BdCws zyYRjO7R+rX_>6KDhWL~sk6gy?%x9}7e~2AL8sYw@JmZ<(9nWQf6mvE%11yitcm!nr zO2^RA&k6Ssq)4J{6V$CUR|{uIlTC+w>@8!L9_qv|KY|85yNuDFse<}hO*VCS7{I%l zVJ%-N*Wu~=ABXwj!oXgCDwYeX1`P|{@x&L|bGNFcm$5e*hga>~icx~lR{~p&?V%?S z@5%hZS+M|y8dkL$dp!>j^Xq;XVrBGm$s;D2JhS7&l%T>uy3oF@k26hk&`hunwG$Q@ zR2$*){0mBs)juNcm*JEItfx+c9+JDg{^Laozd`o)$!ur&BB*wG*0XK)D)VEhc54n( zK#hd|&PK`3dBdci*Jb5z3;u~Si2d5{bQ#H8?t8JOX)iLtX=B8JMgLHe^Je(jY$zwo z>~eM`*4PxSpR6dtoj^E56YQ{B8x=^#>zimi)6P(~BlCGm@Iahx|G>vS?F4`yiog%` z{sU8dNP$&D{J8?DuGJTcq(!1Rs% zi&)xs(^2UhEE@ZfHr3~RA zJG$m04k8#f;)ewR;+5*PD;<*k6JW*pTq2BO_+jt97ETN#><{f7i}v!u>$Y-bMR3@K ze`wWm6N^7-b``_1lFlriU(&Df$;x_nT;>SEtCmOLZp+AJg?zMZETJHe1g8$n#2tI+ zZJ~H{Oq@?#?W_rx8VXy}2;OgfG1|DagM!^iwC=|3j7ep>S8J84R+?psLyNMG;5{ij zg@KY$A)s-_Kzkhu5MqgA#wJ~>KH&xsJtbu`lMnmG80KR*fG^nC*I?e{!SE5E?4c_a z4tmo3nM7^a_;Bh+XpEiWecZN2$Z;?UEO5jX8gWJ&k)dqA$1+vo?I7 zz%Z|~(nSkOXBDiUm2;^24G}D-T}~)$yq}0cJRFlB#=C92em?tFOrxDtiZadWIV?!#17Giq`@p=}^N9*){P zaXZhCDCMOHH8K@<*eFgP#rojlRcWicHoV=`GRdjM6`)%2fQ|q@mnuYN*C6l9g3g)S zh5x7c%`40hM&e^k^6Q}fd>jGwB_l+(Ah1_bZ+&oK?PbV=fx8gm1hrhA?sDDts?F!D z1sS@kvhUl}$Qh(x&i4fcLnXjA+K%JsNgN|z5w`(@#UIlC-({m|V>&oCv1tLRR#U9x zoBgd#if|I9ey%^Rahk`C^9<^0A6;#(I~>d3{~VX!Yd#K|L^#_=Yz%fzL25|tb=naJ zB(HSZZl4-4$g_OeF`Z8Ch;y0-S>|j1Upos}r2c}EX&PH6^I|8ThVJ?#+wjnkR;uC%;mrTci%YY9A$m z{u-JcS^S^91+}hT@>%Jjpy%$dO(l5Uc6yy0ucNYz>Zy=Gxd_jPDsLGqe|i!s-+!7_ zJRnruX27MIf^fN>-r2=dvH$5WC@;NpG)p&XlTm3L6mI76Q@VLWl|U!=d7jz!-T{%K z*_99wjgR=8CUNSL%-`4Jr#11Y&aHp(4rB)=n8LB4H)%wNBTng*OP&4JNV1P*;=Hzs zc``t*+&vLX`@#~ZFB3dZ{-#j-41SOweu`@oxmujhaPl=GVsLO29Mn~0kcRkueAgRoB`aRBNsi=uN0h4|iOTT?aFXpkmw z)v|-1pG!sIf23KoMHl?1q2QLPc9rsWk!OR=sm4#^B(uv|2o)l~83@eg;7s1S^QU|v zn%>pr1L?xRF@?a8poRXmOuIGCL1@CGW;FDs ztr_oIKWD=G&uX+DreGjy#zd{DS>l*Y?$HL@BKvO@{8|fQ%r7Q?=tm3zQf$VUxOnEDH+`Wh~bNlbO zL#gN$qN|yU--+AuyuocyS9;vzH*1FQ-uu2F`#WZJuq2X;)lqisg&T8?h`c)f#h=r! z+=z63g#TxlZ{2F64T!sUg;&iy4q|6 zJ2@T9->b@c$Fv7roJhDP13F@MHcS>#p$gqRauBd$O#h#-8j$H=@y3oFKO&jV_rMtBi8tk|Y*To!`XQMj1b% zCf&d33HajArt!y6z2qjdvZbW(??{Sa-mv3;z1gJ1O@>z=ew~wgq#a#E_i4Z8U6;@j zN?`R#VvqJxrY#yjdIrd;{Nf&>l$0zYswY90T^6t-6S&e(A%D#>BCl|y^xfYeEg8HV zrG`s4`A5(i1n*WA`ddb0fJu!aejh%$zOotnI91e2yic1dva0sbd1af$uX8v73qW!U+AqKU7I zoS->kNOESn8*63d^Zj9$6XkEJ65i1b1aeWeiMcQKP-vDVjXF|pstXhZmu^{ zpGiSS_Mxq_f{6|d-T|(jaZGorJ&cHGE3b0PQ7`%^*R-*5qc)7QOl>5TZ(t)Ai9mqC z1~7-1tlW=iLWBn}zOvBkjar%9`2&Vp6{O{~t`k|yK8l@;Qk>O0&k;v1=+snTqGR3O6i z{o|^ofTXz!ck3cASFm2gphrRAuogW)ak?6Y`<(B!+=rKD&s*;x1p#~ZhsiG2-oX;b z^r810#W|Zz*Bk5pvtPO*roiRmYWC9^QzwU0&#HNR9#}l%I-OWi=Ppv`uXl#Y>BI}j zd29@p@0oVo7kgDKRj1XHM+n(wb$fq*fB$jeg0j{0JtL9U#OuY7a^3@C94x{&;9%>jfORPEvxU7!#iC_c)xvQ!+jGR#L_H^1#a z3SC>)I8gkFNPKGYPH72{&sD!5xIxTq^op4eymIH%w>i~!x;ooCmS1C;wMXVO#iBYg zW$O5yq@^em{Pl5nhKbphC%IFj$bxei%SC%9COsk(H!|-gp-tE6vBi;ZVq_HwEma-tAf6ZgVJB>l&CNApPy(M$ zt>UW7V-O5qafdEpX@F>$=49(ExI@--ELKOAo+q8HhEc{7b7y_&#!?mV!}MZ1{Anl*|naWy)mZ1mJ4 zer~H*X-lVGMy+J&VZkh>rh{v2nNvV z=;j2gy6KWDnQx-OtQ8ENdHOq-XGVO-+_OV@>SXr_Sl8&2%hleTJOF4(I&@jH!B2xt zNL;RE(0$+x9lE~^`qsnx?3+>Dw04wr9Y!K{#h@kSLrhRKe*?o-8deLQ4hXCmig*{X znuzov0>^ZK5P2O1mWiqR%K?H*(YXms zMkq?aJH+9N9)5vrLguyvl>xBjoUQf$@Ki#X0wRIcPMh=dT-lO84UH|iRI4EhwJX&e zyF_Qz?%jR4?45KM36LgNQWTh;qNjEvs6j}&9n}TRDS2g~C+Fb@agJu!pgYw9t)5RE z)T~Y&xmXK89$zFlewjrN7d~J_$yfy62-5~X|In8>=W%)U_Rb;y72JT z7=N2<{sibbX){rE&PFl6^xm%Je%ynmMAnf3--o@%I`84m21tOlVMQw*{ zaq!#@G&X#;kc@5NezR(^tr+6tEY2Wc;kY(;C?-CQu1~7syv#sTR&US6@|ul;d?2q= zh?gC`!%a68Wq?wmOnj;`By^p$bK=#!@(QT8vzyb0f({wCvOcRtGoi*qzqf>)7`x_w zwx@qtc->0Io+icc$&ph?{)P{?@g?Znp9;lQT6IC~;@WMU3Q#9)%20|!hIoZZp*p|B zR0Se%MerpgTJoZhk+ z0(6}#9S8V)Yzw}g8k@89H{EYC53H`fbsxH(GyJ*JNr&*%0;*s(Qb)(S^1+PXn*;JF z3dk@j(#F*!;xpdc!6SowB-8v>)^rVTTFpx%#f$~2il)Wm3D6;7>xtT0qMA1!>tOVW z>?#kX!}oqAz9JWM=^6ITC&h>f&*nwpwtq0UwalFz==G4JnZQSMj!PU9MG{FtF^7cQ zS%4ceY!#py3Y~UIqIwGf(`eAzJJKy4#dWPxOjko?Ls+gpf{o}6O|g;azb?vLo$myE zlTga(-p8Z-aG}quKcbNDVm}ed>6|rN_$l+!w;cqu`80$$Xj#J+F85s<<2HCMW0#FF4&k*zPdXi7@I;+&qq!>&uoU*G#h`i)IS4<0 zJxZ%xtnOtjEQqtGlW~sYGT8FBe{Npol6>QCm&2q$;D2)@&%gnKq($nkY}pBM<|`+K ze<%4z^X$r<(u@o($lEc8i7VBTH}@<;5@z#Xp9DS>gnkQ*l-#-Hds<)F(a1u zOfl4Y?|SZSYiR!ykPo&eToH2dS|ycT7y%DJd2(2}OlYMpi``wK#{~UQ zP-vV^`B1OUaT!}>W})Qg19oG{emH?lWbdI=b>&JoO~{oi%h(hOc<$p9kZPGSVto!6 zA1*iz;_ooZzhKZT^juEQfd)69AwTHSl*O>tJ6A#Tg&QNUDDVAOUlnhqD7Kb zIFcC{ba;P-63T`09XeXGN5!voxs=_G(}q=sAC zz6_toBO)^6L?iB%Rw;j3-^+dq70%Pscg(L$WsutU`7j7UduM`aVy4z#+BYmFzCI?3 z3es5^JP2K+TO7ar)|7XRb-iQZ_CwYik`{$NRbr_uV3nHLfF%%QP)-_?iC=bG+jn#9*e`mDGL;Z}eV0d-EL zyVkg5>~!~=WioxItqpZd_2Wf(xkZ^D1YNeD3iE-8LC{)t~;75HqxQn z2H6R8Wt6dryi4(!w^?(viu3C_2u}SqX(DF;G~KKudVf*BYWj?zYMeuz2Z*v8^Yi!M& z(rp9$W`ECFBO?1*krzzMXHxhgG*aY;dBPIW1~kg5I9dQCS4K+6< zdT6Fb2k@p;c*OkZH$fMdi$X_b(ziZ1cfB7N>>ZZaM)7sV2Wf-nu=wpkLXJnHL~Y4s zC>C^ZNLJi4x+&hVqi^1yM#AI${b?|E?C)SrUX@zh1{g*SW@{#0>5%K9NN7h}V0)9+y6S1|x`@ncmMDC6G~pq? zxEezmz|U}L@yBx{lBPoJ*iv@=}*8#fh`Vj_7U3>-w26B zixmMCC9g8TcMj;|Er!-`|dhQ;-_8%To_45=L%x&D^j6w0$74`1ioTP-Q`=}d# z#Y8&$!gt`vcZb|dbmfjE=2Yk|0LMrv$gNp6H|+(N?l(|1xb3kun{AiDTkC$v?d{<*Okmrj_MHF#+?^ zn_;<@g75$CW6U3aTqk1cKmUjK$nRS7p69qpGBZ8g z2I-PBHmge*5hBsyWxuQ-}n&zuC% z{`0Ww##d4d8>wJoj8~8$M25wUsmC2@w(FBiF(Gy!(Tfq7@gcZT=lQ8wB&YQv)r0$w ztZ;O$?dDXng3bF}*PO@7fi#UCXU}risXJqhTQ=Cp2~OR-$y&tT=0d<85PTA{W;lYW^V5(J zE^cx0yy7_En5p(}UGx`NIiSN@EttTkSer4i&31NF-;0dnD0Xz`X14@8c<6It?fIS8 z#PIts2B`+iH928KM8$=KM^^RHe|8tXcXvPwykO9xxkNA@ot zJqOWJDBpg!dv3_hULHPB5mh>I4fI=(VOu*ff$ugYGLdKgcNC6WYsyyZj*wu_881hC zTJ)b0Q)abu3(}?Hm+de^h?sAFZQ}gRe97QN#c3|Jfl#r0v`=|*+5EZ7`w9$<5w+0- zk!1whGZe!+Q=eOx63c4Aom5vRJw^kIOr*|Jewz{+7qr;Ka>gn~&-etW(j&_fQa)V- zk_C*)&;W(Xz5@f_P6<^(2X9bI7@2REKfEm2R5mh=%WYznW{4yQ1zrtW#z9_}P}Rxa z^8@6ch2c`Zk8y;DM1rQ9Rb97L^EC?$>0*+Swe{8|b!P5VC;g^d3tUpa{>LQ!2rx-= z{$rBnHkHv!o>!f~nx!@&s{Q>2t7zBVRvvJD>@!0Pf{uj|M^z`E7w87`r0Sdi5bh0~7Dxn@p$!O93 zg+YvoK?8d$Y~SNAUYQZvyI#9OjaNCNw9w0z57xYgGmu$SpW!Fn$|9H2%X27vHM)B; z14RH;uc7F6{II8%&fTg!&Kmv76g+|8(EQH|Y%hXelpG9tr^_P_`H;+E87I=duPLJF z2S~{r&@HXDlslce_J-Q_?M8DK?c5%MQi)uHOfPeM=(w{I0`36OQox}rh0hD?M2sPj zcI4isxsQF48QmlWYo0R_Sdrd`!?Vy?%lFDt?1`v0DPVWGGuES+Pw!8b?mPao5bK7Ya=r?_?fx=#5M>CXG>7-by!5P2Z{38sP!Ylx%B;D6oJ(BKP{pG55t2=6H?BBoAn`Q#h<|BO))es;JkCU>CG`duLW zT;R@Gqvw0;d2qzicVROLMsSk=erPRC+Us=Cm~c8T*QmK+j6whYuygxHctkR423{w|Y_H}lw?c;jx**t` zkyI%i$go{bhwMrG#RGv8mndu!-q$7UGl}oF{F&FNjtKCS_&l0iSNr;r+f=GB-=z$~ z>%;-w$~zV)Gb_x%+22s;Yi2Sj*~l-Q4mvy10HJm|Bx0M3HWL@Tsk_odCU0=x8gQlV zG!q^JjZqdgng`Fp$#=)tYMZBxG$tqZ_o=wkJvMo=v)W3Fumyql>@QQpp?~sHwVE+= z*(u`+0v+oQ>=N6qn?PDT@ll_(;Fap(#$>F@>>t-7isb*|Iagyg4?Po>^jw#)elmVS zK1?NP`d#IYPM=4ACfHC-33acl_QpQvT}`~@@y3o@{kNY`nfK=|*Ja}ObG)Z@B7r0= z`42l77lEu6UKkuzR$W|&)R0cLM%&?zzn&nm0xTs6>({oGa`%=OsfeLI(o+hCpZ(nox;g9hFr=`49Q)DJYoN8Ic=53wH ztN4Qq4wVRFc{L`vGyi#Ct=ugwAI!9$$Wm4~x*)sQhr$6;v|akN^d4OPaZ_+te%Lde zreBKvGYtdO>FiHN(+rP1{X~{W$RQx90M15iGw~2EoV~is$w?-kGPC@3%!g&8fZ?)s zQXxT}XDhu&zoVc!-0mQ_glGQZw3Nv*Go$H_Ijh-ivu9>oo=N5^yu|G@()$D52zpvR zy1|mL+1=y&U@F~AczwD9xDX0Zp^W*k(kA-G` zs{TI5dgBQ*2Qg4UvTrVgi9L4M;=uyQc#BT#^9s_lVFJzFXN*Qacv9<0T^W%bY^tId zsWi%yia&hH%l$S>6MJaM9W{4b^5)|~2MU2Qr%Oal8H91G@5zJTr)cDUFDGNq68GWR zXJSzHa<6G`(t}|QRWL-A3eu>giY+9o1%-FJEh6QT9)%>e59nR=LB=7BYUuOMl9WH} z2@ng{+>qyCm0tRJ70sG$p+Lh`e1)YW1)FIxKdWQ=ge*TKb%T}_y@|W>%f?I!=&%AB>@=A!}ac4byYz&8xv2O_1U|3bnW8mAj2L-;bO!FoehIE&ws9 zvDYt<2A6{phT$t;wl$V-_zcoJ=}bgsQR5Hz&3#rCZG-0@0Vy=*^z^?#FPjpx_yVT0 z2n{*_VgZ-Im*EcfSteFcnTYvZNfo(g>tl7C$Y~pE@Z~Gl{bgR1vFCtfcdMHHyvT%< zdX9au42%R;F=I4R+94Avg_Jn?z+Q7P*6C!MhT3w@uW>XHj&O2%f(RX3A!qZ}+T+i5 zsJW({XtFK`)H*0=45W*SD%Aj_e>yqTlEF@O`8kXX`AWlKVaq}!H@dU!3z|Wh+2G!A z$`c3*b>Ovd*fM1T^%MUAMzza&UYcKl1`sW3GkK@})V**WMgRJXqW@#L|F7I)*X+}| zl-cf*5y)ygyit^$>*U{5MF(VNMfB7aJ(1(!!1w!lk*qI))8~FVs=WNz5(gJ^O3P*aH4MY;W>HR+v0o1skqPsPnNx#PA zmzCWkhP}Iqeh8MY;^Hg8uX-)JT(;fY%1Rul*uQ-yXRmC0o_JsXK`%q{Qh?vB<6CXZ zbtP%TM-alVnfOO*n&EiC1Z{Vj2!QzJ#b7yDwocmxt!7%!EuJ-8d(-yBT89e|a3#g6B@Fv!5}W{rdxC3)Z1j#^ zU3KR99!2j!5`hPgXXskknt|i$3Ycc~A-_jd7_u@JFE#WD5E7>7%BP&pIf%F6!uG=# zy4}G_5#)Z{;&B29V(4D*+v*Uhwq&&eh z0f%^%t9MY9$%$V6Lssc&a9^(@L7U0<0`L!Io(V6w4DPkDoZgEy3fWX;jxRLVaw+gG zKhSAT-#x3e=v{eeoDX%IA@hT^aB^|Gc#74 z7JdL)mYCO1qp-h)`Vf(^I5YEX&zQp|lipXjrar>BHySqCR4MdQ5NMSQ2L7Q$e#|(| z1tKYvzj&{1%tvtbBaf?8nXey;FQx#~po6$|5;o!D-0Y5C%_0Au_#*QI2eA(zbFd-q z!68WqM`sjWQ=#UVbxZBtWV3Mv1|e?AM-9Ie=~C-Ay5Xb@7ng6CXb;~^{j;LY^6Jq4 zv!Ypb`-;2=RH@U*EwvduP`tzN>5uCp`T6eF@A*=U{+bWXazsJ5ha}IADH*5f19y8NM>Z7cw zekPuaR2z;-isfIq&9r_W4s2gKG-Vde@`wC<<1Hq`JnjUqpAM`Wn^C5(eiW>om{;<{ zR*qhlzDcJH8`24S3o3y57b}xQOW$rE1pt7%Myq-a8gx_C9ih&<|mK3UE8S zEu4o`0WP)v1q-S(xSr&-Ip=Pn)v-~(Kdb4qMdL|&ao8f z2qJK4O1IIyrK~GtT5-+!k@MzJ#XsoF%NX5v{D z)>r)^|7L8elM$kgIfy+OQc!EHALn2C?cu_=J^ViM?QpVVA>{d88wwIqd5FWz@<_BD zR(+W}{eav8!pnrr?|g#F!~G7*l`En$i1gq51$RX}OlS~xF3Hn4l?AY2EVv zxD^|f_c9TDO7_Z0VmjCl`OZ@A;mhI2HdTEuX3Vh^D@*)ez5>)jCEUqHU6n%uPOYo7 zPOM;)Ei**(A=gJ>Uw5^LLOEC~na_BsxPG*?t)k(wLNc?Ap?HO>JHw+jBF7DcHaB3w z${pU9wqBkJ*3-jOguC$Pp>}hkw1bCs*@I}u?^)G)XItf^5FJ*rFGW3j_)->tR&IHR ztW{5(Y7xvaC$plyI#7i(r22j%XMYo2q=-n0fAE23_dtfs+pAsg8iaXssT|E=>~z}5 zDT>}tJgYWkmVTIbAHPmllR(D$^)2qcdyyA==j|4cr>6lFys)cm8r?l^W@;~1>5zbC zjZVpcWy%r!vLZ^Cd-!J<)u}qFzrgcD*kBIo`y71EW>ZB zgqiFK6EQBcnh@E0Pk8lew`%S+?@4ZLWPI;zC52KSE51`~UXpRvW05_r4p|D}A$8>m z=aUR2Qd0X&{k7;lqS5`)J$*z&ywcnF4<9MGmAfR?Kdoqmv^)YN@3ClJQk}Y~TJLw0 zCtuhQ)nRfj1zCdY!_U6hvUGo*xv-@q$}}BG4t$ztlC35}Ee!0qV-}h%rK@qy(K%Hj zg-V)&Q{&4fG8tt!$4ky7*}Yp-xtI;PDQ7>!QVptf_kc$onH(s-6yFdBr+xMY$dx4c zY12{S&c>%@qiEhFCSE3EQ9nscYnv>EpOA~)lC;}>RFj0-(=@&_{+N7s;t%wg|RwVJ~BsC4E{ zl@8Hbko7M1bCP*o^@rSyYi3^`UTlPXUB$tC5%U>Ids7BkUhBL5rmlydtxpGx*=w8k zCr>`kyq?^%o#W2Zz=kZ5L>yXJz$L=6y{Wy0Z&&8XQsZmEF&Jm-7_V?oVDee zuZ}n99>l9ejC`%*<6QjG&5YC}WJTX5Qd;espN!>$w+8C!wO-I%!vnjqJ%_WcC4>x9 z$g)MO@PNgAZ?66^Zn5!GpWGA(JWknUlcgRK<%P_gd!WSb=rW)6Tnb@7q3lx1&``Tx z@3q29faU&mncV%2TC-XoG08L<&zs!@N%t-knC`jj#{Z2-fW7K-!ove_b9krdWmc4) zTJ6Ni4ZmTn#1Dvc7d%(j5P7A`yZ0mfig)F0*h+7Vo%YU1Ux()c0<7hc?l9BzsAst?=KrT6W<|667ZRlt7rI>3Ffx)uG=-1d2wZyJY_ zNlJ!qp=bF4eJSYNaWz(t&fT-P)DO);959T6BujFu4WHL0A|(TG&oJ+6z%GS5pd<6G zU`Vl2YpLnH6f#vbp^vx>B*yVk+#^j#A>B27o>ny6by-{`{Ba8PQn z(}>vIuK1E26cwY&o{k2YXp|+n1hR!4 z5=CJ*^tA<`54wwLAPw=;&-J!@ z6TEDjCP&!-$+U@KQJfu{mF`?6Kl+Z~?~lAs4b-#%Do!dt)mqhD`1r}DhZ*bgl-jrx zYJP08aBPn~X&@$W@fmG|Q^M!~1Xk+zy2MG---$;6Q;i*Se=$w|HPO{n({>p1_QmCTtMwj|e zG16~o-q8FIZkP--Nf=dpJlGB}ouuzEUxU0!<$EJi{tN|dZmSD+2@EgDi`g*5zM^44 zJdI`Z>syE+!l zpnpEm0*$I|jNRIu@1GS&v^QJRqhZ*f56-w=VX>_yaZRFtNbYC-REP^!p<#K zy%rgI)W47ZFf^>B7Bica^nRXj5M6DmgcN(atn!KcX^%jxsWs1b+t*~%Bll0q;$z)Y zk{(w#igc7Q1@G;^rj@$wifn8&D_}OZAGZ}v$JUTnZ$^=6l|$=4eXQjx<=NhBBsO|} z`LOZ9(Sx?HKS$NRbt&dKV!m~p(YwNHi4nAvrvFL!S9}4H0~Yz7AI?}O<2=_CWX*sP zScD#YEKzHC+Vtj4jp&atvw)jOo{C2Ycqfk^j4@d>s$Qw65m`d$*_xn3PL=8bS+xOJ|CK&f};Q+)b z7pvD5bxec%og(2}B+UI!J8? zDU}?~6yt`{Ry1mnzN&Ye|Kgdwe-ptsN!+3zor;XFNZ7&MKR)?>t+8b9BEtW$2R6R@D!5y`Y8V{AD$H?|TJyJ0TM|(;c^KY{jhB}3g)H7fAMIkU1QCixwuIxS1nb@Ej9*mmNMH^un-K7 zyJzC<-cuFWu2E)MIclw541>QMWFb}>*!bK$CKXhtEtaPYp?ae7$H!u~B7EUQ2n(cI zKNtwaX_c3@Sv-((2QQ5AZ&DU5aUOou(~D~6YWmtb9WVm^iznRL1hsh7^d#E?n>g$N z_;!jd^iehBr#{F3?quo-$gwT z9;3=*ty}4ED?V!ENzHLKgXJfuyssbNEn?pMof1q{mPHOAlET72jGW4~)P@Fbisaut zW}x=xm3O?KEtb1I6w59T7{{sfMEu3umCgH$wqfht zTI$BMMj!=!)f*ue3O})inAWa&W^D1Iza|i03d*B<1H%2#EaElW{SMj|F;ow|FQ&xd z*-&LL`$ALEdot#9IMvt1$Ig{Ef2}D>Sd2_ul@%)fuk~ilj~1m*hqDfAez~D%)t$H@ zp03oP{Q}D0b*9*AxCIk_hp}KF+&HS*{p=%bh{A6v%`Bg^D=i~F_Eg-*K6eMpOha+U z@9gioqF%he6;ixs4KnRhS43pkjxHR_ky`RdnVQ5k^PX-ol??e0Zp!d`UruQsLh~!4 zJXHJ?3GG3`Jvza1b|vBdf+%H|+Pf|<8xxY;lE{93KI)q@Zh4O3Z3P@)SWVg6f%Xnl z>J<)0F%Q@Ap!ero3N9k>q7yu-@Y25#%!N>sm9U2jxA5D`P#r2q!Pv%Y!G4mZfAK8s z+qtEolY7pOw^CYkqu~1F{R&E-)#((Eq+*0EKSO%_^f2WWOQaz!58x;sj;a(hUr^?K z*KhkzL@(bNXUE&xMj$e(pK$%Mq2T@n_s`(K?>`wYY`=6mXV&t$0`2Fl$2P!l98-Z` zTU3Svss7@%%VOx;Q^ZiM=oTgbSA`KPya7wK3OSW0R~u#F_h(8E>S~jS3060`snVaf zlD9C6MTx|)9<-l(Qp?zdd&u(3W$DTlziOQ}$f2oXmFHXg@RF*n@8vzR>f&`jy$WzE zxy(bX98khEQm_pJxCTixhZ(KVWv?sI@AVZaBE~j+!;JeiJipl9i$|6BT!VjCG|4VI zQ4s!-r^0lHu4ynt@d%ZGJx7JQxF`|}uyYF8wj7!dx@dha zO|k%}C{iQ?f4S##*~yUkl_q>bq>-S41zzu+TdyUpG)<{O@?!AC^i|KqM1xCbE1B^% zIR=>ybt=684d>h8pRI+qwJ&I@WZ_aL@hJ!-VzBv_?mBEbNd;sgjswm8t;YI zGz+=U#WeiC?M~vnssM~<6C3guPhlaV731m(*mkDmmR%xnf-P9d?3==_hP|E{s1s;x zXK13pMTXqP^2-A6G0QRgg{JcGd;t)hvS$GtQas+kA@xu)5cjG)%lMEqRQMoNhCXwk zUC^Q%jVg+8s@SfOviFO+eUNU0u+rLZU#t8nqW};gVNWxJw`#)?&DqlzKi+cbe<;c1 z!X5Yk$5LQ}>%u+R)oLs$uH%gPQistM&Dp^lXf(Ej;(+6NFuRRkrl3|%W#72Tmc?lT zF1n{=-ac7%imRn5rrcQ|XknGSHp1wqq%SRyY$C+y<`PvO(>a)_sA~o_jCj0H6N0m& zex5pTXs38jp2oH`wV4-gqFjnv;5gd($e!YYgUY(UsFrdQ7uewIogmoSIQ`HzBk4U=4@8& zx^eKW%#jkI%Ztd9J)0_A-}gJ&ytiR6E1v0X^V&knVzYM!w;%x+Cxg zcP6iv^eMAMNsGx92reNv0mqNn`ttnl-~o<^oQo)zr?iB-z0%C$dht5mFS|ZU8C+^C zhXkE@mBEOI%I-Y@Qwjyw<4aYC>SU_0*Kznh7l8-`!_D@;{5;})4AQba^Tmt_>&QK4 zGO_fzhx8i>#F2AM{SdP20Mk8!6KJl+~es?JbPEa@{|e zix-H;cS}jbIWDewjUSmj7Bi7flB4{QWC2(4E4Jk`=P7=BA)msw=1B62*%uGyXr#m; znm`Y+q=OeT=t|y_-GA$BS~dTpk~pk=4-fhTp|rAhHWs5uxoUI##O<(K#;T%LEy%3D zzU>aa7ybc3ZVG9Q3WtDcV$HyFV=C$l5Q{<`{<&-A;s*1JnAis*p~}7$$D(;<2ROxy zSB{v17D@|iBWl4n)9HcJ7z4Sa@P|cOZ}u5Js9qd3S}mz`5)F$gga#1*#6EzaA`Q(Sb9G8mq~K-Rd$4Auo6L zb9HB|Z5t3N`0wevnx^FN59DMhfzZW+Fecu=cs~Ow?Ed1JZbTa8#o_KTVAKIPu9l&y z?^@;hs{B*&G&c3@2Zr=>Eqxs?zc6s=yo(K&OI%irG1n^u3oL+w)ylWBV`-B!BIe$) z#;DI8uYmAlmeN&2Is!Pu_i&6F1NR0+4{LGXjHB?8Uzfh$5voGik;{I6&SV<>R4eY+ zLS{iKAl8Vud}{4tr)=T^yq2K9cowM4rJw4H(!Pt~;rkpKkan^xa)(Z|kpdI!(HkfD zIA@AY3VtMu=v`%S7VR7xla?H&5U3TXKGc}~i2peUne3rq<A+{=LE>y$)xGkJSn4|k zWBS#(0HvS>PznoO1q}}8>K5jZtbe5xq<45dVu!W@W)T4h@e!=440p)-_yNr0LEQa~ zj!P#*swDq8or(R5r~C&sinqyn(M4=OvC}ISWIGLrtio;3Sz(b8F`IHD71A(Ko$Nb& z#uF@B#pc7eiV#$<+J|Hv2QYzK8?N{xt`)P=_bkB3G2mdSTJ!NTsfs>0zVBsiKa;YH zd+OaPUwKIR^}(VO6OLn4IE3LcWA1qNs|2)4KOws=Qj{x?&p>!sD0&L9qWSWRS_V^G zo}tk>_-13cU*9(Lhl7>OgiBeLDmVvxT^{=%(h9<(>zIu=GpTz^n^e41Vji*nuOq_G zViI?qrffc?5FaIr%MA;X0`&fad0^Ikz0)C!B`*mCVh=1!M$!uR7rJg1*5b}%c@!T8 z45uDg1BOapfK?b*?lI>?`Ejm5OqxjzT1LwkIvRvEWU|~aD!m>9@^7ojRQij1Doy!6Sd$FW+WIdbTr_COBH;YS6sAK%==ECCCoWEhl2#DlEw|=w$l||F2IA7vX z6@EJ@GsvNps)+*GLW0>ve?`wFGHMc(^RnyOy(+J46ZYJGYfTe%x7P-L9XqU{dYw zRKCRz;b=SlUGnOkZz%g>$hz<=il%s@igbttk)K93ILX0ntJP_Y1^sl=qjU-kj>~30j!87x@BGn#6$Q<+|2d~UpcHuz_4B!-|`_F2&7)?T2{pTBN ztj~fm&V~8j!97MsEek(Yb2kx{JED<85ca72nV`@w_r{|KIxqflsi@{XG z{hA_suS9Q%Lg>EmOd&EMS3>{$Gh+e{w-VQJmXG=sk9X4WV`NCMS~vm_>j4UE$ZetzJ+XlQCJVEnFsAxp-aLs%f1XAELrpU_5+pbiU zC_^EppAg%vV)M-fi|j!o!w%pvBIdlx@~ItZcWX8qz6SXJi1mPQ*bxLy_G>#H=RD^s zeq!cs8rW&ZsgL!?q%N&>HShNsb^O~kX>>2%(v#ns_auus=dpg-1J5Kd8{564|^CY zi>+iV7RZD1BY%YEWf4IE+%#mK35mHuWi1av(0NsX)}}6Liy|$V1hME>sYLzO{sU{a z`U(ka)r|_6g@0+M>$V8Dm_d^i=J*#{R38Px9aoXZp0kRL&Zo59Yr_&YAE&CQ@xy*t z>K6i8;{FRB)5lPKm6hUQ4?T;<^Rh9tZ2yEmKvQDhUM^e%PHf<^@({)k6mxJFqWo?# zRnmWIF_n#;m4SV_7B}Q;BB=n`o8X$gbA;uK;m2XoAJevsEO_5=!SNHXGUx2PA^s+;3-x)kh6D2CE zK|IW&(EPe1Ie@l@kDmIX2M(ms6tdWn~Vbc zOo?%Lqol0Z&~$C>mNWbOE6$;Yv~@p*-DAX^+Q%epXIY2R^T?GUiQYUwE0h_Ms|qea z7aQ>oHt45|({g0Ql1uf`&gSVnw_?+l=3WUulZnCa9wFJvvTSJ%S>{E+N*qu#>|j2Z z`&FznJf*?b!9b2OJyFkxsay`VslGm0r|{Nmv3CDu$o8L7S;K{8T+>Jvpx?PnTDtvT zvF7||e^YpjGJk5Cb+OqbwgRNu3GHa>sFtPzW*xP&-4ZjEM1jfic$wxNz^LFt<{-mV zCj_2y1Jz%(Y3kRpIP0}_YYM(BA=sn8uNTZ^HmY?V6#5shNeF(U?9vhEAYzhiKe99m z0G)v&2a=L5QHF;UG1d^qMlv-MXZbw0hxmL^Bb;j+JG}@Q9uuG2qQ8@8%e#~Fquk41 z;-A0#b>Z5BiR&4$iO6w$!4Mrxz;Z)SpkLfP{=#EyG`F=L+w4~o(B}ACW%R;{W3oe2 zx&J4nDOX4vd%T-gA?1KW3pYxnRoHyn@R2f~SXWb-9ZgT~i{?*TQ)zuUNlyF1iKBoJ zO2rO_b!n$+VZr8OlsnP3IXxxVz)l=|S}Czg?hbX-QGH^TD1n$Xwp zDb{wCVc8YjANH}teB+j~k>rVl)gpVilvm#76kFM{e_>{F=EYK$#F*cy{yU&xn1w+_}ButV?m2mMcX$$ah_>S5Sk zPe2#wE#wORm^ldXeJWd*Q~?>#!*{++h2od?evvkwfU;&|!aHH0@kRX5yp#p?i3-ap zs3eVxh?yv19~&}uTw{ibLrLk^v+OzJN!D0l+Za#A*6;P89)D zC;4$)2}iQ2Ha=txvU(X@N~y1S>+K@m%L+S^?HeUkj^C#Bfc=PHLg|oZKCR!xWjba^NDusvME4Gb{-9}YuXR(B=&)=2x(<*HbVpo=8>^gAlV{4Pb>3gEjPt3TUWgbm0Qvk(oC2A!` zL|x_vI!uYkry^_6bg%o&vbPFNH|684-_>mcqv%t0`IJ*Py2ijT88TnTj zRm1DAc!roW2xog*IMGV0jzqk>vkP>&1f!}q&4BBSm zgV!E9N05HWb|O^zw*5kd=T!Tk0Mxs8_A_RK+D*_|*Xl7@rmhg}_c#{HO zOle=X{SZ|~`L9w4@=9<*k*r0DrC%cH5lE3VL=DAGz!ddN_zB@0} zPrCQJE#%lpaT zY-{VinkaSykK2KYX-U@tL_ht?AOaWS#|OU5kRjvF4nCHQ@BL3v2xp`Q4@Y9l^odqSoIU zcH>rvKc`tl3GX~lqfVRYXdvQ4jprRwnLYhYk@)1E-!7j=YY3V+d9MlKl`{VnWtlne@tj=~acOUB zD^+@%faQn)HZl#st8~L5ht}-|AKzE_7lIt<<~|$7gG`%rW(zZO9V7GbY2MQ~-mGjp zn29Z0eBr?nU`>V^5R=z1JKdU)E4TIq-76{b8SuQRj(9IP5BzQdBXGb3|2a?r1L<~TnYzpiMseSEnpFnbXc@7K4| z6gR*kc$4bd-y2pLAZQOVh*;hsrN9El7NvRMJ7V$fx6^@6K~u6vx}q!?z@40KC#1|( ztIFv|-Ac1}x>m&fnSjco6^tfY=AcgeUG!!$^SB+~+?xy$C>eW9+fj}^^*dQsxHTSS zMI_kwBh}T_-bJ99*62R2G-7=(XYUYl3~V=l{-?O`zr&Mn1BU4-7oyLrxo)zTJ+tmW zEnWJzKS~=oWW8?) z{#8zmO?i1Hu@Or{$$6FkYjuhf>Qmt-h2n$yliuB&vPi<(W8hlX!R+^_dd? z9Y0fGgO*O;#e=rKP0gj>TS{;Sn^^BIU~Ke2kt`~)-J1$)AA`2D-+rV&TziB8wa(>k zCV}qj-d;%~Km#ksa>T;Z3tB096HJup zoR9Vs1j!#$l+<^-nwM?r#TX4guCO^%g@SgRd!iT=L0>u5@;%E@`x>CJhOwLemfL^v z5-gU*Zi1}-;*IBrx}Gjh}x`jWK{o}ij>yP@Om=uELrv=t9U{kzU8DdscIU@5s{ z@H}e+2EMTl(IPjg9cprT***u#m5SA*x#L6^WJJXw7XaXTVN(2J0IoN;B_sTWM`A94 z3WQ3RhRqIhDj)>#>Z0(22>Zi5-5%rh4AoYI$vpiH@2eH}SU_x%IX!Y{czb9uE#DRV z**D75d-Q1FNa+5>?-io@2w#5Z3HFto+Wm%Rij*w3-&5xc22npA@2>e8pTxr27FrI> zrmL>xyg5OmQgYTMrp7*L>h_ns-zH!j>gg8J9*rNYgkBGR!bG>ZCx)8djxPIu3F~b) z;Ku@-zebbNp|_n*lKJEqvAW85uF2DQldW7a(NQPzVqzv6q-jaJR)SEkk&n>&nQ*cq zv|s_4!WOUNoU=Gl+!7kakmlC!(D8kTc{}Nq3ZkumXIR3e(gl3pS=VXE$GHjg(?W@n zk5#bp?;EO*zkESHpvzIgs>~TENzy(^v>f-IT6S*Do%QxrPC2-;?x^y%mb)WA`Ki8I z8?BM;&fpm6w&5NpN|DHSj@~v(Tb5znlBno7_}og$$9v$Z*1~~uIcc_jlRU{OcRzV; zR_-Zf7%jmncWy4*T@PCzWqVn)c!{3^LZ{#zNq9r})`eu#UA5R=G=Avr6};5ok7Ja4 z0z>_+oCKhVSBFGh+HG;dEYQbYY3vv>Zy`Hz&?C+x+i+p)?Zdg>n!1n;Pn97)ByBq& zHJ$JBUp&RlPvXHxd1c}6ysl)j>QncqpR+^Y%11T*>eS-;T)_wJ{P>$X|M0|fS+Q`R zNoeD9%j(RrOGzZtN6MHWqj`vKFp<(>(!Q=OpCUA4>RM4rPgxn)DoodWPf!-~VTOI9?lrEQ^y%GFWV znuSYL;fs5+z^s%j!`(6gRXJ^B&6;iy-J!J@k&k?uW}koOr`0mEyTQ2bQqJ(a@AqSg#CMm<@)g<`0Qpa+q zsY-DLvQM!`)~1f%E?Ii|=gy8uRA`p8#FlRCuBbuq2^I@JduGqUnApNF(;s{Ni9#c$ zhi1e>d87_g2;J{IgDvKLl}~~C?K%kaOPwli;?%Aa--9*!!w`NE4j3o2o zl!>n!GmMSi1yk_^bB%=mOj*7`J)2jeI{px;x-NR>lqG;QWkEMVO4fdaK~JToKZ3ou zuIK?Zjg%NZ^NW{w)-;q)(~Hf_&4k@eRSpR_xyfA;0^P9fC(Pk$r7XL{2X)O@wqhkZu!PbG-~)B?K}(EXe-iZ3<4nZ_>bL_opN^yhNJ_MW#MW`7Xsc z_{+REAvQp*DzgYgJXEVdy5iH$OyO^trX-bYXHrirO~7O1ciyxDIE;_Akb2vI9#nRSl2&npK)%$$#%ZyP>zmW~Ij=pTI6pn9i8BiV-e4FO1pRF5UHXt5Z z`N1e6E@SJP*D4b>v0c~B#fNgLFq1g=z5m~q+F>DLk^dsKyQ9S)xuW4~2(5XM-%`{C zJNd2S*cp2)_+@$|-jk8y zcpeOjhlEP4qb&s9k1aqN4tyee&h~V#pS+Lj9e?EKG&<$>Vz!=EZ-nv~T8V21TpvyW z7KB?kgX8*Bte+b;(BTo#>>_XsXX?6B z?HEG+(c*<(Pkp4?t?qRL!&p_efb(Us4ig|mh3<6=S#wcb?I3 zy^9)0lpqoYiP0i@h~A=vAj%L#9l|Jo1kn;DMhK!r3`QRj`Rk&NUSbe67$w0di3u_j zB+4-QBt~-gJ?E~w&bsUW;hwwB`F20-FYkx_VefaZ{XWn8d!OfSWr~koiK=Raw!7lh zbaeB3kvpbMPqW4;750E3N{04dCZjgfzyHMUGB&j>tjxJO8r$J-`)Du75PZr}X85tv^2mKa`lE36XLdq%4=1qCU;pi^SqJEOUh6RV`v_I`tVGyzd_$teSn3+`GJ+*>Y zjFO~HCn8O82kXJOaeh0tU|H`aL9>YZxn)f>sj4H)Ex4R2IO$jKzuMf@wyWBF?r6Ul zfHd22`qEcdfevz}bb}BVnn+(DL!ams7m}*uJhP>o-yQXVbn)VRrV%~v}XbXjJUwAwzhQ9m|nZs|&!nU__Qy~54ZQcR+g2f{dM-`9rYUtrKc?p{t%_CCkt*jEv6ZJ+)$9 z`2oYdwg0kEez6{E6e6SKS}EaQM>q#S24O_;$q6j9iumH2><0JM8wH>_L(#{`Lru8&1L< zdEIR??rA#w#szK@giKKOE7%nNE9W8nt#8J+k|h|@9{^U=A-1_Q8)FpjOI&45ow#ar4pJ(nsZsbbWLk(vrUU?Y}drNMbjbd3^Vm} zr6tFVuV63b>^EPc@;DG5?qFJ;w-M8CkCYv}r`_zORv&1q&R;Pyobl)|6e4x8KA;8n z3A*})-jF_zhycwVcsW)?-i&bU3c_aBqd{nHO1rH!z9vSx9~yq z@E|7mtC(#1NZdyaI>?QvF9P9T3uF-s+#9-!O3ZHS5Qo77{~!@jY%r(j(UOfqI9UVB z6Plz88#VsGgnaX@7;So)+sUVZBhD1l);@P|bw>gP+icCKbu zf$#D({q>THs)ad8Blv~>>O0jfiZ<1jSyhI2fuC}8@eI{~Y@@N$`+;oaorer+gLnOM+fu^1hCazp0~Oq8tMPL3GB zy;mt@xfM#fbBY=|duY619axd43Kn}>0+1mbFYgV78C!@0N{?Y(0?;#cEj{4x$6J`i z>|J{c?g=zr=ue)Sz~m7S1CwO4s_{bV6=_Unq}*KS<-Y+OpAv_>UmjJ-XAPWudt}&- zn`uuUZLYL4w3Flgs!-T@&2ycqOn%!;kV9(IG|ww1lX!uNqiq{^rwuOZp(b^P;Q=$) z4t&To-6{0-n(|i`%*jum#huWJP4oxxrdJPVR;~Uf^q|Hhud(&=Zj--IdQ`25Xh7*D z+U;ISZ1FCgYc)DCy>I%2?_zAP6zx3;KPu8FjPfZz{f25Xc7{FW ze8^Iyd6Zxu@*zb~6DQ-b&-n`kGv6Z&(D6D1tUl=w&|~bS_p~2T40cgBNo%b!vBKrR z+`jy5t8+hKmN}o_Wy9)|C`YMhjCh4M1!X&d(c^u zBkwI=1)ops@;`JfQ+^3B5q9inACFn8eisR_5tNo{3`)a1=8CbOm0emh3-Q0 z=448C&eUFL<@@*!@!EcbWVHf|WJ!#i&)piICXJ@>xu!3swAUAr@q*)u50+N=V|900 zO__E>*zcpl6z@w4#|~<4?`OZG_ZE?SOyF|8>PmOmTd!1aLwOh+>iH!fOZtWqyQIXZ zaI3!IdFhjtHaJU)0@a{*^pMXgKMrTj+hCRE?ojNl%>wt~cTM8}w!YGSs^-DedN1=* zk_`YhU{S>AyzGaNEBeTF}K!Tu@_h%-;n8iaDDA?w)vSQO(D0WKtCw1s}tOdbO~ z0KZf8ZYXY3=aN?FC4lZ)tVq?;%MAkHE-Q0PEz#&!Y;Or_Ig_h1T{F-xR3#@m@QbFn zt)ResUcLkyu~S*di$}d_GhO$Lkb4!WrtqY#&qM^qC%5^u<;v zBzXRz)t%bu?f>p(*-R@sa1gTv#dMR_njg}?v#hTxfC$BaZH+zmB$Fg+8kfT+T8|; zs zKaA;J>pQ$`S2*^)_&sdG#2tBe`OvDDTR&l?mmF^&p?$S_liqr1Vt?H3QOG_=10n7G zIicf@yO$^DH^^aPXKdqX-=uMeSB#g6LeanO>!QucMf zO4?(kkkmJQ?@vDs(2CVwQew@QJUmOdSYEa#^11j9I~eS^a((!bh**<3abP;JATdWr zZga(ex%uXL1pVlyR;-Q&!9^*7@2RFj$`;ly44?H&N<#+?RupfFJ`bA4X)Rjx8#&9U!!bbB)HB?hrG zo`buN2g#eJLsqCx~8`ncQKp3_%g;j7MceEOnKLMnLHVUScgs`~ESWR(X!s82L+jI*6}|LhF1 zjQ`sWif_RC4c@Xy93Wc2pa0c*<$rTO?oU+pnb-UEAtMVi#~k75wIkcC($X4ky4OSO z&MEBsTdq5Ka^afayu>tafA9>C#63YQ5hZ0azNsFg2#>Jc&##@gO;UH_cUAWKvx9q^ z^pS_?%lD#AI7gU{St}ZM<)YG*_9osJ#R&Y zG7XvNf78&NOQ09rzz;`VR{U%pn)q~EH)sv4U#ayxPcL0>g-VEfM9;F7VAFp6zGa}> z-YGIH{-dd~p2K@9N!$7H06P9A>WlZ2&{DONn;If+oJPvb*N#-jr;Wekxgl2^OwtFR z(awq`4+0;yNPsIJ07&Yi`#rt0HnQpg;0!MQ_0TtACN1^{c?|KlaZ@Ui`bB*_q#;{sWGTNSy!x literal 49431 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%0DsClS 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 diff --git a/doc/salome/gui/SMESH/images/image99.gif b/doc/salome/gui/SMESH/images/image99.gif index 4959ed82548939a522238bb5b9c57adb0d1dfb6d..2672e99f3241466518910e294744154285d7cc9b 100755 GIT binary patch literal 15691 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 C$i&J3 literal 10733 zcmeI$Zp9sn6p9uvi@Uo!#fukrcZcHIqAdk}-P@bz zKX_i>$tNfCW-`en=OlCF73Bo@Eiynqf#1OY3ladJ0stle-~<3c0FVLzB>>O@03!gf z0stof@B{#V00;+wSO7=`fLs751AsaJXa#^C02l#)830%TfE@rh0RRL*#R*Ue0!;r% z0h~$zrxqaij}ahc1xPsoO8Nn||K0@vf&f4ea)pM%ek@dc zW|OgoqQOWU8l_x?#^T`^5^l$>vBr{7I7B>}T(PNiJcUua+C-3xb~1y*Y9d#$xm-1Z z{r&mYcyq;U0gES?LaC*4zC<{J+SI5?{&lE&mQvn?7SnPKX$g2Py0u0>PVZZE;N#NS zTC+XHXVpo)LhX8&gM3pKVwcwxUU$)DHN-XX-`t+j%_crxFMJF7N@f<@!eLbi$L$JK zA+0=^;HQxvnOZ+Nn&IMAMpfN7K3QOrO^}-wIzC%rkR8l7P4iZ*$Z@&g`{Vapt{K34 zhO#&DyT_Q^K;QMw3wXl&3Y1?7Z(H4;udxWtid_r+{)zL|3h_#+xBJiC>0($A`(FXS z3JH#pS8ktre*S8^c->+yxfg&5pfc_S1K2$8f>6)xC> z{V`fz8zz)_P!}mS%=D$+JDawIdbhY3~7Bb13@1ltPbM*U7zrBT9X;NwZbvAfFP6t^)jgzd6Z!x4XD zmg_nmJ`V|=07fr7hJA^gq0=gh=G=hrUM*dRa7@gH1uP_&rEy_JmHP?fE2qZn!zv(r zT7pOPZe8=I1mysgIN8s#C&xg7RsOP@%*k4 z6Yo>g%`)V9St(xMd8lps$7{RKn2ho&w?@@$l>Y+CiyGC{Vc9T{KgM-z5G3@XTswPs zGsk?=N&P!}@o)E?y3#kK;N|yd6|;tvlY!YH5_|vsW{#lL4nUoI(>KN6GO|4(a(-d5 z=#v4Z8^)4MV9~lANf(ElCRo4J#F+(~2LtHVmSz}hzY=Bh@k`Z1oP-llocjidIyu}W z5<`5`TiQ)|WBkEYg(z<`B{Ls?(gF9dKZtWaP9#6&cMKdBuk51N>l8w}fooX!`(8a^+B_;U0<)tvYsX z`vB8Mupi0V0b!$p0-J}De!2g=gi_idMf^=@BFlmNOl2|*m4g`^Z~)=frx9Gxj8Y#e zVVrFn?N_~V@t*=cK*p7%N6 zB;};f-n2pygw*pZ zS*za6-i_j_EE){P^yLWOse~Yr*QloxI@ZjopZXlxXu7Jz3wn6OO6cljRBCX4BI5?1 z1>mjWbr}>)tf1iPY;Jh0YHoFMxqonB4h%S_4U0Yf^tebDA>*%cq!!*mf;N@11exdm zTNAhR;NWcchWo0C&GG%9%f84)D3Ok5m8ZxX-y^vq;Xl(k1I>;e+s`Bx^k92hTm~iP+FXR&)?M$88%cR~qv|VSuWAEsfws$dVA% zSG{FvUE_|oX4vWyKuGSm^vMI8n;W?$A>gKLZj+EX#8<*uq<$+&l6a18#;&JukesdR?<2BG{ zSwWikQwkv5nywZGUEc&~mU^%y%NOXly7Nyt4p8J2OK+MPyeDUn9&eK#<32Q{d3%B^ z|K|kyDy)2zq4YAIUK}GT-+VJbcVL44xHn>}`cul(?n_KicLmf`z18f#WVK@YH z-n(Gfk4!sT=7Mo49XTQ-zl;!;Fs$%z6=bWILsagFC)&Xv(SxOOjsRjx+|OuPo8;al zO0zQ13H@G`%#T8%IZVSd^4w{@6;G}wmmgDaYx_eZ`Dl}#pYj=mewFgFUGbv?zZM~` z9f<8l4Ew47iOFYs%>H6`bF!m1_cQRT7cW&Hk%r%idiSCEhi#%V-u%t7 ztsgA4WGkp^?6{5Q*2PQXQoSP5ND3Q4ZuFNV>U@fIYrE|GRWE z9WP~bYKsOUwcu8bza`;FW8rF#x~X~&J;z2V71jo);JwdU%re{w+_E4KX!o#=L}A!H zf*24P6ByUl_{}FrA{|b8@|lc5@jFd0xn!{FX<%2mB6!sQND_>h7;Pv3KMSz~ywx>- z3v_#h*g>MEj}4Kvquza0UeXU2V+idI=l5o$WH=2kX=i)ncPr0`uC5e0YLsC8YWe%n zO$kNg)FS52TRg+t{gTka{V}eGD3-Y>T>cTKkR-aq$AR|#BYt13L3?!hBOfs}uilE( zy+yzeIX5LaHc_})Gl7d6#2@@U2DyWJAC8w_X^R-eImC@td-VC$>ThG?C$SfQy~ar( z0a~`E60ialuSkuiJ0E|C*MX^w7~TdgdXX@=+__6;S4JIG@~&~k26^JjoFqCRD%kM; zI2{#5vzSNoBqot5A|Z!z3-?j#c{_L5n6pWM*!qxY4aGw;JTs(x5}K1E86@8d8gZU+ zq)4SmG$pnZIh;QF5Kw=b$+Uib4IIwL+7PBnbtHj3xN$?dIgn$pR#Vl`(nui4SO79o zU)XV)pYd0};npCKVIXcx+7?NCwKjvfL!u|dgIp)QlUPa^4f&M>)Jf6OKp{ekGy_Ts zqhO*+r!$v;rK+!Id_v1iI+fj#OLJxnkBW-wl1ZGW&r0H^M?>>i=E6mWMEl`?g7STW zxdAyH=}sLyMOjH6QJ-`xg zRoR{!`fsl$?#NqHd`>qg$r?jLp6JM(UCf;^6ooERTV!T0t;2uZW{|BV43~Ny{z>>R z!#!gp54%%*2#@*<&4FOT$M-Sc?#z}|!T773yRlV41pZLGNWqI1(K>>b#6GO2o3-ig!E{ z^E}U>BgV|v!qqV}b-7BwH}>3s`7jCabu6eL1AQ{0)+5j&#i?5ms+$TgcF%&cT(iTg zEA!}b?gSHos!ZXGs6C%F7)b@^!kcfM;kgs}*il6mX|YJJkjJuXCHiU~jS9IK!xlHb z=zRdKR2S4FSDsNv?Fbd{Jry3I)!Rnr2_t>QJdFb1kn&iRj`fis+dd zH8|y|DRlTOmcj}8h+ZawllP05lGYeX%+U(UNdjaeU_+inhfUh!m5}U`!^Rq+&+P4; zF&s_JxLvRa$wpF(d{V8f*MdANSw&fjU-Ti!8ZEV&1Z}}WO-n{d+RCi}Sq3Ku2zaQr zc-9ggY7LJ{)_rK$W2zT=iiJl~YmK9(@EVqdVpaeEu53 z(oSvE{@E$-w5T1-WGJ%NYJil2CLF%&nN;9Fbua*_ad3@Kd(au6p4r}lSkG%mMsA&~w3tXUt>}_&SH*f$pPtk9 z%Ytx_MeHgnax|vfV>0psQZxHTcY)xSIl~N^819wHPBOHFA5zerXI+cQE=p2JJcuJip+l~R>44rz_BEcxXr+v@^UT##ADTzTx#re&5 zaOmB`kcJ5jnum!54p{Uoo%J%8$x`4Q!UU@8t!`c0x8nr0c;&AvJNk8~6;-RIFS*xd zve(NwCr5zcP2s4Jdwc;p@CkDmIeWzMC7jZ64AeD@%q8tP&WzIsZpR!yq5}3>x>7d% znz~wfi^ul``>%}q`>5Oc%h)L@aLY|-t6qk151Drfz@V1&_7-r#ndXur4C)1fdQn-h zRMrkmjs^tw1!OKdLtBl9K!3UfoXTY|8~4xJE^d&-=ZJndWX-bAD)ekv8(da=T0P->Utj;p?Ti$$Gttt%1j+@x#Z^q?ICz(m1vkvYlrWfWqN%f~K?1CW!sU7F z?0I_(?~mOuT2UfQ>6RZ0vmC>DsUmY~N>GGMUUjLgB{_^fW)Z+d7TI15VHg)9_BOy; zdO~XEoh%`W&9R*v#}Fz%PoA~3@J}Zlo)1`Nt$XWRy-exHcZ`eVPO2cG(brMBCMdBe zXi8^YHu*gr+CL?|AlHGTGOFMbZl}CjR948(Z2Jons<}om!FUIo%%Q5|zJjsVVFx!0VR`oTz z^K!Z^HaAMI^!oy8j}RdRyN9(353uFz&6*tL@>8Ron&^j$dG^|M)<3hdtV`!HUHs1@ zLT|Pua#u?%yI143J7@=rC`=k6YjX|3khE$tE7|KXC_Br@RX9U?%Z`D)AHn4S=HNHn zH4H#UIYMM7{e7ecOx4(xqT^faG4H_AQ(nnjT-vqC{--}n8dyiNR7Zii6GG@}$I;)p zv6oDK(Vpo|;vv8^fHGye$L77#4$0p*nVl8KPwsAc{qoqOdt|FV(}(x{PA|nLxCd3o z7RwEBCA)@D-|8c+Y?Lnk zYqBW{Mr?vvOd6)T1yZr`oV)=;#_`V-QMZ*}&{vt6oxcRlOni*{PMW**4SO?+Xhjn75>CqKZ7+#X%^mnYRj~CN2K0;6%|i}d_{&B zx}6^1e40QQ>w$}k-?`rM_S}DAPgVc&JK=A}G3FS#>qCO_*;vFiF6HhK#zsQTom8ww z!rQHKtDyS(G#qA})kCf8a9)r%-^sdvSjZCR=FfSlBBdnOIax zhIGDgD2bZM139rFL=p+rtoU$!@kG5)G6I{ z<_8r;cZ(3P1T?lxvHx;CjAY4@!>9iWCCn+rpiud1VSflR2DMJ5d+`*URJ85Bt7&gH z-ps-*e7)7$JPrC9UyR)IdM6ak{kZ#i>CSGhNH)k;=!ppjs#PO46x~X_pGQti4hMFqu%3^VuuTgz22 z(kzVeTbfpOJ=Zu9`de{qT_LzIS`P*q*C=Kanh4B8=(QM;@rR_A-)4tru;uFNS+QE` zp=+8myu#_WMjY13+7nF7_`w(3OJ~8P7JRhkYpGnEa*7&hk0Ivaurb?e;4uj42^iesUW8}Z|lKEt*vfV{5}_%$Ylecqa15k5Z@L;&na_0a5T9D_k9Z>;(Fiz(r^uF@Xo(!7x^=ifUA{4c*}x2#_pRy2B;yA&hY?Ej!4 zyS)uo)>vDi&Y54~z4bliMM2hprtpg9Q`-`^aSw-~h-A3bw zX;=%a_+CdomvmBTPui@hlrAq{RY_Vng}~QwKXJrDGl@|8yXMxAltAE(7x5ttX-?z_ zt?18p{p%*CK0Y|;ki$sP#niFH5B%5tE>U7#2eSfNGOUvH@c{(*z8ooIvd6dKMjvPo z$QbH%R2jLxlxkx+R2CtF8TDPG@=fPZ!!^!_6GqQBVGIa}bQh^}_O>!+9?7DlavJxlR>e7)V{EK6+H^_oYy)i~@9t)PBQD%fcjVmBbGd?B zv^xV5ykb1@fv~OVS9$nYx-=2{lk8IFCdMF4)SppgP#iSpp6_GhMBrTbTnrdX_H>!+ zR!M3?Ep~&}{?eSRoMt0V>wN!21%}QUrKMBpq-Cc8?I4Roy`vh|p`X*h7u^{~?{b?tWhT({eWOSoJ(1sMB6NUM$vcZ?Ug~YvZkv zb~L~ooJpE%j1rlpZ^L9n2hpGz;Y={wsL>NWpF`-nz76;gE+MVCpofdfTc6{isd+Xb zOSB-99CLJVlbfz-euUI0q^`HhK9kK;nPRWK? zt@;Do)DwyZnL7K8pG~YUt+p~RI-iS|HNKRcO^;z{fc53;c)LyvtfFY2wAhB$tkJ^j z1T4rC%9DuVOP$D@EIQfJzr|^tQg*F&lDobOGiw6wfJ|)6CyP}*m(>k-{Pv0Pk94vReLZe9Ycar+!h-cM} z+z1GLBe-$Dxxn;c6OqqH55K%EcBxC1`)Oms>va>!za&q$$+wuI#~J#L?D>#?^MdwEgZ-9Kj!x% zE<=7!7Y+i?5ytUTgnI~;hC#4ZHn#vhG4~Kb>hly|i#ttkax86;^7jXsRV=@cw=I@p zqbNll7K$;4WSi><@2z#BzRZ#G*ANttJZX7N?vbx&tu74jF3XOBk#m4De(lL17j$dq z8?dl_ip-)@JXQ#!=i|E|8cJX=J=CQ1mGN-<*nJ}Uil*dw>=kx!h%$L1=}6}a)@(}l z;_8J!!bz-)u$2yW;99epJs*lnRhEaU`mJl5^ph)+pM}KFl2Vu)&387buVpQG=l zh?Ir3fS}k_M^1HPGu)ig2BOMq_GTvFmvGSDNmM+ozINaX zQX!9Fo@gT){V#|o?)IJ7suWk#xd46)EY1xO5$^51!sgO%BfutdN%n)vL zA#wiPH_6Nu%3L%+_O+S0E(rZ~=^*#3J~9|w99G!h)7+1KNf>9&2j$6s21&tQKva0t z>jG#Wp4f14vv5FY7&p-fde+vhyh|R6f!0QAEOkzlvb}5np;8nA3)-|JNzq4)&aq49%?T0^hN1MypsnmzXjJ%zaZQt)Xi^lwc z6s)o}(rXN34j1pVic&eOFYOev=Na{!;>15Br8nVAd`>`n6!9(XUw9UYG?&X+lz;p# z|5ir6eM9sPNe~gnIOcPRC6pU;>>n&bD`2!G506!dQjr(BD7=~*2(|Bpq)PP0h$pbN zZZGydkd52tjue3SPVL$(6{d1j{9Ph{OfZ%Z zFnt<3b0$);>o|RJIPIF+=a(|zPuqVTuJ(PZj1^gqMP}yy!?#Fa^q5@rcfjm*?5r#o zcbbV>xj%$C7w5lwHAWq3-1ThHd zXr4u4)7*)j2qOuJywpI1&pm=PVX%;rMYx|e9G^}jnVW#fMUyyi{wB2`0tOIWz3tW&RsxY zM`)I>_k{_7VD=$I8uX-<+N2~Bcg7I1wM7l;MPeTil@^ExB^3Kqg*QT#uZ)BY6pA0L zEts|#(EtdG!r65@Ix_p-j4izp$YI}J6g|R$YJeo^7XFIpV4JFFRcTeu!{y=@iQHt! z_7cH?G^*1&H4_QqY>QzyONv~}Omu{lIOu$u%et-65y4C1C}8zC-BS)hU=F}aT&6$? zwe|u<-)p`TUH*Lya`hs6t-BP46SC|-Xrim9K1|rno%*3}wmc=|m`U4-P7|L41Oq_M z(|RsPE3Vr@mZrM6IQn*_D<1zXVZfI$=7eGGA-`~v^N za;T_&O6#&~?X0~nYZM_dQ`|aJ-g;cx%q!g`95yYO0f_BrHq1Z|zSd==yN1@X6p;z~ zLa6OXNKN1~5C+jKeb6m?0KHe#*%O3l*#K28YDn68XJbYY(@bI48>9vh)1yi#?@}|? zY}P|mj?1Q`D7@W80+JXKUbmbw2pYRuARRMqP}Pfj-0T}(>o+CiM+wb{Gpe#)HyW;) zH-?X;nS5~}Fx91>n%>GZHF7hB_}PGn<{-j0CZl!2;i_6NxCsI_xB2Bko7+^hsmEYd zchMYWwW`u!qij2@eLD=;pfFvfh%osK*+Cm$-bFX)6E*v3`ufy-XG4|*-UEVbbkuBj zm0fJ_PS2JvF83ZW`d{t*tlMqF3c;C!Z=h_d$MrwxzN;@&3NhVoX?lmmo)$Lt&chHA zMX_kZ`>ow@*Ca3m?fXDw^kdb3V-iSca{$+1a`}Xw|B92NH`!8Wo!TT z2u*eyGd()D83fp&AzX^4C^U<=m2+7(k2gr869A)xs?6B_ z!rI|Z-!_Z0)yhA{w@*biQ*&?;GWa}6A`b;_7Oi)vk! z!*}|6-XX+hHA{{KFqpP5J1G8qSn?TSYWgmYaU0!BSK+9zlKnjQbE?C`OkjTBg*9AW z)T#K#dF9_aYaN>>mDNoirxshM)_SL_v7y8oNv|D8_C}{~dU)GbRkqTZhJTy}%_{tv mPY2DMM_ippKRJ)ZJCEl(Pt-e4_Bv0^I8X0fj$=ar;r{`46an}E diff --git a/doc/salome/gui/SMESH/images/max_element_length_2d.png b/doc/salome/gui/SMESH/images/max_element_length_2d.png new file mode 100755 index 0000000000000000000000000000000000000000..d19c80e7fd7b3a84a325c7e558fff417aa45b002 GIT binary patch literal 17544 zcmZ5|c{tQx_%NuS`Uq;(Awn;&St9qU*EbQB9!#!yMtBD zyV*n;HoRFa=A5Gk{gQkx6AL};Tgu!Bf?GawsTwG2KLdOx&pTdL+0i!}E{ggvV9qx( ztAm4!x@7!|!>lC$|J`;rxQg=Rzi-|YdTOXox+9a^c7e@aO5ONUYTJyXo(ES4wWxgL z#7}w=14(=$CHsooSe(2&~MyLRoqWH|XQzGXr7ITIw#^uS?_CAFVnkeQ5W8V zN+e*?6Pn)B<^KYDF@8Tw)izUq3@%^;^t8 zQ;eK~or0x&YYoHM2pBwapb?D4Yn<7Inc0e1S1 zjuO!xmuPZ)J`Tqpdw9tDU>3^~7hTYo%rT(bz;u(70bgtOMR zi4+W2bqenB4toGWtK(S0i84|HmWRu44haJie6b7F(PjU5>x2 z&#Qq+jq^tHWEYWuDXQad<(k0w({K6kI7{(0MDrK4;d0hztCoh-jcTzS&ljVgcSFAD z<(srkbISDSoy<4WB6Ukui@ZqzLuQyf7)mas&R=G-WWSHDxLnOu8T2}YGq(sKKfvH& zC)2}1@xOPqAHwuzHf_a2I(tA78hy6(B>bFXvYY2MW#e7a+p61YMcXhXr5wk2`-h$| zx`NKe@D4_{=Wb`r8b;>2)Zyzr(@4GHW_w{MrtwmisiKd7>1G&2GRM9*92li!Tx{y+n8Gp0PEFD6$w}TTXpUW2qKop#0vq##Dq)<@0&b>?4=|A8 z`S`_de_|_VA%!x|HR$F6+r|XhW8z>#`!VJ|#zSv$QTHVV1dbhMNYLW)XxZmr5Tuid z!wYoYobck+`3<#%JI2^AK+wNopY=EH0@+J-G8GVzRi@=JiJ9j$jWq;JekfALPK z1f&{~!kPbGQA%fnVBi6|EwiNa^^7Um_ougU^e@_5pvA7+!5lO3vbjrwimhX_F0VO7?v;PvKgge-!PWsdu8TB4Z3w;{e!@6@->xqL#|8EkSir zYq%267oWHS`{rA^vV%A^;My{uk%8I4!{(rZcEhu~+v@u>_sB4^SXT zrshBSg{g2j!m;E|^df8jj!~+kj#6`Md(0?8b(yt{MzfHine47QE>=gHjZv($xr!D{ zcLKDsbU8@-;1#nAi`DPpgRi3gyeXo^nhFppIsq~6pKh8FLm2}cZ~5C;l5#S_^C@TY zf=8K*A7qQelwz1h%`fNg+nfkG&JcFm1LK2D)M$zzm6*6Z3|5|iIC$KRHfu7s=3*DP zZ+FI&gLo$&$=YjPYfvz9^&X?tvLoOMvB+{3@cKu}DZ0p#WNHhfj;*}VDwy3BgyeHX zduJymB*@pBgX67?N2K`9$MJV?1Go(1jWZM=5hZ&S1Nb|JU*+)r#iHc~g70WZri_9$ z?%jY@nf5c8BRcwV(qA}YXzltAYTlpPVRNSfQVbaTt7dE;wZ~+f{%9yn@)t!o0-+f> zJ{EeVzR}$2_tM+)1XB>UgmbW+YWk@3+{5n+#dmUWms2RE>=Ne5pQT#uv1r%p13`v# zi2;9N_v?@60Rs&x&Bu(5L%;|DQes|EruuDmLhAXm)CnEy3aA}m==K<<`FBrwDmx3e zO%k|1olVTU*C+q){(#xcEtthgfd|z$!`&~!@X=A}cb?wDslgZJnjY>ood5AunyfZn z;ZD%WpMbR_JxqLm=pe+`z-+J0*jCgIDw@skF6-1#@aF#0h3j(>84{#Uz+1}W_&JJnH*`Nb~X{Gw}|sW#CmtaaF&c1Zca z>~Sh`VV_Ql#0$h*JDWWr0(SiIO?Kla%{oROa6VnRtO4YpOa3AG^}E{@P6Ss*z({xU zZQQR*IyKJb1tq-$)jwkY0;*#U*yv@4=*V>QE(qp0F3P96lFYKJ8~qPu=jsUT&kZ<$ zJ>+;^5Iv2!71dY0fJOVpr;G8%pZ|=^j4ts`QUCz$q@qi4drWYgO)gP7(==^&CVfDV zbl3b+0@JYpm|1EvPs~Vw1t7utPxEs7sQ~_bOiv4z%M#!C4lWQgR>lX1NS3pgM>35L z+|eGHEF=2yM!Y!kQaMGvSj$%4&CCITqBJH1_eRWn^Y+h0%*SYo0lC+Tct2aW+!1Ff zqxq3ws!w_kEb)dEFUpG8?K$cJdVQV=QoZXo;&O{hK=!s;!>lEpM!{k3Hx!rc^WV!V z;TDhgvqs2AQyB$Sod&Ed z(sVmu?o6%4bd$fP=UCLj^chpMx$GJxk_I&~ADPS3VkcBG68)2U`5{j=H@_Dk%y-sR zdBptr4U2tPP_>TL4%v_b@OtX1BRF9c>|Oj*zV8_U7Zxszq?1%ICjV&QKXS zWw?!pS4k+JJ6=E$_^FA3mI6=LP4)QI^k?X4-#n6%?!S!7D1 z%bDXBtAV6M$fhFgV$8hJYTE~pi=&zo;=xs^|F&Jn1}tQ#h8h6gxm2+Ymj3`DGZd{Q zr-#9u8rZPc(LdoNh1*U?ny$2HJ7&JXoXfNlV>4}&U z?|8rMdOG6C!Di--kA<%{f8y^CQu^JRn%LSP-IlENF812j9a1=y`>5fkpcp2O7#KGX zT60@T|C;fXbC&7;VJ)1b3b&3fX>zgFc64+iPj4{feEHT-YUr*|OzUnvhS}h$&bvMo5BbCMF(69*s_k z^Cmbkws_Yc3^&gsioPtK0Ih?)8H`)dpE5WD0hsZ*&HNY(un~T05D;$?yv8{!sl_)w zG(v(Im9=w!F?mQD)0q~7cHdj`JlR&p7i#+aGaM%bvdQVY3-)r>h~h*Jukq<$*(7c_Ixa1)iljjXidoQ_kCFHcSWIR90zhLJ9Y-G{1IhQ~GpAX=rot@7&e46> z{TAm7hg0tWu@Gf25KZf6GOR3b(~N5LuZ4|^ZSK0&*?;9*oC;VuV%iBJ$HR`<3X>Vz z;5ooJF|L3IK9g<o;ZGQ2{t2ysep=vq0^L!_)xVU*Ms&)qa3&b!o4};_YE}2{ zx}ABEp~wgdvNs2!y3xKbeo$i-c}Pb^ zeGz@OhbLFT#9jF;e?{v{Iss8M8FOApoNg#dTxY?dk3J9z?-jv`W$*c~PZ7Ru5?w(L z7^PwW!*$#T{AzHFYLLrH3O0}|ZqO1^a6>DM zL|x8&M;O;L14odljGQsvv@0tp{vInkx(gC;)cqv(`E%GpkeY6UgtMUWR~B<=Vtf~< z?zbR`@Lr$Vu#0mP0gQ)HL6BlVv+e%fBeR{TS2U-}Kxop(pTXBEuJ zQRmof@fVP!4u!k}-hvF|_57rI3J4(C$UX-0w5689z+b>s%ZA2}4L!cG&!E}~6bKUJ z=`{6woB=dbvx>E4R(oIK&r^6zltR`LjK%*ajE-1zLw`PDT^Qv!J@(J)QH!@udn>)-rY{O!%38#o#7ROqym+EhK{mh$upqb&967CYINX8LSwY=9X;W> z*VGjEg(_jDfsxpamwC#l6O(SGB`62PU#DKasA8|qAYkCsA~1l+ zpy{&HrJ>94-qyj-11OntWN3D4eJa}^Nm2y0e|g5@ognqTOSjq|L#)~Bk<7!JLyMDy zU#rcb-t*s;l8k`T@x)IcGMzX8@4oQz#sVV<%eNd!xj&|unXG-NC92h5?w0LX`T9MK zKeJ$@`IYl?q+0fN^89uTABQW*=j9J>P&QBRU<>QN{`j8=x=v%Y{FwRr7p#ZasW!ms zt?yr5c-BfOI-8#^3%fu11Rcdkj$zNMN`K%JN3r zaH?g|SxC93S$1&!RlW-*Mh|m~SU*?CTLiR?@Y3;neWj^?YE%Fv1T=gfd_Bj zKC-u(tr6NFy+#KGKT|rqU|ot;GY~LUBQC*}-O%RehCOs^pW8Z&l90`gJVp3RY&FPN zQC@wIOP~g+$)VEO;IXo=mRh8^IkR<@U*a(Olic+GNj%ON4{o)*%ZYHMiEmaBYHtY0 zYl!mav7EVMXNw~*H&TAmXngaPxSRah0TMqTe;d{>l7cAotB*O^SsyW3B5e&`Ppo~-NMMm!Sh0<38uFFRt=hu&cuihedjt((W==MjnTh%{HD?lQluYh^ z7j!Z}7K)L*{Zxc%0$Z>NIwlO2G*zMMmnO3JasX*4FlC^n?Tn$yLw1BQiE=OIrJZ!I zrm{8(Gsi)U@+@xuLik&&f=df7naM%GoPyl0tVfHtn}r%@Z~NVR=2C`lA2J}uZ=f$; zNkA@6C^h;k!4@Xwn;z$lnZG+XrcV0IIz1Uo@&w(K;l7JZIXV2V8LsfeDYAjN5;0oD zv+VzRsbwV z(?>1kCoGd|{GhIVmAe!=U?wAr?&fM|sy(FNykZHSd>y-zJm z3u6S5I!0bBloO#%5aR*Afd0IHqCOm9uIcH80%>5U&^?f!G_VfbnL zFk6zWmtq2tUc9tWtX&3t%~Y%0&>tQVHXkk;YZzWE2t;?zYJBmY8sn^&P>7h&p|4o?pMa46MwNDPX(0*9*`P~nx&d|?Dcle#r{i(qi|Lr z8qi%dOyfV;oUQZW!{I-5o>(aZdcuqRkR03JxdbmpsbIxe$`}uKr~KhhN0%q-|BAFm zwjVfntVw44c}BtL=s^#~0uzw_wlrJiP{nhi`cK74#H0CGnO9K`qvrkqw+buznoH1; zIlMrUjIpJY-yrj+v*;Fl@);TP4_`s=-bm$`gd83Xce95TeRm~fNZ+gR?J%-r)Fa&| z6BB5Z>7Ce@5ABM1c61gnvMIX9qO}jEfM#y%yw>*W1RB23wPqmOarb4uNpZcu9c<)i zW@Khz{$?c1Cn)C(I{Qbig~d{>%?;m6I(Q66n;9Bk(H>>qPi+-X{hPXp?S)WpUNe>< z>BO8Hb6GBbTZ(AtSF?I{6jBij&1WNA2%q;ifnqHEcR+4I zn&{C(V_w8HsldfD1DMICDm233=n02tZQlputq|L*gst(K+v9E z3nYDH9Cew38j~~g_7@hMsyz{}u$f%~~2A4A0ZTM;8 z0F1xJn2RvxQqtatUdC4k*G?AO0upm`e}UQdnH;_jYN${E-0n|t6XovJ!u6P_b|-Xk z!8pV#p0!imRQj1y!QZE$$2dyJ3{%P2XDXz zYp+B=f${hM>5$S$TVF2G_w~^m5g zA(L)o0wYS_8tH{AjX99u$}u^0l#r^VdfhQf{%JO2XN*(eKTMFI&^=HW;eM1mneyW1 zYV%6;SyXkmTtyiZr%nE7X4;vkdh=3*n#gJ5?|8ETd1go@&8NPvS28HW6P+Y|>k1e* z8ih=LP=;apq^m*#`!POpPefMV?rWHZZIt7Gy5}ITp%#CAJvYX7^K+!3<`aw<6WWX5 zB@sMExoA^~CpEwZgUpQmlBDep_;F@sx{ZWfEy8BS*mE}iLl!R~CbSbFSU_BHP}b0{ z7}zvwtK*;6vM&TLY66^Qq&ScG&aZ@O6-XipOBu+4LrJHJP9!-r!y}s2tu)`5dh;^G zKqo*$W~c1_Ibl1F=lV!GB>l$&~=KG+{4|$2H`;wkEJFE-~23 zj|_7{1Cvqt3HKQ|?Q`SDhbw=w<6#WId}<}tMqHM}p~l%=3hj_zQ;b-{ppvf-8wtgy zoyip#!c(57NQvzVZxBUP9AH!eyUeG9-WB(-#Q#nGJ=j_9w1T7eU&)=evQ%JBOa zxp?u#D+=Yv96bT8@`mDMI5YKQ&eJ&AWyk*F!P2&OT>zCgpy#hWUO0X;Z0H0k-*>h$ zHs?H#3W`#>fe%CiG|YgOY@`|-g}XiyEqja2*qAiLD>I=5V713h3-zK0$zczi$>N~8 zZVigCy}@nf@*`LE!=nrQNYd6SBL_zyI`1e)#KNup*illj^zL$ zwdP^jOianTOGNNzE!(1nQ2lTC`u{x(FukPApelA|2WTSxSHkNCn=?`s<6cdLhx=uD z+g7xHLHphrn`+RmX&_Ha%9`@J*Fwj!%i3tCmR@-gNLArs@CQ_LSgX(SX)V%y<(3k|Cu~+^o{> zy}YpIRTe;Q&aIAPM@p#2~QfLdq@0IRNEHlab|Z z3^-X6%G11|_Qqcrpz?2H(?spZD%pdX`sGNGc@xS+pagcDUM~ZY;#eggyG{X^0_ZLx zjhOTP{S_}A)|x|49r0%~+dA@%FvC~=x}b}{gEc~G0i*nvO&noLIGxu^MUR&oo;c6>n>XVft-!eQe@w}ok)`Lv{ z`XrWjhF^JFg;I$D#Y%_seB(L+m$rCzeO33zhY)@?<1*wLqPX$ucSv=Ml}Pm!l4>k+ zOmdEPjTTD2G!B_Q?e8%VR4`5pXJ<1`_XL$bISE=33fMq(y<-;fv9WRZ z>XW>LQg;bsBDpz%8qevUCToLpaDOuc0J0_@MfV|i!ODmdSmM1&*DXsv|zV)033yd*wyO7gPpUl#&a z;+FrFJ z&d$w+t}DXyj+*~ya@lq>wtOxn$MlW$F$P5+O-A~4pI5enp z{wXDlcs)$Dzj;{W%7S6dr_GZA^3 ztZmDte&Sl0+p}J;E@~^p96t)gqq*lQ;2mZ^0yI%+^dwxA@qT~b!xGX98_$z*h6eyj zM+fZ^xJCzFY2HOpq@oK@>c*k}qq&sVx~;hgPuCNC{^tHIx{l*^fAOt)Q*`1ja{dOh z(1ZRTy!@_}?0w1}#7zfKEWnlMlXIpUTvJdlJLhxrtm-Y)J}(A`sA1+;ADd=&-`4U? zrXssOAA|TmrK`A-(}(p->FLQw;xY103gMfCpXIUGY?1j zSGwT1m-zJfcfGoBUcfZ%5jT2+d27rnc70{rYY3u@D!*l>{U*$Cd5}>N+d*B|X*9og zXSsFamRx$EC;GW`%XX_|%-F#{tr+n2PrMG~H5@h{Oyra$tSQZWq z5iy%HNxixT5I0^Cvu;p?Rf41xkZBAn7~Ta0RDHLx?Cq;5#tRc(5?<6Z7egE0 zlP$|GN;r1^fB6)6ucX~8WOcl>jpgXzzwNk>&$Wo*b_~X9q{u7Eoe*9#ec~nt-H7%P zeknNz8^LwF<_^6$#IG@4ozv>Y&229{b%CV75s7dFJ;;bx9KjlTkS2MRDSdy@8!N!9 zdPT;t|GH{|wkeYQ*vo6?p_f+21p%2%y8DY_?{j$KdOQP>I%cjQ$^hgBHj2)qb;fa| zA7$VKOAe^XjX{Lm`Hd~JYg|9jM)cPC**w8m;jRi>Y7TAU7s;w2r?a9-mfhOcI zUCyg50Zxzm%BhEEi77we5n@_zVXI( zO9Gp6s`1-Ml^lu5xV8Iuu<8qmb9X(vRe!hO2k5$5EZY@w7`~s-qIjDz!d2o zkNgzHSnpCd0e%wqyX|5*?YI9O++wyg72N@vZy3J9G!c`04aN(9zIE}g(=+7o3xygR z27pW$RwwoozdM0^RuOXx`mg_QiNX|;wc~KhudfU9akHVMy(o+U0RKorWAt&|lbEE) z4|MCw#Yn%~J|er?jP?lk-7`h>$g*4cD%_Fy3U<{CHD&mS_)1owNi@HaM~pnKV)$Uz=IkATJe=Ow<@`;~yA`W6FkGNF3wo^dfb zbYPjfb$CeN0N@2j^u&0&3&E+X8Bn46?~vl**3}ZY>SDW@C$Xl!afflr9-ha@ABoO- z;{FNw>WNvU$M3D<)PD=_4rK8KVGx|Q$F=>Gs}fpvkcMp(xp#(yiD8VyJA+C|iCiH{ zFzcrTcc9j4x%xe*rD=KXj6jhahrJ@aytM+0f>Sfzk7&1VEygQ1x>UA*M_&Ff zskDC-VA#|jW*dTlFMe$^xXTL|W);{-)(*4x`otxehVjs*-@{j8|7s_irw|$=*HEMq z_i=8wxX9mDX(twu+52i5r>?ANV1Ts33rRroU=JJS-jUM6?7XX;1-Lwu@_-{hL5-s> z-lOY7g3)LPRdpm^^XJMJ$_su%u5Sf;m23gy9nv70?*-NbRMmOb?b z%_=^!Wf0B0Zy;3qn8wTosBnuDfMnAELnvrro2m7L9EqfVt0tEsC!N}UGKH%B{g!(4 zkjkbo{yfLfpMvB`y5sRb>0^PZqZ{Nh{k`e~znJwq>ed4)ka0FW`gcw@U?lFP^$aZ- z5qE{zLA|3uDvefU&_pfvokGWy<9STq+TPW+kqQrRJ|}(POlR4?(|o-}?8eFc7_YuR z8;{G{`!4Gf1D!wwX(RXdrMbiq@f*>=*eQ0GxzEH4{seX1ObrF_%?*v^x#gfY_*;Ky)_9t0bqpQRPfXqcxU@wd|q$yLF`NZegc|wnoYZY42)V{)ajMD=tIc$G0)(;WE zb0PCE;Aq^;7&YU3BSamA$hHlV{fqb70;p4%6$5~{@to`yF9WmVM8V4clLwNd7p&$9 z{zr^dw&^6ngsiuKHp*s78DbFopz&<$2%z-E>fn=d|SGI-W>^thD?)IoY=;*61T ztKKn;4s+?b=X_+;vr!y!5qR>722bjL{RRGd&30sBl;6-nDfBSHSbqYEXRjr*c z_kPBmh?MY&On&7Fx`w_@6o<9UVOPK{EI>m6YOQ^Jf@`|&El(Mu3tc$P4_CVLWTg2f z>$c*~`ET|t^^^*lmDXuu2Fxc|+Dpx79%yLtcJiJiPhST=H!lO~6?#?tWvTeP9q9GJ zotoH_EWgh%00l_mHJ|_~gDPMa4kgFIYTd&Xz(SgXo=xqW-0V|4E^*56J^gxP&7!dY ztiHI?Nfo9kZ<3E8UWVj<;cjVrBZ#iML%Ui2R}Y?TTbaZX%fEL*7lt^=$Uqo?RAY`S zIm2hZBrDk#BcOZh0f2aq938x%}GXp;?`y~ zQ9s62KZW>w_wk6X_Jvw|EMb3@5$Li^gMoL-k%$Q8J^ER!#4Fg^)jkLWRf@?W?M!3L zMD|ok#KFtGkh73+CJ#%PGLNR{brw{!zah>^llbs#v8hoyRI^|D_|NY?aNGh^GsJKz`L%zPy zTSuUAv^3PkDoZcS_)qo9a0N9G4rNbtQ(uYhqHB;(-khwzIsv)I_14j8v{|!rBs9wn zIKlY-O*?#9%p1^^a)dnK3)N-A69U)yB0a=zU`j+TGeAbEUY6_(FpVMWo&%)U_*4tLdp=5RT%a4{G~O?Oy?-+0Cos`B;*1BzoR#{xw&nH zGqPu$7y8#NZ;D)CrZz*IEwmkEMOzfP-sG-TB8sq=i%2o=;jd|53P)(jn2KXV)SAT^8Y6o ze^ShfU4|$+ge(xPnwT>ajWMlOiGJ5;3?I2@Hp{&?%hX@b2(FQ60>2XEzP1MT8%CV-!Q zd~hP%mUNqj_Hl>84HvKVf;{^JXy6iVspveXgFz}`Wx(c!e^;+)z%=x)3s7og<>MJO zd4o)|dM`Cm{A34Sbia`>b_+>}T#y{+&x3+BhVr2AUVxR$h4bPAAZs#}?cM0UuW2R| zuaUV8#f<HGMkUNhHfL;VS*#0P3<)fXmOSFSZvLmBy1 z(%(`LjfCtk46qoUA{aENF>pf@^VA|r zl4@>3d#^uswI=)FnFP~5jx4O%y7}7>Uerv8EfdGL5A3jBkV`bX6Cs!7PVQ%+2ZK-r zaWG1EVI9|4p|Y!ciUAZlFLlDGi(43IcRaa>Bp>$5XKnM>mqA01xLpA5ww&FWaksV1Vs=QQLG?%`BV9Z+cO@y22FbHcf9y=C#k+{#hG5tieVB%=@So*+D4# zX_xzQinHZqcuuf5JgJg4GG9=5zV52WYt|7;B)$h!H(-}r$lO901z`M@=>4^;l|AhD zDO=vnkV8toW7M#ujBgLM(OSE=fAXEEI_fJd3z&7alc%!R_CxN8sUZhnH;S0CFj;kO zSrMy(%=YN-c}KpN*~|ZRg*i$ZQ~9Ujwr;FnPin2yO*2IiwPR8ZSAIKcQJr{NXQN_4 zJAB<_;FL1Ch%4ecY^35|6uxM|97D~xH8v}2=dul_8^zjtw3wxB-gqt@kRT8;@k#k_ zUg=gpGjQ7Ip46AO37q{)koEiMJK9oy3i2Z1<#U7Zaq6dKUR%%5Pf3~0W0F(fo*?N>ab*Hux*kC z7ylo{Wvw=u#p+wDWkZ$K8ce8Xfm{bXKStdRDnEJ)5TlTN8O3LYXYzyJOFzcOzr|jF zv6ycE&59Z=ehyopj(PPj>C=tlbA$bRTpucoOGd>cYOFFo`g`uRgNMPb$B`uqzh!X) zFY;tQZo_(K^ml5uroc;McZ2a?M_wl0j)3=MxT^ISOcKbAG8xAe_VzE}% zKeMd#-kTHUSz4$Pvel~Yoz7Cj@};-M*)=6!4#K76-DaVaehCW0 z^JkMUib(-S+sGM%)3Uf{z4WW~K)u~EejD^SEN3n&{>If-YG7s%eDySEe(*z!1lu-r zF?|5OaQ2iZsES9B2nPCACjP421mG^3j>TVhaOD8iW`>3{drdqQ6#w_ZZ+gQha7H&M z`R%OGnQEDrFXZRiv1gqL{<~+rZ;AH&l;q4`06?N7qK-B>!{62?{OUPu$G82;wd?t& z={X$&^Z|?(6oo|U{%{bJ(>UGzrQXpnh~vdiSzJYmGuYkL8Ouj+?u}O9-h7_(#(~>N zn#7$~ckoLV2RmzLeFbPBX2nTUA?u5LCJs!O3`6KI2|G zxveSAM5fx0682?^)?_Vs67m#T&G^XP-S-7N{S3|2wgTT|7<=*0Sb4j}+MQ5Sz?F;J z32X_FOKBf~6H>`1IjAG9b9C`Wd+i3`9AirGbb7(w)%BO$wv4ol?np8M^u9 z2|v54Hl?GJiP`%n_R`cvLYN3|{pYUTQ$Ybc5)R9}jbgaYq))HQ?+R2~bs)T*MNGrW zK`O~k$msa{NpFJSk_F0d>}}SBHNXC)XE@|~zIo3Rjsw~%r`6XK?JF;~mF9iFa&2;A zaykh4MPkvccg;~MtDSlMHGEH*t2iZxXzPxRkT0U4F zJje@w*?!icrZrXD>XA2dNKt8CcWGfW?3yt#OTg3;xC)pK$7z1jBH3bhEBy6-yh*mp zkLIh9Ta_Q?`DU>OUSIq{wLDx$u3A;A{BLIWO39yi_rId zkQ;0kpI%4gy`3E~Sd{uLi`5Jzt8Q)QO7&39pt>J=I1xUKxu4q{*D%u7^1HqZOaxA; zg8_>*jC@-uPpziHHN5H9WFSgmexciKfBY1nms2Btrl-Nr_4Hbd+E23#>|Wph0PORb z(+WKz^Ff9fVA)l~?VTT={op-I>mu>yhEw?1Y&e4I7;p^*D3!96x z17jmK$N&8QZ~y-9U0~o6<_vvP%xfkj4K)}MAA*}suiNvj4cjkG=DBfL@Q^N5^x>R$ z(!^TwVO#R&-2=-%%R3Pv;c=}lRr7;dpM$qpSC}4tof*NVb?+=|9c{J~r2ph~vUcVP zkTSOFOGQXz&9L1rvCr15>ozJj?&Or}|$vvmq`}=dK!|$jxo{7EEt>Ue|4nMeHoE(bs&9PJmE5ODmeTqMOTgVKwkM zFV^s_xoSn+(c>+=#uP?gV|Fs4e7nR89*(a$It( zI{kucS5li_m$lk_`_|tf!#{ZsJ@Z#IaEiZI?8E6Kg&~XjwUxK_bv7&Zns?RK#~)7G z9foa6_oNiYgs!OoQ8oSn60-` zp;uN2uYEXNX}U0T!(<5gr&Qowljf{7_fbN`uEb=mYtZE94SSWrC7UQfz<_P8p2d^J5+GY`YT-@VH$eRo^)U<{?T*W%X6I@Miyw6Qr- z+UDB(-|*w~@rcmMyUX2`X+PHK_7TDtE3WR39+fAk_T^p0PJ7E2LxnFFzuhrXP^f%W z9%B>~Q`)%>a!hVR8~lDX$GqG*874IOlH7mb>~FHQVQDn^-Yu}Duw_ebJpAG2!=4`{ zsaE6~&4l|wz32?sfA;Vt?zqcMQe(Cs+$L)Ms?~~E+4%Flv*5}kFsNVJw`-j_?p2xN zLUw|Ozj!9)ytn@xRH{^J?a;^PW&t0A*9qL+7mC`**$5s9vC9y#;p&Mn?4lM)uND2+99$@(=xwq%E+|UOtE8t=}JSuc8Letu$?Y1WQpuNbF|U9 zT_f0>zL|q0R3|ebqAH+P04a~+X-j>BwvtD4n2xpiT(3#GHh#n zcRha3NK>3=>uA4!`o&6(+RprB>!iq-bqZs4=g+@wLv@E92Oeup#p*`+v2%(m;U9kf zQ8)X%ou@GUI;>sn4)Rd_=Hx-!!zq=-G@dk6(__5CGGyiR-rwC5&7IqyaqEynKIPOE z;k1`*TDqlq11DW@=Pm}<9^Tp8ef+fM)UER^m#rpR9$E_`rh}~vc7J~m4Y&RM=5;tY z{490b!6Tu4MY#5G>-+2dE@`6}`JL?#THyz~0YQrN+ymDGy>Hv1PBQ6RJ#)2XMn7GCn>UIS`HnsZAFl6~ zPt)!lWWI52PRDA@Cbw-^YJ5L!KWeSHSJRW$g4++i+|fbKHNE=^+nFQp4PvI?Vf9>Ir>$9KFUexf>(Vi?ZtoAJV-fc%E9WcUOmD(!!qUe- zYt)6k9RK{qOQFa6wM!*W=~%+j=ETmjbs#X(sFb+;Gq;iDotPbX>5!V*?*FsAdW-#ky~}>5mi<2Z^DR)z@tbekZ@y&*DoQu6Y~10S uH~IDxvz>INVwd~EiVdV=I%53(*`L3oQ<x{iZmein85@Q*Lv81tO8N2L^ zWQiEER(8>550USg?)!dxzMp^K^FwcM%XM96d7bBW&NT$1Yq~s~BAk2n?BUV7s$;Te z&t3xf*TKO8e&X+QLK=L5d0xHYvu6(%ocV9>p5&B6d-j~zqo;Gp)Gy`7C(Rs*>%oeP z2Lue$tsn6qJkzZoOL>m(-7n|Y1g~v;A}s$%7!~^Xm{Bq7foDV3hXv$YxP)j;Vc)DT z9pEk{@PQvTrt@%{6rb478+XoV+?r)S=TXCAy}CD*Z+g^&{%&{w{yk@!TKG3eCY(|~ zFmNlo`xm1jZ}j))mZqsCKa^;6+yD7;rCSBEY+wUFA}FUieM!r)rNnXB2`$=)T%qn02sF&6DJB=sad|YWi6es94h3cXc#aHj zQr!EPzJL9)y0ZF%|CH&*;L(#&5VLnvRHFV~svwHLWm?N0b@HwGt5_Z0J8ENr6)b35 zvXykSQyj@^Q9(bh=zNPnLa>&M&GJ*wlec_j230x`c?;&?@ULqldvEk!#W(hAOKX#u zR}J((IUV=JjhJDij$Ou}qO(10z24|cJZ#s=30CrFomuj2Pv)1w^>GZ0GKcPMnns|=9}}!C%)t%w(NW`RV$FkKuM3LZ#I}}BTINq1 zPGp#aYSyY!tJd1%T;J|LuPfL{ENCzmjBA-Dy;Qc`r^N*KbPFU+!gYk%#V7%@Ox(iA zmEmR`j>|1saU7w{fy&Fx#Siu8MlIN56#Cyz zCV}l=<1fm>uzi)rJJubiZ|X`Gf}x)aV9m>->5W~vF>K26)wp)-%gWD^RiQ{OV%nsC zp@LtHeJeaas;^PUAWo46UCQajF0*%(?!GfEDS=^MdXkfIe8SXVo;Y?e8l`j2rX}SB z_m>=`IQ|Lb+QAMw^QV>4W}tbrs7PE%{F8me0;6yx(88W;nI4G&qj4t(U?-Cxgm6Z{ z5U7kf6T2J}O>(#7n_Ie)3Wgo*d2mp;bIZ1cu^G?}r?~C%&vTu9meQe+ZAQQ-7#D?; zVP{@KIB_M}9m%D+r9M6B(}pY=<_~3#*+e^)(Vec)#{?gTjk1Bl6W~%!hBhus`;a*! zmIo_4OUCYHpjai1_vG&1Yk`OSd?bq7D?&>i!CcZ;mH7B)3?}2aW`>njx$Mn)+2j_p z+CXiZOIwniGpck$CHeM(ML2wpjdSb%cXkW4XZFbXu!X%CC}&pe!&SDC)kVo@r_>V{ z4=oG0&M%TjaW*EL0|Qi@9KY?(dO3+^8|E;YELOCBr0%0S&~T~t$aehACTb%_D%>8d zT1x#yq;)HX8zbLeq2v{|z=pY$Np8!}#kWjn`%x5P%4HEqL7NiSbVDqQrmM9r#yB&u zx?y)?Dzq+)AN%Eqbo8aTwW4XlL%lB-4>$K?)9sZ)`3I~cL#nl;GE~TSGf>T6Yxtv} zHYbm!ESK~yoH*WfB<>8GK7MF*QBLSe38=2Cnb-AN;Dxc&P-c0V9v}*8pEFb!k)DG5 zQND&Fl2MQ{sfx$+I*C7HOAi#Ax%B9jt|QWD)md4XUtc4gKQ9gX_JIDVeLS$R1pFT9~G`XO;gOW%LtabFHKyHckg;OjCOE=Im4d8=+E7m?|S}-E^?{_+xEJ z%_Sn}Dq(#Jw~bneUV>75O~$&LA0L>DILA(f{wFcH_T8A6tYqk$ijkF~3Xdr-*_B7Y z8J;Lcrxt3>SI(oN_`PcEo#7C_4aOsbZoz>E6>OX%Vu;`uQ@YFFv99j@t*>^Hl#@k+ zNf5$w^Nl(t?O_9>)D6i~$h8*$fPY+OR#Vu>iEvpjf3%;Zr4 zyhs}&!RVcu{g3_|v`P7)G^U%+89qxH12@a?sseJ%L3$-^V2=MHZA zw0g*jx?dxHFSVajm`Sw`qQ=uG4a3pdZ*k1l`d zAPMH{3A?`43n)C&px9*s48Ii_%%T+8JHwSuy2{oJKqe}MYJ3EtO-a@@kTI1aab&zO zi94;+(r+of*U&cOO>>+TURIO~PN)JyX2x+{QjX$DqHC>H$eeHOl=~1VHb%Xs<$|4L zqMqQPzM*NYV<*jJX7vzpdk~>U--ZN4a)P;O)@r+Ed$k+!ckm@)xxPA|c{`QW&ByhS zqea)HU+E{a>$AcYOf^Za{A=r=Cd^nt$(Dxp4FNWiUs^p^h~hU~LVZb&6!cNUB9*-S zl|x~C9dv4@#;?yumnBV`IkiHSk~kc=;HLz*5D7YLhIL_m=#43^(fa{8^vQN1YUyvG za_F2ko8eq(hyYn7+bOPSbt7 zljs2V$dl}{;qB()M-ij!d2RSFWFxtp{^?vf!)ha&ze#7TMwtXKy?iY#_^zAZLpBmpKvq*rZV`_P6GJ0Z zeblaKHws`Er1%CA+8M90nMb5wK`Pp<@yBI@w(*Ha?))AWq6&&g2X=OL9- zhk#@`NcFL*h#)wpTPV>E<>d;4pZc`>i}U2muC=Dj?P z?Nb5xt1lwGb?Qc!(W^&&ef1LLNYq_H&f`mrWO7rMa9#vtEa-w`IqW*pZzjETh*Rg= zUQFM`q$4_&26|C*2|=w<;id zZc2es@=IIsr!dbd0Kgq#k+{6tGot~$8@;=H*k;f;!lCt<26aDiebs{1rN=|~z`OfM zt2}WqL#vFBWx2<-S;%0~AJw+Sh>#YWq8of~GPn`N!HPWyyi}CY#|Rq((&T%0Z$VT( ze!s$XBN!eqYtOwyXzi>Ly=~-+BJA(*D5Q|E3%u`mJ6;(NX83Li5Rq}0FDsdTY1`oO z2PF=$`ioD7Gf7|f63ThzkHfx40(RAJ+oBu6s+?sijs0*jf&82*ZayW4GruQUDWcT5n&06!xd>1KsxxiS?5Ow{Qi{xrl*;B-o_iOzGykj(4V!n zFZARAW!m#JB@s4IOWe53u*ne#b(8i7qX&`4x_f@btyRg9RZzE_UrX68Kh?QH)3cHV zL=ICe2LSm9Q?5RIh-xT(hO}-?q+}P|%nl}UQ=XLHxvLTh?RQ}v=%G%Fn_@B9zxiz= z@A(z+i=OZy6%JBo{J!k`d79p0E}J22g-gt2E`*;a^1C0j2%I&l;2yXik$m}HkGPuj z@h=VGm6B4ve=7AFF<6FU!+|89rt%hFkKM7|bI4Rd*0TGbPDdVj)ve2!WPm`^t#+qI z9b$&r1lKm^?J?a9H7&l@(gWxxP&gRGY*BNi_>s&>UGb^Vkv#}F#e$djhY2@v)c!3d zu-}eielYI_D!*2+G{md#9P-#Zc6~>(Nf((B3UTnAS zv%)Woup+bsb%%7s#}M!g6?pWY+V^WuWhIqpezvcX!Je@b2e?Ywi$f=y`*TB0MkJim z14adehm_x`OH7Vr3Fx1nS(JJ;_`2LcgzQ(23Jw?r%q*X{R-xS}DQy$l|CSH-2Gz{m76Ev(cnuYG@W%>mM?6`PDLGl@f)-3+Ag&$1y z?BF#o+Il#Vp(xm2+eDZlf+wyT%2)_!)KM}G{nPclP>Y~j;?Kr|Q!A_YPYi(>=du$= zvt|hA*3%(BRtGL(N$3I_y!RsQwv<686^c2*+SD)5Aq1#b|0mn14C4?Jm}K zsb2s{N`Sig(B%x*A|U_9G8cNOVeRGu-8_c- z#wnTv(8#Cat{hHstB@#gWUP7~TQqNka}bB9&Yqbs&jj0&Z8ctedOkSsgt5@9Zz{L~ zui)2BE;sd83)gu9oaH58qhI0cul8{QMWfDfS8iO-5pI#ODOM#xzIJ_?^T~&+?O@0S zijq+JCj=4;0{=86)+TfvwjH+rd~qHZ`Qda0Oe!}GqUjSLd7wo+$(c(s&sTo5j^a-U z{`_u(slT}-+VW_+W57~80Sec;(S$#1^aNsw4OooJk87k)>N#Qx4w1Ek{E@2u;xE)b zwd_*l;M9@S)yp}BHw&it4iMvwDv+vSfB?kWKT=1oL`r^`ChWtE=UO~`Cw4(@eW|4+ z_X$&474f4APMG>d&b;l=nn1cJXstaY2<15vON>iqa)%W7l*CXj*k-*qegN?tt}cmQ zU6J@>ay?`DRNJ+J#{z?h8>~Pyf7h3HMSeW3RJ5hY8#pv&QNYQO-3aWG|$=e4(;rewD?uxmaYcwYa`xwXWyG4zh^mEnJ?Jj`S#z5 zAyBU|nHUe;6klTdn$o~pZe6(1=Y2YAE|;rXOb8B`E{r>-Ky8e=EbWPNT{d;2KCes~ zEB?42y~GyjRea0>!2)~hfz^pT`lESlUgb@ROo?iw8CT%;&Ak#C$d|R%jNkx-{VWh7f>L##PtXBP<*&gMO@-A6d~K+3==+KuD6Gw{e>P9*M-P?(-vI~u~2?~+>M%+jqRdZ zJI-T31TVP0yhT&(1HKc;To`i^wgLE z#4BfrnYv%38K=^zrzEK=h2^EV7Pb*40rigR)Q(P}W{_)BGX7Vwj27LgiYXc4JPv&N zdHx~$K7f&wYG{+)j%<%=w{FI{-dA^rqfBmLwfq)ri0Ppv+X zXlVTt!n!sYDTd+$YqJ@bS8$`0a5vJan~~c%>49*^g3;)!wdO&u+C4?m{8&Ecxr~`9 z^&(Gq_-{YFp#5xw6WNQJ$7%Vw_SrdLB#hOTQ}MRLY)GSyL77s5bD}c|h>Yj<*Z)z` zM_O(>hJjE=|Cr_4C|_Z_s89Bebv@~!5Z4GOK-u44o{}u9ievHbYwRy0`0!65_uB0r z(OJO{=`8k_!EWyT`%+ysoDIb%p&Ie&`5vU94y(fq!Wo{!ZwqgRZyw+|kjM#i^LH&# z%|r*xkH=F#C>*G%7Qeh(_-35eRV~MY+dvEJu?}Qp5bxZaY{oCf9e>LBITcp}Sy_1cMz)D$Ti zbQ(?2u_77zE1%Fi6LcwKQRL)RlM%L(a)jY!O0)67mbg&~jS_v5!dt}fpY6?zkv{ND zWl|jSllnTtvdMbA7{-@(!;wQzZb;{j@GpBz7ZGMSi}d1JS0O1Xyrs&#(eeI!ZJ?Km zmwE+-O4UJma+7JF*~tmVRQU88Vv>!@_3dK7U}CwWi_A~N9iomQBn=7BWJ~0z@9pln zFEXNG}85OpkV@+ftPTGgncH9X>5 zrMDl_izPtqIvwu9-BKQ=+8R!&YYPAE+3BOU7u~8C8zuVd@e~WG z+v)quV)@-vePnxCGjCA-Yy7J%PrGfyD@Z;~y4(SAK4(m?Oeoa0KUPWAQYzGFBN>YA z?orf_FO7t<6HQTV5y{lq%}@O$G9pR3tqzkzc;~QeGxtGzA}O0;eJKPThA<2_?ggT( zI7wfY$2iv+6D4IOodjKub45GU@ZrJzN_M!FXH->L}m!iSkMs2@)V{IcKn zvpy(GgRM$Ow0BTnU5rDX()Nu)!u&d%k8~o0(C1AIUeQd&v98NHd)P+sFYu!h=LSz= z#YZIH6wz^!M{)o==$$v58WP}*pQUyIbG?FzTGn6$aL(^-)9PH>o;IlK0REyap2so`5`dBSfmhO9!O6{f{ zHhn;BhYeBfpA_~2DvFQD$C@n1jb{C#a9c{f$ZpxZoRcC;lMf(2@u?d^bh{@vWtHV_ zT#SPB&cDNUM7&GC+SWrty7F+@K@Cs^td)EnF{krOrAR7mVB+o zk(KzCS}Qb$xDt7R@XLQ^qNW7+oYHem3p`pkjBVX9du99@9tsXA{pg}jN*^};x-oA< ze3(6kIE_{%+kYuFkV;5}$Sd~ss+OcGq-0IY48h`#BZkISg&eptAAoE2UvMQplWGRt znE727g^g4|@i;LyJ4YL-fp;vBy>eXGy!X5DxXccpZQl|?C+0n3FZvd^j3qy=G zQ;vL1aW=sL?xYGc939c=3QU0L(znV17p|(EL+20EcZ&V)h94fL&!3n+UJ7(#Ccit} z$6i8-hIK8hCP1swGHwi92@Twufk?@ID`6RvZMAnthO$K~A1qZjtb*RT%9FpI|Ajo= zHvlxp2q=Lk;O;;C9qlot&Tc}^BGOAQzY5#2z-{3>TQ(CN^)qH(C>=pJMN zfZHK1izdW${Mk=?ZCG&4J-lNGmE=@=3X0bWL(GoHiE|#x3cbr0St{}^m&bYm2S32* zKu)l}k}<3#G{K$W&EQ);6pXXP{H^?nMt05{mlkUgN_tNlAS4FMo?a0>DZz#oFqp|o@#s~ zly@(CmSAX|Hw*}7h#m&6Qq^`QSJ}-VjW2YS6UJRE$*w3p$IpJq%bqIO62HjXNE-NS ziH9!7$ZVjkdX>2^AvW|8rUy~zt}TxDoaQn09<~32P?|w{+1zYHOssm68((9=!ViU1 z0sjd4^BdOVrJx|hOhM&IKG|)zDhD`;pUehUb!?Mqsh-AJd24U7NX@BIkgRn9GO;Cl zQ|wn1XZ3Dmdc|16__-YFAvnpFY!4nmu#p|fNR#Sq@&XuLM~>+-lZdFP&~GnW}>4|@(MnuX)?U(j^js{ z@*g((SfC#U5br%%jLoZDerdgZN*DykuJnq8tj%Zhwae6p!Rwmbrgk-6)?>0Nr4$irwdn6768v zJHa)MA0#90J|>t>y0GcrJsa%$z-*MZ(qz^o0Lh~sr0>GuOO+_x8BPey?)czh` zUBX7*J~B!bH+%QOHsT5w!xqqR6GGh(hHh1RW$*yxfG1Yc{d&fc6O2mLYUtkLeAcYX zo1zeHihSkDVsn{N>a`r6@K4Sx&)hK@R`2(wtlMDRJ#jj5j3=*nm0ocxo<9uG&qa;T zx|KM5rTccg5CTr7GVY5}#*W5up}v?79xuS^>)+i)&eZT6*qbP&L;kk%zq0@miXI16 zm0v^p6x)4E807b*;j|y{QBm9 z6Wg}}Hp7>Cy&Y*JI~{#`hb!dhABBre&6# zk5bB_f3On!sCyX2NU;zU`>I^7PNj@+$1K^l=htp|iCzx|OAOCGdh#^7nnQ$Q$}8W% z%}P>1wkplzI2F6-REIJ?a-*iOEXHLQIovFORc0dpG(i3?jIsD(^ko4$s{OcG5D&W& z0jF`*$6p7tzJH(wmiJXz0K&<22C}~ypePjNNlCs~ z>^E5eQ!m;J+!6M#$$<4hai2vY3au^1M( z4FE<}W=k9aQw?BQ{3laO4iDoO*$NsTsIihRl9QEi&hXR4%4BcS7M_`8P0?^v+|>=pyA&4$_Ro9_`h-fhw5Ulw)}Kr381JOmxG* z5rq&N@KxpFb*ALTperBgbCR}TESxb!sRZcTqOTVc#{rQ2w-)6`#FY z(Ued#B=H!`%BqTwI{6@|hSq%#^pLQ1;#$ru-Wm{8nH0d!)kkzx>Zju2*Fw~%rG$Ne zb~ymZ8QX>)_r1MQ<6lwSa;z1QXNGaRUSc|Ik%rdCF;|_ z3WD#Le{4%xMV?ZUkx9DQ>tO{0>z$uUN4$5lY(ofvtf4T|LwOoxPBGxtr_ll6)(9kD z5C)zquHO29ZIrNuIQ0)aX;8;t!l=Y!La~bja6nYXivkhn@ZB*JqY!5qxMJ}o&sOH=w#QfG$h==!hefs=(Ow&ccU4fO@Rk|&o=m*w`U2rj%R z&E`GR#0JtOX4`lSF9VL8SHOR{O@Wjt>@+6DFq+|mh|_0Z&s4?4VAXyk*4lc#1A(zk zBu;twJ%C#vp(R>^)KY@Lh>EW}A$iO)9pn;tT4fpfw|5V~TLnn-S0r zH-?L8&z-j$G6&Aq&)G7k3%QTNhIAPV)!e&C$7k<}ye-sniZrC6o}%w2<8lllK==OS zgn_`Qys-_9qc^1vGUpALNYC;|Q{5@LXCnen8-w64z>530MjS*lTAs}>mLb12;)T1z z%|1;<9P+i_jRy~jLwbF>l(0$rb=;u!Ey&K-T^Ry(28UC_Ty_`Hsiz7ceXz9uB{DSk z15H3E{qnYrTZ2>C=c%jGUvZrK z$!-VLlelqxD{+26s_(yS_-ukz6*=Q^3Zb-CN}#+gyOI6CR7n;0C^BICL}}zXR5;R$ zN8D-7P904H%;f!yjuN~SBV)HAO@lURACKr#48;OGGhDxD&b{LH?Ls0tsC(UHFXUC(D&%f64&(wQ!4iF6=yO)3FB^xih zs*_GQ+KY*k{Xb$NUYT@}b{R8I$ z$-|~(6aq+g@fVzTvt>RPOzai^TxUOSFEN1aTQp6%%|hV-VQT>v&MKhYP*F@U*QQ(f z&ypG?N^@_!<&}IA5j}xG67?oL_KDi{*hb)45AD(Sc2Ad;HbO+;Dq7hE2IuUil0@i)zKR052*vS9(M!cQ|jeaI& z8%y)k`X7_@(=V@>6+&I^@Ae=Pp!etPScspge+!#REHH-v`fM$H4|FC#iZJdzv|Q4`nKI%}Il{aM}tD%9#wT; zyr7CCjNE1=9V9R2+OmKtIYi9_yL;<)@Wn!qqy9(Z#||6o?5_q{w6*dN8GHh`_K{lPuEsLcPpI()kVs{LEMO$)Fi zU!*La*Ig;A1|bqXaC-H_t{DIf7gcf+K%Gn=`N{)9it@vR0qTZH&{b!On7A&E z1~&Xm+?PWP#9?reJ)?yU%!n$GD1uM7ma+UP+zddWG;F5-$k=~LAV8Pp%2Gr4KkVmk z0V-(hWM}m?t(|=?E~&TEp-1;%Ww2@BX(B3&xhn4n}ga znns0GKrTJ0+;E6Yui+fQFVcY((nIcgQ^HGR7F9~1005U+Nr%8`DWs}R-;gh&f5Z5v z6qBNvCWnqun$U9rK^Fn)?0T!3B;OpMpboMoePDCqN}HKO%V8KmuJxE)0ww+q_>Z?B z0p&yukJz_zRsqfP1KZakFq)Odj{rewsM0OVFRMvcq?y?wlUcNf%NFs54%)tlq-^hz zOP0TtB@0o5ffW+RHrtd`eO?`w94?bD3341ZopLz}xC?BItbCt+C?AeG>^|p?IsQeQ z%a8=l^{r&&L-HiwFWFDQ#y-8s;w^j-3_8>0tonE*Jx_-&Ce=kV9uN7-N1w(fH~&#` zgg+Y0`1`x&hF|JO6%sds>AIRh7mQ}7r2KnX08`9>v?L(uw)Viawnn%X+ULecm9loc z6!{eXyd4|7^Vs;;p)NK!$s3eFyT*eXIZI2#2KS#c*_W^Z{`U?KJQKr<(y23HhexvJ z+Q%oBtSaY8&vqLtVHTLLW~b`OU}my+P6=#$T-+m5@9WO`YObA5P2|09QoTpLQ`iU4 z!AL$dkuy9(PlFAtF;zgp9=O@aRK(EU6saUY)UdMslj3%K_7ITQ{_~LpV|Ar82_dDV zp)w{$owYDfB>;=hU z`NZwxe7+V~#2+F>HQ!NGik{1XN71;&u>sz%ZO)M6P(Z@?<;5575t-0-_4&ktcm?+LIV zeWU+c3QMT|muCXL1*5(Am%l?i<67=mL~JxLGfAd zw70)D!1dxr>r_O|^~;otWd7*BB(+*5?|@(}(;%^x=Yc~2(*sw?M7Vg8mwiqj%++68 zGVt5xxcB|Vt>8?Y_*H$TNg94c${x7}`wv6Zs*-(zE&u>@omBFb=iYyKhA$9ljN0EFHHBr#j= zN+!ni=SJ^$n{gQhJ0ZQxU=#(9%Z=v_bKe}MPr~GH(U18a^AxcFn>^t3<@RtV+rLq* zg4j%qTjx9OZA;%@_Ec*i#(>a=h4K-w$9yJEt9a-GRUG6~aVPI)>RXlq5}K`~atSTS=6Xt_d5g;Y`fpMHKI(;hon86;!?=ac?l=Tij&CF9>* zRQx`G)+a!fs~ED7U4cpE1S@4=VMzoho?^aSMg>upB@pbuYS652egOuJJgU|0k8)k$9H4(9!2ZAtA+q0qTClvNMkS#YOl(Sa0an}( z%=Q$R?QYCOgE$G4p0zl3vbn4tf=Cv~8DP!C9DpCw>$W}v)bzm&B#khuXAQ(SFl!VQ zuY9_8+eD8U-inE|L#|!x;m9z%5S$>TU+QlayV0gcE?g%6}h3;9~k4`0@h| ztWBQaTG()wF$^?|N$3ADXuxkV10^Q-t8eE&28jR+7;`3{vjBrR0non}ERPPZZCh+# zKHG@SBC}BbAvD;gIJo1Yx8wE839uGO2n@ds_2WV4B;VgUWUqYT63FeC)Ck-eb5kT# zisRGEGp5Q@w2u6un9w4yr0}kF#nKr+;I9Fig)xm96 z81|C4sNu*ra4voxWMlmQqQYEf;M_7GVO9oz=~;9ab-Q#Qs3pLwk${d7V_ZvL+eKSL zu^eD92C)2%aYMdG#koNw^t{K9(96|2DWhUkB0g`A83zd7GA|s;`61(`RIg{!kSQZ_ zBj>==;wg1kkdx_?uuNDqRjxT0Jm33_Wsn-du5Wy37OC!k?g78P#KnmFH}8ufC(=UQ zd6VCPJnJ%?R}uFoIlB7qIYWQIUw#r%fnn&470 zrc+%c+MB$JYDLQUkEB8E&e9-KW5Kbcs&yZY(S^t_*z<094HlXl)sk*TB%fM3`<-g; zOC4MA2Z`yTsXY5qRZ=6^Tsyu$3fc=qp=!458U0n6vDqS+?Z~vO8Rlq-_{FwM-?wcZ z<@l9df1=O{Sf@F{lrS6(f$VFE&uaRtyii!4P;$i8&lhLd#bj?RW&MhG1w_cCGo60e z{jU<=F!V#rhlIC(KtM(GN8rHWGQSV$16`|?KlDdzJTyTw*P4-(8g=XiclV7cz7k#M zt$mo4LG!Ekn!akBNF4_w9&Kdpdp=Ks)^Z0 z5p~cU#u*3BZY;chjhZwxW>bL&0n`J33iszq@oi7TLQgZQ& zZ32hPJ}V?S1d*2`=)a%%GZ6%R)&C*uI}4u4x9rsSxDLl_>))PTuXOqL=<_WVEnv!+ zy^A|q-?RqyuC)d)wGM+g21rnS#uW$RA;k6E2j*1^rj|E);GQwS9;ZmvB9rYn3K|c# zu_MM1EFh4ANNlL~A{Br0C$B^M?wplDVzwDHN80cZ+p=#p^7I33LD0tM@R!AZWP$eb zuPM7!r8TdZY~;wy&hVo^;s!Gk{sY_qy!-Kh!Oo)>LUcMu5Z7I%#+<3$1?ud4?H>88$c=P!>w;YmIWLQ zH%PGLL4x%>qUOBQ*3h)F2pq?+vGInp}{68$RRH<;TUlE@|AIy$)2mRMDY;Q!h5m!cQz$Vc^zqVqKPLbb z`v^-9#>cS9VQCSHeYBbRulf9(3y9Ol4|WcQ533B=lpJG|BO|W2pQQM+P@eaM?R-sp zfw`!BBadzNpKP9%^-nMUBANu2 z{7vhdLh9(Hr-PlgHT&uyjBnDNGvnoar6uiV%Sw;V8ohIc8G=Z^t#y6E?q6Cv{UcWQ zkdbsi>QMv_h-?BV_plglFtj6!7134s(>KJRj3-4Ot@&5tm}z~;jL04A@qC(0DA?Ln zFOGWrQ`X=7>9cG>CX@vZ+uCA}OEU#6#7vacW7HpT_g*y1&p!YVA`{HDMGd1JQSuH4 zL@555Q>v*)BFZvL+H{j51Qr_5RQ|3hq}9sYyN>p(ATswd?;l0Tp zX#~~Sd9UBZb3LOzn4Jl6vhSG1mtH3dy;k2;BO(3=o%XJ}s z*C*yrSJ!%mi3}s~f`8<`v5tZXQqV95p2&5X-keEzI-73=0Hqf&?nuB*f0R(u5%3b1 zGo|YG2l~5uiDEr=Ks=un{O=ty%CX&fVw365|KifcmbyER0M{N#E&gE#qtfHT3C~ze*y?Ou7)T zsVTxv?0va$r}X{JmNPSN|`vY$ao&7#IUi~xhegl2!d{d{%)mz>3?(Teu#@0Yg74)6jKGlw0b`g74 zZ4}Bchv}-ca|2UBSXuD&^J%Dkvs-k>vG47RY!W}*yz8v3Gx(hz|LC;RFg-8y4L`Z| z*7Ee`*S}bI+I&r)pjR|1AcJ3jwS?qx$p!pn?#w_nRJ6SU&Gs(FVKV8h+Y=&WD@oqe zAp|<{$&nm!Ns&8U$K^^v5%P+rNq=e)%$t2@1SCHwxv>r38!}Z!_>;D_0jPszU@5+v zBsvb9K=nR<7dO8I^fN$<=jhaO1~xtUIY;{Z(!mjckf@H0@1TT?o}9FD3wV8}6kJE5 z&wWUc;k;XotkxH8`RdqbTK!`}VglxiZ-t`c;h;g$xMyGpat+2VPCVx>rdAqIZX2U> z+a1qPv{x@=Y^|PK{}G=*Jum!}FhgXh$Wtnq$gp}KB;Zp@LfY{I4fS^df&D#&t{5D= zCE3GiJml-cOLRUWD&fcaYWJ$ZU!4O)r_?9d!w`I#Q=JH8g+6ifeE3G?YyrMiKMN8t6Rz-Y5SK0(96% z&z^gJCKXINSdfTdjmlq!bHiIReyFZ0qd(8Vs{OvPz2=8{{1&`!*mlOfN(-6}Q3o$P zD_0pUB_ANRP2D(o4!vJf61)QJ#xBri170vblBE|t3SMbO8nArGZ<%<>*x9@eE^!)= z-&1$~XnoCGdr{Z}6vcRXwoD$?>O}!>Cp&KbOv#R}2xi{dC-M4ki6G%6=1b9|b1xao z3)B7Nf;+MQzjv(v?>DZ&^&&~s`SoA!Qx9f$BSQp#Z#NeGT^uMu?QX8L$TkerYzS2J z9Pxr|Zw(PrHA9w(RcMScDvYQM9}E?Rvw5weILIrvq(7d)&`l?@rv^o_VPo zov_<|c6Qel>-yP_;)M;EOTAyek*zp;1pW7WJFn(8xb!pn^Pj(88bW^ed{GU=iS}rK zi%X-^f>uMGYo?v~;B9TIU*e0*5yk4S`!TzZz0JdeCQum6l#4?*5*s9T_8a@m4?B z8?xc*V)*&buU~vcY{NI-bnb4g?ce?O*kNi3tnoR%a}P`tTGJ=xl63t(W0pyND9WD> z|JC(dMP=K+3nK#l^!BFT30ZH|45pQtt~3<=ofz=m4SZ18Rjo_fO+A9QcN0t7{vp+= z?xWYk{@$TsdVLltu=!_qWoPs4pWUgQjdiO5y0*qfKJV<2QjyXV6M9eo2)a*MlJ9S> zG-wtc{^i|w_EdB-?Ld)O_xDfV28-_eU2s^MdEfG9Hfpyjw2jeWa^8opyQ6EY>uhuC z%8mA^w0E5H1S-twa)YC$`P{mlF5v+1JecTmV*w+>~m|BsZ7f{4@{zg)iHK zWGS@hNap4}>C)<7emlpD67xT8evExU*?qraL8~55+$y?7pU}v1f!CMQsl}aigQzs$ z;LMGVPvX}nzAta<3{5Qw@XI=BT>7)Xd#Ck2b3N=5t1U|&XRJ6GIivuWv&V(_NztV{LIcc-3&rDucwTZ!m~-M@dT zzjfUyZksx9kdspFqOTaEBOKnaGgY~A;?So8@`oGI*4OS{CnLP)) zJ~sUMvQ72{pB9jW4qj?cY}oalm}*Z`PkNAZgII6}e0adp*osQpz4!0CL47Z7dT55M zuD>j}6Z5~NcgBi2=LtQZx(%vSHdYlWpMzKy3w&p4dd7oS*1T0uZ)SaQkKI1_@qwnl zqE%ba&eqy;27OhmA<(#%y*3*kR7*b6u)BN?vAb-x98|ciJG7pd#VM*DAfREgyZI$s ziqg6@f>~xsYMcH!$5~%JI-~e^{^>@k;{L#kqME_mKaMxts)vqfMArnW`2RJj|BDiC zak_FZX_D9G*vdy6(Vv08=ay~-zpyPAt`43I3Ivnf(v$uktm5#2oZeC6SXq)y^2BZT zhV6mQjYmPW`g>$dXxCTNpW)J(dZ*)>TxsFwi`nfdJ}ZwCM<-TXR>tc$i_ZG|)VSsS z7qPgL60-aEr@`)vU>7Gs2!~ty7)KX$seTr=7UxT?`!UCOl$c3_WjKY zWuyM~PHi5u3-(Cykhn8)BldXnP31wS?b9=oJt2R${ZQ*}n3Cwy3oCJIvuMV0OQToh z%S!UJnUbBrHOtxX)9w;e@@wUjag1=G#x#4G6j(MK|)Se^O>e$eqhS ze{BE06V6CFmr?&QB<7oh!a+L1_u_1KpeW-NPtCWsYdi~qC+l66&e~0k4D@wy{v6b;+Vfn_m?FEknj39JN4#AtAEfWo>Utsh z^E4gV>VTXYK{^I|jQtd%Jz(7c-8eDA;A*jO5S`8jC!7rE${2BAg;lTEeur*0Z-IxMGVt!i6ThTK0A{M}7& zsm*!tLCg_{;WmH6*`L;%qMjQEyf$D}fvf9@T7tEANk>9ArUWLg>r1Sa54inI&bpXj zFwhwxo8aaXA$R29e?BCHB6dbKL3eohC3bUZbD4pLK)xNoWqoTGWp{Qi0W@YAXMeY3Qlfmy2ewEHd&vkaJqdT5~?{I|);i|A>i3hz0-vrj(?(G62A-gRe~#cyLPrGD{Zt zhH59N`u6Z>&mrd@NRIe^ z=xQu_Bi(bbZfic}Za#iq4C2kZr0Nb$pwpdoYecwxw7joS!{PPb0cfh*$deZAqJ5t zvLDoodsU&+UDF?WsmE_rrSTy~L>tYXzzN$O>1>h;(NR)anYQ@ZKTp6q1irbS-OYP$eII3| zk4ii`R=qA5ze=re%G$B&FfLMd6yz>zYD`Fi2EBpPcW-q%Xe>ua4r!v;O#?lS47 zYJr>iS-q?f$`4698m`>PSgt;n(;aLj8ISd62Uo5MTY`h3Ld$G+=}_%Yn;G5dkM&g= z)7YwLNI{y9Q?AHox9+nipd#@^OcNMV|n%9MO$a6Kgu_UzQei}T7yy?Jqezkw+ zqxJhBIg(PvEK=LKP_35{9}bAz9Uhn){UVPaUt~Vc3IK(5;XF7`L=}&9S!wsXvn1>m zTGqy>#w9-4ALQ+^&VNo{WX;v9w1*^BGU@&4q2;GeyI&5n>M$pd>_Y+!P2oBZgzNor z6pJ0Qzr>csDAFC>&Iul_9$M_pC+?1aRHstHqo#GR>C1?J$FN`d!3EObkQ5Y<<*_Rs z2=F!Qi&*HG|6X#U=Oc`>-dd&kMJkr}O(y-JNUdbPAv;@F;QAxLys-fAHX4X3T>fT5Vy8oD9hTR8 z2GGTS)$=3?(QvE_cKw7LgqAIjCWK|bz1OY76?CT^d!06@j#o*|Db=_o9VRW8O@tx* zlnoC=s(VJgd4&k}0tDDmM?^oW!XwJL&+=y8%aKs-F4N*K8}*FZ@hBW>z1ca=T50|@7VcjYDU&CLY!TTkW$*rjw@jpp)n=XAf{ z2$v{Xj!VmEo1$s;Tau2KJw*_>4u*}|#L}`aiB!P{Gsoha!UI8~`6KV7>4L6Pq^aQi z;?vjydUIK32!noYQk1?C09wBo_y7FFS~?B1R@YShtj=bE0_=FKW6%{%kvPTZ0fLerg%Jy4B!-TNfcw=3F=N+!XG&ZHedEU2+<_t5s@?yedG(BVCQHz*Ac&;_lMa38NQ>!YgJI?Uf^ zJb8=gd}rgfVwM7%imw*`?vhiSjRSm-M?%{1o#$!FI=V}li7Hcf;m1u9B@ZB;dMTMZ zpS$EPsGHGAN`)^zk4F~Q%T5?1k>los=3{5?3Hu-^9aPVchZbgrktRVNCkY7WOzM6G zA938IwogEqDzzjt0i{g8I0unb4iGlKjq?=}%?kXO2yi%UhKYZ^=S`jNmDy(Z>@bC+ z_^KBV+LA&vx%f%nYVpZ}BMwuW-4Dq-wO|2N;)4FrlRp5abH#pfP< zy3%*g@q(QNWG19s@jn?`AFVH_<)~{_l+v3y0hvlYSo}jGj;`|pPrg$wLlv99TuHBJ zk;eT4OgDvY_Kw(y1RAi8o*sV(l4?-u&aka_l%r=nc;Br<@^mZ?wikVWd(=cCjLlYP z_pIhxB0uuh*WEtdQF6eVFW8fhV9S;_H6RRfAA6Zee%@ zKQ77}Z%P^ZzHnCQF^|7Sl!8WIs;aj)zp=XskkdWK6yrWlnJTIwI&J)v5xy&)2jPycOjFW)IswKQ@(@~u!1?&1WOZ;12JnfP354aE~X<}12Z|EaAv4H(< zS>u-FIU@PEB&pL&QmJz{4z&k{<$yA+kGKLDKFq)yiEFf8%Fuqh?{xha{gBa#fF^WR z!qW*FXRiXLQ2PS%D|j4Hx!_+(G>@5<>eh~3oln~m87MlwBB^gfpBm5;i>mDocwPY8 z7uWTu&*76#_G(eGX1^n});S@sCGA#Wx8QRuGrkM_L--O9^bXNA6$~6s+1h={k1pKP z_!&jGr}Xc|!ySX4XxqmClq7T*MDE_-6b>bc1LOa?fIYjHolXd{tua67>r`W0Kpg)) z&V@K#$#A?jaXV9ylowx_V1r~Kv-=X>?#Y&ZP_NOV+r$Dkn_$zE(kd%>7FkEIykQmc zRMYP33^s7RwD)A%ZSv(c8F=R`I(u;5-?EWEQ~}JU4ForN)E2}RnS1uAaotg^mj2Wy zCgrlLrlK0DG*^)%(BL|eCrN409G63!QlwnO>wL(7^OEHihFI6$pJA`igtN3a z3#oPKWsPv&o@Lq%`I(uSf|zgn`br?DhxRGl=w#~OrSmKv$R|qKAGG`=pv_N1LY+$l zIXSvI$yUP^n+Y-TDRKJ8{4zhU8W2Qde(IMWCM7XL>Xj}=e^mjx%WHf*_1ruWuQ~WR zsOoy>)K%g-Zxbx;QwnyDkYv*Y*Ve-fJD0knAK0yb-*qn4=TMz=ccG66EFP}@fsu~4 zxJsX{CBJ48&p3KHKG4-m?k1e^eZ4!8x$AsqW+BN^2>iV2alAtN>j`3`U9EW>w4hV< zPX)GD#QPHsL&4556ZqAxLx+A?f`dAqzWPT34UZa1N`e-hioo%u-3A{I3GYvApjpT% zvwKcg$NdeqpzY>4EfPgcS!{CCGayX7@jNctyJ_J@KC0q>wv zc$9;b#ac8jnWDeNK=zhigN&}P=a2PN*~32eqOFqvW40VubG+GYm7i;YY!i;Re39y= zk*TQ>Kj|y}Uz1iW1UbIpay@@~ug(%S$1@7=7sz!k^`OS|_06Mkfsiz8Sy3ku{baZr6`Ha=gKNly<%uilLqFH|R z1~$+UxgQxqpRGc}@$E<)a? zh%sB>jWd+MoN5vpO635%)r+Yjl`We%EAnZoeXLF zTFv}w9wfAgwE3LnsKqc@MKCkMlBkfzulMxjOel42dHMMM!(fnpSt^fp>CuH%F5g*{q}JWqQXf5uq0p<6C2#*0*;w(WEjy_t)1&Y|7>bOQp+p z+?}NO__FcRYHYvvSl_?G2bK%Dv@9Qk@e7pqwmn5e{L>bESJPfZUp>Sa-nGmT!8j>0 z4ZC4Vdv_P4idCQfbfGu69J*cZ7eSySX6$OLNrz@CRa5Qv{NTfIGEz=1q>wpb5rVO= zAZr1G1Sw~YnDwmBuI=o3>Gw}{zW_Q{rLht{cXn+7MKWBf&hCY}L^E@9V{>!Z`PoK^ zx)({EPtJ))==L+9%4CR`i1kb1mV{_yS^6=R%$C>toOC4H2m3P{1KhFESab8b>oozuBYv4Tc=+_0!L{sCtPi+MuN4)*>lcu`S_CCSj*nu^2at))Ws3G@IF zWS~M^R2CoqYjVxw7)>-bA%8Ap^+&~;0n^hhKfUYmx2&qgjAsBPu9Q%KKkn$hchZ zYM4`UA(0YsvG;B#?LS){8)3W@%D(FA>Ly+~rJ`AxBWCLA46E#;i)|!;(-4-C8Y?(~ zr5W_@8T^2keZqbka5w3{D_Z>>sWEfT4AY$2-MZpU07ix_9OWQd#UmqRXQ$c^y!J+#@U;pbRPHX?i^tG z@Q{U>eLs!7jl^qlCE!j#powD2R_DEMI(;;o;=&JPJ5%pw3&z2>d0A}O4uaZ-6f zK|y@3Rw=yByzKm&4r!^k7o?dbTPeEwQ&lYT{CXM94>dN6npANw2?&mgNImx#HYw(s7SBrtb`ga$r)l0|`u)_cNX-WtoSKHLQ$U&5-Z;Q`j9d6;&s^<2y8 z88+YtAG1A1wZetFYRS;G#hCb0-Pf>H2C3Ef1jAH`BW8u&0Qzhlm zWqwQ!^?M5+lX|1i0!TZ|x3|~nM`e)r#^jfBk ztB>fWNWk^-PjP(zXohjJTb=EC-*}roTC>t(;}QzLl!AZ6uLUMV|Kg z?{;uE>SE(B9X&lk<5O`0nh<|)Pv?VKMvI5w1e+0}60oQH$?gv{@S^XIoVBfuC)fmO znXPL9k8{P3-W`{|M$*^f%aNxhOKq$bT%N|eHpraUq5#Z?dsQs%2fK+|iVp!>n0T?m zeLK#v#A{ss;}1UO`9DkZh`vCkg$9B5sHe!jK~Ob*-eVMvXMmuaM*#R(D> zDHuy>c%83>CTjhmUk62%Nc(a;Y;B2jY?8@ch`F+yP(8=^633wtg+1mpD26Z4q;qRWzT){LeA9dy#FNE{ZH6Tce4=+hlH&{a-AG-Mt&9X?%~i zlXqk3rl`e{i_r2(|E4R_dqJZ=ng*}x>~lU&dLiW6EJF;IRTf%d_2fgt=}5fOskcN4rGuE;`97B?jW#arN4@wdG4I!hC$o50j5 zAsY3ZyG(O&aY3R`l9oQrTyBGL0!zhFix|+oIsc2-P1-`fImnlbuFF5cAmq}Cn9brk zFf2}r68E`{1@Y*dBm$1b-Y(yF$^4&xdP>a8yQ$bG;=^`e4|t*{=eBy*Hjf6M0-KX!ru(NI5-pH~I{ z|F@Wgx5XSK4HWY&ea;qA(uJeLHqe(#?l+wPCJe)QsZDM#lN}qV7h8nfJ}tG6O4GqE znkk?~>N4qMwom>KmXoFC18LUZ@*i4XL4YL{gj+m;8JSgxnLyIh7~ z&zF*#IOjZ~zFheKuCyfc~H$jGR(yBj@-f;DMD29?^(PvPTgdhNVBu@N)rXC4F|jG0wGKKhW8ld}^>a@#dsEqdD9+Z!7jzlmDA zwqKL!lQt~xPWYbS@P?RL{zuP>!ycU=73ZagmOD@Ph<*F@31i;(-L!Vp=KPLX1f=jCo(B6EGrxA!*fh!h<{S1-!-8kpjx5#Zq^ zqDkcPlrN&UU@mV!h}H$OoKjX%d5M+>g~~}v_KX;ICpS(pW+SDeY)kC0v+5N#@35IT zaHp2L9u_8$@VepyxkA1tQwyC!whtA?YaSE=3{FhpT^^Sde7u{dMRDEEHw277^wrgG z-}5l?Jea2o< ze^P8JukT}{+}>pU$xR}Ye)c!1-{C^O$<20c_kV4y=hmW%G9$at_kRcm~p~v zC_DFVjXNsIULRiHIBub#p(T1Xn$2xGpKT4gIIaW@rl3P}rpk*j`SB>@dQ)nw=9=~_ z7jRntCE)!aURG6Iz3NaWBcu-o=1LR~V0_CY;MJ>4;S2sj!T4H!9ZnKttDG)M3>?X$WpI&RQnxqb^WHVNc?;cb`Y z!7p(NIXRgW_RpnFQ0qKZ5ktrb!w<+nzfG-MxxNbeeDAOY?3MujVx;`Zk6bKR;zOC% zwGwv>1#TG7Ix!IW!wHOo8Qv8p9q#T*-^XOofQO4cyPSfFWT~356SCG}BDO)SLm@f7 z%)(`=JC9|Bh2RlSb7u!7FH0v1C)oS?5lF(jVtdsf(1dq39VX$%(gw;oBj2PhnC0J| z){-P7Bmj!E_$sfT^j4)P4XDSIUHi;UO||nB&0(Lc4OM9I#|ocFnlPOkD=XoF)HH6^ zI^~=RcracK2dvY>L|eZt`7h+LX7P5w$$etnwL4SQJ_CxZM9B%ge(9Cu}1h zWs58X^z`N@Z2FxN{t;I?AGSe zf0J9xaauPCHBcx3|VVOs?yNBhM|> z;}a6#h5aS*NC_;>w5Zh~v?VTy4TIfqzbiD=iSO^3e(Ny3V`5BHMHT-L7OmX3*Hlad znIDZs1-iPZ%EvY#90mi8Y+lo_rSbww8cTM@78{F+2U2>>I zXx11^gc*Kxjzh+JI0lm{eNqL&NM8F>PknK5+?_kDH+ruwv!WA;PQ;fNn;MwMut~mN z8>lHxwHDLWRaKp(x@QG^LFQ6BB9yCzoKKj-aIUgZqoS}rfBt;yNF)CP=kD&P!R1Ja zF5Zfh@7=qeTJMJ2+G3F|Yin!I^X-$1!zKtL1`%(rr=sEmfsy#yWJI}bi1}DPn962E zM^VT0kQ|brcWm-G*2S|T#bgE8-YqQczm%bbd-TZ>3*KAe01${Zia1_SM>IUn9eG~) zl&I2KTUjl7yRr_2O}%O26c`md zjPkyfSzSpOglW=nesn>V=0}kns|cWY#|V<|B#cb8BA6Ol9wcXiLz7MeGF(JSMmu4l z70;^i&2_o;kyzgbxBq+aq&Dnj_J~EE8X8Pu&Z~*DY)~M|tr!BKW&17yRYz!@pihJ> zyO14T!Yqa@lq}g{n^Ou?79w;SU*ib&eFSuaI)?$PG0X!(xU`OVf)dL)SeMCE8p#r72jTu-Uo zE1|a0FQ9su=b*MwwK}B>lHkf=A zd$^y8(Zvs@3(QSUPWJZFf-{Tc_x_Exwl;o}=q`hq*;y$AMB_ z4IjmOQK&R}qxgL{sqgn*y+MVerAjqh7rPWF}+za$~+xemEY)jQrmvuMQV3GLE$& zkjLw_=!w(w{h71HCeM6p0?|$Q^1|o;tt0*2PxCz~6v2mSgJ=Xt^x|_i&U^Dec4G`E zkX4U{Q$ z8=UvXYDrmSz(Be2{hzsou7IICGm%1BI;v4B+>=oS!OIJmEk2%0wB5^hw5R~uf9A@x z6Pem*eQkru+~$$Hdh_7flozLM!T5TN|B|v(|n?s@IJ778mWplo9g2 zrL^??vjfE8c8uSjjE?n-q&^NWGb0Dpb+e*|#zB$9U70l?x4K%lP@WU_mKe#yk*-)X0*078RDd0v)3xcqOdYP~) zJ2N{d9$(+9m=0~Ap&tpjscLBzm7oD-4<1y9o6u4n@_6aArC)xHgOccY%T;hjV&*`u(d2t*R|S$wq7diDD!&&`tLd#JYQ9<123^+}+&~ zfRK(GtC_FY*P08Z6P7vCR+i}0Rl=0@7u^HQ6ckAb32(4WPr5U3USl{TXMvfh4}+Hg zQ`Y1;c^g8Q&@9ZdWiQ1Rj!cNzcE&X0PufEpbk6nc3=sl#>1llwCxNP$DAIws(|aLo zpwZjwyaXH!|E96B^$iUK_;}l!4%}~6vC+}gy*9-m(xd@6Xn)%~Taw zz$9`;RC|pqV97taTvzsLJG;6zjBiVlF`Wx0kzPX#Q6|Q6SvpeIKi>fm^9B1DoDIcU_6uGwoUf*H+kg}RE1hoB%!4a}KmxQWoL-GDWS{q$JNGY5y ze9XEa>{`qiz+Rr{gnZKr3Drs{Voi54^m&8k;hh z2@OfP!jg|Rm+k!7fGcj1)6n1dZ&o>?oIX(YkN6e*;X)Ieo1zd12M38C=;-ONAFf}p zST41RsVAt5=pyL4r+$0hp&T0*cHVS{b$wmEH^tWz-<>45u`oJ{3vh$qH(vT+Z*Au6 zU=YlT9w{hBuN|(4xphDYw6?)%bKV0AY0#v$g#|-BvuQrDF9O$%9mrQ;V*a6Q>DQ-6 zehm`S$v@_C)Gd~|CNYZJ2Rpnb6K z`?ES$+8cT>p~^V)V*Nnqr|&>ANBIoNnAz-sapBRwA*4pR(ih(OmP{w=hQKgsM#wAk zk0ld??!*qFUh|U!M5IC<;#uGB&JRdoJ_szriX3SmP6+)P!JavYaWN9Ahr?%ATf6iq za7Z0fRphesYy@`y!Ka96q<;nrqc-*W*O=M4@0sU+#!QwVW}-M}&z=g5h={npcFR%} zr;g+2=MTXoUcI&$<}HLC4GuQKo?B|lder5@m5|xvZm)FE>Rgj&Fg9jXlYRKBdzFt_io-ijV)5*C!I$trB`cdk8n>YHZN#RP#=`j( zqQPj-F;3tB(WEl%laIXW?(9b?_9ThG^x(_eowx$i!SvT$F0#XOx-f`!dt?e224SJ6 z*cw`z=6;9dm=8ae8{U2@9ug<_L;20oy@ddPSwhmUuh+Gk^Aq}|_g*(>1`K3$@%5mj zR#Zfr!d3RyQ@pBqyYMLXbhVKH>Yg$hzC@gEnLmGi|NJ?I28RLT?)Y$_1=LJThLRc# zW=uitAUZbo8TLLs1B0BD)NB5qN6{Y@taM00t!DuY#+sIhQMRwu#XPh4uBT?u0ZkaM z!9zW4?YF`w2xPZ_03V-8w~||sDN4RT&cn6u_keboCiR~oeNc)>{ZU?y77ecwij`HneZMS`dFRGclEwmPT~gzY((WlF~BYznG34RgTK(=tO-HMou1ypMgu{*;Lw?y0*>z z`QD94JEcR&3mYhzDx0!cNplT;hIC<;ulM9}FeQS3e7W{56KtRVC0S|#s zox`Tn!CS9xorp(9PI5Myr6HkDQrFqRHF8{+h2$r7oZ<5E^)al1=fJaP~C+ zB{4B$T)#S_ehrgBo+?FDboc}`%2Z*rqg|A%OnYy4)!}r#_xt+z&DoYUq;@iLsKx09 zH%OLM@BU`&JP3W$7Th?|bu+pllOVg<$m0ln8oPzfah8+vngIbOcK0PyO5l&G>Ufhj zL7j4*ViBA$`ZDQq#^rhu(!+)+1LH$4jZAxs<_!-^a8ua;Cj)xyihP=oYguNdU2k`I zjkO+^@1YeJf!=mw9rbpMJ(L#_kAR?~B*x2``;Cp1RG5v!#q2xIx!Eth<9T?Y;LnD3d7@d9E3hPVpceUjQ1a6e@X%J6UDz1ILS_Nl^3gP6cke+MzOD(&&yyI z^0|K(*DvnP)u2Mm6fpF_4{zf3>K!t*z_ycnM`5wH$*5gxHB)cg zKRG?E`Jkm-#LmHCt9z^w|^Sn*7`c@YxV^xqoCYk9c3zw;*^{gE$ zfmEI{;l{=z>pzEY-~TCmi=0FhU@cQyYI3r(1N_?CMX|Bzbqzj$_HSxxvWY!vFIShQ z#D((<5AW~CC@X`h54tO)`L=!|7t5iTVz_^&(^6Ds zW7C=2(BS!5L}b8eN<+72=!F?2kWCY6v81h*k zo7!U~J7x3p4kLyJ2WzCWMlITAf9Hd{l%51Uh;~(tjgbIuK6@jFJc$w{AX0(=4iftx zQ5}cttG9{6OkO^Bm(3$vLyR{@MNBNW_jUel0g(*h+?GB4{gzW@0>Cz@v%U&UZ~Ln2 zIub~`NU1r;+MTR2Wi}Y??L`F~934VU-|+D8biQXo@$-@hfL)`Xq2RS3l0b^dUf|*$uNnp+$V0{x0iGE?uPNQ>N+}& zrc+aL!%hN`+d)x@iC6bX=(ScJJkQAgxsDyPSpEd)-g1@Kw{AFmj3OkiFi|r%rv<=g z3`Fh032K)8B@3wKXZC*f3<+w;LM`DeiRfQt`l;05m6TRjY?#~`gsl>){5JoB&-LFkTX?7GOB3>1HU9hk3+P0L$OM^b)?tzpvKIchn zwP0S5aO@nB+A;A;FyJEyOG!z6aR0F8FAdsZg{xiL3PHhx2xiMA{|@vHK~SB$I6qImY1{X7ed1(wsz>$6vYq*=MiWIm zAxFY}-ccaa?(NP04@uqo`SYSBBvNLs)v(qkPgnhXQhvOXu42#*pr+G2-B@^vGv&8C=ktVc!*E|mP=049>o1>nbY~|!gQC5aDbhrP!8Pu`KlNB-AUY_&0 z;_~dmmGWy@+Wxk3>xzltES)zg`{VuLt!>NE!W~q(sJf!U{c53?pGHs2b9`O$qe3bn z3o9ZJu}@jU5H9;UDP~%0%WP}HV(dZpY0WezjnC6$qR)6|h&81K@&Y8C9EBTrtVz~V zQ$nOuW*qU#NHKa$Wux%lBwKUG%v4zcsgjAlcnfgw&JfXvwz0njVcnq7Fvtc0Rod?t zExwbX2Os_kER^^kV4)Oj(4rb*9xnri8L~mvULQG?aJlV2R zUjmfKX+1ia#QpA1eakt#|AG+ZUrXESL?=s^_)rX+ZES30IhqpS;lJNL|2ATnGihtK zgP+AUbF+Omlp#PQ;8C5w7##wM=3+zq_ux7y9CeLG6EbXuSE*W7%;!pfW)chp%F03} z3`|eUi`0DiaLC8!-y@P4P5#dd*{efgkm6)BmsqB@ju8jGP<6LVx1qAK5(JaNWZMf3SA|MB=cM>}FJFQju|kvIxbOSz`bSWj zMsMT@70p6?_H370iZV7jIyxrihA^3wT-BG+h56I&c##!nN|(Vxog)qTiqI1A`N_$O z9k=7=pQ6ITLIs~d#T=L>3b*^I5%~OiczD>`pMc;}n$pAFJug2W4e<*|{=gL`&7ZAq zK7qrQ7ArLH&CSgzpgCzf-mzmSmbdgnbRonN2$g+#YGVE1Aopi3!F z*^-#3cGA;F;`D7GVKI_RZf9rb-c&g~9vUDiC#PFwGH|{#7N!MiXP_|$_?DJN{Q5PI z&%N8)&2!Q6zaZYrT8g2wxPp;hG(!Z|DPAh z;Ix{Pi+r~AXB&U{#qz-@bD_%m?nWL}SH9MHi?!R2?F}oM#D2L(oj?eiN}%7I?<0%z z>b9Ua^8BweGOD*nPUprlG9|eo*s?#(0>9bkqrkLhtJ6(o+X5b_OVO1Hu`bR7b z5_q8N0~lcrdX+S3*8&+m6aDehNR7NY`ZpWxd1 zErL1bZo$h3er3eQ-0Qq|yyOQoFMG33D=Slch3@wMDf{eThXC8u|xdx!skD`ljsgLr_qC9aeevvw$`L`1tYTLM|jvxkR-y zH*3`ycXP`UHf#Sj1SbvxRWDNfOQU_A5lhB4x=-p#GBh(aBt(6yGobY*>ILZBbqMR_ z7m0dXkPwHob{_shDL~#7@KdFr9z}Py_ZPn%8m-d-t{GS4l|9szJtlK#X3UdB=bvKg zSh{F@7V@n!hebf8EQ&1(;*|dJ!h{ z-j}Z#^q7O;$_r`)zk*uqx!KzSQmmqh-FyBvuBSQq_3ElBWWW7VS%cA-4q{%f^#si4 z#>RQVI`Q+Nw#is;$6bCd7Y2BZ`VEp({-MtapoMqY!$m*%2cQWbMx}p&0C&ZApF~${toYJ zmh3-f^^+_3=kCeP{=otsKe$~wm#byT?W;0x?j5fNL7sFB6)D85BT4*pFIJ*n0=EpB z1KoDQ|7EbTybSp=K=ada3akxaTtEw)<@~Ft;UD!3|6bX^v2h^$#sMLVv!GWL*lAg6 z{fGiXmBWWW?sr6ieQ;y`fAAnpo|2R8tcW$o8Cnt@uz~h3K28-qwFwY`6}p3%AE)8P zQt!w>(%w!V(QxfnJz z>AMBEEXnC|jjKO@2&lDri{nMJ%yy_V@lAHo;r^><|9B~1zL0 z|HFry!slWjs_uwCT6f!S6$Gvyhy6)xUF|pQ`L7$3#tOiIw_ch_FZA%lg}}7zA@i|G zC6@Gs%y-F78KIl$skyYH^=bOTxtv@|04JQDfEnY=#r0(QOb~)Y7bk6LeXuh|!{@xe z+_&acO{VHPU!qlG!e_{&x4lU9t*6C(&4Z6KF4Xnu-f?K53(W0an~OnrBzPsww(EJF zSKYw+TART)@zU`$I1xkwqg}mO3PXpW1>3UQgwWzMRHmqAB6;2Mi)?<^A(Cto=UZ|n zbs;J~KFf>Zjip1rANq=?S3=ldkg;oOYU;c$TtORe-^>A+O8b z;lmv^DUE>FFMBb(7|klH0T--S-0#@VKG?`(0i9iXS10BKqy*@|NyXIN<(@*Ga%6Rz zBKu`$XX_g<*~~r0qi0|Pi;IF@8dIyQt3N<(2=usALA4kzSC6TLGI-SX zD%GJ;;F!D0%ftBKb+e;F1DBa@42tu-t~Zr0_Q9TdNE7GRfts36tmxv|+P?Gm|G^^ZuzcxpS)Hzp3C1&L&HrYSG%J++%Wt2S z=JWM`@3()=!h{Cc=|xIgd~Q<(bM|=Y9~sENqM+a{$NCm(HRRx%|3jG6Ut-7Pq@G7N z0K6jm>;D1>=Km~7Avy{9JB9a;spOdBu^V2#{-x>Zd6$_ku;gyqIXh7TRwpd999cc> zTE4w_Ro-HP9QFcDETWXY89n1#>|e2glZM8cWzj4}gcXNa2HH3!b>wS3YMU=9m2#JT z-=qwKr)1ejJO87r{&xg17$vwKUbko+DR`z+6<)GZ{GTKZOEX%2Qv$#(CML_*X_fZ` zSRQN=Pp_&vk>A){zjirB@Jmg7V{pZ$TC*t=_Y4UeD~+#za8Quj4P~k~Y-|7YfXj1# z|A6oMhN!6E(YmC_e(!7l2E4GIo?e5?0UVhE+55%VWC3X1MCdt02)9t`{_jw0;`E=LdY z6fu9faljH8z^{K}5>f-awgib_!@V=ZHrj&*V5P+y~D$Aq_eHM zQ|>Ag`4sk>1>VF4*Cja843`HFWN<53Z~=P>?l;25rG-;zxzD?XB)}C@3r0sP4c|F-nP?xgm!DYY%{;D z4aot3I+_^NyUkukG-75Sv`5Ok-}r6q32u*QWFGfwlr3y56jI<~Wap;#0=Xuq-Dtz*@1*KH6lGuM{IO#0i8p^;X z;*1zDY54WaYPPyplFFcBy1P3>oI*|Q!Bc1xOx;eeu1u?DY;0^sMn=R}|3hjyp%rb8 zvjR??+hFyU(+1}Doa4eQ2NDue=e&FxAG-JljAtE^T3~&il_b=1QIfZR?MT~Ld@ML8-iOw#BWzM$x3}aZfO0Hp zxjw-SC|7WDa$-WiO6MKU!stQE8v{N%;up|B5lzS;T>{#5XITt?g9Rj@FYp~m>X?`g zdt%-O(`i*2g_W0=`}9>9cGpb7(?-Pb#f|t*71#TMT6P*{sR1k2WSHC;E9f#f z0i7;JtXeSWy~%rB6r9a1g;zwP7zVyqN4`0gpk6=Q<4nqk!iWb6m=R*3QV_?vUsVy3-iV-4*e~B zmUF51%9ArQJnZb_Lqp{dwY^E`-gwcAFmVSvyX*5Y1>40&tt00plOIfof&W>mxb`(+ z)EUnT&|lJ9C{pbscpg(;^}R@?pmN3vKiqk1FfA|;(d{Bt>#AC-WP+NCYJ%Y%9$H67 zNAw#W(VP*du$h?|X1zwY`)km96%CGUpkYZyTKZh(=K9)>JC*1EE9N@Gn#kJrAh3e0 zU;ybY>Vm#VT@j^A5d^8CEFc7=Da9xqL5e^Y42p;`0s^w4^k(QFp$G_sUIJ#3UL;^B z2_PZlJ?yUEwfkNB{r=|9$;@1HWoFKKo^zk)zVGpyx3;zx%FAgr{r`eXxF*y{Sh~G_ z&b&<4o|_l&x>Tfkh#?`q*nMZuMcpv{Sv38?Ppp*rW<f%>gM(-^TAM+=0`=t^$b+__Jf|Ii$u ztR6n}Jxj8Sn031k+>Xak;j?$nWy;yZB$-ID_^!4`j3V#G*!ZhtHW3`26pEr<30Lj`I&O=^aKKh5l zOA~l}db&de>>YSOdq>9xAf-#Cu{Q3|$lwXZ#l`X4(`XZ{JPZdCPu#{u9-hPi@`ywA zohBnqIY2-)_Vk!(x5l^A_db?!^)Il7k>3C8+9#=s9I{gcoRD)9YyIypfzIjed(|3a z>Ems`u|hY>1EA7Ur~G{k_7kC(6+%i%GDOzDD^4WBG7e^{25la^5wHKcUkF*6rGj)t z4;eF)`}*Fgf#fO~w%P=!Hc&QRO2+#rS#sR*^#z}Z_?n)UR*?1+7C1w?ZMXZUKhi`E z6NT%5e?U!JQf=DCv&X7n82smDX;vLTO47(g6B83j&3mB!rsC8X>6xN{XxLqy(v!!M zfr`U_(E_>?5TJRFnwyg&lh!@biuR1sle}x^oSShkFz4G#t&p(3N%$}?@c#+=eIqW| z))f`Om6>$KS3IoU~G0gzzZr!twz~L0Or~_m|9B$wZ34%Yoa_ zZ*I1_Q77blvzr)!UR>1Td~}iv0`kHXRpjSZv|#+it znoaa5=%-u`we-q$vnd}7|b!3aR&uO zz+yphXfz2(@KRO0@-d9HcFDnk0SS%ZRp4NrX-{NrOji$*HhXFG#>%5Nntf)nn?}4bt}|r!bPT6sLirQbp^Ac z;N|h6#>>mg9_Ri@|CqCoG|)|)IpYsvZ#fgxocRyM0vX)WZ~>3F8WqGVZbeYR(N*Xo z_yolX-fuq2DG5iWr>5ZihdALS?>Fs2L+ij+RaJFa+QiJvosx#dE-WmxD_*v+u+Y(o zw8}dXBlM-6fI2ywaa&o^e9M4q-sHqn+=6^5@=L`h5^z_JFBd!kR?#s3*_Lt!g-^G> zo*xL`Qx(HsHn*twP$ZDZOjCQlX@MSWopEORhU-wm;%y@Rv2rVM>+_`L@wwuG9CriN zGedm3&qA*l==OhvwagX|toAW?{l6(=Bbxe-BXb?--XdeXKaOLMOixZK-lN{s`_GAo*L+Lz3zrR$sHGNAO%EK(wLF$|bFwiC27}=z zLb5`OHK!d>3Uz9UD+?Y18p>sNA7oje-PJ^l$@i#dHblt$ggs;vR>Y4q=EsO2i2vp*5 zq~uzK;|vRLLPS@I18Hr?Y_K?Ju`dfKp#fV7?Cx)@PGO9FFmO3=mjH*PrlkSb)M)E2 zgE5x>0kt#xP98$vfMH^f9-_q91d6HeSgwCQlV#!h=_xmG`xqw%6DY>f_I{nbVT0lAma3*}ZyAtbU%PQ1=xX7MfUR<1< zDd+v%{rvp&^rF+!NQJgIDjkj@kG`XEaKgL0yMJuqU^}39-`7?!(qIbzZgpJI%J!Fn z>gw%IjO^Ol+UDja=&SzUfOqueVtGPVDo#sF>&KSTgUpyG&CSiuEhynHf84+!CMMR@ z1g}*HLe}Vnv9Yly(DQnF8eh7!wm}Xnbk2Uf0>Bp#OMf03vUYULc=19=RMacmTpslP zNevr;v*#H*rK|_J2?T;h;PU9J3(IRDh?OQj{5+k6& z=KnJ)tOZ75JDcxp6`nr8@gJ@U6o?7l{g}YSa>CCU9Qe1GU>dSWL_4T4s^f$^q|8)e z0dFOBgrl6@Kv`LNG*E9YlI0cOo;ECZ`}MW0`5<<7Sh93|`7N$33D8k1E0pTmvP!X4 zFnPB>7AMcmwL0#KLTaE-N{a^uo{seo-k9%Bw68BG$|_rP3qjO11n8)S2CaK`v-pb# z@%282iT5^XG>q{ZB_*Xtj~;!vbKVK+^8jOu6TUPuBI9xK()H`lPTgYc+!eqhR+fwgA5F!p|)>i65- z9?u@9teDVOjowyOnVZ*X-rw;zH9ZW^E-ds08hJof{)FmcVU5(MDyjH&0y&V29jYQaKt!>Y!_#XJC;Vfh>jm^M9r2f4}taNnC`;7sJ&PF_<$0L5_DG zLcr2N{PSld>h1FeiG$GUfq$gn{nWibwr8mEk;$+15Q#0klhHh{ju5XzpAj+5d>oB9 zw-%*)qb-91r^2Ij8rOa*I*8?wE4oGt)DSo8eB#3ML75(nte?5&wP<7vVp{?R+3e7NCi&uCN4Hzv zZI57k*+chtCJdTut5d8jJ8CFsR3b;JQpoi10B=J(yAJ!_aVOxjG?}q6OPBB=;_+aS z_H_GbVq(M%BAKKvx9Qh!&I~`{gfLcCh-O<%$ET**C?M3Po8WsqC$F_B+`d&alkKn> z44>(1noQc`8J9%}<41QX+`*3{m-0I&!r$|1x#iz>`S9#Z=0fI(&$nrUho8GSsX8E( z@Zj7A_mRos!h7Kz0hlE;QsKVCotoPG^r1Vn4#ej zj`#eZ+G;8jc;U-#>y z9(j;dL`*~NNk#TmYU9Lly`H^k_*Q;Vo)Ym1vu(pNvLKCqWP+~Mp;b%@R;CB9z9{>Y z_QeoqKKD|Q$->*{@U+u4=81W4*p=;#;pWVey;T$2ySD=H;psuOoe$SZ`0L5lM%@}l zdpWGc_vN$|hmwewAyjumL$JPB|Ej7@rw%>5N-pOLzITe-V{R5awcCsxsll6NR7fyy zIX>RGq`uzrji*%1(C)VdY~})4VRJ;Z1b~3o#g+5vRY3-3Y0mQ()+JeHWMZUqB+iv0 z6PXs2c9eGT9?8#8tA{2rT~L=$P+)&?zGGvd!I9pq%$PX|p(|u9zf4LU64qSL3Z28f zjTIDRX5%lfzG#<8xbIDP-9nMvndI_PeGwA#U~BMa-IiufIB@Z!1blt{`)-~&8+Jcd z_=+y4yx2uyC6`{hba#&kKlYl}0_^gG@$5&)Ua&Yh5i>jgayCS*uf4nDBf=zKgm9KO z^0U&r!}hH|5d7GFX?0<9im5=hXc$6JH;O%BQuD%gCN~=-@g11$N4;9DoAo_K@wlg= zPA-eTXSXIW`j@XHCUUwXeIG&3em@|pw;ayjrs2CSE zi)|`YiDFif!4h0&wT+b0}&)Yndx=#0OaHAXEuEjAj$`JSN(4HTx$50 g1=8R+%*E8^sB*O_hvLn_hlQa_24?!jx=s)N3)J2dw*UYD literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/min_distance_preview.png b/doc/salome/gui/SMESH/images/min_distance_preview.png new file mode 100644 index 0000000000000000000000000000000000000000..c5373d99fec12206f646ea7650c049992ddba6c6 GIT binary patch literal 116380 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 z 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 $hQr;pNQ*qqNeE3l3i4XX! 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 dzaRc9a -
  • \ref free_nodes_page "Free nodes"
  • +
  • \subpage free_nodes_page "Free nodes"
  • -1D mesh quality controls: +Edge quality controls:
      +
    • \subpage free_edges_page "Free edges"
    • \subpage free_borders_page "Free borders"
    • -
    • \subpage borders_at_multi_connection_page "Borders at multi-connection"
    • \subpage length_page "Length"
    • +
    • \subpage borders_at_multi_connection_page "Borders at multi-connection"
    -2D mesh quality controls: +Face quality controls:
      -
    • \subpage free_nodes_page "Free nodes"
    • -
    • \subpage free_edges_page "Free edges"
    • +
    • \subpage free_faces_page "Free faces"
    • \subpage length_2d_page "Length 2D"
    • \subpage borders_at_multi_connection_2d_page "Borders at multi-connection 2D"
    • \subpage area_page "Area"
    • @@ -39,13 +40,14 @@ There are 0D, 1D, 2D and 3D quality controls.
    • \subpage minimum_angle_page "Minimum angle"
    • \subpage warping_page "Warping"
    • \subpage skew_page "Skew"
    • +
    • \subpage max_element_length_2d_page "Max element length 2D"
    -3D mesh quality controls: +Volume quality controls:
    • \subpage aspect_ratio_3d_page "Aspect ratio 3D"
    • \subpage volume_page "Volume"
    • -
    • \subpage free_faces_page "Free faces"
    • +
    • \subpage max_element_length_3d_page "Max element length 3D"
    */ diff --git a/doc/salome/gui/SMESH/input/area.doc b/doc/salome/gui/SMESH/input/area.doc index bef0c0f8a..f650a3fd6 100644 --- a/doc/salome/gui/SMESH/input/area.doc +++ b/doc/salome/gui/SMESH/input/area.doc @@ -11,7 +11,8 @@ quadrangles).
    1. Display your mesh in the viewer.
    2. -
    3. Choose Controls > Area or click "Area" button. +
    4. Choose Controls > Face Controls > Area or click +"Area" button. \image html image35.png
      "Area" button
      diff --git a/doc/salome/gui/SMESH/input/aspect_ratio.doc b/doc/salome/gui/SMESH/input/aspect_ratio.doc index 070d377cc..c6c3dbdee 100644 --- a/doc/salome/gui/SMESH/input/aspect_ratio.doc +++ b/doc/salome/gui/SMESH/input/aspect_ratio.doc @@ -13,10 +13,10 @@ nodes is calculated by the formula: \image html formula4.png -- The Aspect Ratio of a \b quadrangle 2D element consisting of - 4 nodes is the worst (i.e. the greatest) value from all triangles - which can be built taking three nodes of the quadrangle. There are - four triangles to consider: +- The Aspect Ratio of a \b quadrangle 2D element consisting of 4 +nodes is calculated by the formula: + +\image html formula5.png \image html image138.gif @@ -24,8 +24,8 @@ nodes is calculated by the formula:
      1. Display your mesh in the viewer.
      2. -
      3. Choose Controls > Aspect Ratio or click "Aspect -Ratio" button in the toolbar. +
      4. Choose Controls > Face Controls > Aspect Ratio or click +"Aspect Ratio" button in the toolbar. \image html image37.png
        "Aspect Ratio" button
        diff --git a/doc/salome/gui/SMESH/input/aspect_ratio_3d.doc b/doc/salome/gui/SMESH/input/aspect_ratio_3d.doc index 751e41102..6e8b70808 100644 --- a/doc/salome/gui/SMESH/input/aspect_ratio_3d.doc +++ b/doc/salome/gui/SMESH/input/aspect_ratio_3d.doc @@ -21,8 +21,8 @@ by the formula:
        1. Display your mesh in the viewer.
        2. -
        3. Choose Controls > Aspect Ratio 3D or click "Aspect Ratio 3D" -button of the toolbar. +
        4. Choose Controls > Volume Controls > Aspect Ratio 3D or click +"Aspect Ratio 3D" button of the toolbar. \image html image144.png
          "Aspect Ratio 3D" button
          diff --git a/doc/salome/gui/SMESH/input/basic_meshing_algos.doc b/doc/salome/gui/SMESH/input/basic_meshing_algos.doc index e957a9713..274ab7438 100644 --- a/doc/salome/gui/SMESH/input/basic_meshing_algos.doc +++ b/doc/salome/gui/SMESH/input/basic_meshing_algos.doc @@ -62,6 +62,7 @@ license to be used within the Mesh module. There is also a number of more specific algorithms:
          • \subpage projection_algos_page "for meshing by projection of another mesh"
          • +
          • \subpage import_algos_page "for meshing by importing elements from another mesh"
          • \subpage radial_prism_algo_page "for meshing geometrical objects with cavities"
          • \subpage segments_around_vertex_algo_page "for defining the local size of elements around a certain node"
          • \subpage prism_3d_algo_page "for meshing prismatic shapes"
          • diff --git a/doc/salome/gui/SMESH/input/clipping.doc b/doc/salome/gui/SMESH/input/clipping.doc index f3b19f374..df3e39495 100644 --- a/doc/salome/gui/SMESH/input/clipping.doc +++ b/doc/salome/gui/SMESH/input/clipping.doc @@ -9,11 +9,14 @@ To start, click on the \em New button. \image html a-clipping2.png -Now you can define the parameters of your cross-section: \b Orientation -(X-Y, X-Z or Y-Z); \b Distance between the opposite extremities of the -object, if it is set to 0.5 the object is split in two halves; and -\b Rotation (in angle degrees) around X (Y to Z) and around Y (X to -Z). If the Show preview button is on, you can see the clipping plane +Now you can define the parameters of your cross-section: list of +meshes, sub-meshes and groups the cross-section will be applied to +(Select all button allows to select and deselect all available +objects at once), \b Orientation (X-Y, X-Z or Y-Z); \b Distance between the +opposite extremities of the boundary box of selected objects, if it is set +to 0.5 the boundary box is split in two halves; and \b Rotation (in angle +degrees) around X (Y to Z) and around Y (X to Z). +If the Show preview button is on, you can see the clipping plane in the 3D Viewer. \image html image79.jpg "The plane and the cut object" diff --git a/doc/salome/gui/SMESH/input/index.doc b/doc/salome/gui/SMESH/input/index.doc index 0975842ae..5301ce8de 100644 --- a/doc/salome/gui/SMESH/input/index.doc +++ b/doc/salome/gui/SMESH/input/index.doc @@ -12,12 +12,13 @@ previously created or imported by the Geometry component;
          • \subpage viewing_meshes_overview_page "viewing created meshes" in the VTK viewer;
          • \subpage grouping_elements_page "creating groups of mesh elements";
          • -
          • applying to meshes \subpage quality_page "Quality Controls" , -allowing to highlight important elements: +
          • applying to meshes \subpage quality_page "Quality Controls", +allowing to highlight important elements;
          • filtering sub-sets of mesh entities (nodes elements) using -\subpage filters_page "Filters" functionality.
          • +\subpage filters_page "Filters" functionality;
          • \subpage modifying_meshes_page "modifying meshes" with a vast -array of dedicated operations.
          • +array of dedicated operations; +
          • different \subpage measurements_page "measurements" of the mesh objects;
          • easily setting parameters via the variables predefined in \subpage using_notebook_mesh_page "Salome notebook".
          diff --git a/doc/salome/gui/SMESH/input/length_2d.doc b/doc/salome/gui/SMESH/input/length_2d.doc index def8afa95..4ed5b69e6 100644 --- a/doc/salome/gui/SMESH/input/length_2d.doc +++ b/doc/salome/gui/SMESH/input/length_2d.doc @@ -10,8 +10,8 @@ of your mesh.
          1. Display your mesh in the viewer.
          2. -
          3. Choose Controls > Length 2D or click "Length 2D" -button in the toolbar. +
          4. Choose Controls > Face Controls > Length 2D or click +"Length 2D" button in the toolbar. \image html image34.png
            "Length 2D" button
            diff --git a/doc/salome/gui/SMESH/input/max_element_length_2d.doc b/doc/salome/gui/SMESH/input/max_element_length_2d.doc new file mode 100644 index 000000000..0c062f872 --- /dev/null +++ b/doc/salome/gui/SMESH/input/max_element_length_2d.doc @@ -0,0 +1,29 @@ +/*! + +\page max_element_length_2d_page Max Element Length 2D + +\n This quality control criterion consists of calculation of length of +the edges and diagonals combining the meshing elements (triangles and quadrangles) +of your mesh. + +To apply the Max Element Length 2D quality criterion to your mesh: +
              +
            1. Display your mesh in the viewer.
            2. + +
            3. Choose Controls > Face Controls > Max Element Length 2D or click +"Max Element Length 2D" button in the toolbar. + +\image html image42.png +
              "Max Element Length 2D" button
              + +Your mesh will be displayed in the viewer with its elements colored according to the +applied mesh quality control criterion: + +\image html max_element_length_2d.png +
            4. +
            + +
            See Also a sample TUI Script of a +\ref tui_max_element_length_2d "Max Element Length 2D quality control" operation. + +*/ \ No newline at end of file diff --git a/doc/salome/gui/SMESH/input/max_element_length_3d.doc b/doc/salome/gui/SMESH/input/max_element_length_3d.doc new file mode 100644 index 000000000..287c3f24c --- /dev/null +++ b/doc/salome/gui/SMESH/input/max_element_length_3d.doc @@ -0,0 +1,30 @@ +/*! + +\page max_element_length_3d_page Max Element Length 3D + +\n This quality control criterion consists of calculation of length of +the edges and diagonals combining the 3D meshing elements +(tetrahedrons, pyramids, pentahendrons, hexahedrons and polyhedrons) +of your mesh. + +To apply the Max Element Length 3D quality criterion to your mesh: +
              +
            1. Display your mesh in the viewer.
            2. + +
            3. Choose Controls > Volume Controls > Max Element Length 3D or click +"Max Element Length 3D" button in the toolbar. + +\image html image43.png +
              "Max Element Length 3D" button
              + +Your mesh will be displayed in the viewer with its elements colored according to the +applied mesh quality control criterion: + +\image html max_element_length_3d.png +
            4. +
            + +
            See Also a sample TUI Script of a +\ref tui_max_element_length_3d "Max Element Length 3D quality control" operation. + +*/ \ No newline at end of file diff --git a/doc/salome/gui/SMESH/input/measurements.doc b/doc/salome/gui/SMESH/input/measurements.doc new file mode 100644 index 000000000..27894a49a --- /dev/null +++ b/doc/salome/gui/SMESH/input/measurements.doc @@ -0,0 +1,71 @@ +/*! + +\page measurements_page Measurements + +Mesh module provides possibility to perform different measurements +of the selected mesh data. + +All the measurement operations are available via \b Measurements +top-level menu. An access to the measurements operations is +implemented via single dialog box, where each operation is represented +as a separate tab page. + +\section min_distance_anchor Minimum Distance + +This operation allows measuring a distance between two objects. +Currently only node-to-node and node-to-origin operations are +available, but this operation will be extended in future to support +other mesh objects - elements, meshes, sub-meshes and groups. + +To start Minimum Distance operation, select Minimum Distance +item from \b Measurements menu. + +\image html min_distance.png + +In the dialog box choose the first target and second target mode by +switching the corresponding radio buttons, then select the objects +between which the distance is to be calculated (or enter directly IDs +in case of nodes/elements) and press \em Compute button. + +The following types of targets are supported: +- \em Node: single mesh node; +- \em Element: single mesh element (not available in this version); +- \em Object: mesh, sub-mesh or group object (not available in this +version); +- \em Origin: origin of the global co-ordinate system. + +The result will +be shown in the bottom area of the dialog box. In addition, the simple +preview will be shown in the 3D viewer. + +\image html min_distance_preview.png + +\section bounding_box_anchor Bounding Box + +This operation allows to calculate the bounding box of the selected +object(s). + +To start Bounding Box operation, select Bounding Box +item from \b Measurements menu. + +\image html bnd_box.png + +In the dialog box choose desired type of the object by switching the +corresponding radio button, select the desired object(s) and press +\em Compute button. + +The following types of input are available: +- \em Objects: select one or more mesh, sub-mesh, group objects; +- \em Nodes: select set of mesh nodes; +- \em Elements: select set of mesh elements. + +The result of calculation will be shown in the bottom area of the +dialog box. In addition, the simple preview will be shown in the 3D +viewer. + +\image html bnd_box_preview.png + +See Also a sample TUI Script of a +\ref tui_measurements_page "Measurement operations". + +*/ diff --git a/doc/salome/gui/SMESH/input/mesh_infos.doc b/doc/salome/gui/SMESH/input/mesh_infos.doc index 7b855c42c..919f6768e 100644 --- a/doc/salome/gui/SMESH/input/mesh_infos.doc +++ b/doc/salome/gui/SMESH/input/mesh_infos.doc @@ -1,62 +1,67 @@ /*! -\page mesh_infos_page Mesh infos +\page mesh_infos_page Mesh Information -\n There are three information boxes: Standard Mesh -Infos, Advanced Mesh Infos and Mesh Element Info. +The user can obtain an information about the selected mesh object +(mesh, sub-mesh or group) using Mesh Information dialog box. -
            -\anchor standard_mesh_infos_anchor -

            Standard Mesh Infos

            - -The Standard Mesh Infos box gives only the information on the -number of elements of maximum dimension and the number of nodes in the -mesh. However, from this Info you can learn about groups selected on -this mesh. -\n To view the Standard Mesh Infos, select your mesh or submesh -in the Object Browser and select Standard Mesh Infos -from the \b Mesh menu or click "Standard Mesh Infos" button -in the toolbar. - -\image html image49.png -
            "Standard Mesh Infos" button
            - -The following information will be displayed: - -\image html a-standmeshinfo.png +The Mesh Information dialog box provides two tab pages: +- Base Info - to show base information about selected mesh +object +- Element Info - to show detail information about selected mesh +node or element. -
            \anchor advanced_mesh_infos_anchor -

            Advanced Mesh Infos

            +

            Base Info

            -The Advanced Mesh Infos box gives more information about the mesh, -including the total number of faces and volumes and their geometrical -types. -\n To view the Advanced Mesh Infos, select your mesh or submesh -in the Object Browser and select Advanced Mesh Infos -from the \b Mesh menu or click "Advanced Mesh Infos" button -in the toolbar. +The Base Info tab page of the dialog box provides general +information on the selected object - mesh, sub-mesh or mesh group: +name, type, total number of nodes and elements separately for each +type: 0D elements, edges, faces and volumes. + +To view the Mesh Information, select your mesh, sub-mesh or +group in the Object Browser and invoke Mesh Information +item from the \b Mesh menu or click "Mesh Information" button +in the toolbar. -\image html image50.gif -
            "Advanced Mesh Infos" button
            +\image html image49.png +
            "Mesh Information" button
            The following information will be displayed: \image html advanced_mesh_infos.png +
            "Base Info" page
            -
            \anchor mesh_element_info_anchor -

            Mesh Element Info

            +

            Mesh Element Information

            -The Mesh Element Info dialog box gives basic information about the type, coordinates and connectivity of the selected mesh node or element. -\n It is possible to input the Element ID or to select the Element in -the Viewer. +The Element Info tab page of the dialog box gives basic +information about the type, coordinates and connectivity of the +selected mesh node or element. -\image html eleminfo1.png +To view the Mesh Element Information, select your mesh, sub-mesh or +group in the Object Browser and invoke Mesh Element Information +item from the \b Mesh menu or click "Mesh Element Information" button +in the toolbar. + +\image html elem_info.png +
            "Mesh Element Information" button
            +The following information will be displayed: + +\image html eleminfo1.png +
            "Element Info" page, node
            +
            \image html eleminfo2.png +
            "Element Info" page, element
            + +The use can either input the ID of a node or element he wants to +analyze directly in the dialog box or select the node or element in +the 3D viewer. -In case you get Mesh Infos via a TUI script the information is displayed in Python Console. -See the \ref tui_viewing_mesh_infos "TUI Example", +In case you get Mesh Information via a TUI script, the information is +displayed in the Python Console. +See the \ref tui_viewing_mesh_infos "TUI Example". -*/ \ No newline at end of file +*/ + diff --git a/doc/salome/gui/SMESH/input/minimum_angle.doc b/doc/salome/gui/SMESH/input/minimum_angle.doc index af631b0ec..4236d6562 100644 --- a/doc/salome/gui/SMESH/input/minimum_angle.doc +++ b/doc/salome/gui/SMESH/input/minimum_angle.doc @@ -10,7 +10,8 @@ element (triangle or quadrangle).
            1. Display your mesh in the viewer.
            2. -
            3. Choose Controls > Minimum angle or click "Minimum Angle" button. +
            4. Choose Controls > Face Controls > Minimum angle or click +"Minimum Angle" button. \image html image38.png
              "Minimum Angle" button
              diff --git a/doc/salome/gui/SMESH/input/modifying_meshes.doc b/doc/salome/gui/SMESH/input/modifying_meshes.doc index 45e746da4..ddddfad50 100644 --- a/doc/salome/gui/SMESH/input/modifying_meshes.doc +++ b/doc/salome/gui/SMESH/input/modifying_meshes.doc @@ -48,7 +48,6 @@ of the selected node or edge.
            5. \subpage convert_to_from_quadratic_mesh_page "Convert regular mesh to quadratic", or vice versa.
            6. \subpage make_2dmesh_from_3d_page "Generate boundary elements".
            7. - \note It is possible to use the variables defined in the SALOME \b NoteBook diff --git a/doc/salome/gui/SMESH/input/selection_filter_library.doc b/doc/salome/gui/SMESH/input/selection_filter_library.doc index c01dc0a54..00af8c7eb 100644 --- a/doc/salome/gui/SMESH/input/selection_filter_library.doc +++ b/doc/salome/gui/SMESH/input/selection_filter_library.doc @@ -162,6 +162,11 @@ by ID in Threshold Value field, if the angle between the normal to the neighboring face and the normal to the selected face is less then the angular tolerance (defined in degrees). Selection continues among all neighbor faces of already selected ones.
              +
            8. +Max Element Length 2D selects triangles and quadrangles combining of the edges and +diagonals with a value of length, which is more, less or equal +(within a given Tolerance) to the predefined Threshold Value. See also a +\ref max_element_length_2d_page "Max Element Length 2D quality control".
            9. @@ -175,6 +180,11 @@ Additional criteria to select mesh Volumes are the following: \ref volume_page "Volume quality control"), which is more, less or equal (within a given Tolerance) to the predefined Threshold Value.
            10. +Max Element Length 3D selects 3D mesh elements combining of the edges and +diagonals with a value of length, which is more, less or equal +(within a given Tolerance) to the predefined Threshold Value. See also a +\ref max_element_length_3d_page "Max Element Length 3D quality control". +
            11. Bad oriented volume selects mesh volumes, which are incorrectly oriented from the point of view of MED convention.
            12. diff --git a/doc/salome/gui/SMESH/input/skew.doc b/doc/salome/gui/SMESH/input/skew.doc index 5235b4ddd..036c70d83 100644 --- a/doc/salome/gui/SMESH/input/skew.doc +++ b/doc/salome/gui/SMESH/input/skew.doc @@ -14,7 +14,8 @@ criterion can be applied to elements composed of 4 and 3 nodes
              1. Display your mesh in the viewer.
              2. -
              3. Choose Controls > Skew or click "Skew" button of the toolbar. +
              4. Choose Controls > Face Controls > Skew or click +"Skew" button of the toolbar. \image html image40.png
                "Skew" button
                diff --git a/doc/salome/gui/SMESH/input/smeshpy_interface.doc b/doc/salome/gui/SMESH/input/smeshpy_interface.doc index 5e1fe6ebd..8b63ddfa3 100644 --- a/doc/salome/gui/SMESH/input/smeshpy_interface.doc +++ b/doc/salome/gui/SMESH/input/smeshpy_interface.doc @@ -138,5 +138,6 @@ the following links: - \subpage tui_modifying_meshes_page - \subpage tui_transforming_meshes_page - \subpage tui_notebook_smesh_page +- \subpage tui_measurements_page */ diff --git a/doc/salome/gui/SMESH/input/taper.doc b/doc/salome/gui/SMESH/input/taper.doc index d2c4dd2b4..86472eabe 100644 --- a/doc/salome/gui/SMESH/input/taper.doc +++ b/doc/salome/gui/SMESH/input/taper.doc @@ -13,8 +13,8 @@ for elements consisting of 4 nodes.
                1. Display your mesh in the viewer.
                2. -
                3. Choose Controls > Taper or click "Taper" button in -the toolbar. +
                4. Choose Controls > Face Controls > Taper or click +"Taper" button in the toolbar. \image html image36.png
                  "Taper" button
                  diff --git a/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc b/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc index 9932991f8..1581e7c2f 100644 --- a/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc +++ b/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc @@ -551,9 +551,8 @@ mesh.Compute() \anchor tui_quadrangle_parameters

                  Quadrangle Parameters example 1 (meshing a face with 3 edges)

                  \code -import geompy -import smesh -import StdMeshers +from smesh import * +SetCurrentStudy(salome.myStudy) # Get 1/4 part from the disk face. Box_1 = geompy.MakeBoxDXDYDZ(100, 100, 100) @@ -566,16 +565,15 @@ geompy.addToStudy( Common_1, "Common_1" ) # Set the Geometry for meshing Mesh_1 = smesh.Mesh(Common_1) -# Create Quadrangle parameters and define the Base Vertex. -Quadrangle_Parameters_1 = smesh.CreateHypothesis('QuadrangleParams') -Quadrangle_Parameters_1.SetTriaVertex( 8 ) # Define 1D hypothesis and compute the mesh Regular_1D = Mesh_1.Segment() Nb_Segments_1 = Regular_1D.NumberOfSegments(10) Nb_Segments_1.SetDistrType( 0 ) -status = Mesh_1.AddHypothesis(Quadrangle_Parameters_1) -Quadrangle_2D = Mesh_1.Quadrangle() + +# Create Quadrangle parameters and define the Base Vertex. +Quadrangle_2D = Mesh_1.Quadrangle().TriangleVertex( 8 ) + Mesh_1.Compute() \endcode @@ -628,6 +626,52 @@ Quadrangle_Parameters_1.SetQuadType( StdMeshers.QUAD_REDUCED ) isDone = Mesh_1.Compute() \endcode +\anchor tui_import +

                  "Use Existing Elements" example

                  +\code + +from smesh import * +SetCurrentStudy(salome.myStudy) + +# Make a patritioned box + +box = geompy.MakeBoxDXDYDZ(100,100,100) + +N = geompy.MakeVectorDXDYDZ( 1,0,0 ) +O = geompy.MakeVertex( 50,0,0 ) +plane = geompy.MakePlane( O, N, 200 ) # plane YOZ + +shape2boxes = geompy.MakeHalfPartition( box, plane ) +boxes = geompy.SubShapeAllSorted(shape2boxes, geompy.ShapeType["SOLID"]) + +geompy.addToStudy( boxes[0], "boxes[0]") +geompy.addToStudy( boxes[1], "boxes[1]") +midFace0 = geompy.SubShapeAllSorted(boxes[0], geompy.ShapeType["FACE"])[5] +geompy.addToStudyInFather( boxes[0], midFace0, "middle Face") +midFace1 = geompy.SubShapeAllSorted(boxes[1], geompy.ShapeType["FACE"])[0] +geompy.addToStudyInFather( boxes[1], midFace1, "middle Face") + +# Mesh one of boxes with quadrangles. It is a source mesh + +srcMesh = Mesh(boxes[0], "source mesh") # box coloser to CS origin +nSeg1 = srcMesh.Segment().NumberOfSegments(4) +srcMesh.Quadrangle() +srcMesh.Compute() +srcFaceGroup = srcMesh.GroupOnGeom( midFace0, "src faces", FACE ) + +# Import faces from midFace0 to the target mesh + +tgtMesh = Mesh(boxes[1], "target mesh") +importAlgo = tgtMesh.UseExisting2DElements(midFace1) +import2hyp = importAlgo.SourceFaces( [srcFaceGroup] ) +tgtMesh.Segment().NumberOfSegments(3) +tgtMesh.Quadrangle() +tgtMesh.Compute() + +# Import the whole source mesh with groups +import2hyp.SetCopySourceMesh(True,True) +tgtMesh.Compute() +\endcode \n Other meshing algorithms: diff --git a/doc/salome/gui/SMESH/input/tui_filters.doc b/doc/salome/gui/SMESH/input/tui_filters.doc index 0a4fccd3b..a73615808 100755 --- a/doc/salome/gui/SMESH/input/tui_filters.doc +++ b/doc/salome/gui/SMESH/input/tui_filters.doc @@ -337,6 +337,46 @@ print "Number of faces with maximum edge length > 14:", len(ids) \sa \ref tui_length_2d +\section filter_max_element_length_2d Max Element Length 2D + +Filter 2D mesh elements (faces) corresponding to the maximum length +value of its edges and diagonals: +- element type should be \a smesh.FACE +- functor type should be \a smesh.FT_MaxElementLength2D +- threshold is floating point value (edge/diagonal length) + +\code +# create mesh +from SMESH_mechanic import * +# get all faces that have elements with length > 10 +filter = smesh.GetFilter(smesh.FACE, smesh.FT_MaxElementLength2D, smesh.FT_MoreThan, 10) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces with maximum element length > 10:", len(ids) +\endcode + +\sa \ref tui_max_element_length_2d + +\section filter_max_element_length_3d Max Element Length 3D + +Filter 3D mesh elements (volumes) corresponding to the maximum length +value of its edges and diagonals: +- element type should be \a smesh.VOLUME +- functor type should be \a smesh.FT_MaxElementLength3D +- threshold is floating point value (edge/diagonal length) + +\code +# create mesh with volumes +from SMESH_mechanic import * +mesh.Tetrahedron( algo=smesh.NETGEN ) +mesh.Compute() +# get all volumes that have elements with length > 10 +filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_MaxElementLength3D, smesh.FT_MoreThan, 10) +ids = mesh.GetIdsFromFilter(filter) +print "Number of volumes with maximum element length > 10:", len(ids) +\endcode + +\sa \ref tui_max_element_length_3d + \section filter_belong_to_geom Belong to Geom Filter mesh entities (nodes or elements) which all nodes lie on the diff --git a/doc/salome/gui/SMESH/input/tui_grouping_elements.doc b/doc/salome/gui/SMESH/input/tui_grouping_elements.doc index 763e939d4..1aa73a484 100644 --- a/doc/salome/gui/SMESH/input/tui_grouping_elements.doc +++ b/doc/salome/gui/SMESH/input/tui_grouping_elements.doc @@ -1,4 +1,4 @@ - /*! +/*! \page tui_grouping_elements_page Grouping Elements diff --git a/doc/salome/gui/SMESH/input/tui_measurements.doc b/doc/salome/gui/SMESH/input/tui_measurements.doc new file mode 100644 index 000000000..aabf0b317 --- /dev/null +++ b/doc/salome/gui/SMESH/input/tui_measurements.doc @@ -0,0 +1,84 @@ +/*! + +\page tui_measurements_page Measurements + +\section tui_min_distance Minimum Distance + +\code + +import smesh +from SMESH_mechanic import mesh as mesh1 +from SMESH_test1 import mesh as mesh2 + +mesh1.Compute() +mesh2.Compute() + +# compute min distance from mesh1 to the origin (not available yet) +smesh.MinDistance(mesh1) + +# compute min distance from node 10 of mesh1 to the origin +smesh.MinDistance(mesh1, id1=10) +# ... or +mesh1.MinDistance(10) + +# compute min distance between nodes 10 and 20 of mesh1 +smesh.MinDistance(mesh1, id1=10, id2=20) +# ... or +mesh1.MinDistance(10, 20) + +# compute min distance from element 100 of mesh1 to the origin (not available yet) +smesh.MinDistance(mesh1, id1=100, isElem1=True) +# ... or +mesh1.MinDistance(100, isElem1=True) + +# compute min distance between elements 100 and 200 of mesh1 (not available yet) +smesh.MinDistance(mesh1, id1=100, id2=200, isElem1=True, isElem2=True) +# ... or +mesh1.MinDistance(100, 200, True, True) + +# compute min distance from element 100 to node 20 of mesh1 (not available yet) +smesh.MinDistance(mesh1, id1=100, id2=20, isElem1=True) +# ... or +mesh1.MinDistance(100, 20, True) + +# compute min distance from mesh1 to mesh2 (not available yet) +smesh.MinDistance(mesh1, mesh2) + +# compute min distance from node 10 of mesh1 to node 20 of mesh2 +smesh.MinDistance(mesh1, mesh2, 10, 20) + +# compute min distance from node 10 of mesh1 to element 200 of mesh2 (not available yet) +smesh.MinDistance(mesh1, mesh2, 10, 200, isElem2=True) + +# etc... + +\endcode + +\section tui_bounding_box Bounding Box + +\code + +import smesh +from SMESH_mechanic import mesh as mesh1 +from SMESH_test1 import mesh as mesh2 + +mesh1.Compute() +mesh2.Compute() + +# compute bounding box for mesh1 +mesh1.BoundingBox() + +# compute bounding box for list of nodes of mesh1 +mesh1.BoundingBox([363, 364, 370, 371, 372, 373, 379, 380, 381]) + +# compute bounding box for list of elements of mesh1 +mesh1.BoundingBox([363, 364, 370, 371, 372, 373, 379, 380, 381], isElem=True) + +# compute common bounding box of mesh1 and mesh2 +smesh.BoundingBox([mesh1, mesh2]) + +# etc... + +\endcode + +*/ diff --git a/doc/salome/gui/SMESH/input/tui_quality_controls.doc b/doc/salome/gui/SMESH/input/tui_quality_controls.doc index 740c42247..acbf89198 100644 --- a/doc/salome/gui/SMESH/input/tui_quality_controls.doc +++ b/doc/salome/gui/SMESH/input/tui_quality_controls.doc @@ -603,6 +603,39 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode +\section tui_max_element_length_2d Max Element Length 2D + +\code +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +# Criterion : MAX ELEMENT LENGTH 2D > 10 +mel_2d_margin = 10 + +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_MaxElementLength2D, smesh.FT_MoreThan, mel_2d_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Max Element Length 2D Ratio > ", mel_2d_margin, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Max Element Length 2D > " + `mel_2d_margin`) +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) +\endcode + \section tui_aspect_ratio_3d Aspect Ratio 3D \code @@ -672,4 +705,37 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode +\section tui_max_element_length_3d Max Element Length 3D + +\code +import SMESH_mechanic_tetra + +smesh = SMESH_mechanic_tetra.smesh +mesh = SMESH_mechanic_tetra.mesh +salome = SMESH_mechanic_tetra.salome + +# Criterion : MAX ELEMENT LENGTH 3D > 10 +mel_3d_margin = 10 + +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_MaxElementLength3D, smesh.FT_MoreThan, mel_3d_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Max Element Length 3D Ratio > ", mel_3d_margin, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Max Element Length 3D > " + `mel_3d_margin`) +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) +\endcode + */ diff --git a/doc/salome/gui/SMESH/input/use_existing_algos.doc b/doc/salome/gui/SMESH/input/use_existing_algos.doc new file mode 100644 index 000000000..b2273a4f0 --- /dev/null +++ b/doc/salome/gui/SMESH/input/use_existing_algos.doc @@ -0,0 +1,58 @@ +/*! + +\page import_algos_page Use Existing Elements Algorithms + +\n Use Existing Elements algorithms allow to define the mesh of a geometrical +object by the importing suitably located mesh elements from another +mesh. The mesh elements to import from the other mesh are to be contained in +groups. If several groups are used to mesh one geometry, validity of +nodal connectivity of result mesh must be assured by connectivity of +the source mesh; no geometrical checks are performed to merge +different nodes at same locations. +
                  The source elements must totally cover the meshed geometry. +The source elements lying partially over the geometry will not be used. +
                  +These algorithms can be used to mesh a very complex geometry part by +part, by storing meshes of parts in files and then fusing them +together using these algorithms. +
                  + +Use Existing 1D Elements algorithm allows to define the mesh of +a geometrical edge (or group of edges) +by the importing of mesh edges of another mesh contained in a group (or groups). +\n To apply this algorithm select the edge to be meshed (indicated in +the field \b Geometry of Create mesh dialog box), +Use existing 1D elements in the list of 1D algorithms and click the +"Add Hypothesis" button. +The following dialog box will appear: + +\image html hyp_source_edges.png + +In this menu you can define the \b Name of the algorithm, the +Groups of Edges to import elements from, To copy mesh +the selected Groups of Edges belong to as a whole and To +copy groups along with the whole mesh. +
                  + +Use Existing 2D Elements algorithm allows to define the mesh of +a geometrical face (or group of faces) +by the importing of mesh faces of another mesh contained in a group (or groups). +\n To apply this algorithm select the edge to be meshed (indicated in +the field \b Geometry of Create mesh dialog box), +Use existing 2D elements in the list of 2D algorithms and click the +"Add Hypothesis" button. +The following dialog box will appear: + +\image html hyp_source_faces.png + +In this menu you can define the \b Name of the algorithm, the +Groups of Faces to import elements from, To copy mesh +the selected Groups of Fcaes belong to as a whole and To +copy groups along with the whole mesh. +
                  + +
                  See Also a sample TUI Script of a +\ref tui_import "Use Existing Elements Algorithms". + +*/ + diff --git a/doc/salome/gui/SMESH/input/volume.doc b/doc/salome/gui/SMESH/input/volume.doc index ba99c193e..4d74fcbf0 100644 --- a/doc/salome/gui/SMESH/input/volume.doc +++ b/doc/salome/gui/SMESH/input/volume.doc @@ -9,8 +9,8 @@
                  1. Display your mesh in the viewer.
                  2. -
                  3. Choose Controls > Volume or click "Volume" button -in the toolbar. +
                  4. Choose Controls > Volume Controls > Volume or click +"Volume" button in the toolbar. \image html image145.png
                    "Volume" button
                    diff --git a/doc/salome/gui/SMESH/input/warping.doc b/doc/salome/gui/SMESH/input/warping.doc index 83bfaa3ac..86ba0c905 100644 --- a/doc/salome/gui/SMESH/input/warping.doc +++ b/doc/salome/gui/SMESH/input/warping.doc @@ -24,8 +24,8 @@ projection height ?h? to the half edge length ?l?.
                    1. Display your mesh in the viewer.
                    2. -
                    3. Choose Controls > Warping Angle or click "Warping angle" -button of the toolbar. +
                    4. Choose Controls > Face Controls > Warping Angle or click +"Warping angle" button of the toolbar. \image html image39.png
                      "Warping angle" button
                      diff --git a/idl/Makefile.am b/idl/Makefile.am index 5a88808b3..491c38667 100644 --- a/idl/Makefile.am +++ b/idl/Makefile.am @@ -32,7 +32,8 @@ BASEIDL_FILES = \ SMESH_Filter.idl \ SMESH_Group.idl \ SMESH_Pattern.idl \ - SMESH_MeshEditor.idl + SMESH_MeshEditor.idl \ + SMESH_Measurements.idl # This variable defines the files to be installed dist_salomeidl_DATA = $(BASEIDL_FILES) @@ -49,7 +50,8 @@ nodist_libSalomeIDLSMESH_la_SOURCES = \ SMESH_FilterSK.cc \ SMESH_GroupSK.cc \ SMESH_PatternSK.cc \ - SMESH_MeshEditorSK.cc + SMESH_MeshEditorSK.cc \ + SMESH_MeasurementsSK.cc # header files must be exported: other modules have to use this library nodist_salomeinclude_HEADERS = $(BASEIDL_FILES:%.idl=%.hh) diff --git a/idl/SMESH_BasicHypothesis.idl b/idl/SMESH_BasicHypothesis.idl index a5ecbcabf..88b0ab751 100644 --- a/idl/SMESH_BasicHypothesis.idl +++ b/idl/SMESH_BasicHypothesis.idl @@ -796,6 +796,48 @@ module StdMeshers QuadType GetQuadType(); }; + /*! + * interface of "Source edges" hypothesis. + * This hypothesis specifies groups of edges of other mesh to be imported + * in this mesh + */ + interface StdMeshers_ImportSource1D : SMESH::SMESH_Hypothesis + { + /*! + * Set edges to import from other mesh + */ + void SetSourceEdges(in SMESH::ListOfGroups groups); + SMESH::string_array GetSourceEdges(); + + /*! + * Set to import the whole other mesh or not, and if yes, to + * copy groups of not. By default the mesh is not copied. + */ + void SetCopySourceMesh(in boolean toCopyMesh, in boolean toCopyGroups); + void GetCopySourceMesh(out boolean toCopyMesh,out boolean toCopyGroups); + }; + + /*! + * interface of "Source faces" hypothesis. + * This hypothesis specifies groups of faces of other mesh to be imported + * in this mesh + */ + interface StdMeshers_ImportSource2D : SMESH::SMESH_Hypothesis + { + /*! + * Set faces to import from other mesh + */ + void SetSourceFaces(in SMESH::ListOfGroups groups); + SMESH::string_array GetSourceFaces(); + + /*! + * Set to import the whole other mesh or not, and if yes, to + * copy groups of not. By default the mesh is not copied. + */ + void SetCopySourceMesh(in boolean toCopyMesh,in boolean toCopyGroups); + void GetCopySourceMesh(out boolean toCopyMesh,out boolean toCopyGroups); + }; + /*! * StdMeshers_SegmentAroundVertex_0D: interface of "SegmentAroundVertex" algorithm */ @@ -896,6 +938,19 @@ module StdMeshers { }; + /*! + * StdMeshers_Import_1D2D: interface of "Use existing 2D elements" algorithm + */ + interface StdMeshers_Import_1D2D : SMESH::SMESH_2D_Algo + { + }; + /*! + * StdMeshers_Import_1D: interface of "Use existing 1D elements" algorithm + */ + interface StdMeshers_Import_1D : SMESH::SMESH_1D_Algo + { + }; + }; #endif diff --git a/idl/SMESH_Filter.idl b/idl/SMESH_Filter.idl index 3b478fec0..e12607bcd 100644 --- a/idl/SMESH_Filter.idl +++ b/idl/SMESH_Filter.idl @@ -47,6 +47,8 @@ module SMESH FT_Skew, FT_Area, FT_Volume3D, + FT_MaxElementLength2D, + FT_MaxElementLength3D, FT_FreeBorders, FT_FreeEdges, FT_FreeNodes, @@ -75,6 +77,17 @@ module SMESH FT_Undefined }; + /*! + * Parameters of a reclangle of histogram + */ + struct HistogramRectangle + { + long nbEvents; + double min; + double max; + }; + typedef sequence Histogram; + /*! * Base interface for all functors ( i.e. numerical functors and predicates ) */ @@ -94,6 +107,8 @@ module SMESH { double GetValue( in long theElementId ); + Histogram GetHistogram( in short nbIntervals ); + /*! * Set precision for calculation. It is a position after point which is * used to functor value after calculation. @@ -109,6 +124,8 @@ module SMESH interface Skew : NumericalFunctor{}; interface Area : NumericalFunctor{}; interface Volume3D : NumericalFunctor{}; + interface MaxElementLength2D : NumericalFunctor{}; + interface MaxElementLength3D : NumericalFunctor{}; interface Length : NumericalFunctor{}; interface Length2D : NumericalFunctor { @@ -461,6 +478,8 @@ module SMESH Skew CreateSkew(); Area CreateArea(); Volume3D CreateVolume3D(); + MaxElementLength2D CreateMaxElementLength2D(); + MaxElementLength3D CreateMaxElementLength3D(); Length CreateLength(); Length2D CreateLength2D(); MultiConnection CreateMultiConnection(); diff --git a/idl/SMESH_Gen.idl b/idl/SMESH_Gen.idl index 14527a9b3..3c375e625 100644 --- a/idl/SMESH_Gen.idl +++ b/idl/SMESH_Gen.idl @@ -42,6 +42,7 @@ module SMESH interface FilterManager; interface SMESH_Pattern; + interface Measurements; /*! * Tags definition @@ -119,6 +120,8 @@ module SMESH SMESH_Pattern GetPattern(); + Measurements CreateMeasurements(); + /*! Set the current mode */ @@ -244,7 +247,6 @@ module SMESH */ long_array Evaluate(in SMESH_Mesh theMesh, in GEOM::GEOM_Object theSubObject) - //inout long_array theNbElems) raises ( SALOME::SALOME_Exception ); /*! diff --git a/idl/SMESH_Group.idl b/idl/SMESH_Group.idl index b41e57df3..adf63dd83 100644 --- a/idl/SMESH_Group.idl +++ b/idl/SMESH_Group.idl @@ -82,11 +82,6 @@ module SMESH */ long_array GetListOfID(); - /*! - * Returns the mesh object this group belongs to - */ - SMESH_Mesh GetMesh(); - /*! * Sets group color */ diff --git a/idl/SMESH_Measurements.idl b/idl/SMESH_Measurements.idl new file mode 100644 index 000000000..6a177f51a --- /dev/null +++ b/idl/SMESH_Measurements.idl @@ -0,0 +1,61 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 : SMESH_Measurements.idl +// Author : Pavel Telkov, OCC +// +#ifndef _SMESH_MEASUREMENTS_IDL_ +#define _SMESH_MEASUREMENTS_IDL_ + +#include "SALOME_GenericObj.idl" +#include "SMESH_Mesh.idl" + +module SMESH +{ + + /* + * Measure component + */ + struct Measure { + double minX, minY, minZ; + double maxX, maxY, maxZ; + long node1, node2; + long elem1, elem2; + double value; + }; + + interface Measurements: SALOME::GenericObj + { + /*! + * minimal distance between two entities + */ + Measure MinDistance(in SMESH_IDSource source1, + in SMESH_IDSource source2); + + /*! + * common bounding box of entities + */ + Measure BoundingBox(in ListOfIDSources sources); + }; +}; + +#endif diff --git a/idl/SMESH_Mesh.idl b/idl/SMESH_Mesh.idl index cc97d1e14..8165d5c00 100644 --- a/idl/SMESH_Mesh.idl +++ b/idl/SMESH_Mesh.idl @@ -248,6 +248,8 @@ module SMESH long_array elementConnectivities; types_array elementTypes; }; + interface SMESH_Mesh; + interface SMESH_IDSource { /*! @@ -265,6 +267,11 @@ module SMESH * Returns types of elements it contains */ array_of_ElementType GetTypes(); + + /*! + * Returns the mesh + */ + SMESH_Mesh GetMesh(); }; interface SMESH_Group; diff --git a/resources/Makefile.am b/resources/Makefile.am index 9541a2133..cc7d5a885 100644 --- a/resources/Makefile.am +++ b/resources/Makefile.am @@ -49,6 +49,7 @@ dist_salomeres_DATA = \ mesh_info.png \ advanced_mesh_info.png \ standard_mesh_info.png \ + mesh_elem_info.png \ mesh_whatis.png \ mesh_init.png \ mesh_length.png \ @@ -57,6 +58,8 @@ dist_salomeres_DATA = \ mesh_free_edges.png \ mesh_free_edges_2d.png \ mesh_free_nodes.png \ + mesh_max_element_length_2d.png \ + mesh_max_element_length_3d.png \ mesh_multi_edges.png \ mesh_multi_edges_2d.png \ mesh_line_n.png \ @@ -180,7 +183,9 @@ dist_salomeres_DATA = \ scale_along_axes.png \ split_into_tetra.png \ mesh_duplicate_nodes.png \ - mesh_duplicate_nodes_with_elem.png + mesh_duplicate_nodes_with_elem.png \ + mesh_bounding_box.png \ + mesh_min_dist.png # VSR: little trick to avoid putting if SMESHCatalog.xml to the distribution archive nodist_salomeres_SCRIPTS = SMESHCatalog.xml diff --git a/resources/SalomeApp.xml b/resources/SalomeApp.xml index b7993a340..ea6daa0bf 100644 --- a/resources/SalomeApp.xml +++ b/resources/SalomeApp.xml @@ -65,12 +65,16 @@ + + + + diff --git a/resources/StdMeshers.xml b/resources/StdMeshers.xml index 557cd9613..41c83c997 100644 --- a/resources/StdMeshers.xml +++ b/resources/StdMeshers.xml @@ -122,7 +122,6 @@ + + + + + + + + r16)Z&K~y-)t(0A8TV)u>f9G_qG+ncmnq{3AQrCi$ff<`#bWX}z zos-Ebi)$||yKoy`)UH7(aa0kUqOBL&MzJ6$1wke_YS_At`mw=u6Dn=8Q9oK`R+F@3 z%~{V$&PQ_2>&0?PyG?Pj2Y()TpXcKDJ|FxaNeIE6G?_bWtK5eqNdRjuLyw&{NJ2(!gswzy=WNd6q`cFX1vS@05jei$(JvlHiPy?VS z3c4kbfTxapR0Ow(TrNjE9+&=g%bKQP<{cVZUnLj}CV}Z_G`jnPmmVi;+US;po_E+2 z8sgz#4?f@B!sGD>zu#YbOW^ft9CD_^&O-wP0)Zruip65#zQfzNrsbLWDbAH2`f0v@ zl+zgJ_0L)+nIoG~PS3 z3E0)YVmTq2-hi0!^7iz4{j)hnoPt z1vG%gt4T^qD}V4*ZQ!1&IfhTv)fue{n*rO{VOUMO9>0oWUDf4gmX#?T!{N z&#vMJ)4+LPqPn`eKA+FG+O~b4ZQJ99VSET&yA`mm2u&3|0QiBKA~5A{{h#b_!jiRi UrkA3>01E&B07*qoM6N<$f=q+RS^xk5 delta 933 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 b%C`XkOU=6O=JF+100000NkvXXu0mjfKW>gN literal 0 HcmV?d00001 diff --git a/resources/mesh_elem_info.png b/resources/mesh_elem_info.png new file mode 100644 index 0000000000000000000000000000000000000000..9937d6d88586b9f0b8f62db1f680167ffcf779bd GIT binary patch literal 907 zcmV;619bd}P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igi8 z69p{^#?W>E00Rq2L_t(I%dM16Xk1kk$A5R`<$DaRDQ|)rD|QwJDo#74?T{3!bTP?` zn~uQW-qG>>_~>X`Jb*p`Gz`P6t*z}?SQsS| ziJbI2?^dZ)Dpr1C{Hvx;kSzgdF4!X)jfTQumDu}o%UhPU^|jX4dAXO}*E^h^y_+8S zv;W4=e|-bkJfyK3fHupzEWnn^W;7a&9ysvg#reB^;ujB!@AZi9b%~SPEg!u9teB>` zeYM7R06P>i2xbS{yQ`}&aeaD>ufD!aHamk~`h$J1YU=Ab*4WrswVG1w zp`k>3clYFY07b<2zdOJ1_lKvJIex;)9y*-8Id(qJ?b}6W=ZaKS$&yI|ORnp}Bg~-zXzT8ttkhDa zQWpg1d}Z&`mwx+Ym;5^SjJ)^mCW*(JmTPKi4g>X%G6x5+wHAP8%bF->GJ9f%VQgw? zsf&sf`RRt{+&Qu{GfuzfdEWw_v4%A5vuC%rTh_$5)*e8!*4n#zHD5S!(j}WMGdriR z=kxBTz$~EGvM&d)MKqbro<1OE7{*dE8B!me4s-mN;Ijm`$!Q2OAnwpxPDwRraXsw^uTL0*}?kB*##{s?s h^aOex2z39@xDUtgVtTen16BY4002ovPDHLkV1klprFZ}U literal 0 HcmV?d00001 diff --git a/resources/mesh_max_element_length_2d.png b/resources/mesh_max_element_length_2d.png new file mode 100755 index 0000000000000000000000000000000000000000..d0120fa1ede5f2785da08336bfa85689607c8d9d GIT binary patch literal 857 zcmV-f1E&0mP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ;&q+i>;4wDVIRNfJ{J{9CArAN&bQyOcrGSfFQDgb#hQa*=6x!u9?Xpr*tB5 zoSvR;+pekFgWa0!dJ%HSgD+Kw$LIavy(f$@d`pvjWBdMrVqsyySeAulS(M9VaaO?m z{JaT*fP;ermX?-;9Yql-n(7KSFi|09cwi_FZ- z0A%eT2pAh1!}C0KuVAjgg6m^F`zZH+t6+s;ut*dCR0;WL{S7VE`Te*P2kE0 z(_5%+zE6PSD<~Ynj(~S9SYBSHbgPGKHe0AxtM`B%phm0JVqjpv z%+1Xi*L49p9mg@iqii;79LM=e&!7Ke9LF)Uv$FFDTS zcX!v^cypL%UhgQl2iHYNCPQ5l~JTAv;ngsYg4RqYY jGXlRHliGjF1^9OWjdNV6x1YOp00000NkvXXu0mjfRrhtP literal 0 HcmV?d00001 diff --git a/resources/mesh_max_element_length_3d.png b/resources/mesh_max_element_length_3d.png new file mode 100755 index 0000000000000000000000000000000000000000..7b6b895a1d83a5d1393a3af60c2a8fbe4a7c0433 GIT binary patch literal 965 zcmV;$13LVPP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZq>)?Vof(C zC13~yM`(&}M6`?8O1r2b5?W%XNEbp2VxZt!QX&$v4B03F#ejC@!laF5bcQ5;kQp+R z(#*Vj-+OcKJucqIq$PIcfy@7LIsDJp|6ET*_&+TN;CbF-kF&G0S(LfCIqzu%larIu zYPIlvpVie>FL#(zS63JLe4cu}&I5TzzyShu0U#J4L{NP6uBNxQmqw!jFp&GN$h*6{ z7-RVJ*QJ<5!1H1h0c+#4zkh~Wt%flM;7w0N9xM5QyeI$M{RZd2xeh^UBJsPm!iysV z{PshcBgc>OTHnJpU_A#gH8myO-Q9Se$KM-YWMl^kQ_@?v&Ju{>!VhyadhZ((jScwB>l2U524i>pin4KsZ>y^iPnlh15gJxasW{jv9q&- zbB^s_zRgNHtYoF$pi-$|ttAXKQ50a>oeaAGs?{o=&zHG$=_{OrD_6#{UX@B?T)P$@ zYlZ9Azr#7l`1m-+v~kYz@!97)3IQ<2aQb9~2ux3pptVkjM;IL)<>t*bZru2hnVFM_ zIFwR^VTf}U=WIIRj# zn0~*Pp`oFfEW_BbjdPO7#SsKL>(#`>XNWj1Uw$2>nwh^+O{}$~96%uxc3obPKYqH0 zF%GR;Xzde4ai2WT!#Rhw24f=nj*U~kvqThyEG~YUt?TCIW+_`eLDOzqe19LMngl^i zDB_Y0k&LjpFKF#^R=lwkGA!2b>aM@J*Ey`lN)00000NkvXXu0mjfoe{Pk literal 0 HcmV?d00001 diff --git a/resources/mesh_min_dist.png b/resources/mesh_min_dist.png new file mode 100755 index 0000000000000000000000000000000000000000..6713caf0ae83217fe99fb810ec5d3778cbe84470 GIT binary patch literal 3360 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 nbEvents, + std::vector& funValues) +{ + 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; + SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator(GetType()); + while ( elemIt->more() ) + values.insert( GetValue( elemIt->next()->GetID() )); + + // case nbIntervals == 1 + funValues[0] = *values.begin(); + funValues[nbIntervals] = *values.rbegin(); + 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 ) + { + double r = (i+1) / double( nbIntervals ); + funValues[i+1] = funValues.front() * (1-r) + funValues.back() * r; + if ( min != values.end() && *min <= funValues[i+1] ) + { + max = values.upper_bound( funValues[i+1] ); // greater than funValues[i+1], or end() + nbEvents[i] = std::distance( min, max ); + min = max; + } + } +} + //======================================================================= //function : GetValue //purpose : @@ -340,6 +397,246 @@ SMDSAbs_ElementType Volume::GetType() const } +/* + Class : MaxElementLength2D + Description : Functor calculating maximum length of 2D element +*/ + +double MaxElementLength2D::GetValue( long theElementId ) +{ + 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_Face: + 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; + } + 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)); + break; + } + 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)); + break; + } + else if( len == 8 ) { // 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)); + break; + } + } + + if( myPrecision >= 0 ) + { + double prec = pow( 10., (double)myPrecision ); + aVal = floor( aVal * prec + 0.5 ) / prec; + } + return aVal; + } + return 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 +*/ + +double MaxElementLength3D::GetValue( long theElementId ) +{ + 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 == 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 ) { // 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 @@ -435,47 +732,94 @@ double AspectRatio::GetValue( const TSequenceOfXYZ& P ) 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 <= Precision::Confusion() ) + return 0.; + return alpha * L * C1 / C2; + } + else if( nbNodes == 8 ){ // 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 <= Precision::Confusion() ) + return 0.; + return alpha * L * C1 / C2; } + return 0; } double AspectRatio::GetBadRate( double Value, int /*nbNodes*/ ) const @@ -991,16 +1335,20 @@ SMDSAbs_ElementType Skew::GetType() const */ 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 @@ -1117,7 +1465,7 @@ double Length2D::GetValue( long theElementId) else if (len == 5){ // piramids double L1 = getDistance(P( 1 ),P( 2 )); double L2 = getDistance(P( 2 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 1 )); + 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 )); @@ -1177,7 +1525,7 @@ double Length2D::GetValue( long theElementId) else if (len == 13){ // quadratic piramids 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( 1 )); + 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 )); diff --git a/src/Controls/SMESH_ControlsDef.hxx b/src/Controls/SMESH_ControlsDef.hxx index 1fde3f281..915bd9f4b 100644 --- a/src/Controls/SMESH_ControlsDef.hxx +++ b/src/Controls/SMESH_ControlsDef.hxx @@ -127,6 +127,9 @@ 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); virtual SMDSAbs_ElementType GetType() const = 0; virtual double GetBadRate( double Value, int nbNodes ) const = 0; long GetPrecision() const; @@ -156,6 +159,30 @@ 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 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 diff --git a/src/OBJECT/Makefile.am b/src/OBJECT/Makefile.am index 0e8cdabd9..219350562 100644 --- a/src/OBJECT/Makefile.am +++ b/src/OBJECT/Makefile.am @@ -34,7 +34,9 @@ salomeinclude_HEADERS = \ SMESH_DeviceActor.h \ SMESH_PreviewActorsCollection.h \ SMESH_ExtractGeometry.h \ - SMESH_FaceOrientationFilter.h + SMESH_FaceOrientationFilter.h \ + SMESH_ScalarBarActor.h + # Libraries targets @@ -46,7 +48,8 @@ dist_libSMESHObject_la_SOURCES = \ SMESH_PreviewActorsCollection.cxx \ SMESH_ExtractGeometry.cxx \ SMESH_ActorUtils.cxx \ - SMESH_FaceOrientationFilter.cxx + SMESH_FaceOrientationFilter.cxx \ + SMESH_ScalarBarActor.cxx libSMESHObject_la_CPPFLAGS = \ $(QT_INCLUDES) \ diff --git a/src/OBJECT/SMESH_Actor.cxx b/src/OBJECT/SMESH_Actor.cxx index 8f5c5bae6..4afc7f4ca 100644 --- a/src/OBJECT/SMESH_Actor.cxx +++ b/src/OBJECT/SMESH_Actor.cxx @@ -30,6 +30,7 @@ #include "SMESH_DeviceActor.h" #include "SMESH_ObjectDef.h" #include "SMESH_ControlsDef.hxx" +#include "SMESH_ScalarBarActor.h" #include "VTKViewer_CellCenters.h" #include "VTKViewer_ExtractUnstructuredGrid.h" #include "VTKViewer_FramedTextActor.h" @@ -64,7 +65,6 @@ #include #include -#include #include #include @@ -371,7 +371,7 @@ SMESH_ActorDef::SMESH_ActorDef() //Controls - Aspect Ratio: incorrect colors of the best and worst values myLookupTable->SetHueRange(0.667,0.0); - myScalarBarActor = vtkScalarBarActor::New(); + myScalarBarActor = SMESH_ScalarBarActor::New(); myScalarBarActor->SetVisibility(false); myScalarBarActor->SetLookupTable(myLookupTable); @@ -500,6 +500,9 @@ SMESH_ActorDef::~SMESH_ActorDef() { if(MYDEBUG) MESSAGE("~SMESH_ActorDef - "<InvokeEvent( SMESH::DeleteActorEvent, NULL ); + myScalarBarActor->Delete(); myLookupTable->Delete(); @@ -721,51 +724,50 @@ SetControlMode(eControl theMode, bool anIsScalarVisible = theMode > eNone; if(anIsScalarVisible){ - SMESH::Controls::FunctorPtr aFunctor; switch(theMode){ case eLength: { SMESH::Controls::Length* aControl = new SMESH::Controls::Length(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my1DActor; break; } case eLength2D: { - aFunctor.reset(new SMESH::Controls::Length2D()); + myFunctor.reset(new SMESH::Controls::Length2D()); myControlActor = my2DActor; break; } case eFreeBorders: - aFunctor.reset(new SMESH::Controls::FreeBorders()); + myFunctor.reset(new SMESH::Controls::FreeBorders()); myControlActor = my1DActor; break; case eFreeEdges: - aFunctor.reset(new SMESH::Controls::FreeEdges()); + myFunctor.reset(new SMESH::Controls::FreeEdges()); myControlActor = my2DActor; break; case eFreeNodes: - aFunctor.reset(new SMESH::Controls::FreeNodes()); + myFunctor.reset(new SMESH::Controls::FreeNodes()); myControlActor = myNodeActor; break; case eFreeFaces: - aFunctor.reset(new SMESH::Controls::FreeFaces()); + myFunctor.reset(new SMESH::Controls::FreeFaces()); myControlActor = my2DActor; break; case eMultiConnection: - aFunctor.reset(new SMESH::Controls::MultiConnection()); + myFunctor.reset(new SMESH::Controls::MultiConnection()); myControlActor = my1DActor; break; case eMultiConnection2D: - aFunctor.reset(new SMESH::Controls::MultiConnection2D()); + myFunctor.reset(new SMESH::Controls::MultiConnection2D()); myControlActor = my2DActor; break; case eArea: { SMESH::Controls::Area* aControl = new SMESH::Controls::Area(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my2DActor; break; } @@ -773,7 +775,7 @@ SetControlMode(eControl theMode, { SMESH::Controls::Taper* aControl = new SMESH::Controls::Taper(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my2DActor; break; } @@ -781,7 +783,7 @@ SetControlMode(eControl theMode, { SMESH::Controls::AspectRatio* aControl = new SMESH::Controls::AspectRatio(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my2DActor; break; } @@ -789,7 +791,7 @@ SetControlMode(eControl theMode, { SMESH::Controls::AspectRatio3D* aControl = new SMESH::Controls::AspectRatio3D(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my3DActor; break; } @@ -797,7 +799,23 @@ SetControlMode(eControl theMode, { SMESH::Controls::Volume* aControl = new SMESH::Controls::Volume(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); + myControlActor = my3DActor; + break; + } + case eMaxElementLength2D: + { + SMESH::Controls::MaxElementLength2D* aControl = new SMESH::Controls::MaxElementLength2D(); + aControl->SetPrecision( myControlsPrecision ); + myFunctor.reset( aControl ); + myControlActor = my2DActor; + break; + } + case eMaxElementLength3D: + { + SMESH::Controls::MaxElementLength3D* aControl = new SMESH::Controls::MaxElementLength3D(); + aControl->SetPrecision( myControlsPrecision ); + myFunctor.reset( aControl ); myControlActor = my3DActor; break; } @@ -805,7 +823,7 @@ SetControlMode(eControl theMode, { SMESH::Controls::MinimumAngle* aControl = new SMESH::Controls::MinimumAngle(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my2DActor; break; } @@ -813,7 +831,7 @@ SetControlMode(eControl theMode, { SMESH::Controls::Warping* aControl = new SMESH::Controls::Warping(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my2DActor; break; } @@ -821,7 +839,7 @@ SetControlMode(eControl theMode, { SMESH::Controls::Skew* aControl = new SMESH::Controls::Skew(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my2DActor; break; } @@ -835,21 +853,21 @@ SetControlMode(eControl theMode, myControlMode = theMode; switch(myControlMode){ case eFreeNodes: - myNodeExtActor->SetExtControlMode(aFunctor); + myNodeExtActor->SetExtControlMode(myFunctor); break; case eFreeEdges: case eFreeBorders: - my1DExtActor->SetExtControlMode(aFunctor); + my1DExtActor->SetExtControlMode(myFunctor); break; case eFreeFaces: - my2DExtActor->SetExtControlMode(aFunctor); + my2DExtActor->SetExtControlMode(myFunctor); break; case eLength2D: case eMultiConnection2D: - my1DExtActor->SetExtControlMode(aFunctor,myScalarBarActor,myLookupTable); + my1DExtActor->SetExtControlMode(myFunctor,myScalarBarActor,myLookupTable); break; default: - myControlActor->SetControlMode(aFunctor,myScalarBarActor,myLookupTable); + myControlActor->SetControlMode(myFunctor,myScalarBarActor,myLookupTable); } } @@ -872,8 +890,11 @@ SetControlMode(eControl theMode, SetEntityMode(eVolumes); } - }else if(theCheckEntityMode){ - myEntityMode = eAllEntity; + } + else { + if(theCheckEntityMode) + myEntityMode = eAllEntity; + myFunctor.reset(); } SetRepresentation(GetRepresentation()); @@ -1805,92 +1826,6 @@ GetClippingPlane(vtkIdType theID) return myCippingPlaneCont[theID].Get(); } - -static void ComputeBoundsParam(vtkDataSet* theDataSet, - vtkFloatingPointType theDirection[3], vtkFloatingPointType theMinPnt[3], - vtkFloatingPointType& theMaxBoundPrj, vtkFloatingPointType& theMinBoundPrj) -{ - vtkFloatingPointType aBounds[6]; - theDataSet->GetBounds(aBounds); - - //Enlarge bounds in order to avoid conflicts of precision - for(int i = 0; i < 6; i += 2){ - static double EPS = 1.0E-3; - vtkFloatingPointType aDelta = (aBounds[i+1] - aBounds[i])*EPS; - aBounds[i] -= aDelta; - aBounds[i+1] += aDelta; - } - - vtkFloatingPointType aBoundPoints[8][3] = { {aBounds[0],aBounds[2],aBounds[4]}, - {aBounds[1],aBounds[2],aBounds[4]}, - {aBounds[0],aBounds[3],aBounds[4]}, - {aBounds[1],aBounds[3],aBounds[4]}, - {aBounds[0],aBounds[2],aBounds[5]}, - {aBounds[1],aBounds[2],aBounds[5]}, - {aBounds[0],aBounds[3],aBounds[5]}, - {aBounds[1],aBounds[3],aBounds[5]}}; - - int aMaxId = 0, aMinId = aMaxId; - theMaxBoundPrj = vtkMath::Dot(theDirection,aBoundPoints[aMaxId]); - theMinBoundPrj = theMaxBoundPrj; - for(int i = 1; i < 8; i++){ - vtkFloatingPointType aTmp = vtkMath::Dot(theDirection,aBoundPoints[i]); - if(theMaxBoundPrj < aTmp){ - theMaxBoundPrj = aTmp; - aMaxId = i; - } - if(theMinBoundPrj > aTmp){ - theMinBoundPrj = aTmp; - aMinId = i; - } - } - vtkFloatingPointType *aMinPnt = aBoundPoints[aMaxId]; - theMinPnt[0] = aMinPnt[0]; - theMinPnt[1] = aMinPnt[1]; - theMinPnt[2] = aMinPnt[2]; -} - - -static void DistanceToPosition(vtkDataSet* theDataSet, - vtkFloatingPointType theDirection[3], vtkFloatingPointType theDist, vtkFloatingPointType thePos[3]) -{ - vtkFloatingPointType aMaxBoundPrj, aMinBoundPrj, aMinPnt[3]; - ComputeBoundsParam(theDataSet,theDirection,aMinPnt,aMaxBoundPrj,aMinBoundPrj); - vtkFloatingPointType aLength = (aMaxBoundPrj-aMinBoundPrj)*theDist; - thePos[0] = aMinPnt[0]-theDirection[0]*aLength; - thePos[1] = aMinPnt[1]-theDirection[1]*aLength; - thePos[2] = aMinPnt[2]-theDirection[2]*aLength; -} - - -static void PositionToDistance(vtkDataSet* theDataSet, - vtkFloatingPointType theDirection[3], vtkFloatingPointType thePos[3], vtkFloatingPointType& theDist) -{ - vtkFloatingPointType aMaxBoundPrj, aMinBoundPrj, aMinPnt[3]; - ComputeBoundsParam(theDataSet,theDirection,aMinPnt,aMaxBoundPrj,aMinBoundPrj); - vtkFloatingPointType aPrj = vtkMath::Dot(theDirection,thePos); - theDist = (aPrj-aMinBoundPrj)/(aMaxBoundPrj-aMinBoundPrj); -} - - -void SMESH_ActorDef::SetPlaneParam(vtkFloatingPointType theDir[3], vtkFloatingPointType theDist, vtkPlane* thePlane) -{ - thePlane->SetNormal(theDir); - vtkFloatingPointType anOrigin[3]; - ::DistanceToPosition(GetUnstructuredGrid(),theDir,theDist,anOrigin); - thePlane->SetOrigin(anOrigin); -} - - -void SMESH_ActorDef::GetPlaneParam(vtkFloatingPointType theDir[3], vtkFloatingPointType& theDist, vtkPlane* thePlane) -{ - thePlane->GetNormal(theDir); - - vtkFloatingPointType anOrigin[3]; - thePlane->GetOrigin(anOrigin); - ::PositionToDistance(GetUnstructuredGrid(),theDir,anOrigin,theDist); -} - void SMESH_ActorDef::UpdateScalarBar() { SUIT_ResourceMgr* mgr = SUIT_Session::session()->resourceMgr(); @@ -2004,6 +1939,21 @@ void SMESH_ActorDef::UpdateScalarBar() if( mgr->hasValue( "SMESH", "scalar_bar_num_colors" ) ) anIntVal = mgr->integerValue( "SMESH", "scalar_bar_num_colors", anIntVal ); myScalarBarActor->SetMaximumNumberOfColors( anIntVal == 0 ? 64 : anIntVal ); + + bool distributionVisibility = mgr->booleanValue("SMESH","distribution_visibility"); + myScalarBarActor->SetDistributionVisibility(distributionVisibility); + + int coloringType = mgr->integerValue("SMESH", "distribution_coloring_type", 0); + myScalarBarActor->SetDistributionColoringType(coloringType); + + QColor distributionColor = mgr->colorValue("SMESH", "distribution_color", + QColor(255, 255, 255)); + double rgb[3]; + rgb[0]= distributionColor.red()/255.; + rgb[1]= distributionColor.green()/255.; + rgb[2]= distributionColor.blue()/255.; + myScalarBarActor->SetDistributionColor(rgb); + } diff --git a/src/OBJECT/SMESH_Actor.h b/src/OBJECT/SMESH_Actor.h index bb4e2fb68..24a57a00a 100644 --- a/src/OBJECT/SMESH_Actor.h +++ b/src/OBJECT/SMESH_Actor.h @@ -31,13 +31,20 @@ #include #include "SMESH_Object.h" +#include + class vtkUnstructuredGrid; -class vtkScalarBarActor; +class SMESH_ScalarBarActor; class vtkPlane; class vtkImplicitBoolean; +namespace SMESH +{ + const vtkIdType DeleteActorEvent = vtkCommand::UserEvent + 100; +} + class SMESHOBJECT_EXPORT SMESH_Actor: public SALOME_Actor { static SMESH_Actor* New() { return NULL;} @@ -115,14 +122,13 @@ class SMESHOBJECT_EXPORT SMESH_Actor: public SALOME_Actor enum eControl{eNone, eLength, eLength2D, eFreeBorders, eFreeEdges, eFreeNodes, eFreeFaces, eMultiConnection, eArea, eTaper, eAspectRatio, - eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D}; + eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D, + eMaxElementLength2D, eMaxElementLength3D}; virtual void SetControlMode(eControl theMode) = 0; virtual eControl GetControlMode() = 0; + virtual SMESH::Controls::FunctorPtr GetFunctor() = 0; - virtual vtkScalarBarActor* GetScalarBarActor() = 0; - - virtual void SetPlaneParam(vtkFloatingPointType theDir[3], vtkFloatingPointType theDist, vtkPlane* thePlane) = 0; - virtual void GetPlaneParam(vtkFloatingPointType theDir[3], vtkFloatingPointType& theDist, vtkPlane* thePlane) = 0; + virtual SMESH_ScalarBarActor* GetScalarBarActor() = 0; virtual void RemoveAllClippingPlanes() = 0; virtual vtkIdType GetNumberOfClippingPlanes() = 0; diff --git a/src/OBJECT/SMESH_ActorDef.h b/src/OBJECT/SMESH_ActorDef.h index 0a740163b..09b2232f0 100644 --- a/src/OBJECT/SMESH_ActorDef.h +++ b/src/OBJECT/SMESH_ActorDef.h @@ -59,24 +59,20 @@ class vtkPolyDataMapper; class vtkUnstructuredGrid; class vtkMergeFilter; class vtkPolyData; - class vtkMapper; class vtkActor2D; class vtkMaskPoints; class vtkLabeledDataMapper; class vtkSelectVisiblePoints; - -class vtkScalarBarActor; class vtkLookupTable; - class vtkPlane; class vtkImplicitBoolean; - class vtkTimeStamp; class VTKViewer_CellCenters; class SMESH_DeviceActor; +class SMESH_ScalarBarActor; class SMESH_ActorDef : public SMESH_Actor @@ -185,11 +181,9 @@ class SMESH_ActorDef : public SMESH_Actor virtual void SetControlMode(eControl theMode); virtual eControl GetControlMode(){ return myControlMode;} + virtual SMESH::Controls::FunctorPtr GetFunctor() { return myFunctor; } - virtual vtkScalarBarActor* GetScalarBarActor(){ return myScalarBarActor;} - - virtual void SetPlaneParam(vtkFloatingPointType theDir[3], vtkFloatingPointType theDist, vtkPlane* thePlane); - virtual void GetPlaneParam(vtkFloatingPointType theDir[3], vtkFloatingPointType& theDist, vtkPlane* thePlane); + virtual SMESH_ScalarBarActor* GetScalarBarActor(){ return myScalarBarActor;} virtual void RemoveAllClippingPlanes(); virtual vtkIdType GetNumberOfClippingPlanes(); @@ -218,7 +212,7 @@ class SMESH_ActorDef : public SMESH_Actor TVisualObjPtr myVisualObj; vtkTimeStamp* myTimeStamp; - vtkScalarBarActor* myScalarBarActor; + SMESH_ScalarBarActor* myScalarBarActor; vtkLookupTable* myLookupTable; vtkProperty* mySurfaceProp; @@ -235,6 +229,7 @@ class SMESH_ActorDef : public SMESH_Actor SMESH_DeviceActor* myHighlitableActor; eControl myControlMode; + SMESH::Controls::FunctorPtr myFunctor; vtkProperty* my2DExtProp; SMESH_DeviceActor* my2DActor; SMESH_DeviceActor* my2DExtActor; diff --git a/src/OBJECT/SMESH_DeviceActor.cxx b/src/OBJECT/SMESH_DeviceActor.cxx index 4be8cadec..600a4987c 100644 --- a/src/OBJECT/SMESH_DeviceActor.cxx +++ b/src/OBJECT/SMESH_DeviceActor.cxx @@ -26,6 +26,7 @@ // Module : SMESH // #include "SMESH_DeviceActor.h" +#include "SMESH_ScalarBarActor.h" #include "SMESH_ExtractGeometry.h" #include "SMESH_ControlsDef.hxx" #include "SMESH_ActorUtils.h" @@ -48,7 +49,6 @@ #include #include -#include #include #include #include @@ -282,7 +282,7 @@ SMESH_DeviceActor void SMESH_DeviceActor ::SetControlMode(SMESH::Controls::FunctorPtr theFunctor, - vtkScalarBarActor* theScalarBarActor, + SMESH_ScalarBarActor* theScalarBarActor, vtkLookupTable* theLookupTable) { bool anIsInitialized = theFunctor; @@ -310,6 +310,12 @@ SMESH_DeviceActor double aValue = aNumericalFunctor->GetValue(anObjId); aScalars->SetValue(i,aValue); } + int nbIntervals = theScalarBarActor->GetMaximumNumberOfColors(); + std::vector nbEvents; + std::vector funValues; + aNumericalFunctor->GetHistogram(nbIntervals, nbEvents, funValues); + theScalarBarActor->SetDistribution(nbEvents); + }else if(Predicate* aPredicate = dynamic_cast(theFunctor.get())){ for(vtkIdType i = 0; i < aNbCells; i++){ vtkIdType anId = myExtractUnstructuredGrid->GetInputId(i); @@ -336,7 +342,7 @@ SMESH_DeviceActor void SMESH_DeviceActor ::SetExtControlMode(SMESH::Controls::FunctorPtr theFunctor, - vtkScalarBarActor* theScalarBarActor, + SMESH_ScalarBarActor* theScalarBarActor, vtkLookupTable* theLookupTable) { bool anIsInitialized = theFunctor; @@ -469,6 +475,16 @@ SMESH_DeviceActor myMergeFilter->SetScalars(aDataSet); aDataSet->Delete(); } + + //Set Distribution + if(NumericalFunctor* aNumericalFunctor = dynamic_cast(theFunctor.get())){ + int nbIntervals = theScalarBarActor->GetMaximumNumberOfColors(); + std::vector nbEvents; + std::vector funValues; + aNumericalFunctor->GetHistogram(nbIntervals, nbEvents, funValues); + theScalarBarActor->SetDistribution(nbEvents); + } + } GetMapper()->SetScalarVisibility(anIsInitialized); theScalarBarActor->SetVisibility(anIsInitialized); diff --git a/src/OBJECT/SMESH_DeviceActor.h b/src/OBJECT/SMESH_DeviceActor.h index 7c506bd38..1e598fa84 100644 --- a/src/OBJECT/SMESH_DeviceActor.h +++ b/src/OBJECT/SMESH_DeviceActor.h @@ -42,7 +42,6 @@ class vtkProperty; class vtkMergeFilter; class vtkShrinkFilter; class vtkUnstructuredGrid; -class vtkScalarBarActor; class vtkLookupTable; class vtkImplicitBoolean; class vtkPassThroughFilter; @@ -54,6 +53,7 @@ class VTKViewer_PolyDataMapper; class SMESH_ExtractGeometry; class SMESH_FaceOrientationFilter; +class SMESH_ScalarBarActor; class SMESHOBJECT_EXPORT SMESH_DeviceActor: public vtkLODActor{ @@ -120,10 +120,10 @@ class SMESHOBJECT_EXPORT SMESH_DeviceActor: public vtkLODActor{ vtkUnstructuredGrid* GetUnstructuredGrid(); void SetControlMode(SMESH::Controls::FunctorPtr theFunctor, - vtkScalarBarActor* theScalarBarActor, + SMESH_ScalarBarActor* theScalarBarActor, vtkLookupTable* theLookupTable); void SetExtControlMode(SMESH::Controls::FunctorPtr theFunctor, - vtkScalarBarActor* theScalarBarActor, + SMESH_ScalarBarActor* theScalarBarActor, vtkLookupTable* theLookupTable); void SetExtControlMode(SMESH::Controls::FunctorPtr theFunctor); diff --git a/src/OBJECT/SMESH_PreviewActorsCollection.cxx b/src/OBJECT/SMESH_PreviewActorsCollection.cxx index d014af78c..059edd927 100644 --- a/src/OBJECT/SMESH_PreviewActorsCollection.cxx +++ b/src/OBJECT/SMESH_PreviewActorsCollection.cxx @@ -35,7 +35,6 @@ // VTK includes #include -#include #include #include #include diff --git a/src/OBJECT/SMESH_ScalarBarActor.cxx b/src/OBJECT/SMESH_ScalarBarActor.cxx new file mode 100644 index 000000000..3f7622672 --- /dev/null +++ b/src/OBJECT/SMESH_ScalarBarActor.cxx @@ -0,0 +1,923 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 : SMESH_ScalarBarActor.cxx +// Author : Roman NIKOLAEV +// Module : SMESH +// + +#include "SMESH_ScalarBarActor.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SHRINK_COEF 0.08; + +vtkStandardNewMacro(SMESH_ScalarBarActor); + +vtkCxxSetObjectMacro(SMESH_ScalarBarActor,LookupTable,vtkScalarsToColors); +vtkCxxSetObjectMacro(SMESH_ScalarBarActor,LabelTextProperty,vtkTextProperty); +vtkCxxSetObjectMacro(SMESH_ScalarBarActor,TitleTextProperty,vtkTextProperty); + +//---------------------------------------------------------------------------- +// Instantiate object with 64 maximum colors; 5 labels; %%-#6.3g label +// format, no title, and vertical orientation. The initial scalar bar +// size is (0.05 x 0.8) of the viewport size. +SMESH_ScalarBarActor::SMESH_ScalarBarActor() { + this->LookupTable = NULL; + this->Position2Coordinate->SetValue(0.17, 0.8); + + this->PositionCoordinate->SetCoordinateSystemToNormalizedViewport(); + this->PositionCoordinate->SetValue(0.82,0.1); + + this->MaximumNumberOfColors = 64; + this->NumberOfLabels = 5; + this->NumberOfLabelsBuilt = 0; + this->Orientation = VTK_ORIENT_VERTICAL; + this->Title = NULL; + + this->LabelTextProperty = vtkTextProperty::New(); + this->LabelTextProperty->SetFontSize(12); + this->LabelTextProperty->SetBold(1); + this->LabelTextProperty->SetItalic(1); + this->LabelTextProperty->SetShadow(1); + this->LabelTextProperty->SetFontFamilyToArial(); + + this->TitleTextProperty = vtkTextProperty::New(); + this->TitleTextProperty->ShallowCopy(this->LabelTextProperty); + + this->LabelFormat = new char[8]; + sprintf(this->LabelFormat,"%s","%-#6.3g"); + + this->TitleMapper = vtkTextMapper::New(); + this->TitleActor = vtkActor2D::New(); + this->TitleActor->SetMapper(this->TitleMapper); + this->TitleActor->GetPositionCoordinate()-> + SetReferenceCoordinate(this->PositionCoordinate); + + this->TextMappers = NULL; + this->TextActors = NULL; + + this->ScalarBar = vtkPolyData::New(); + this->ScalarBarMapper = vtkPolyDataMapper2D::New(); + this->ScalarBarMapper->SetInput(this->ScalarBar); + this->ScalarBarActor = vtkActor2D::New(); + this->ScalarBarActor->SetMapper(this->ScalarBarMapper); + this->ScalarBarActor->GetPositionCoordinate()-> + SetReferenceCoordinate(this->PositionCoordinate); + this->LastOrigin[0] = 0; + this->LastOrigin[1] = 0; + this->LastSize[0] = 0; + this->LastSize[1] = 0; + + + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + myDistribution = vtkPolyData::New(); + myDistributionMapper = vtkPolyDataMapper2D::New(); + myDistributionMapper->SetInput(this->myDistribution); + + myDistributionActor = vtkActor2D::New(); + myDistributionActor->SetMapper(this->myDistributionMapper); + myDistributionActor->GetPositionCoordinate()-> + SetReferenceCoordinate(this->PositionCoordinate); + + // By default distribution histogram is invisible + myDistributionActor->SetVisibility(0); + + // By default monocolor + myDistributionColoringType = SMESH_MONOCOLOR_TYPE; + // rnv end +} + +//---------------------------------------------------------------------------- +// Release any graphics resources that are being consumed by this actor. +// The parameter window could be used to determine which graphic +// resources to release. +void SMESH_ScalarBarActor::ReleaseGraphicsResources(vtkWindow *win) +{ + this->TitleActor->ReleaseGraphicsResources(win); + if (this->TextMappers != NULL ) + { + for (int i=0; i < this->NumberOfLabelsBuilt; i++) + { + this->TextActors[i]->ReleaseGraphicsResources(win); + } + } + this->ScalarBarActor->ReleaseGraphicsResources(win); + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + myDistributionActor->ReleaseGraphicsResources(win); +} + + +/*--------------------------------------------------------------------------*/ +SMESH_ScalarBarActor::~SMESH_ScalarBarActor() { + if (this->LabelFormat) + { + delete [] this->LabelFormat; + this->LabelFormat = NULL; + } + + this->TitleMapper->Delete(); + this->TitleActor->Delete(); + + if (this->TextMappers != NULL ) + { + for (int i=0; i < this->NumberOfLabelsBuilt; i++) + { + this->TextMappers[i]->Delete(); + this->TextActors[i]->Delete(); + } + delete [] this->TextMappers; + delete [] this->TextActors; + } + + this->ScalarBar->Delete(); + this->ScalarBarMapper->Delete(); + this->ScalarBarActor->Delete(); + + if (this->Title) + { + delete [] this->Title; + this->Title = NULL; + } + + this->SetLookupTable(NULL); + this->SetLabelTextProperty(NULL); + this->SetTitleTextProperty(NULL); + + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram: + myDistribution->Delete(); + myDistributionMapper->Delete(); + myDistributionActor->Delete(); + // rnv end +} + +//---------------------------------------------------------------------------- +int SMESH_ScalarBarActor::RenderOverlay(vtkViewport *viewport) +{ + int renderedSomething = 0; + int i; + + // Everything is built, just have to render + if (this->Title != NULL) + { + renderedSomething += this->TitleActor->RenderOverlay(viewport); + } + this->ScalarBarActor->RenderOverlay(viewport); + this->myDistributionActor->RenderOverlay(viewport); + if( this->TextActors == NULL) + { + vtkWarningMacro(<<"Need a mapper to render a scalar bar"); + return renderedSomething; + } + + for (i=0; iNumberOfLabels; i++) + { + renderedSomething += this->TextActors[i]->RenderOverlay(viewport); + } + + renderedSomething = (renderedSomething > 0)?(1):(0); + + return renderedSomething; +} + + +//---------------------------------------------------------------------------- +int SMESH_ScalarBarActor::RenderOpaqueGeometry(vtkViewport *viewport) +{ + int renderedSomething = 0; + int i; + int size[2]; + + if (!this->LookupTable) + { + vtkWarningMacro(<<"Need a mapper to render a scalar bar"); + return 0; + } + + if (!this->TitleTextProperty) + { + vtkErrorMacro(<<"Need title text property to render a scalar bar"); + return 0; + } + + if (!this->LabelTextProperty) + { + vtkErrorMacro(<<"Need label text property to render a scalar bar"); + return 0; + } + + // Check to see whether we have to rebuild everything + int positionsHaveChanged = 0; + if (viewport->GetMTime() > this->BuildTime || + (viewport->GetVTKWindow() && + viewport->GetVTKWindow()->GetMTime() > this->BuildTime)) + { + // if the viewport has changed we may - or may not need + // to rebuild, it depends on if the projected coords chage + int *barOrigin; + barOrigin = this->PositionCoordinate->GetComputedViewportValue(viewport); + size[0] = + this->Position2Coordinate->GetComputedViewportValue(viewport)[0] - + barOrigin[0]; + size[1] = + this->Position2Coordinate->GetComputedViewportValue(viewport)[1] - + barOrigin[1]; + if (this->LastSize[0] != size[0] || + this->LastSize[1] != size[1] || + this->LastOrigin[0] != barOrigin[0] || + this->LastOrigin[1] != barOrigin[1]) + { + positionsHaveChanged = 1; + } + } + + // Check to see whether we have to rebuild everything + if (positionsHaveChanged || + this->GetMTime() > this->BuildTime || + this->LookupTable->GetMTime() > this->BuildTime || + this->LabelTextProperty->GetMTime() > this->BuildTime || + this->TitleTextProperty->GetMTime() > this->BuildTime) + { + vtkDebugMacro(<<"Rebuilding subobjects"); + + // Delete previously constructed objects + // + if (this->TextMappers != NULL ) + { + for (i=0; i < this->NumberOfLabelsBuilt; i++) + { + this->TextMappers[i]->Delete(); + this->TextActors[i]->Delete(); + } + delete [] this->TextMappers; + delete [] this->TextActors; + } + + // Build scalar bar object; determine its type + // + // is this a vtkLookupTable or a subclass of vtkLookupTable + // with its scale set to log + // NOTE: it's possible we could to without the 'lut' variable + // later in the code, but if the vtkLookupTableSafeDownCast operation + // fails for some reason, this code will break in new ways. So, the 'LUT' + // variable is used for this operation only + vtkLookupTable *LUT = vtkLookupTable::SafeDownCast( this->LookupTable ); + int isLogTable = 0; + if ( LUT ) + { + if ( LUT->GetScale() == VTK_SCALE_LOG10 ) + { + isLogTable = 1; + } + } + + // we hard code how many steps to display + vtkScalarsToColors *lut = this->LookupTable; + int numColors = this->MaximumNumberOfColors; + double *range = lut->GetRange(); + + int numPts = 2*(numColors + 1); + vtkPoints *pts = vtkPoints::New(); + pts->SetNumberOfPoints(numPts); + vtkCellArray *polys = vtkCellArray::New(); + polys->Allocate(polys->EstimateSize(numColors,4)); + vtkUnsignedCharArray *colors = vtkUnsignedCharArray::New(); + colors->SetNumberOfComponents(3); + colors->SetNumberOfTuples(numColors); + + + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + bool distrVisibility = (numColors == this->myNbValues.size()); + vtkPoints *distrPts; + vtkCellArray *distrPolys; + vtkUnsignedCharArray *distColors = 0; + int numDistrPts = 0, numPositiveVal=0, maxValue=0; + if(!distrVisibility) + vtkDebugMacro(<<" Distribution invisible, because numColors == this->myNbValues.size()"); + + if (distrVisibility && GetDistributionVisibility()) { + for( i=0 ;iSetNumberOfPoints(numDistrPts); + distrPolys->Allocate(distrPolys->EstimateSize(numPositiveVal,4)); + this->myDistribution->Initialize(); + this->myDistribution->SetPoints(distrPts); + this->myDistribution->SetPolys(distrPolys); + distrPts->Delete(); + distrPolys->Delete(); + if ( myDistributionColoringType == SMESH_MULTICOLOR_TYPE ) { + distColors = vtkUnsignedCharArray::New(); + distColors->SetNumberOfComponents(3); + distColors->SetNumberOfTuples(numPositiveVal); + this->myDistribution->GetCellData()->SetScalars(distColors); + distColors->Delete(); + } else if( myDistributionColoringType == SMESH_MONOCOLOR_TYPE ){ + this->myDistribution->GetCellData()->SetScalars(NULL); + } + } else { + myDistribution->Reset(); + } + // rnv end + + this->ScalarBarActor->SetProperty(this->GetProperty()); + this->ScalarBar->Initialize(); + this->ScalarBar->SetPoints(pts); + this->ScalarBar->SetPolys(polys); + this->ScalarBar->GetCellData()->SetScalars(colors); + pts->Delete(); polys->Delete(); colors->Delete(); + + // get the viewport size in display coordinates + int *barOrigin, barWidth, barHeight, distrHeight; + barOrigin = this->PositionCoordinate->GetComputedViewportValue(viewport); + size[0] = + this->Position2Coordinate->GetComputedViewportValue(viewport)[0] - + barOrigin[0]; + size[1] = + this->Position2Coordinate->GetComputedViewportValue(viewport)[1] - + barOrigin[1]; + this->LastOrigin[0] = barOrigin[0]; + this->LastOrigin[1] = barOrigin[1]; + this->LastSize[0] = size[0]; + this->LastSize[1] = size[1]; + + // Update all the composing objects + this->TitleActor->SetProperty(this->GetProperty()); + this->TitleMapper->SetInput(this->Title); + if (this->TitleTextProperty->GetMTime() > this->BuildTime) + { + // Shallow copy here so that the size of the title prop is not affected + // by the automatic adjustment of its text mapper's size (i.e. its + // mapper's text property is identical except for the font size + // which will be modified later). This allows text actors to + // share the same text property, and in that case specifically allows + // the title and label text prop to be the same. + this->TitleMapper->GetTextProperty()->ShallowCopy(this->TitleTextProperty); + this->TitleMapper->GetTextProperty()->SetJustificationToCentered(); + } + + // find the best size for the title font + int titleSize[2]; + this->SizeTitle(titleSize, size, viewport); + + // find the best size for the ticks + int labelSize[2]; + this->AllocateAndSizeLabels(labelSize, size, viewport,range); + this->NumberOfLabelsBuilt = this->NumberOfLabels; + + // generate points + double x[3]; x[2] = 0.0; + double delta, itemH, shrink; + if ( this->Orientation == VTK_ORIENT_VERTICAL ) { + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + double delimeter=0.0; + if(GetDistributionVisibility() && distrVisibility) { + delimeter=0.01*size[0]; //1 % from horizontal size of the full presentation size. + barWidth = size[0] - 4 - labelSize[0]; + distrHeight = barWidth/2; + } else { + barWidth = size[0] - 4 - labelSize[0]; + distrHeight = 0; + } + + barHeight = (int)(0.86*size[1]); + delta=(double)barHeight/numColors; + + for ( i=0; iSetPoint(2*i,x); + x[0] = barWidth; + pts->SetPoint(2*i+1,x); + } + + if(GetDistributionVisibility() && distrVisibility) { + // Distribution points + shrink = delta*SHRINK_COEF; + vtkIdType distPtsId=0; + vtkIdType distPtsIds[4]; + for(i=0; iSetPoint(distPtsId++,x); + + // second point of polygon (quadrangle) + x[0] = itemH; + distPtsIds[1] = distPtsId; + distrPts->SetPoint(distPtsId++,x); + + x[1] = i*delta+delta-shrink; + + // third point of polygon (quadrangle) + x[0] = 0; + distPtsIds[3] = distPtsId; + distrPts->SetPoint(distPtsId++,x); + + // fourth point of polygon (quadrangle) + x[0] = itemH; + distPtsIds[2] = distPtsId; + distrPts->SetPoint(distPtsId++,x); + + //Inser Quadrangle + distrPolys->InsertNextCell(4,distPtsIds); + } + } + } + } + // rnv end + else { + barWidth = size[0]; + + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + double coef1, delimeter=0.0; + if(GetDistributionVisibility() && distrVisibility) { + coef1=0.62; + distrHeight = (int)((coef1/2)*size[1]); + //delimeter between distribution diagram and scalar bar + delimeter=0.02*size[1]; + } + else { + coef1=0.4; + barHeight = (int)(coef1*size[1]); + distrHeight = 0; + } + + barHeight = (int)(coef1*size[1]); + + delta=(double)barWidth/numColors; + for (i=0; iSetPoint(2*i,x); + x[1] = distrHeight + delimeter; + pts->SetPoint(2*i+1,x); + } + + if(GetDistributionVisibility() && distrVisibility) { + // Distribution points + shrink = delta*SHRINK_COEF; + vtkIdType distPtsId=0; + vtkIdType distPtsIds[4]; + for(i=0; iSetPoint(distPtsId++,x); + + // second point of polygon (quadrangle) + x[0] = i*delta+shrink; + x[1] = itemH; + distPtsIds[3] = distPtsId; + distrPts->SetPoint(distPtsId++,x); + + // third point of polygon (quadrangle) + x[0] = i*delta+delta-shrink; + x[1] = 0; + distPtsIds[1] = distPtsId; + distrPts->SetPoint(distPtsId++,x); + + // fourth point of polygon (quadrangle) + x[0] = i*delta+delta-shrink; + x[1] = itemH; + distPtsIds[2] = distPtsId; + distrPts->SetPoint(distPtsId++,x); + + // Add polygon into poly data + distrPolys->InsertNextCell(4,distPtsIds); + } + } + } + // rnv end + } + + //polygons & cell colors + unsigned char *rgba, *rgb; + vtkIdType ptIds[4], dcCount=0; + for (i=0; iInsertNextCell(4,ptIds); + + if ( isLogTable ) + { + double rgbval = log10(range[0]) + + i*(log10(range[1])-log10(range[0]))/(numColors -1); + rgba = lut->MapValue(pow(10.0,rgbval)); + } + else + { + rgba = lut->MapValue(range[0] + (range[1] - range[0])* + ((double)i /(numColors-1.0))); + } + + rgb = colors->GetPointer(3*i); //write into array directly + rgb[0] = rgba[0]; + rgb[1] = rgba[1]; + rgb[2] = rgba[2]; + + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + if(myNbValues[i] && myDistributionColoringType == SMESH_MULTICOLOR_TYPE && GetDistributionVisibility() && distrVisibility) + { + rgb = distColors->GetPointer(3*dcCount); //write into array directly + rgb[0] = rgba[0]; + rgb[1] = rgba[1]; + rgb[2] = rgba[2]; + dcCount++; + } + } + + // Now position everything properly + // + double val; + if (this->Orientation == VTK_ORIENT_VERTICAL) + { + int sizeTextData[2]; + + // center the title + this->TitleActor->SetPosition(size[0]/2, 0.9*size[1]); + + for (i=0; i < this->NumberOfLabels; i++) + { + if (this->NumberOfLabels > 1) + { + val = (double)i/(this->NumberOfLabels-1) *barHeight; + } + else + { + val = 0.5*barHeight; + } + this->TextMappers[i]->GetSize(viewport,sizeTextData); + this->TextMappers[i]->GetTextProperty()->SetJustificationToLeft(); + this->TextActors[i]->SetPosition(barWidth+3, + val - sizeTextData[1]/2); + } + } + else + { + this->TitleActor->SetPosition(size[0]/2, + barHeight + labelSize[1] + 0.1*size[1]); + for (i=0; i < this->NumberOfLabels; i++) + { + this->TextMappers[i]->GetTextProperty()->SetJustificationToCentered(); + if (this->NumberOfLabels > 1) + { + val = (double)i/(this->NumberOfLabels-1) * barWidth; + } + else + { + val = 0.5*barWidth; + } + this->TextActors[i]->SetPosition(val, barHeight + 0.05*size[1]); + } + } + + this->BuildTime.Modified(); + } + + // Everything is built, just have to render + if (this->Title != NULL) + { + renderedSomething += this->TitleActor->RenderOpaqueGeometry(viewport); + } + this->ScalarBarActor->RenderOpaqueGeometry(viewport); + this->myDistributionActor->RenderOpaqueGeometry(viewport); + for (i=0; iNumberOfLabels; i++) + { + renderedSomething += this->TextActors[i]->RenderOpaqueGeometry(viewport); + } + + renderedSomething = (renderedSomething > 0)?(1):(0); + + return renderedSomething; +} + +//---------------------------------------------------------------------------- +void SMESH_ScalarBarActor::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); + + if ( this->LookupTable ) + { + os << indent << "Lookup Table:\n"; + this->LookupTable->PrintSelf(os,indent.GetNextIndent()); + } + else + { + os << indent << "Lookup Table: (none)\n"; + } + + if (this->TitleTextProperty) + { + os << indent << "Title Text Property:\n"; + this->TitleTextProperty->PrintSelf(os,indent.GetNextIndent()); + } + else + { + os << indent << "Title Text Property: (none)\n"; + } + + if (this->LabelTextProperty) + { + os << indent << "Label Text Property:\n"; + this->LabelTextProperty->PrintSelf(os,indent.GetNextIndent()); + } + else + { + os << indent << "Label Text Property: (none)\n"; + } + + os << indent << "Title: " << (this->Title ? this->Title : "(none)") << "\n"; + os << indent << "Maximum Number Of Colors: " + << this->MaximumNumberOfColors << "\n"; + os << indent << "Number Of Labels: " << this->NumberOfLabels << "\n"; + os << indent << "Number Of Labels Built: " << this->NumberOfLabelsBuilt << "\n"; + + os << indent << "Orientation: "; + if ( this->Orientation == VTK_ORIENT_HORIZONTAL ) + { + os << "Horizontal\n"; + } + else + { + os << "Vertical\n"; + } + + os << indent << "Label Format: " << this->LabelFormat << "\n"; +} + +//---------------------------------------------------------------------------- +void SMESH_ScalarBarActor::ShallowCopy(vtkProp *prop) +{ + SMESH_ScalarBarActor *a = SMESH_ScalarBarActor::SafeDownCast(prop); + if ( a != NULL ) + { + this->SetPosition2(a->GetPosition2()); + this->SetLookupTable(a->GetLookupTable()); + this->SetMaximumNumberOfColors(a->GetMaximumNumberOfColors()); + this->SetOrientation(a->GetOrientation()); + this->SetLabelTextProperty(a->GetLabelTextProperty()); + this->SetTitleTextProperty(a->GetTitleTextProperty()); + this->SetLabelFormat(a->GetLabelFormat()); + this->SetTitle(a->GetTitle()); + this->GetPositionCoordinate()->SetCoordinateSystem( + a->GetPositionCoordinate()->GetCoordinateSystem()); + this->GetPositionCoordinate()->SetValue( + a->GetPositionCoordinate()->GetValue()); + this->GetPosition2Coordinate()->SetCoordinateSystem( + a->GetPosition2Coordinate()->GetCoordinateSystem()); + this->GetPosition2Coordinate()->SetValue( + a->GetPosition2Coordinate()->GetValue()); + } + + // Now do superclass + this->vtkActor2D::ShallowCopy(prop); +} + +//---------------------------------------------------------------------------- +void SMESH_ScalarBarActor::AllocateAndSizeLabels(int *labelSize, + int *size, + vtkViewport *viewport, + double *range) +{ + labelSize[0] = labelSize[1] = 0; + + this->TextMappers = new vtkTextMapper * [this->NumberOfLabels]; + this->TextActors = new vtkActor2D * [this->NumberOfLabels]; + + char string[512]; + + double val; + int i; + + // TODO: this should be optimized, maybe by keeping a list of + // allocated mappers, in order to avoid creation/destruction of + // their underlying text properties (i.e. each time a mapper is + // created, text properties are created and shallow-assigned a font size + // which value might be "far" from the target font size). + + // is this a vtkLookupTable or a subclass of vtkLookupTable + // with its scale set to log + vtkLookupTable *LUT = vtkLookupTable::SafeDownCast( this->LookupTable ); + int isLogTable = 0; + if ( LUT ) + { + if ( LUT->GetScale() == VTK_SCALE_LOG10 ) + { + isLogTable = 1; + } + } + + for (i=0; i < this->NumberOfLabels; i++) + { + this->TextMappers[i] = vtkTextMapper::New(); + + if ( isLogTable ) + { + double lval; + if (this->NumberOfLabels > 1) + { + lval = log10(range[0]) + (double)i/(this->NumberOfLabels-1) * + (log10(range[1])-log10(range[0])); + } + else + { + lval = log10(range[0]) + 0.5*(log10(range[1])-log10(range[0])); + } + val = pow(10.0,lval); + } + else + { + if (this->NumberOfLabels > 1) + { + val = range[0] + + (double)i/(this->NumberOfLabels-1) * (range[1]-range[0]); + } + else + { + val = range[0] + 0.5*(range[1]-range[0]); + } + } + + sprintf(string, this->LabelFormat, val); + this->TextMappers[i]->SetInput(string); + + // Shallow copy here so that the size of the label prop is not affected + // by the automatic adjustment of its text mapper's size (i.e. its + // mapper's text property is identical except for the font size + // which will be modified later). This allows text actors to + // share the same text property, and in that case specifically allows + // the title and label text prop to be the same. + this->TextMappers[i]->GetTextProperty()->ShallowCopy( + this->LabelTextProperty); + + this->TextActors[i] = vtkActor2D::New(); + this->TextActors[i]->SetMapper(this->TextMappers[i]); + this->TextActors[i]->SetProperty(this->GetProperty()); + this->TextActors[i]->GetPositionCoordinate()-> + SetReferenceCoordinate(this->PositionCoordinate); + } + + if (this->NumberOfLabels) + { + int targetWidth, targetHeight; + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + bool distrVisibility = this->MaximumNumberOfColors == this->myNbValues.size(); + double coef; + if( GetDistributionVisibility() && distrVisibility ) + if(this->Orientation == VTK_ORIENT_VERTICAL) + coef = 0.4; + else + coef = 0.18; + else + if(this->Orientation == VTK_ORIENT_VERTICAL) + coef = 0.6; + else + coef=0.25; + + + if ( this->Orientation == VTK_ORIENT_VERTICAL ) + { + targetWidth = (int)(coef*size[0]); + targetHeight = (int)(0.86*size[1]/this->NumberOfLabels); + } + else + { + targetWidth = (int)(size[0]*0.8/this->NumberOfLabels); + targetHeight = (int)(coef*size[1]); + } + // rnv end + + vtkTextMapper::SetMultipleConstrainedFontSize(viewport, + targetWidth, + targetHeight, + this->TextMappers, + this->NumberOfLabels, + labelSize); + } +} + +//---------------------------------------------------------------------------- +void SMESH_ScalarBarActor::SizeTitle(int *titleSize, + int *size, + vtkViewport *viewport) +{ + titleSize[0] = titleSize[1] = 0; + + if (this->Title == NULL || !strlen(this->Title)) + { + return; + } + + int targetWidth, targetHeight; + + targetWidth = size[0]; + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + bool distrVisibility = this->MaximumNumberOfColors == this->myNbValues.size(); + double coef; + if( GetDistributionVisibility() && distrVisibility ) + coef=0.18; + else + coef=0.25; + + if ( this->Orientation == VTK_ORIENT_VERTICAL ) + { + targetHeight = (int)(0.1*size[1]); + } + else + { + targetHeight = (int)(coef*size[1]); + } + + this->TitleMapper->SetConstrainedFontSize( + viewport, targetWidth, targetHeight); + + this->TitleMapper->GetSize(viewport, titleSize); +} + + +/*--------------------------------------------------------------------------*/ +void SMESH_ScalarBarActor::SetDistributionVisibility(int flag) { + myDistributionActor->SetVisibility(flag); + Modified(); +} + + +/*--------------------------------------------------------------------------*/ +int SMESH_ScalarBarActor::GetDistributionVisibility() { + return myDistributionActor->GetVisibility(); +} + + +void SMESH_ScalarBarActor::SetDistribution(std::vector theNbValues) { + myNbValues = theNbValues; +} + + +void SMESH_ScalarBarActor::SetDistributionColor (double rgb[3]) { + myDistributionActor->GetProperty()->SetColor(rgb); + Modified(); +} + +void SMESH_ScalarBarActor::GetDistributionColor (double rgb[3]) { + myDistributionActor->GetProperty()->GetColor(rgb); +} diff --git a/src/OBJECT/SMESH_ScalarBarActor.h b/src/OBJECT/SMESH_ScalarBarActor.h new file mode 100644 index 000000000..0f895cd57 --- /dev/null +++ b/src/OBJECT/SMESH_ScalarBarActor.h @@ -0,0 +1,246 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 SCALAR BAR : 2D Actor for the visualization scalar bar with the distribution diagram +// it is customized vtkScalarBarActor. +// File : SMESH_ScalarBarActor.h +// Author : Roman NIKOLAEV +// Module : SMESH + + +// .NAME vtkScalarBarActor - Create a scalar bar with labels +// .SECTION Description +// vtkScalarBarActor creates a scalar bar with annotation text. A scalar +// bar is a legend that indicates to the viewer the correspondence between +// color value and data value. The legend consists of a rectangular bar +// made of rectangular pieces each colored a constant value. Since +// vtkScalarBarActor is a subclass of vtkActor2D, it is drawn in the image +// plane (i.e., in the renderer's viewport) on top of the 3D graphics window. +// +// To use vtkScalarBarActor you must associate a vtkScalarsToColors (or +// subclass) with it. The lookup table defines the colors and the +// range of scalar values used to map scalar data. Typically, the +// number of colors shown in the scalar bar is not equal to the number +// of colors in the lookup table, in which case sampling of +// the lookup table is performed. +// +// Other optional capabilities include specifying the fraction of the +// viewport size (both x and y directions) which will control the size +// of the scalar bar and the number of annotation labels. The actual position +// of the scalar bar on the screen is controlled by using the +// vtkActor2D::SetPosition() method (by default the scalar bar is +// centered in the viewport). Other features include the ability to +// orient the scalar bar horizontally of vertically and controlling +// the format (printf style) with which to print the labels on the +// scalar bar. Also, the vtkScalarBarActor's property is applied to +// the scalar bar and annotation (including layer, and +// compositing operator). +// +// Set the text property/attributes of the title and the labels through the +// vtkTextProperty objects associated to this actor. +// +// .SECTION Caveats +// If a vtkLogLookupTable is specified as the lookup table to use, then the +// labels are created using a logarithmic scale. +// +// .SECTION See Also +// vtkActor2D vtkTextProperty vtkTextMapper vtkPolyDataMapper2D + +#ifndef SMESH_SCALAR_BAR_ACTOR_H +#define SMESH_SCALAR_BAR_ACTOR_H + +#include + +#include + +#include + +class vtkPolyData; +class vtkPolyDataMapper2D; +class vtkScalarsToColors; +class vtkTextMapper; +class vtkTextProperty; + +#define VTK_ORIENT_HORIZONTAL 0 +#define VTK_ORIENT_VERTICAL 1 + +#define SMESH_MONOCOLOR_TYPE 0 +#define SMESH_MULTICOLOR_TYPE 1 + + +class SMESHOBJECT_EXPORT SMESH_ScalarBarActor: public vtkActor2D { + public: + void PrintSelf(ostream& os, vtkIndent indent); + + vtkTypeMacro(SMESH_ScalarBarActor,vtkActor2D); + + // Description: + // Instantiate object with 64 maximum colors; 5 labels; %%-#6.3g label + // format, no title, and vertical orientation. The initial scalar bar + // size is (0.05 x 0.8) of the viewport size. + static SMESH_ScalarBarActor *New(); + + // Description: + // Draw the scalar bar and annotation text to the screen. + int RenderOpaqueGeometry(vtkViewport* viewport); + int RenderTranslucentGeometry(vtkViewport*) { return 0; }; + int RenderOverlay(vtkViewport* viewport); + + // Description: + // Release any graphics resources that are being consumed by this actor. + // The parameter window could be used to determine which graphic + // resources to release. + virtual void ReleaseGraphicsResources(vtkWindow *); + + // Description: + // Set/Get the vtkLookupTable to use. The lookup table specifies the number + // of colors to use in the table (if not overridden), as well as the scalar + // range. + virtual void SetLookupTable(vtkScalarsToColors*); + vtkGetObjectMacro(LookupTable,vtkScalarsToColors); + + // Description: + // Set/Get the maximum number of scalar bar segments to show. This may + // differ from the number of colors in the lookup table, in which case + // the colors are samples from the lookup table. + vtkSetClampMacro(MaximumNumberOfColors, int, 2, VTK_LARGE_INTEGER); + vtkGetMacro(MaximumNumberOfColors, int); + + // Description: + // Set/Get the number of annotation labels to show. + vtkSetClampMacro(NumberOfLabels, int, 0, 64); + vtkGetMacro(NumberOfLabels, int); + + // Description: + // Control the orientation of the scalar bar. + vtkSetClampMacro(Orientation,int,VTK_ORIENT_HORIZONTAL, VTK_ORIENT_VERTICAL); + vtkGetMacro(Orientation, int); + void SetOrientationToHorizontal() + {this->SetOrientation(VTK_ORIENT_HORIZONTAL);}; + void SetOrientationToVertical() {this->SetOrientation(VTK_ORIENT_VERTICAL);}; + + // Description: + // Set/Get the title text property. + virtual void SetTitleTextProperty(vtkTextProperty *p); + vtkGetObjectMacro(TitleTextProperty,vtkTextProperty); + + // Description: + // Set/Get the labels text property. + virtual void SetLabelTextProperty(vtkTextProperty *p); + vtkGetObjectMacro(LabelTextProperty,vtkTextProperty); + + // Description: + // Set/Get the format with which to print the labels on the scalar + // bar. + vtkSetStringMacro(LabelFormat); + vtkGetStringMacro(LabelFormat); + + // Description: + // Set/Get the title of the scalar bar actor, + vtkSetStringMacro(Title); + vtkGetStringMacro(Title); + + // Description: + // Shallow copy of a scalar bar actor. Overloads the virtual vtkProp method. + void ShallowCopy(vtkProp *prop); + + // Description: + // Set visibility of the distribution histogram + // rnv: Customization of the vtkScalarBarActor to show distribution histogram: + virtual void SetDistributionVisibility(int flag); + + // Description: + // Set visibility of the distribution histogram + // rnv: Customization of the vtkScalarBarActor to show distribution histogram: + virtual int GetDistributionVisibility(); + // Description: + // Set distribution + virtual void SetDistribution(std::vector theNbValues); + + // Description: + // Set distribution coloring type (SMESH_MONOCOLOR_TYPE or SMESH_MULTICOLOR_TYPE) + void SetDistributionColoringType(int theDistributionColoringType) {myDistributionColoringType = theDistributionColoringType;Modified();} + + // Description: + // Get distribution coloring type ((SMESH_MONOCOLOR_TYPE or SMESH_MULTICOLOR_TYPE)) + int GetDistributionColoringType() {return myDistributionColoringType;} + + // Description: + // Set Distribution Color + void SetDistributionColor (double rgb[3]); + + // Description: + // Get Distribution Color + void GetDistributionColor (double rgb[3]); + + + + protected: + SMESH_ScalarBarActor(); + ~SMESH_ScalarBarActor(); + + vtkScalarsToColors *LookupTable; + vtkTextProperty *TitleTextProperty; + vtkTextProperty *LabelTextProperty; + + int MaximumNumberOfColors; + int NumberOfLabels; + int NumberOfLabelsBuilt; + int Orientation; + char *Title; + char *LabelFormat; + + vtkTextMapper **TextMappers; + virtual void AllocateAndSizeLabels(int *labelSize, int *size, + vtkViewport *viewport, double *range); + + + + private: + vtkTextMapper *TitleMapper; + vtkActor2D *TitleActor; + + vtkActor2D **TextActors; + + vtkPolyData *ScalarBar; + vtkPolyDataMapper2D *ScalarBarMapper; + vtkActor2D *ScalarBarActor; + + vtkTimeStamp BuildTime; + int LastSize[2]; + int LastOrigin[2]; + + void SizeTitle(int *titleSize, int *size, vtkViewport *viewport); + + // rnv: Customization of the vtkScalarBarActor to show distribution histogram: + vtkPolyData* myDistribution; //Distribution polygonal data + vtkActor2D* myDistributionActor; //Distribution actor + vtkPolyDataMapper2D* myDistributionMapper; //Distribution mapper + std::vector myNbValues; //Nb values for the range + int myDistributionColoringType; //Distribution color type (monocolor or multicolor) + + private: + SMESH_ScalarBarActor(const SMESH_ScalarBarActor&); // Not implemented. + void operator=(const SMESH_ScalarBarActor&); // Not implemented. +}; + +#endif //SMESH_SCALAR_BAR_ACTOR_H diff --git a/src/SMDS/SMDS_MeshElement.hxx b/src/SMDS/SMDS_MeshElement.hxx index 938abf0b2..593b7fe00 100644 --- a/src/SMDS/SMDS_MeshElement.hxx +++ b/src/SMDS/SMDS_MeshElement.hxx @@ -69,7 +69,7 @@ public: ///Return the type of the current element virtual SMDSAbs_ElementType GetType() const = 0; - virtual bool IsPoly() const { return false; }; + virtual bool IsPoly() const { return false; } virtual bool IsQuadratic() const; //! Return type of entity virtual SMDSAbs_EntityType GetEntityType() const = 0; diff --git a/src/SMESH/SMESH_Algo.hxx b/src/SMESH/SMESH_Algo.hxx index 03c0b7bdb..83b34c3a9 100644 --- a/src/SMESH/SMESH_Algo.hxx +++ b/src/SMESH/SMESH_Algo.hxx @@ -86,14 +86,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); @@ -236,7 +236,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); @@ -323,7 +323,8 @@ public: */ static std::vector< const SMDS_MeshNode*> GetCommonNodes(const SMDS_MeshElement* e1, const SMDS_MeshElement* e2); -protected: + + protected: /*! * \brief store error and comment and then return ( error == COMPERR_OK ) diff --git a/src/SMESH/SMESH_Group.cxx b/src/SMESH/SMESH_Group.cxx index 4d88aed63..b2f5a125d 100644 --- a/src/SMESH/SMESH_Group.cxx +++ b/src/SMESH/SMESH_Group.cxx @@ -63,5 +63,5 @@ SMESH_Group::SMESH_Group (int theID, SMESH_Group::~SMESH_Group () { - delete myGroupDS; + delete myGroupDS; myGroupDS=0; } diff --git a/src/SMESH/SMESH_Group.hxx b/src/SMESH/SMESH_Group.hxx index 8d942bce4..c3e62ad2a 100644 --- a/src/SMESH/SMESH_Group.hxx +++ b/src/SMESH/SMESH_Group.hxx @@ -24,7 +24,6 @@ // File : SMESH_Group.hxx // Author : Michael Sazonov (OCC) // Module : SMESH -// $Header$ // #ifndef _SMESH_Group_HeaderFile #define _SMESH_Group_HeaderFile diff --git a/src/SMESH/SMESH_HypoFilter.hxx b/src/SMESH/SMESH_HypoFilter.hxx index c2ad8b753..e7c7c274b 100644 --- a/src/SMESH/SMESH_HypoFilter.hxx +++ b/src/SMESH/SMESH_HypoFilter.hxx @@ -77,6 +77,8 @@ class SMESH_EXPORT SMESH_HypoFilter: public SMESH_HypoPredicate static SMESH_HypoPredicate* HasDim(const int theDim); static SMESH_HypoPredicate* HasType(const int theHypType); + bool IsEmpty() const { return myPredicates.empty(); } + /*! * \brief check aHyp or/and aShape it is assigned to */ diff --git a/src/SMESH/SMESH_Hypothesis.cxx b/src/SMESH/SMESH_Hypothesis.cxx index 8210f156d..9ababf9e4 100644 --- a/src/SMESH/SMESH_Hypothesis.cxx +++ b/src/SMESH/SMESH_Hypothesis.cxx @@ -151,6 +151,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; +} + //============================================================================= /*! * diff --git a/src/SMESH/SMESH_Hypothesis.hxx b/src/SMESH/SMESH_Hypothesis.hxx index 1eb5ae8c8..82afd4bbc 100644 --- a/src/SMESH/SMESH_Hypothesis.hxx +++ b/src/SMESH/SMESH_Hypothesis.hxx @@ -114,6 +114,11 @@ 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; diff --git a/src/SMESH/SMESH_Mesh.cxx b/src/SMESH/SMESH_Mesh.cxx index d7fb290db..39c2ca976 100644 --- a/src/SMESH/SMESH_Mesh.cxx +++ b/src/SMESH/SMESH_Mesh.cxx @@ -101,6 +101,7 @@ SMESH_Mesh::SMESH_Mesh(int theLocalId, _isAutoColor = false; _isModified = false; _shapeDiagonal = 0.0; + _rmGroupCallUp = 0; _myMeshDS->ShapeToMesh( PseudoShape() ); } @@ -126,6 +127,9 @@ SMESH_Mesh::~SMESH_Mesh() delete aGroup; } _mapGroup.clear(); + + if ( _rmGroupCallUp) delete _rmGroupCallUp; + _rmGroupCallUp = 0; } //============================================================================= @@ -267,6 +271,7 @@ void SMESH_Mesh::Clear() while ( smIt->more() ) { sm = smIt->next(); sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); // for event listeners (issue 0020918) } } _isModified = false; @@ -973,7 +978,7 @@ void SMESH_Mesh::NotifySubMeshesHypothesisModification(const SMESH_Hypothesis* h } } } - HasModificationsToDiscard(); // to reset _isModified flag if mesh become empty + HasModificationsToDiscard(); // to reset _isModified flag if mesh becomes empty } //============================================================================= @@ -1413,6 +1418,18 @@ list SMESH_Mesh::GetGroupIds() const return anIds; } +//================================================================================ +/*! + * \brief Set a caller of RemoveGroup() at level of CORBA API implementation. + * The set upCaller will be deleted by SMESH_Mesh + */ +//================================================================================ + +void SMESH_Mesh::SetRemoveGroupCallUp( TRmGroupCallUp* upCaller ) +{ + if ( _rmGroupCallUp ) delete _rmGroupCallUp; + _rmGroupCallUp = upCaller; +} //============================================================================= /*! @@ -1420,13 +1437,16 @@ 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 (_rmGroupCallUp) + _rmGroupCallUp->RemoveGroup( theGroupID ); + return true; } //======================================================================= diff --git a/src/SMESH/SMESH_Mesh.hxx b/src/SMESH/SMESH_Mesh.hxx index ac504ced6..c88bbd02d 100644 --- a/src/SMESH/SMESH_Mesh.hxx +++ b/src/SMESH/SMESH_Mesh.hxx @@ -141,12 +141,14 @@ public: void ClearLog() throw(SALOME_Exception); - int GetId() { return _id; } + int GetId() const { return _id; } SMESHDS_Mesh * GetMeshDS() { return _myMeshDS; } - SMESH_Gen *GetGen() { return _gen; } + const SMESHDS_Mesh * GetMeshDS() const { return _myMeshDS; } + SMESH_Gen *GetGen() { return _gen; } + SMESH_subMesh *GetSubMesh(const TopoDS_Shape & aSubShape) throw(SALOME_Exception); @@ -266,10 +268,18 @@ public: SMESH_Group* GetGroup (const int theGroupID); - void RemoveGroup (const int theGroupID); + bool RemoveGroup (const int theGroupID); SMESH_Group* ConvertToStandalone ( int theGroupID ); + struct TRmGroupCallUp + { + virtual void RemoveGroup (const int theGroupID)=0; + virtual ~TRmGroupCallUp() {} + }; + void SetRemoveGroupCallUp( TRmGroupCallUp * upCaller ); + + SMDSAbs_ElementType GetElementType( const int id, const bool iselem ); void ClearMeshOrder(); @@ -303,9 +313,9 @@ protected: std::list _subMeshesUsingHypothesisList; SMESHDS_Document * _myDocument; SMESHDS_Mesh * _myMeshDS; + SMESH_Gen * _gen; std::map _mapSubMesh; std::map _mapGroup; - SMESH_Gen * _gen; bool _isAutoColor; bool _isModified; //!< modified since last total re-compute, issue 0020693 @@ -316,6 +326,11 @@ protected: TListOfListOfInt _mySubMeshOrder; + // Struct calling RemoveGroup at CORBA API implementation level, used + // to make an upper level be consistent with a lower one when group removal + // is invoked by hyp modification + TRmGroupCallUp* _rmGroupCallUp; + protected: SMESH_Mesh() {}; SMESH_Mesh(const SMESH_Mesh&) {}; diff --git a/src/SMESH/SMESH_MesherHelper.cxx b/src/SMESH/SMESH_MesherHelper.cxx index b695e1276..bb96f0352 100644 --- a/src/SMESH/SMESH_MesherHelper.cxx +++ b/src/SMESH/SMESH_MesherHelper.cxx @@ -89,9 +89,16 @@ SMESH_MesherHelper::SMESH_MesherHelper(SMESH_Mesh& theMesh) SMESH_MesherHelper::~SMESH_MesherHelper() { - TID2Projector::iterator i_proj = myFace2Projector.begin(); - for ( ; i_proj != myFace2Projector.end(); ++i_proj ) - delete i_proj->second; + { + 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; + } } //======================================================================= @@ -517,8 +524,8 @@ GeomAPI_ProjectPointOnSurf& SMESH_MesherHelper::GetProjector(const TopoDS_Face& { Handle(Geom_Surface) surface = BRep_Tool::Surface( F,loc ); int faceID = GetMeshDS()->ShapeToIndex( F ); - TID2Projector& i2proj = const_cast< TID2Projector&>( myFace2Projector ); - TID2Projector::iterator i_proj = i2proj.find( faceID ); + 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 ); @@ -672,13 +679,23 @@ bool SMESH_MesherHelper::CheckNodeU(const TopoDS_Edge& E, if ( dist > tol ) { // u incorrect, project the node to the curve - GeomAPI_ProjectPointOnCurve projector( nodePnt, curve, f, l ); - if ( projector.NbPoints() < 1 ) + 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 ); + } + GeomAPI_ProjectPointOnCurve* projector = i_proj->second; + projector->Perform( nodePnt ); + if ( projector->NbPoints() < 1 ) { MESSAGE( "SMESH_MesherHelper::CheckNodeU() failed to project" ); return false; } - Quantity_Parameter U = projector.LowerDistanceParameter(); + Quantity_Parameter U = projector->LowerDistanceParameter(); u = double( U ); dist = nodePnt.Distance( curve->Value( U )); if ( distance ) *distance = dist; diff --git a/src/SMESH/SMESH_MesherHelper.hxx b/src/SMESH/SMESH_MesherHelper.hxx index 7af79e5cf..2f89ce789 100644 --- a/src/SMESH/SMESH_MesherHelper.hxx +++ b/src/SMESH/SMESH_MesherHelper.hxx @@ -42,6 +42,7 @@ #include class GeomAPI_ProjectPointOnSurf; +class GeomAPI_ProjectPointOnCurve; typedef std::map TLinkNodeMap; typedef std::map::iterator ItTLinkNode; @@ -232,7 +233,7 @@ public: 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, @@ -488,8 +489,10 @@ protected: double myPar1[2], myPar2[2]; // U and V bounds of a closed periodic surface int myParIndex; // bounds' index (1-U, 2-V, 3-both) - typedef std::map< int, GeomAPI_ProjectPointOnSurf* > TID2Projector; - TID2Projector myFace2Projector; + typedef std::map< int, GeomAPI_ProjectPointOnSurf* > TID2ProjectorOnSurf; + TID2ProjectorOnSurf myFace2Projector; + typedef std::map< int, GeomAPI_ProjectPointOnCurve* > TID2ProjectorOnCurve; + TID2ProjectorOnCurve myEdge2Projector; TopoDS_Shape myShape; SMESH_Mesh* myMesh; diff --git a/src/SMESH/SMESH_subMesh.cxx b/src/SMESH/SMESH_subMesh.cxx index 91993b332..69b33a94c 100644 --- a/src/SMESH/SMESH_subMesh.cxx +++ b/src/SMESH/SMESH_subMesh.cxx @@ -1000,9 +1000,12 @@ SMESH_Hypothesis::Hypothesis_Status if ( ret == SMESH_Hypothesis::HYP_OK && !algo->NeedDescretBoundary() && !algo->SupportSubmeshes()) { + TopoDS_Shape algoAssignedTo, otherAssignedTo; + gen->GetAlgo( *_father, _subShape, &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( *_father, i_sm->second->_subShape, &otherAssignedTo ) && + SMESH_MesherHelper::IsSubShape( /*sub=*/otherAssignedTo, /*main=*/algoAssignedTo )) ret = SMESH_Hypothesis::HYP_HIDING_ALGO; } } @@ -1544,6 +1547,8 @@ bool SMESH_subMesh::ComputeStateEngine(int event) switch (event) { case MODIF_ALGO_STATE: + if ( !IsEmpty() ) + ComputeStateEngine( CLEAN ); algo = gen->GetAlgo((*_father), _subShape); if (algo && !algo->NeedDescretBoundary()) CleanDependsOn(); // clean sub-meshes with event CLEAN diff --git a/src/SMESHDS/SMESHDS_Group.cxx b/src/SMESHDS/SMESHDS_Group.cxx index 46fc68259..e86089c8f 100644 --- a/src/SMESHDS/SMESHDS_Group.cxx +++ b/src/SMESHDS/SMESHDS_Group.cxx @@ -156,7 +156,7 @@ class MyGroupIterator: public SMDS_ElemIterator //purpose : //======================================================================= -SMDS_ElemIteratorPtr SMESHDS_Group::GetElements() +SMDS_ElemIteratorPtr SMESHDS_Group::GetElements() const { return SMDS_ElemIteratorPtr( new MyGroupIterator ( myGroup )); } diff --git a/src/SMESHDS/SMESHDS_Group.hxx b/src/SMESHDS/SMESHDS_Group.hxx index fc4bbc503..5538e1635 100644 --- a/src/SMESHDS/SMESHDS_Group.hxx +++ b/src/SMESHDS/SMESHDS_Group.hxx @@ -54,7 +54,7 @@ class SMESHDS_EXPORT SMESHDS_Group : public SMESHDS_GroupBase virtual bool Contains (const SMDS_MeshElement* elem); - virtual SMDS_ElemIteratorPtr GetElements(); + virtual SMDS_ElemIteratorPtr GetElements() const; bool Add (const int theID); diff --git a/src/SMESHDS/SMESHDS_GroupBase.hxx b/src/SMESHDS/SMESHDS_GroupBase.hxx index 9fefca27d..2782e8951 100644 --- a/src/SMESHDS/SMESHDS_GroupBase.hxx +++ b/src/SMESHDS/SMESHDS_GroupBase.hxx @@ -66,7 +66,7 @@ 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); // use it for iterations 1..Extent() diff --git a/src/SMESHDS/SMESHDS_GroupOnGeom.cxx b/src/SMESHDS/SMESHDS_GroupOnGeom.cxx index abd5d552b..aad0ee4f2 100644 --- a/src/SMESHDS/SMESHDS_GroupOnGeom.cxx +++ b/src/SMESHDS/SMESHDS_GroupOnGeom.cxx @@ -102,7 +102,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 )); } diff --git a/src/SMESHDS/SMESHDS_GroupOnGeom.hxx b/src/SMESHDS/SMESHDS_GroupOnGeom.hxx index bb6f0900d..1b4b5a924 100644 --- a/src/SMESHDS/SMESHDS_GroupOnGeom.hxx +++ b/src/SMESHDS/SMESHDS_GroupOnGeom.hxx @@ -51,7 +51,7 @@ class SMESHDS_EXPORT SMESHDS_GroupOnGeom: public SMESHDS_GroupBase virtual bool Contains (const SMDS_MeshElement* elem); - virtual SMDS_ElemIteratorPtr GetElements(); + virtual SMDS_ElemIteratorPtr GetElements() const; private: diff --git a/src/SMESHDS/SMESHDS_Mesh.cxx b/src/SMESHDS/SMESHDS_Mesh.cxx index 55c27411b..0ae03d0c5 100644 --- a/src/SMESHDS/SMESHDS_Mesh.cxx +++ b/src/SMESHDS/SMESHDS_Mesh.cxx @@ -61,6 +61,7 @@ SMESHDS_Mesh::SMESHDS_Mesh(int theMeshID, bool theIsEmbeddedMode): { myScript = new SMESHDS_Script(theIsEmbeddedMode); myCurSubMesh = 0; + SetPersistentId(theMeshID); } //======================================================================= @@ -69,6 +70,28 @@ bool SMESHDS_Mesh::IsEmbeddedMode() return myIsEmbeddedMode; } +//================================================================================ +/*! + * \brief Store ID persistent during lifecycle + */ +//================================================================================ + +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 : @@ -1247,6 +1270,17 @@ const TopoDS_Shape& SMESHDS_Mesh::IndexToShape(int ShapeIndex) const return nullShape; } +//================================================================================ +/*! + * \brief Return max index of sub-mesh + */ +//================================================================================ + +int SMESHDS_Mesh::MaxSubMeshIndex() const +{ + return myShapeIndexToSubMesh.empty() ? 0 : myShapeIndexToSubMesh.rbegin()->first; +} + //======================================================================= //function : ShapeToIndex //purpose : diff --git a/src/SMESHDS/SMESHDS_Mesh.hxx b/src/SMESHDS/SMESHDS_Mesh.hxx index b53c5e879..7e852c774 100644 --- a/src/SMESHDS/SMESHDS_Mesh.hxx +++ b/src/SMESHDS/SMESHDS_Mesh.hxx @@ -50,7 +50,7 @@ #include #include /* - * 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 "SMESHDS_DataMapOfShape.hxx" @@ -61,6 +61,8 @@ 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; @@ -423,6 +425,7 @@ public: 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); @@ -449,7 +452,7 @@ private: 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 { @@ -462,7 +465,7 @@ private: ShapeToHypothesis myShapeToHypothesis; - int myMeshID; + int myMeshID, myPersistentID; TopoDS_Shape myShape; typedef std::map TShapeIndexToSubMesh; diff --git a/src/SMESHFiltersSelection/SMESH_Type.h b/src/SMESHFiltersSelection/SMESH_Type.h index 4531a8760..89857d89c 100644 --- a/src/SMESHFiltersSelection/SMESH_Type.h +++ b/src/SMESHFiltersSelection/SMESH_Type.h @@ -52,6 +52,11 @@ enum MeshObjectType { SUBMESH_SOLID, SUBMESH_COMPOUND, GROUP, + GROUP_NODE, + GROUP_EDGE, + GROUP_FACE, + GROUP_VOLUME, + GROUP_0D, COMPONENT }; diff --git a/src/SMESHFiltersSelection/SMESH_TypeFilter.cxx b/src/SMESHFiltersSelection/SMESH_TypeFilter.cxx index bfede0418..1fbb37516 100644 --- a/src/SMESHFiltersSelection/SMESH_TypeFilter.cxx +++ b/src/SMESHFiltersSelection/SMESH_TypeFilter.cxx @@ -81,6 +81,7 @@ bool SMESH_TypeFilter::isOk (const SUIT_DataOwner* theDataOwner) const // 4 | |- Applied algorithms ( selectable in Use Case Browser ) // 5 | |- Regular 1D // |- Group Of Nodes + // |- Group 1 if (aLevel <= 0) return false; @@ -172,6 +173,36 @@ bool SMESH_TypeFilter::isOk (const SUIT_DataOwner* theDataOwner) const Ok = true; break; } + case GROUP_NODE: + { + if (aLevel == 3 && (objFather->Tag() == SMESH::Tag_NodeGroups)) + Ok = true; + break; + } + case GROUP_EDGE: + { + if (aLevel == 3 && (objFather->Tag() == SMESH::Tag_EdgeGroups)) + Ok = true; + break; + } + case GROUP_FACE: + { + if (aLevel == 3 && (objFather->Tag() == SMESH::Tag_FaceGroups)) + Ok = true; + break; + } + case GROUP_VOLUME: + { + if (aLevel == 3 && (objFather->Tag() == SMESH::Tag_VolumeGroups)) + Ok = true; + break; + } + case GROUP_0D: + { + if (aLevel == 3 && (objFather->Tag() == SMESH::Tag_VolumeGroups+1)) + Ok = true; + break; + } } } return Ok; diff --git a/src/SMESHGUI/Makefile.am b/src/SMESHGUI/Makefile.am index aef8dcfb4..7e7448f59 100644 --- a/src/SMESHGUI/Makefile.am +++ b/src/SMESHGUI/Makefile.am @@ -47,9 +47,8 @@ salomeinclude_HEADERS = \ SMESHGUI_GroupDlg.h \ SMESHGUI_RemoveNodesDlg.h \ SMESHGUI_RemoveElementsDlg.h \ - SMESHGUI_MeshInfosDlg.h \ - SMESHGUI_StandardMeshInfosDlg.h \ - SMESHGUI_WhatIsDlg.h \ + SMESHGUI_MeshInfo.h \ + SMESHGUI_Measurements.h \ SMESHGUI_Preferences_ColorDlg.h \ SMESHGUI_Preferences_ScalarBarDlg.h \ SMESHGUI_AddMeshElementDlg.h \ @@ -111,9 +110,8 @@ dist_libSMESH_la_SOURCES = \ SMESHGUI_GroupDlg.cxx \ SMESHGUI_RemoveNodesDlg.cxx \ SMESHGUI_RemoveElementsDlg.cxx \ - SMESHGUI_MeshInfosDlg.cxx \ - SMESHGUI_StandardMeshInfosDlg.cxx \ - SMESHGUI_WhatIsDlg.cxx \ + SMESHGUI_MeshInfo.cxx \ + SMESHGUI_Measurements.cxx \ SMESHGUI_Preferences_ColorDlg.cxx \ SMESHGUI_Preferences_ScalarBarDlg.cxx \ SMESHGUI_AddMeshElementDlg.cxx \ @@ -183,9 +181,8 @@ MOC_FILES = \ SMESHGUI_GroupDlg_moc.cxx \ SMESHGUI_RemoveNodesDlg_moc.cxx \ SMESHGUI_RemoveElementsDlg_moc.cxx \ - SMESHGUI_MeshInfosDlg_moc.cxx \ - SMESHGUI_StandardMeshInfosDlg_moc.cxx \ - SMESHGUI_WhatIsDlg_moc.cxx \ + SMESHGUI_MeshInfo_moc.cxx \ + SMESHGUI_Measurements_moc.cxx \ SMESHGUI_Preferences_ColorDlg_moc.cxx \ SMESHGUI_Preferences_ScalarBarDlg_moc.cxx \ SMESHGUI_AddMeshElementDlg_moc.cxx \ diff --git a/src/SMESHGUI/SMESHGUI.cxx b/src/SMESHGUI/SMESHGUI.cxx index 1efc41fd2..fdccc8737 100644 --- a/src/SMESHGUI/SMESHGUI.cxx +++ b/src/SMESHGUI/SMESHGUI.cxx @@ -48,7 +48,9 @@ #include "SMESHGUI_Hypotheses.h" #include "SMESHGUI_Make2DFrom3DOp.h" #include "SMESHGUI_MakeNodeAtPointDlg.h" -#include "SMESHGUI_MeshInfosDlg.h" +//#include "SMESHGUI_MeshInfosDlg.h" +#include "SMESHGUI_Measurements.h" +#include "SMESHGUI_MeshInfo.h" #include "SMESHGUI_MeshOp.h" #include "SMESHGUI_MeshOrderOp.h" #include "SMESHGUI_MeshPatternDlg.h" @@ -65,12 +67,12 @@ #include "SMESHGUI_SewingDlg.h" #include "SMESHGUI_SingleEditDlg.h" #include "SMESHGUI_SmoothingDlg.h" -#include "SMESHGUI_StandardMeshInfosDlg.h" +//#include "SMESHGUI_StandardMeshInfosDlg.h" #include "SMESHGUI_SymmetryDlg.h" #include "SMESHGUI_TranslationDlg.h" #include "SMESHGUI_ScaleDlg.h" #include "SMESHGUI_TransparencyDlg.h" -#include "SMESHGUI_WhatIsDlg.h" +//#include "SMESHGUI_WhatIsDlg.h" #include "SMESHGUI_DuplicateNodesDlg.h" #include "SMESHGUI_Utils.h" @@ -83,7 +85,9 @@ #include #include +#include #include +#include "SMESH_ControlsDef.hxx" // SALOME GUI includes #include @@ -120,19 +124,21 @@ #include #include CORBA_CLIENT_HEADER(SALOMEDS_Attributes) #include CORBA_CLIENT_HEADER(SMESH_MeshEditor) +#include CORBA_CLIENT_HEADER(SMESH_Measurements) // Qt includes // #define INCLUDE_MENUITEM_DEF // VSR commented ???????? #include +#include // BOOST includes #include // VTK includes -#include #include #include #include +#include // SALOME KERNEL includes #include @@ -173,14 +179,14 @@ std::string myExtension; if ( theCommandID == 113 ) { - filter.append( QObject::tr( "MED files (*.med)" ) ); - filter.append( QObject::tr( "All files (*)" ) ); + filter.append( QObject::tr( "MED_FILES_FILTER" ) + " (*.med)" ); + filter.append( QObject::tr( "ALL_FILES_FILTER" ) + " (*)" ); } else if ( theCommandID == 112 ) { - filter.append( QObject::tr( "IDEAS files (*.unv)" ) ); + filter.append( QObject::tr( "IDEAS_FILES_FILTER" ) + " (*.unv)" ); } else if ( theCommandID == 111 ) { - filter.append( QObject::tr( "DAT files (*.dat)" ) ); + filter.append( QObject::tr( "DAT_FILES_FILTER" ) + " (*.dat)" ); } QString anInitialPath = ""; @@ -333,7 +339,7 @@ QList aReservedColors; - QString aFilter, aTitle = QObject::tr("Export mesh"); + QString aFilter, aTitle = QObject::tr("SMESH_EXPORT_MESH"); QMap aFilterMap; QMap aFilterMapSTL; switch ( theCommandID ) { @@ -356,13 +362,13 @@ // PAL18696 QString v21 (aMesh->GetVersionString(SMESH::MED_V2_1, 2)); QString v22 (aMesh->GetVersionString(SMESH::MED_V2_2, 2)); - aFilterMap.insert( QString("MED ") + v21 + " (*.med)", SMESH::MED_V2_1 ); - aFilterMap.insert( QString("MED ") + v22 + " (*.med)", SMESH::MED_V2_2 ); + aFilterMap.insert( QObject::tr( "MED_VX_FILES_FILTER" ).arg( v21 ) + " (*.med)", SMESH::MED_V2_1 ); + aFilterMap.insert( QObject::tr( "MED_VX_FILES_FILTER" ).arg( v22 ) + " (*.med)", SMESH::MED_V2_2 ); } break; case 124: case 121: - aFilter = QObject::tr("DAT files (*.dat)"); + aFilter = QObject::tr( "DAT_FILES_FILTER" ) + " (*.dat)"; break; case 126: case 123: @@ -377,7 +383,7 @@ if (aRet != 0) return; } - aFilter = QObject::tr("IDEAS files (*.unv)"); + aFilter = QObject::tr( "IDEAS_FILES_FILTER" ) + " (*.unv)"; } break; case 140: @@ -405,8 +411,8 @@ return; } - aFilterMapSTL.insert( QObject::tr("STL ASCII (*.stl)"), 1 ); // 1 - ASCII mode - aFilterMapSTL.insert( QObject::tr("STL Binary (*.stl)"), 0 ); // 0 - Binary mode + aFilterMapSTL.insert( QObject::tr( "STL_ASCII_FILES_FILTER" ) + " (*.stl)", 1 ); // 1 - ASCII mode + aFilterMapSTL.insert( QObject::tr( "STL_BIN_FILES_FILTER" ) + " (*.stl)", 0 ); // 0 - Binary mode } break; default: @@ -441,7 +447,7 @@ SUIT_FileDlg* fd = new SUIT_FileDlg( SMESHGUI::desktop(), false, true, true ); fd->setWindowTitle( aTitle ); fd->setNameFilters( filters ); - fd->selectNameFilter( QObject::tr("STL ASCII (*.stl)") ); + fd->selectNameFilter( QObject::tr( "STL_ASCII_FILES_FILTER" ) + " (*.stl)" ); if ( !anInitialPath.isEmpty() ) fd->setDirectory( anInitialPath ); fd->selectFile(aMeshName); @@ -712,6 +718,121 @@ SMESH::RepaintCurrentView(); } + QString functorToString( SMESH::Controls::FunctorPtr f ) + { + QString type = QObject::tr( "UNKNOWN_CONTROL" ); + if ( dynamic_cast< SMESH::Controls::Volume* >( f.get() ) ) + type = QObject::tr( "VOLUME_3D_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::MaxElementLength2D* >( f.get() ) ) + type = QObject::tr( "MAX_ELEMENT_LENGTH_2D" ); + else if ( dynamic_cast< SMESH::Controls::MaxElementLength3D* >( f.get() ) ) + type = QObject::tr( "MAX_ELEMENT_LENGTH_3D" ); + else if ( dynamic_cast< SMESH::Controls::MinimumAngle* >( f.get() ) ) + type = QObject::tr( "MINIMUMANGLE_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::AspectRatio* >( f.get() ) ) + type = QObject::tr( "ASPECTRATIO_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::AspectRatio3D* >( f.get() ) ) + type = QObject::tr( "ASPECTRATIO_3D_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::Warping* >( f.get() ) ) + type = QObject::tr( "WARP_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::Taper* >( f.get() ) ) + type = QObject::tr( "TAPER_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::Skew* >( f.get() ) ) + type = QObject::tr( "SKEW_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::Area* >( f.get() ) ) + type = QObject::tr( "AREA_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::Length* >( f.get() ) ) + type = QObject::tr( "LENGTH_EDGES" ); + else if ( dynamic_cast< SMESH::Controls::Length2D* >( f.get() ) ) + type = QObject::tr( "LENGTH2D_EDGES" ); + else if ( dynamic_cast< SMESH::Controls::MultiConnection* >( f.get() ) ) + type = QObject::tr( "MULTI_BORDERS" ); + else if ( dynamic_cast< SMESH::Controls::MultiConnection2D* >( f.get() ) ) + type = QObject::tr( "MULTI2D_BORDERS" ); + else if ( dynamic_cast< SMESH::Controls::FreeNodes* >( f.get() ) ) + type = QObject::tr( "FREE_NODES" ); + else if ( dynamic_cast< SMESH::Controls::FreeEdges* >( f.get() ) ) + type = QObject::tr( "FREE_EDGES" ); + else if ( dynamic_cast< SMESH::Controls::FreeBorders* >( f.get() ) ) + type = QObject::tr( "FREE_BORDERS" ); + else if ( dynamic_cast< SMESH::Controls::FreeFaces* >( f.get() ) ) + type = QObject::tr( "FREE_FACES" ); + return type; + } + + void SaveDistribution() + { + LightApp_SelectionMgr* aSel = SMESHGUI::selectionMgr(); + SALOME_ListIO selected; + if ( aSel ) + aSel->selectedObjects( selected ); + + if ( selected.Extent() == 1 ) { + Handle(SALOME_InteractiveObject) anIO = selected.First(); + if ( anIO->hasEntry() ) { + SMESH_Actor* anActor = SMESH::FindActorByEntry( anIO->getEntry() ); + if ( anActor && anActor->GetScalarBarActor() && anActor->GetControlMode() != SMESH_Actor::eNone ) { + SMESH_ScalarBarActor* aScalarBarActor = anActor->GetScalarBarActor(); + SMESH::Controls::FunctorPtr aFunctor = anActor->GetFunctor(); + if ( aScalarBarActor && aFunctor ) { + SMESH::Controls::NumericalFunctor* aNumFun = dynamic_cast( aFunctor.get() ); + if ( aNumFun ) { + int nbRanges = aScalarBarActor->GetMaximumNumberOfColors(); + std::vector nbEvents; + std::vector funValues; + aNumFun->GetHistogram( nbRanges, nbEvents, funValues ); + QString anInitialPath = ""; + if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() ) + anInitialPath = QDir::currentPath(); + QString aMeshName = anIO->getName(); + QStringList filter; + filter.append( QObject::tr( "TEXT_FILES_FILTER" ) + " (*.txt)" ); + filter.append( QObject::tr( "ALL_FILES_FILTER" ) + " (*)" ); + QString aFilename = anInitialPath + "/" + aMeshName + "_" + + functorToString( aFunctor ).toLower().simplified().replace( QRegExp( " |-" ), "_" ) + ".txt"; + aFilename = SUIT_FileDlg::getFileName( SMESHGUI::desktop(), + aFilename, + filter, + QObject::tr( "SMESH_SAVE_DISTRIBUTION" ), + false ); + if ( !aFilename.isEmpty() ) { + QFile f( aFilename ); + if ( f.open( QFile::WriteOnly | QFile::Truncate ) ) { + QTextStream out( &f ); + out << "# Mesh: " << aMeshName << endl; + out << "# Control: " << functorToString( aFunctor ) << endl; + out << "#" << endl; + out.setFieldWidth( 10 ); + for ( int i = 0; i < qMin( nbEvents.size(), funValues.size()-1 ); i++ ) + out << funValues[i] << "\t" << funValues[i+1] << "\t" << nbEvents[i] << endl; + f.close(); + } + } + } + } + } + } + } + } + + void ShowDistribution() { + LightApp_SelectionMgr* aSel = SMESHGUI::selectionMgr(); + SALOME_ListIO selected; + if ( aSel ) + aSel->selectedObjects( selected ); + + if ( selected.Extent() == 1 ) { + Handle(SALOME_InteractiveObject) anIO = selected.First(); + if ( anIO->hasEntry() ) { + SMESH_Actor* anActor = SMESH::FindActorByEntry( anIO->getEntry() ); + if ( anActor && anActor->GetScalarBarActor() && anActor->GetControlMode() != SMESH_Actor::eNone ) { + SMESH_ScalarBarActor *aScalarBarActor = anActor->GetScalarBarActor(); + aScalarBarActor->SetDistributionVisibility(!aScalarBarActor->GetDistributionVisibility()); + } + } + } + } + void DisableAutoColor(){ LightApp_SelectionMgr *aSel = SMESHGUI::selectionMgr(); SALOME_ListIO selected; @@ -738,136 +859,144 @@ if( !aSel || !appStudy ) return; + if( theCommandID == 1134 ) { // Clipping dialog can be activated without selection + if( SMESHGUI* aModule = SMESHGUI::GetSMESHGUI() ) { + aModule->EmitSignalDeactivateDialog(); + if( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( aModule ) ) + (new SMESHGUI_ClippingDlg( aModule, aViewWindow ))->show(); + } + return; + } + _PTR(Study) aStudy = appStudy->studyDS(); aSel->selectedObjects( selected ); if(selected.Extent() >= 1){ switch(theCommandID){ - case 1134:{ - SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog(); - (new SMESHGUI_ClippingDlg( SMESHGUI::GetSMESHGUI() ))->show(); - return; - } case 1133:{ SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog(); (new SMESHGUI_TransparencyDlg( SMESHGUI::GetSMESHGUI() ))->show(); return; - }} - SALOME_ListIteratorOfListIO It( selected ); - for( ; It.More(); It.Next()){ - Handle(SALOME_InteractiveObject) IObject = It.Value(); - if(IObject->hasEntry()){ - if(SMESH_Actor *anActor = SMESH::FindActorByEntry(IObject->getEntry())){ - switch(theCommandID){ - case 211: - anActor->SetRepresentation(SMESH_Actor::eEdge); - break; - case 212: - anActor->SetRepresentation(SMESH_Actor::eSurface); - break; - case 213: - if(anActor->IsShrunk()) - anActor->UnShrink(); - else - anActor->SetShrink(); - break; - case 215: - anActor->SetRepresentation(SMESH_Actor::ePoint); - break; - case 231: - if(anActor->GetQuadratic2DRepresentation() != SMESH_Actor::eLines) - anActor->SetQuadratic2DRepresentation(SMESH_Actor::eLines); - break; - case 232: - if(anActor->GetQuadratic2DRepresentation() != SMESH_Actor::eArcs) - anActor->SetQuadratic2DRepresentation(SMESH_Actor::eArcs); - break; - case 1132:{ + } + case 1132:{ + QColor c, e, b, n, c0D, o; + int size0D = 0; + int Edgewidth = 0; + vtkFloatingPointType Shrink = 0.0; + vtkFloatingPointType faces_orientation_scale = 0.0; + bool faces_orientation_3dvectors = false; + + VTK::MarkerType aMarkerTypeCurrent = VTK::MT_NONE; + VTK::MarkerScale aMarkerScaleCurrent = VTK::MS_NONE; + int aMarkerTextureCurrent = 0; + + SALOME_ListIteratorOfListIO It( selected ); + for( ; It.More(); It.Next()){ + Handle(SALOME_InteractiveObject) IObject = It.Value(); + if(IObject->hasEntry()){ + if(SMESH_Actor *anActor = SMESH::FindActorByEntry(IObject->getEntry())){ vtkFloatingPointType color[3]; anActor->GetSufaceColor(color[0], color[1], color[2]); int c0 = int (color[0] * 255); int c1 = int (color[1] * 255); int c2 = int (color[2] * 255); - QColor c(c0, c1, c2); + c.setRgb(c0, c1, c2); vtkFloatingPointType edgecolor[3]; anActor->GetEdgeColor(edgecolor[0], edgecolor[1], edgecolor[2]); c0 = int (edgecolor[0] * 255); c1 = int (edgecolor[1] * 255); c2 = int (edgecolor[2] * 255); - QColor e(c0, c1, c2); + e.setRgb(c0, c1, c2); vtkFloatingPointType backfacecolor[3]; anActor->GetBackSufaceColor(backfacecolor[0], backfacecolor[1], backfacecolor[2]); c0 = int (backfacecolor[0] * 255); c1 = int (backfacecolor[1] * 255); c2 = int (backfacecolor[2] * 255); - QColor b(c0, c1, c2); + b.setRgb(c0, c1, c2); vtkFloatingPointType nodecolor[3]; anActor->GetNodeColor(nodecolor[0], nodecolor[1], nodecolor[2]); c0 = int (nodecolor[0] * 255); c1 = int (nodecolor[1] * 255); c2 = int (nodecolor[2] * 255); - QColor n(c0, c1, c2); + n.setRgb(c0, c1, c2); vtkFloatingPointType color0D[3]; anActor->Get0DColor(color0D[0], color0D[1], color0D[2]); c0 = int (color0D[0] * 255); c1 = int (color0D[1] * 255); c2 = int (color0D[2] * 255); - QColor c0D(c0, c1, c2); + c0D.setRgb(c0, c1, c2); - int size0D = (int)anActor->Get0DSize(); + size0D = (int)anActor->Get0DSize(); if(size0D == 0) size0D = 1; - int Edgewidth = (int)anActor->GetLineWidth(); + Edgewidth = (int)anActor->GetLineWidth(); if(Edgewidth == 0) Edgewidth = 1; - vtkFloatingPointType Shrink = anActor->GetShrinkFactor(); + Shrink = anActor->GetShrinkFactor(); vtkFloatingPointType faces_orientation_color[3]; anActor->GetFacesOrientationColor(faces_orientation_color); c0 = int (faces_orientation_color[0] * 255); c1 = int (faces_orientation_color[1] * 255); c2 = int (faces_orientation_color[2] * 255); - QColor o(c0, c1, c2); - - vtkFloatingPointType faces_orientation_scale = anActor->GetFacesOrientationScale(); - bool faces_orientation_3dvectors = anActor->GetFacesOrientation3DVectors(); - - SMESHGUI_Preferences_ColorDlg *aDlg = - new SMESHGUI_Preferences_ColorDlg( SMESHGUI::GetSMESHGUI() ); - aDlg->SetColor(1, c); - aDlg->SetColor(2, e); - aDlg->SetColor(3, n); - aDlg->SetColor(4, b); - aDlg->SetColor(5, c0D); - aDlg->SetColor(6, o); - aDlg->SetIntValue(1, Edgewidth); - aDlg->SetIntValue(2, int(Shrink*100.)); - aDlg->SetIntValue(3, size0D); - aDlg->SetDoubleValue(1, faces_orientation_scale); - aDlg->SetBooleanValue(1, faces_orientation_3dvectors); - - aDlg->setCustomMarkerMap( theMarkerMap[ aStudy->StudyId() ] ); - - VTK::MarkerType aMarkerTypeCurrent = anActor->GetMarkerType(); - VTK::MarkerScale aMarkerScaleCurrent = anActor->GetMarkerScale(); - int aMarkerTextureCurrent = anActor->GetMarkerTexture(); - if( aMarkerTypeCurrent != VTK::MT_USER ) - aDlg->setStandardMarker( aMarkerTypeCurrent, aMarkerScaleCurrent ); - else - aDlg->setCustomMarker( aMarkerTextureCurrent ); - - if(aDlg->exec()){ - QColor color = aDlg->GetColor(1); - QColor edgecolor = aDlg->GetColor(2); - QColor nodecolor = aDlg->GetColor(3); - QColor backfacecolor = aDlg->GetColor(4); - QColor color0D = aDlg->GetColor(5); - QColor faces_orientation_color = aDlg->GetColor(6); + o.setRgb(c0, c1, c2); + + faces_orientation_scale = anActor->GetFacesOrientationScale(); + faces_orientation_3dvectors = anActor->GetFacesOrientation3DVectors(); + + aMarkerTypeCurrent = anActor->GetMarkerType(); + aMarkerScaleCurrent = anActor->GetMarkerScale(); + aMarkerTextureCurrent = anActor->GetMarkerTexture(); + + // even if there are multiple objects in the selection, + // we need only the first one to get values for the dialog + break; + } + } + } + + SMESHGUI_Preferences_ColorDlg *aDlg = + new SMESHGUI_Preferences_ColorDlg( SMESHGUI::GetSMESHGUI() ); + aDlg->SetColor(1, c); + aDlg->SetColor(2, e); + aDlg->SetColor(3, n); + aDlg->SetColor(4, b); + aDlg->SetColor(5, c0D); + aDlg->SetColor(6, o); + aDlg->SetIntValue(1, Edgewidth); + aDlg->SetIntValue(2, int(Shrink*100.)); + aDlg->SetIntValue(3, size0D); + aDlg->SetDoubleValue(1, faces_orientation_scale); + aDlg->SetBooleanValue(1, faces_orientation_3dvectors); + + aDlg->setCustomMarkerMap( theMarkerMap[ aStudy->StudyId() ] ); + + if( aMarkerTypeCurrent != VTK::MT_USER ) + aDlg->setStandardMarker( aMarkerTypeCurrent, aMarkerScaleCurrent ); + else + aDlg->setCustomMarker( aMarkerTextureCurrent ); + + if(aDlg->exec()){ + QColor color = aDlg->GetColor(1); + QColor edgecolor = aDlg->GetColor(2); + QColor nodecolor = aDlg->GetColor(3); + QColor backfacecolor = aDlg->GetColor(4); + QColor color0D = aDlg->GetColor(5); + QColor faces_orientation_color = aDlg->GetColor(6); + + /* Point marker */ + theMarkerMap[ aStudy->StudyId() ] = aDlg->getCustomMarkerMap(); + + SALOME_ListIteratorOfListIO It( selected ); + for( ; It.More(); It.Next()){ + Handle(SALOME_InteractiveObject) IObject = It.Value(); + if(IObject->hasEntry()){ + if(SMESH_Actor *anActor = SMESH::FindActorByEntry(IObject->getEntry())){ /* actor color and backface color */ anActor->SetSufaceColor(vtkFloatingPointType (color.red()) / 255., vtkFloatingPointType (color.green()) / 255., @@ -904,9 +1033,6 @@ anActor->SetFacesOrientationScale(aDlg->GetDoubleValue(1)); anActor->SetFacesOrientation3DVectors(aDlg->GetBooleanValue(1)); - /* Point marker */ - theMarkerMap[ aStudy->StudyId() ] = aDlg->getCustomMarkerMap(); - VTK::MarkerType aMarkerTypeNew = aDlg->getMarkerType(); VTK::MarkerScale aMarkerScaleNew = aDlg->getStandardMarkerScale(); int aMarkerTextureNew = aDlg->getCustomMarkerID(); @@ -937,11 +1063,45 @@ aGroupColor.B = (float)aColor.blue() / 255.0; aGroupObject->SetColor( aGroupColor ); } - - delete aDlg; } + } + } + SMESH::RepaintCurrentView(); + } + delete aDlg; + return; + } + } + SALOME_ListIteratorOfListIO It( selected ); + for( ; It.More(); It.Next()){ + Handle(SALOME_InteractiveObject) IObject = It.Value(); + if(IObject->hasEntry()){ + if(SMESH_Actor *anActor = SMESH::FindActorByEntry(IObject->getEntry())){ + switch(theCommandID){ + case 211: + anActor->SetRepresentation(SMESH_Actor::eEdge); + break; + case 212: + anActor->SetRepresentation(SMESH_Actor::eSurface); + break; + case 213: + if(anActor->IsShrunk()) + anActor->UnShrink(); + else + anActor->SetShrink(); + break; + case 215: + anActor->SetRepresentation(SMESH_Actor::ePoint); + break; + case 231: + if(anActor->GetQuadratic2DRepresentation() != SMESH_Actor::eLines) + anActor->SetQuadratic2DRepresentation(SMESH_Actor::eLines); + break; + case 232: + if(anActor->GetQuadratic2DRepresentation() != SMESH_Actor::eArcs) + anActor->SetQuadratic2DRepresentation(SMESH_Actor::eArcs); break; - }} + } } } } @@ -959,77 +1119,66 @@ if( !selected.IsEmpty() ){ Handle(SALOME_InteractiveObject) anIO = selected.First(); if(!anIO.IsNull()){ - QString aTitle; SMESH_Actor::eControl aControl = SMESH_Actor::eNone; if(SMESH_Actor *anActor = SMESH::FindActorByEntry(anIO->getEntry())){ switch ( theCommandID ){ case 6001: - aTitle = QObject::tr( "LENGTH_EDGES" ); aControl = SMESH_Actor::eLength; break; case 6018: - aTitle = QObject::tr( "LENGTH2D_EDGES" ); aControl = SMESH_Actor::eLength2D; break; case 6002: - aTitle = QObject::tr( "FREE_EDGES" ); aControl = SMESH_Actor::eFreeEdges; break; case 6003: - aTitle = QObject::tr( "FREE_BORDERS" ); aControl = SMESH_Actor::eFreeBorders; break; case 6004: - aTitle = QObject::tr( "MULTI_BORDERS" ); aControl = SMESH_Actor::eMultiConnection; break; case 6005: - aTitle = QObject::tr( "FREE_NODES" ); aControl = SMESH_Actor::eFreeNodes; break; case 6019: - aTitle = QObject::tr( "MULTI2D_BORDERS" ); aControl = SMESH_Actor::eMultiConnection2D; break; case 6011: - aTitle = QObject::tr( "AREA_ELEMENTS" ); aControl = SMESH_Actor::eArea; break; case 6012: - aTitle = QObject::tr( "TAPER_ELEMENTS" ); aControl = SMESH_Actor::eTaper; break; case 6013: - aTitle = QObject::tr( "ASPECTRATIO_ELEMENTS" ); aControl = SMESH_Actor::eAspectRatio; break; case 6017: - aTitle = QObject::tr( "ASPECTRATIO_3D_ELEMENTS" ); aControl = SMESH_Actor::eAspectRatio3D; break; case 6014: - aTitle = QObject::tr( "MINIMUMANGLE_ELEMENTS" ); aControl = SMESH_Actor::eMinimumAngle; break; case 6015: - aTitle = QObject::tr( "WARP_ELEMENTS" ); aControl = SMESH_Actor::eWarping; break; case 6016: - aTitle = QObject::tr( "SKEW_ELEMENTS" ); aControl = SMESH_Actor::eSkew; break; case 6009: - aTitle = QObject::tr( "SMESH_VOLUME" ); aControl = SMESH_Actor::eVolume3D; break; case 6021: - aTitle = QObject::tr( "FREE_FACES" ); aControl = SMESH_Actor::eFreeFaces; break; + case 6022: + aControl = SMESH_Actor::eMaxElementLength2D; + break; + case 6023: + aControl = SMESH_Actor::eMaxElementLength3D; + break; } anActor->SetControlMode(aControl); - anActor->GetScalarBarActor()->SetTitle(aTitle.toLatin1().data()); + anActor->GetScalarBarActor()->SetTitle( functorToString( anActor->GetFunctor() ).toLatin1().constData() ); SMESH::RepaintCurrentView(); } } @@ -1296,8 +1445,15 @@ LightApp_Module( "SMESH" ) myState = -1; myDisplayer = 0; + myEventCallbackCommand = vtkCallbackCommand::New(); + myEventCallbackCommand->Delete(); + myEventCallbackCommand->SetClientData( this ); + myEventCallbackCommand->SetCallback( SMESHGUI::ProcessEvents ); + myPriority = 0.0; + SMESH::GetFilterManager(); SMESH::GetPattern(); + SMESH::GetMeasurements(); /* load resources for all available meshers */ SMESH::InitAvailableHypotheses(); @@ -1312,8 +1468,10 @@ SMESHGUI::~SMESHGUI() { #ifdef WITHGENERICOBJ SMESH::GetFilterManager()->Destroy(); + SMESH::GetMeasurements()->Destroy(); #endif SMESH::GetFilterManager() = SMESH::FilterManager::_nil(); + SMESH::GetMeasurements() = SMESH::Measurements::_nil(); } //============================================================================= @@ -1660,6 +1818,19 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) SMESHGUI_Preferences_ScalarBarDlg::ScalarBarProperties( this ); break; } + case 202: + { + // dump control distribution data to the text file + ::SaveDistribution(); + break; + } + + case 203: + { + // show/ distribution + ::ShowDistribution(); + break; + } // Auto-color case 1136: @@ -2238,7 +2409,9 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) } case 900: // MESH INFOS + case 903: // WHAT IS { + int page = theCommandID == 900 ? SMESHGUI_MeshInfoDlg::BaseInfo : SMESHGUI_MeshInfoDlg::ElemInfo; EmitSignalDeactivateDialog(); LightApp_SelectionMgr *aSel = SMESHGUI::selectionMgr(); SALOME_ListIO selected; @@ -2246,21 +2419,20 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) aSel->selectedObjects( selected ); if ( selected.Extent() > 1 ) { // a dlg for each IO - SALOME_ListIO IOs; - SALOME_ListIteratorOfListIO It (selected); + SALOME_ListIteratorOfListIO It( selected ); for ( ; It.More(); It.Next() ) { - IOs.Clear(); IOs.Append( It.Value() ); - aSel->setSelectedObjects( IOs ); - ( new SMESHGUI_MeshInfosDlg( this ) )->show(); + SMESHGUI_MeshInfoDlg* dlg = new SMESHGUI_MeshInfoDlg( SMESHGUI::desktop(), page ); + dlg->showInfo( It.Value() ); + dlg->show(); } - // restore selection - aSel->setSelectedObjects( selected ); } - else - ( new SMESHGUI_MeshInfosDlg( this ) )->show(); + else { + SMESHGUI_MeshInfoDlg* dlg = new SMESHGUI_MeshInfoDlg( SMESHGUI::desktop(), page ); + dlg->show(); + } break; } - + /* case 902: // STANDARD MESH INFOS { EmitSignalDeactivateDialog(); @@ -2285,13 +2457,13 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) ( new SMESHGUI_StandardMeshInfosDlg( this ) )->show(); break; } - case 903: // WHAT IS { EmitSignalDeactivateDialog(); ( new SMESHGUI_WhatIsDlg( this ) )->show(); break; } + */ case 904: // FIND ELEM { @@ -2786,6 +2958,8 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) case 6005: case 6009: case 6021: + case 6022: + case 6023: if ( vtkwnd ) { LightApp_SelectionMgr* mgr = selectionMgr(); @@ -2846,6 +3020,15 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) } break; } + case 501: + case 502: + { + int page = theCommandID == 501 ? SMESHGUI_MeasureDlg::MinDistance : SMESHGUI_MeasureDlg::BoundingBox; + EmitSignalDeactivateDialog(); + SMESHGUI_MeasureDlg* dlg = new SMESHGUI_MeasureDlg( SMESHGUI::desktop(), page ); + dlg->show(); + break; + } } anApp->updateActions(); //SRN: To update a Save button in the toolbar @@ -3010,12 +3193,14 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( 814, "UNDERLYING_ELEMS","ICON_UNDERLYING_ELEMS" ); createSMESHAction( 813, "DEL_GROUP", "ICON_DEL_GROUP" ); createSMESHAction( 900, "ADV_INFO", "ICON_ADV_INFO" ); - createSMESHAction( 902, "STD_INFO", "ICON_STD_INFO" ); + //createSMESHAction( 902, "STD_INFO", "ICON_STD_INFO" ); createSMESHAction( 903, "WHAT_IS", "ICON_WHAT_IS" ); createSMESHAction( 904, "FIND_ELEM", "ICON_FIND_ELEM" ); createSMESHAction( 6001, "LENGTH", "ICON_LENGTH", 0, true ); createSMESHAction( 6002, "FREE_EDGE", "ICON_FREE_EDGE", 0, true ); createSMESHAction( 6021, "FREE_FACES", "ICON_FREE_FACES", 0, true ); + createSMESHAction( 6022, "MAX_ELEMENT_LENGTH_2D", "ICON_MAX_ELEMENT_LENGTH_2D", 0, true ); + createSMESHAction( 6023, "MAX_ELEMENT_LENGTH_3D", "ICON_MAX_ELEMENT_LENGTH_3D", 0, true ); createSMESHAction( 6003, "FREE_BORDER", "ICON_FREE_EDGE_2D", 0, true ); createSMESHAction( 6004, "CONNECTION", "ICON_CONNECTION", 0, true ); createSMESHAction( 6005, "FREE_NODE", "ICON_FREE_NODE", 0, true ); @@ -3067,6 +3252,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( 419, "SPLIT_TO_TETRA", "ICON_SPLIT_TO_TETRA" ); createSMESHAction( 200, "RESET" ); createSMESHAction( 201, "SCALAR_BAR_PROP" ); + createSMESHAction( 202, "SAVE_DISTRIBUTION" ); + createSMESHAction( 203, "SHOW_DISTRIBUTION","",0, true ); createSMESHAction( 211, "WIRE", "ICON_WIRE", 0, true ); createSMESHAction( 212, "SHADE", "ICON_SHADE", 0, true ); createSMESHAction( 213, "SHRINK", "ICON_SHRINK", 0, true ); @@ -3096,6 +3283,9 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( 1137, "DISABLE_AUTO_COLOR" ); createSMESHAction( 2000, "CTRL" ); + createSMESHAction( 501, "MEASURE_MIN_DIST", "ICON_MEASURE_MIN_DIST" ); + createSMESHAction( 502, "MEASURE_BND_BOX", "ICON_MEASURE_BND_BOX" ); + createSMESHAction( 300, "ERASE" ); createSMESHAction( 301, "DISPLAY" ); createSMESHAction( 302, "DISPLAY_ONLY" ); @@ -3109,18 +3299,23 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( 4040, "QUADRATIC_HEXAHEDRON", "ICON_DLG_QUADRATIC_HEXAHEDRON" ); // ----- create menu -------------- - int fileId = createMenu( tr( "MEN_FILE" ), -1, 1 ), - editId = createMenu( tr( "MEN_EDIT" ), -1, 3 ), - toolsId = createMenu( tr( "MEN_TOOLS" ), -1, 5, 50 ), - meshId = createMenu( tr( "MEN_MESH" ), -1, 70, 10 ), - ctrlId = createMenu( tr( "MEN_CTRL" ), -1, 60, 10 ), - modifyId = createMenu( tr( "MEN_MODIFY" ), -1, 40, 10 ), - viewId = createMenu( tr( "MEN_VIEW" ), -1, 2 ); + int fileId = createMenu( tr( "MEN_FILE" ), -1, 1 ), + editId = createMenu( tr( "MEN_EDIT" ), -1, 3 ), + toolsId = createMenu( tr( "MEN_TOOLS" ), -1, 5, 50 ), + meshId = createMenu( tr( "MEN_MESH" ), -1, 70, 10 ), + ctrlId = createMenu( tr( "MEN_CTRL" ), -1, 60, 10 ), + modifyId = createMenu( tr( "MEN_MODIFY" ), -1, 40, 10 ), + measureId = createMenu( tr( "MEN_MEASURE" ), -1, 50, 10 ), + viewId = createMenu( tr( "MEN_VIEW" ), -1, 2 ); createMenu( separator(), fileId ); int importId = createMenu( tr( "MEN_IMPORT" ), fileId, -1, 10 ), exportId = createMenu( tr( "MEN_EXPORT" ), fileId, -1, 10 ), + nodeId = createMenu( tr( "MEN_NODE_CTRL" ), ctrlId, -1, 10 ), + edgeId = createMenu( tr( "MEN_EDGE_CTRL" ), ctrlId, -1, 10 ), + faceId = createMenu( tr( "MEN_FACE_CTRL" ), ctrlId, -1, 10 ), + volumeId = createMenu( tr( "MEN_VOLUME_CTRL" ), ctrlId, -1, 10 ), addId = createMenu( tr( "MEN_ADD" ), modifyId, 402 ), removeId = createMenu( tr( "MEN_REMOVE" ), modifyId, 403 ), renumId = createMenu( tr( "MEN_RENUM" ), modifyId, 404 ), @@ -3166,30 +3361,29 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( 813, meshId, -1 ); createMenu( separator(), meshId, -1 ); createMenu( 900, meshId, -1 ); - createMenu( 902, meshId, -1 ); + //createMenu( 902, meshId, -1 ); createMenu( 903, meshId, -1 ); createMenu( 904, meshId, -1 ); createMenu( separator(), meshId, -1 ); - createMenu( 6003, ctrlId, -1 ); - createMenu( 6001, ctrlId, -1 ); - createMenu( 6004, ctrlId, -1 ); - createMenu( separator(), ctrlId, -1 ); - createMenu( 6005, ctrlId, -1 ); - createMenu( 6002, ctrlId, -1 ); - createMenu( 6018, ctrlId, -1 ); - createMenu( 6019, ctrlId, -1 ); - createMenu( 6011, ctrlId, -1 ); - createMenu( 6012, ctrlId, -1 ); - createMenu( 6013, ctrlId, -1 ); - createMenu( 6014, ctrlId, -1 ); - createMenu( 6015, ctrlId, -1 ); - createMenu( 6016, ctrlId, -1 ); - createMenu( separator(), ctrlId, -1 ); - createMenu( 6017, ctrlId, -1 ); - createMenu( 6009, ctrlId, -1 ); - createMenu( 6021, ctrlId, -1 ); - createMenu( separator(), ctrlId, -1 ); + createMenu( 6005, nodeId, -1 ); + createMenu( 6002, edgeId, -1 ); + createMenu( 6003, edgeId, -1 ); + createMenu( 6001, edgeId, -1 ); + createMenu( 6004, edgeId, -1 ); + createMenu( 6021, faceId, -1 ); + createMenu( 6018, faceId, -1 ); + createMenu( 6019, faceId, -1 ); + createMenu( 6011, faceId, -1 ); + createMenu( 6012, faceId, -1 ); + createMenu( 6013, faceId, -1 ); + createMenu( 6014, faceId, -1 ); + createMenu( 6015, faceId, -1 ); + createMenu( 6016, faceId, -1 ); + createMenu( 6022, faceId, -1 ); + createMenu( 6017, volumeId, -1 ); + createMenu( 6009, volumeId, -1 ); + createMenu( 6023, volumeId, -1 ); createMenu( 4000, addId, -1 ); createMenu( 4009, addId, -1 ); @@ -3242,6 +3436,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( 417, modifyId, -1 ); createMenu( 418, modifyId, -1 ); + createMenu( 501, measureId, -1 ); + createMenu( 502, measureId, -1 ); createMenu( 214, viewId, -1 ); // ----- create toolbars -------------- @@ -3268,17 +3464,19 @@ void SMESHGUI::initialize( CAM_Application* app ) //createTool( 815, meshTb ); createTool( separator(), meshTb ); createTool( 900, meshTb ); - createTool( 902, meshTb ); + //createTool( 902, meshTb ); createTool( 903, meshTb ); createTool( 904, meshTb ); createTool( separator(), meshTb ); - createTool( 6001, ctrlTb ); + createTool( 6005, ctrlTb ); + createTool( separator(), ctrlTb ); + createTool( 6002, ctrlTb ); createTool( 6003, ctrlTb ); + createTool( 6001, ctrlTb ); createTool( 6004, ctrlTb ); createTool( separator(), ctrlTb ); - createTool( 6005, ctrlTb ); - createTool( 6002, ctrlTb ); + createTool( 6021, ctrlTb ); createTool( 6018, ctrlTb ); createTool( 6019, ctrlTb ); createTool( 6011, ctrlTb ); @@ -3287,10 +3485,11 @@ void SMESHGUI::initialize( CAM_Application* app ) createTool( 6014, ctrlTb ); createTool( 6015, ctrlTb ); createTool( 6016, ctrlTb ); + createTool( 6022, ctrlTb ); createTool( separator(), ctrlTb ); createTool( 6017, ctrlTb ); createTool( 6009, ctrlTb ); - createTool( 6021, ctrlTb ); + createTool( 6023, ctrlTb ); createTool( separator(), ctrlTb ); createTool( 4000, addRemTb ); @@ -3398,7 +3597,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createPopupItem( 713, OB, mesh, "&& isComputable" ); // MESH ORDER createPopupItem( 214, OB, mesh_group ); // UPDATE createPopupItem( 900, OB, mesh_group ); // ADV_INFO - createPopupItem( 902, OB, mesh ); // STD_INFO + //createPopupItem( 902, OB, mesh ); // STD_INFO createPopupItem( 903, OB, mesh_group ); // WHAT_IS createPopupItem( 904, OB, mesh_group ); // FIND_ELEM popupMgr()->insert( separator(), -1, 0 ); @@ -3434,7 +3633,7 @@ void SMESHGUI::initialize( CAM_Application* app ) popupMgr()->insert( separator(), -1, 0 ); createPopupItem( 214, View, mesh_group ); // UPDATE createPopupItem( 900, View, mesh_group ); // ADV_INFO - createPopupItem( 902, View, mesh ); // STD_INFO + //createPopupItem( 902, View, mesh ); // STD_INFO createPopupItem( 903, View, mesh_group ); // WHAT_IS createPopupItem( 904, View, mesh_group ); // FIND_ELEM popupMgr()->insert( separator(), -1, 0 ); @@ -3551,14 +3750,6 @@ void SMESHGUI::initialize( CAM_Application* app ) popupMgr()->insert( action( 1133 ), -1, -1 ); popupMgr()->setRule( action( 1133 ), aMeshInVTK + "&& isVisible", QtxPopupMgr::VisibleRule ); - //------------------------------------------------- - // Clipping - //------------------------------------------------- - popupMgr()->insert( action( 1134 ), -1, -1 ); - popupMgr()->setRule( action( 1134 ), aMeshInVTK + "&& selcount=1 && isVisible", QtxPopupMgr::VisibleRule ); - - popupMgr()->insert( separator(), -1, -1 ); - //------------------------------------------------- // Controls //------------------------------------------------- @@ -3575,80 +3766,102 @@ void SMESHGUI::initialize( CAM_Application* app ) popupMgr()->insert( separator(), anId, -1 ); - popupMgr()->insert( action( 6003 ), anId, -1 ); // FREE_BORDER + int aSubId = popupMgr()->insert( tr( "MEN_NODE_CTRL" ), anId, -1 ); // NODE CONTROLS + + popupMgr()->insert( action( 6005 ), aSubId, -1 ); // FREE_NODE + popupMgr()->setRule( action( 6005 ), aMeshInVtkHasNodes, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6005 ), "controlMode = 'eFreeNodes'", QtxPopupMgr::ToggleRule ); + + aSubId = popupMgr()->insert( tr( "MEN_EDGE_CTRL" ), anId, -1 ); // EDGE CONTROLS + + popupMgr()->insert( action( 6002 ), aSubId, -1 ); // FREE_EDGE + popupMgr()->setRule( action( 6002 ), aMeshInVtkHasEdges, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6002 ), "controlMode = 'eFreeEdges'", QtxPopupMgr::ToggleRule ); + + popupMgr()->insert( action( 6003 ), aSubId, -1 ); // FREE_BORDER popupMgr()->setRule( action( 6003 ), aMeshInVtkHasEdges, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6003 ), "controlMode = 'eFreeBorders'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6001 ), anId, -1 ); // LENGTH + popupMgr()->insert( action( 6001 ), aSubId, -1 ); // LENGTH popupMgr()->setRule( action( 6001 ), aMeshInVtkHasEdges, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6001 ), "controlMode = 'eLength'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6004 ), anId, -1 ); // CONNECTION + popupMgr()->insert( action( 6004 ), aSubId, -1 ); // CONNECTION popupMgr()->setRule( action( 6004 ), aMeshInVtkHasEdges, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6004 ), "controlMode = 'eMultiConnection'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( separator(), anId, -1 ); + aSubId = popupMgr()->insert( tr( "MEN_FACE_CTRL" ), anId, -1 ); // FACE CONTROLS - popupMgr()->insert( action( 6005 ), anId, -1 ); // FREE_NODE - popupMgr()->setRule( action( 6005 ), aMeshInVtkHasNodes, QtxPopupMgr::VisibleRule ); - popupMgr()->setRule( action( 6005 ), "controlMode = 'eFreeNodes'", QtxPopupMgr::ToggleRule ); - - popupMgr()->insert( action( 6002 ), anId, -1 ); // FREE_EDGE - popupMgr()->setRule( action( 6002 ), aMeshInVtkHasEdges, QtxPopupMgr::VisibleRule ); - popupMgr()->setRule( action( 6002 ), "controlMode = 'eFreeEdges'", QtxPopupMgr::ToggleRule ); + popupMgr()->insert( action( 6021 ), aSubId, -1 ); // FREE_FACE + popupMgr()->setRule( action( 6021 ), aMeshInVtkHasFaces /*aMeshInVtkHasVolumes*/, + QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6021 ), "controlMode = 'eFreeFaces'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6018 ), anId, -1 ); // LENGTH_2D + popupMgr()->insert( action( 6018 ), aSubId, -1 ); // LENGTH_2D popupMgr()->setRule( action( 6018 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6018 ), "controlMode = 'eLength2D'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6019 ), anId, -1 ); // CONNECTION_2D + popupMgr()->insert( action( 6019 ), aSubId, -1 ); // CONNECTION_2D popupMgr()->setRule( action( 6019 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6019 ), "controlMode = 'eMultiConnection2D'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6011 ), anId, -1 ); // AREA + popupMgr()->insert( action( 6011 ), aSubId, -1 ); // AREA popupMgr()->setRule( action( 6011 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6011 ), "controlMode = 'eArea'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6012 ), anId, -1 ); // TAPER + popupMgr()->insert( action( 6012 ), aSubId, -1 ); // TAPER popupMgr()->setRule( action( 6012 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6012 ), "controlMode = 'eTaper'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6013 ), anId, -1 ); // ASPECT + popupMgr()->insert( action( 6013 ), aSubId, -1 ); // ASPECT popupMgr()->setRule( action( 6013 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6013 ), "controlMode = 'eAspectRatio'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6014 ), anId, -1 ); // MIN_ANG + popupMgr()->insert( action( 6014 ), aSubId, -1 ); // MIN_ANG popupMgr()->setRule( action( 6014 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6014 ), "controlMode = 'eMinimumAngle'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6015 ), anId, -1 ); // WARP + popupMgr()->insert( action( 6015 ), aSubId, -1 ); // WARP popupMgr()->setRule( action( 6015 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6015 ), "controlMode = 'eWarping'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6016 ), anId, -1 ); // SKEW + popupMgr()->insert( action( 6016 ), aSubId, -1 ); // SKEW popupMgr()->setRule( action( 6016 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6016 ), "controlMode = 'eSkew'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( separator(), anId, -1 ); + popupMgr()->insert( action( 6022 ), aSubId, -1 ); // MAX_ELEMENT_LENGTH_2D + popupMgr()->setRule( action( 6022 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6022 ), "controlMode = 'eMaxElementLength2D'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6017 ), anId, -1 ); // ASPECT_3D + aSubId = popupMgr()->insert( tr( "MEN_VOLUME_CTRL" ), anId, -1 ); // VOLUME CONTROLS + + popupMgr()->insert( action( 6017 ), aSubId, -1 ); // ASPECT_3D popupMgr()->setRule( action( 6017 ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6017 ), "controlMode = 'eAspectRatio3D'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert ( action( 6009 ), anId, -1 ); // VOLUME_3D + popupMgr()->insert ( action( 6009 ), aSubId, -1 ); // VOLUME_3D popupMgr()->setRule( action( 6009 ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6009 ), "controlMode = 'eVolume3D'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6021 ), anId, -1 ); // FREE_FACE - popupMgr()->setRule( action( 6021 ), aMeshInVtkHasFaces /*aMeshInVtkHasVolumes*/, - QtxPopupMgr::VisibleRule ); - popupMgr()->setRule( action( 6021 ), "controlMode = 'eFreeFaces'", QtxPopupMgr::ToggleRule ); + popupMgr()->insert( action( 6023 ), aSubId, -1 ); // MAX_ELEMENT_LENGTH_3D + popupMgr()->setRule( action( 6023 ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6023 ), "controlMode = 'eMaxElementLength3D'", QtxPopupMgr::ToggleRule ); popupMgr()->insert( separator(), anId, -1 ); popupMgr()->insert( action( 201 ), anId, -1 ); // SCALAR_BAR_PROP popupMgr()->setRule( action( 201 ), aMeshInVTK + "&& controlMode <> 'eNone'", QtxPopupMgr::VisibleRule ); + popupMgr()->insert( separator(), anId, -1 ); + + popupMgr()->insert( action( 202 ), anId, -1 ); // SAVE_DISTRIBUTION + popupMgr()->setRule( action( 202 ), aMeshInVTK + "&& isNumFunctor", QtxPopupMgr::VisibleRule ); + + popupMgr()->insert( action( 203 ), anId, -1 ); // SHOW_DISTRIBUTION + popupMgr()->setRule( action( 203 ), aMeshInVTK + "&& isNumFunctor", QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 203 ), aMeshInVTK + "&& isNumFunctor && isDistributionVisible", QtxPopupMgr::ToggleRule); + + popupMgr()->insert( separator(), -1, -1 ); //------------------------------------------------- @@ -3667,8 +3880,19 @@ void SMESHGUI::initialize( CAM_Application* app ) popupMgr()->insert( separator(), -1, -1 ); + //------------------------------------------------- + // Clipping + //------------------------------------------------- + popupMgr()->insert( action( 1134 ), -1, -1 ); + popupMgr()->setRule( action( 1134 ), "client='VTKViewer'", QtxPopupMgr::VisibleRule ); + + popupMgr()->insert( separator(), -1, -1 ); + connect( application(), SIGNAL( viewManagerActivated( SUIT_ViewManager* ) ), this, SLOT( onViewManagerActivated( SUIT_ViewManager* ) ) ); + + connect( application(), SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ), + this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ) ); } //================================================================================ @@ -3825,6 +4049,49 @@ void SMESHGUI::onViewManagerActivated( SUIT_ViewManager* mgr ) SMESH::UpdateSelectionProp( this ); } +void SMESHGUI::onViewManagerRemoved( SUIT_ViewManager* theViewManager ) +{ + if( theViewManager && theViewManager->getType() == SVTK_Viewer::Type() ) + myClippingPlaneInfoMap.erase( theViewManager ); +} + +void SMESHGUI::addActorAsObserver( SMESH_Actor* theActor ) +{ + theActor->AddObserver( SMESH::DeleteActorEvent, + myEventCallbackCommand.GetPointer(), + myPriority ); +} + +void SMESHGUI::ProcessEvents( vtkObject* theObject, + unsigned long theEvent, + void* theClientData, + void* theCallData ) +{ + if( SMESHGUI* aSMESHGUI = reinterpret_cast( theClientData ) ) { + if( theObject && theEvent == SMESH::DeleteActorEvent ) { + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( theObject ) ) { + SMESHGUI_ClippingPlaneInfoMap& aClippingPlaneInfoMap = aSMESHGUI->getClippingPlaneInfoMap(); + SMESHGUI_ClippingPlaneInfoMap::iterator anIter1 = aClippingPlaneInfoMap.begin(); + for( ; anIter1 != aClippingPlaneInfoMap.end(); anIter1++ ) { + SMESHGUI_ClippingPlaneInfoList& aClippingPlaneInfoList = anIter1->second; + SMESHGUI_ClippingPlaneInfoList::iterator anIter2 = aClippingPlaneInfoList.begin(); + for( ; anIter2 != aClippingPlaneInfoList.end(); anIter2++ ) { + SMESH::ClippingPlaneInfo& aClippingPlaneInfo = *anIter2; + std::list& anActorList = aClippingPlaneInfo.ActorList; + SMESH::TActorList::iterator anIter3 = anActorList.begin(); + for ( ; anIter3 != anActorList.end(); anIter3++ ) { + if( anActor == *anIter3 ) { + anActorList.erase( anIter3 ); + break; + } + } + } + } + } + } + } +} + void SMESHGUI::createPreferences() { // General tab ------------------------------------------------------------------------ @@ -3889,9 +4156,9 @@ void SMESHGUI::createPreferences() setPreferenceProperty( computeGroup, "columns", 2 ); int notifyMode = addPreference( tr( "PREF_NOTIFY_MODE" ), computeGroup, LightApp_Preferences::Selector, "SMESH", "show_result_notification" ); modes.clear(); - modes.append( "Never" ); - modes.append( "Errors only" ); - modes.append( "Always" ); + modes.append( tr( "PREF_NOTIFY_NEVER" ) ); + modes.append( tr( "PREF_NOTIFY_ERROR" ) ); + modes.append( tr( "PREF_NOTIFY_ALWAYS" ) ); indices.clear(); indices.append( 0 ); indices.append( 1 ); @@ -3899,6 +4166,18 @@ void SMESHGUI::createPreferences() setPreferenceProperty( notifyMode, "strings", modes ); setPreferenceProperty( notifyMode, "indexes", indices ); + int infoGroup = addPreference( tr( "PREF_GROUP_INFO" ), genTab ); + setPreferenceProperty( computeGroup, "columns", 2 ); + int elemInfo = addPreference( tr( "PREF_ELEM_INFO" ), infoGroup, LightApp_Preferences::Selector, "SMESH", "mesh_elem_info" ); + modes.clear(); + modes.append( tr( "PREF_ELEM_INFO_SIMPLE" ) ); + modes.append( tr( "PREF_ELEM_INFO_TREE" ) ); + indices.clear(); + indices.append( 0 ); + indices.append( 1 ); + setPreferenceProperty( elemInfo, "strings", modes ); + setPreferenceProperty( elemInfo, "indexes", indices ); + int segGroup = addPreference( tr( "PREF_GROUP_SEGMENT_LENGTH" ), genTab ); setPreferenceProperty( segGroup, "columns", 2 ); int segLen = addPreference( tr( "PREF_SEGMENT_LENGTH" ), segGroup, LightApp_Preferences::IntSpin, @@ -4118,6 +4397,18 @@ void SMESHGUI::createPreferences() setPreferenceProperty( hh, "min", 0.0 ); setPreferenceProperty( hh, "max", 1.0 ); setPreferenceProperty( hh, "step", 0.1 ); + + int distributionGr = addPreference( tr( "SMESH_DISTRIBUTION_SCALARBAR" ), sbarTab, LightApp_Preferences::Auto, "SMESH", "distribution_visibility" ); + int coloringType = addPreference( tr( "SMESH_DISTRIBUTION_COLORING_TYPE" ), distributionGr, LightApp_Preferences::Selector, "SMESH", "distribution_coloring_type" ); + setPreferenceProperty( distributionGr, "columns", 3 ); + QStringList types; + types.append( tr( "SMESH_MONOCOLOR" ) ); + types.append( tr( "SMESH_MULTICOLOR" ) ); + indices.clear(); indices.append( 0 ); indices.append( 1 ); + setPreferenceProperty( coloringType, "strings", types ); + setPreferenceProperty( coloringType, "indexes", indices ); + addPreference( tr( "SMESH_DISTRIBUTION_COLOR" ), distributionGr, LightApp_Preferences::Color, "SMESH", "distribution_color" ); + } void SMESHGUI::preferencesChanged( const QString& sect, const QString& name ) @@ -4337,12 +4628,9 @@ SALOMEDS::Color SMESHGUI::getUniqueColor( const QList& theReser if( aTolerance < 1 ) break; } - //cout << "Iteration N" << anIterations << " (tolerance=" << aTolerance << ")"<< endl; aHue = (int)( 360.0 * rand() / RAND_MAX ); - //cout << "Hue = " << aHue << endl; - //cout << "Auto colors : "; bool ok = true; QList::const_iterator it = theReservedColors.constBegin(); QList::const_iterator itEnd = theReservedColors.constEnd(); @@ -4353,21 +4641,17 @@ SALOMEDS::Color SMESHGUI::getUniqueColor( const QList& theReser int h, s, v; aQColor.getHsv( &h, &s, &v ); - //cout << h << " "; if( abs( h - aHue ) < aTolerance ) { ok = false; - //cout << "break (diff = " << abs( h - aHue ) << ")"; break; } } - //cout << endl; if( ok ) break; } - //cout << "Hue of the returned color = " << aHue << endl; QColor aColor; aColor.setHsv( aHue, 255, 255 ); @@ -4455,6 +4739,37 @@ void SMESHGUI::storeVisualParameters (int savePoint) // saving VTK actors properties if (vType == SVTK_Viewer::Type()) { + // store the clipping planes attached to the view manager + SMESHGUI_ClippingPlaneInfoList aClippingPlaneInfoList; + SMESHGUI_ClippingPlaneInfoMap::const_iterator anIter = myClippingPlaneInfoMap.find( vman ); + if( anIter != myClippingPlaneInfoMap.end() ) + aClippingPlaneInfoList = anIter->second; + + if( !aClippingPlaneInfoList.empty() ) { + SMESHGUI_ClippingPlaneInfoList::const_iterator anIter = aClippingPlaneInfoList.begin(); + for( int anId = 0; anIter != aClippingPlaneInfoList.end(); anIter++, anId++ ) + { + const SMESH::ClippingPlaneInfo& aClippingPlaneInfo = *anIter; + SMESH::OrientedPlane* aPlane = aClippingPlaneInfo.Plane; + + QString aPropertyName( "ClippingPlane" ); + aPropertyName += gSeparator; + aPropertyName += QString::number( vtkViewers ); + aPropertyName += gSeparator; + aPropertyName += QString::number( anId ); + + QString aPropertyValue = QString::number( (int)aPlane->GetOrientation() ).toLatin1().constData(); + aPropertyValue += gDigitsSep; + aPropertyValue += QString::number( aPlane->GetDistance() ).toLatin1().constData(); + aPropertyValue += gDigitsSep; + aPropertyValue += QString::number( aPlane->myAngle[0] ).toLatin1().constData(); + aPropertyValue += gDigitsSep; + aPropertyValue += QString::number( aPlane->myAngle[1] ).toLatin1().constData(); + + ip->setProperty( aPropertyName.toStdString(), aPropertyValue.toStdString() ); + } + } + QVector views = vman->getViews(); for (int i = 0, iEnd = vman->getViewsCount(); i < iEnd; i++) { @@ -4580,22 +4895,25 @@ void SMESHGUI::storeVisualParameters (int savePoint) // Clipping param = vtkParam + "ClippingPlane"; - int nPlanes = aSmeshActor->GetNumberOfClippingPlanes(); - if (!nPlanes) - ip->setParameter(entry, param, "Off"); - for (int ipl = 0; ipl < nPlanes; ipl++) { - //vtkPlane* plane = aSmeshActor->GetClippingPlane(ipl); - SMESH::Orientation anOrientation; - double aDistance; - vtkFloatingPointType anAngle[2]; - SMESHGUI_ClippingDlg::GetPlaneParam(aSmeshActor, ipl, anOrientation, aDistance, anAngle); - std::string planeValue = QString::number((int)anOrientation).toLatin1().data(); - planeValue += gDigitsSep; planeValue += QString::number(aDistance).toLatin1().data(); - planeValue += gDigitsSep; planeValue += QString::number(anAngle[0]).toLatin1().data(); - planeValue += gDigitsSep; planeValue += QString::number(anAngle[1]).toLatin1().data(); - - ip->setParameter(entry, param + QString::number(ipl+1).toLatin1().data(), planeValue); + int aPlaneId = 0; + if( !aClippingPlaneInfoList.empty() ) { + SMESHGUI_ClippingPlaneInfoList::const_iterator anIter1 = aClippingPlaneInfoList.begin(); + for( int anId = 0; anIter1 != aClippingPlaneInfoList.end(); anIter1++, anId++ ) + { + const SMESH::ClippingPlaneInfo& aClippingPlaneInfo = *anIter1; + std::list anActorList = aClippingPlaneInfo.ActorList; + SMESH::TActorList::iterator anIter2 = anActorList.begin(); + for ( ; anIter2 != anActorList.end(); anIter2++ ) { + if( aSmeshActor == *anIter2 ) { + ip->setParameter( entry, param + QString::number( ++aPlaneId ).toLatin1().constData(), + QString::number( anId ).toLatin1().constData() ); + break; + } + } + } } + if( aPlaneId == 0 ) + ip->setParameter( entry, param, "Off" ); } // if (io->hasEntry()) } // SMESH_Actor && hasIO } // isVisible @@ -4607,6 +4925,25 @@ void SMESHGUI::storeVisualParameters (int savePoint) } // for (viewManagers) } +// data structures for clipping planes processing +typedef struct { + int Id; + vtkIdType Orientation; + vtkFloatingPointType Distance; + vtkFloatingPointType Angle[2]; +} TPlaneData; +typedef std::list TPlaneDataList; +typedef std::map TPlaneDataMap; + +typedef std::list TActorList; +typedef struct { + int PlaneId; + TActorList ActorList; + SUIT_ViewManager* ViewManager; +} TPlaneInfo; +typedef std::list TPlaneInfoList; +typedef std::map TPlaneInfoMap; + /*! * \brief Restore visual parameters * @@ -4631,8 +4968,9 @@ void SMESHGUI::restoreVisualParameters (int savePoint) savePoint); _PTR(IParameters) ip = ClientFactory::getIParameters(ap); - // restore map of custom markers + // restore map of custom markers and map of clipping planes VTK::MarkerMap& aMarkerMap = myMarkerMap[ studyDS->StudyId() ]; + TPlaneDataMap aPlaneDataMap; std::vector properties = ip->getProperties(); for (std::vector::iterator propIt = properties.begin(); propIt != properties.end(); ++propIt) @@ -4642,52 +4980,103 @@ void SMESHGUI::restoreVisualParameters (int savePoint) QString aPropertyValue( ip->getProperty( property ).c_str() ); QStringList aPropertyNameList = aPropertyName.split( gSeparator, QString::SkipEmptyParts ); - if( aPropertyNameList.size() != 2 ) + if( aPropertyNameList.isEmpty() ) continue; - int anId = 0; - bool ok = false; - if( aPropertyNameList[0] == "texture" ) - anId = aPropertyNameList[1].toInt( &ok ); + QString aPropertyType = aPropertyNameList[0]; + if( aPropertyType == "texture" ) + { + if( aPropertyNameList.size() != 2 ) + continue; - if( !ok || anId < 1 ) - continue; + bool ok = false; + int anId = aPropertyNameList[1].toInt( &ok ); + if( !ok || anId < 1 ) + continue; - QStringList aPropertyValueList = aPropertyValue.split( gPathSep, QString::SkipEmptyParts ); - if( aPropertyValueList.size() != 2 ) - continue; + QStringList aPropertyValueList = aPropertyValue.split( gPathSep, QString::SkipEmptyParts ); + if( aPropertyValueList.size() != 2 ) + continue; - std::string aMarkerFileName = aPropertyValueList[0].toStdString(); - QString aMarkerTextureString = aPropertyValueList[1]; - QStringList aMarkerTextureStringList = aMarkerTextureString.split( gDigitsSep, QString::SkipEmptyParts ); - if( aMarkerTextureStringList.size() != 3 ) - continue; + std::string aMarkerFileName = aPropertyValueList[0].toStdString(); + QString aMarkerTextureString = aPropertyValueList[1]; + QStringList aMarkerTextureStringList = aMarkerTextureString.split( gDigitsSep, QString::SkipEmptyParts ); + if( aMarkerTextureStringList.size() != 3 ) + continue; - ok = false; - ushort aWidth = aMarkerTextureStringList[0].toUShort( &ok ); - if( !ok ) - continue; + ok = false; + ushort aWidth = aMarkerTextureStringList[0].toUShort( &ok ); + if( !ok ) + continue; - ok = false; - ushort aHeight = aMarkerTextureStringList[1].toUShort( &ok ); - if( !ok ) - continue; + ok = false; + ushort aHeight = aMarkerTextureStringList[1].toUShort( &ok ); + if( !ok ) + continue; - VTK::MarkerTexture aMarkerTexture; - aMarkerTexture.push_back( aWidth ); - aMarkerTexture.push_back( aHeight ); + VTK::MarkerTexture aMarkerTexture; + aMarkerTexture.push_back( aWidth ); + aMarkerTexture.push_back( aHeight ); - QString aMarkerTextureData = aMarkerTextureStringList[2]; - for( int i = 0, n = aMarkerTextureData.length(); i < n; i++ ) - { - QChar aChar = aMarkerTextureData.at( i ); - if( aChar.isDigit() ) - aMarkerTexture.push_back( aChar.digitValue() ); + QString aMarkerTextureData = aMarkerTextureStringList[2]; + for( int i = 0, n = aMarkerTextureData.length(); i < n; i++ ) + { + QChar aChar = aMarkerTextureData.at( i ); + if( aChar.isDigit() ) + aMarkerTexture.push_back( aChar.digitValue() ); + } + + aMarkerMap[ anId ] = VTK::MarkerData( aMarkerFileName, aMarkerTexture ); } + else if( aPropertyType == "ClippingPlane" ) + { + if( aPropertyNameList.size() != 3 ) + continue; - aMarkerMap[ anId ] = VTK::MarkerData( aMarkerFileName, aMarkerTexture ); + bool ok = false; + int aViewId = aPropertyNameList[1].toInt( &ok ); + if( !ok || aViewId < 0 ) + continue; + + ok = false; + int aClippingPlaneId = aPropertyNameList[2].toInt( &ok ); + if( !ok || aClippingPlaneId < 0 ) + continue; + + QStringList aPropertyValueList = aPropertyValue.split( gDigitsSep, QString::SkipEmptyParts ); + if( aPropertyValueList.size() != 4 ) + continue; + + TPlaneData aPlaneData; + aPlaneData.Id = aClippingPlaneId; + + ok = false; + aPlaneData.Orientation = aPropertyValueList[0].toInt( &ok ); + if( !ok ) + continue; + + ok = false; + aPlaneData.Distance = aPropertyValueList[1].toDouble( &ok ); + if( !ok ) + continue; + + ok = false; + aPlaneData.Angle[0] = aPropertyValueList[2].toDouble( &ok ); + if( !ok ) + continue; + + ok = false; + aPlaneData.Angle[1] = aPropertyValueList[3].toDouble( &ok ); + if( !ok ) + continue; + + TPlaneDataList& aPlaneDataList = aPlaneDataMap[ aViewId ]; + aPlaneDataList.push_back( aPlaneData ); + } } + TPlaneInfoMap aPlaneInfoMap; + std::vector entries = ip->getEntries(); for (std::vector::iterator entIt = entries.begin(); entIt != entries.end(); ++entIt) @@ -4734,39 +5123,40 @@ void SMESHGUI::restoreVisualParameters (int savePoint) if (vtkActors.IsBound(viewIndex)) aSmeshActor = vtkActors.Find(viewIndex); + QList lst; + getApp()->viewManagers(viewerTypStr, lst); + + // SVTK ViewManager always has 1 ViewWindow, so view index is index of view manager + SUIT_ViewManager* vman = NULL; + if (viewIndex >= 0 && viewIndex < lst.count()) + vman = lst.at(viewIndex); + if (paramNameStr == "Visibility") { - if (!aSmeshActor && displayer()) + if (!aSmeshActor && displayer() && vman) { - QList lst; - getApp()->viewManagers(viewerTypStr, lst); - - // SVTK ViewManager always has 1 ViewWindow, so view index is index of view manager - if (viewIndex >= 0 && viewIndex < lst.count()) { - SUIT_ViewManager* vman = lst.at(viewIndex); - SUIT_ViewModel* vmodel = vman->getViewModel(); - // SVTK view model can be casted to SALOME_View - displayer()->Display(entry, true, dynamic_cast(vmodel)); - - // store displayed actor in a temporary map for quicker - // access later when restoring other parameters - SVTK_ViewWindow* vtkView = (SVTK_ViewWindow*) vman->getActiveView(); - vtkRenderer* Renderer = vtkView->getRenderer(); - VTK::ActorCollectionCopy aCopy(Renderer->GetActors()); - vtkActorCollection* theActors = aCopy.GetActors(); - theActors->InitTraversal(); - bool isFound = false; - vtkActor *ac = theActors->GetNextActor(); - for (; ac != NULL && !isFound; ac = theActors->GetNextActor()) { - if (ac->IsA("SMESH_Actor")) { - SMESH_Actor* aGeomAc = SMESH_Actor::SafeDownCast(ac); - if (aGeomAc->hasIO()) { - Handle(SALOME_InteractiveObject) io = - Handle(SALOME_InteractiveObject)::DownCast(aGeomAc->getIO()); - if (io->hasEntry() && strcmp(io->getEntry(), entry.toLatin1().data()) == 0) { - isFound = true; - vtkActors.Bind(viewIndex, aGeomAc); - } + SUIT_ViewModel* vmodel = vman->getViewModel(); + // SVTK view model can be casted to SALOME_View + displayer()->Display(entry, true, dynamic_cast(vmodel)); + + // store displayed actor in a temporary map for quicker + // access later when restoring other parameters + SVTK_ViewWindow* vtkView = (SVTK_ViewWindow*) vman->getActiveView(); + vtkRenderer* Renderer = vtkView->getRenderer(); + VTK::ActorCollectionCopy aCopy(Renderer->GetActors()); + vtkActorCollection* theActors = aCopy.GetActors(); + theActors->InitTraversal(); + bool isFound = false; + vtkActor *ac = theActors->GetNextActor(); + for (; ac != NULL && !isFound; ac = theActors->GetNextActor()) { + if (ac->IsA("SMESH_Actor")) { + SMESH_Actor* aGeomAc = SMESH_Actor::SafeDownCast(ac); + if (aGeomAc->hasIO()) { + Handle(SALOME_InteractiveObject) io = + Handle(SALOME_InteractiveObject)::DownCast(aGeomAc->getIO()); + if (io->hasEntry() && strcmp(io->getEntry(), entry.toLatin1().data()) == 0) { + isFound = true; + vtkActors.Bind(viewIndex, aGeomAc); } } } @@ -4883,14 +5273,16 @@ void SMESHGUI::restoreVisualParameters (int savePoint) } // Clipping else if (paramNameStr.startsWith("ClippingPlane")) { - cout << "$$$ ClippingPlane 1" << endl; - if (paramNameStr == "ClippingPlane1" || val == "Off") - aSmeshActor->RemoveAllClippingPlanes(); - if (val != "Off") { - cout << "$$$ ClippingPlane 2" << endl; - QStringList vals = val.split(gDigitsSep, QString::SkipEmptyParts); - if (vals.count() == 4) { // format check: 4 values - cout << "$$$ ClippingPlane 3" << endl; + QStringList vals = val.split(gDigitsSep, QString::SkipEmptyParts); + // old format - val looks like "Off" or "0:0.5:0:0" (orientation, distance, two angles) + // new format - val looks like "Off" or "0" (plane id) + // (note: in new format "Off" value is used only for consistency, + // so it is processed together with values in old format) + bool anIsOldFormat = ( vals.count() == 4 || val == "Off" ); + if( anIsOldFormat ) { + if (paramNameStr == "ClippingPlane1" || val == "Off") + aSmeshActor->RemoveAllClippingPlanes(); + if (val != "Off") { SMESH::Orientation anOrientation = (SMESH::Orientation)vals[0].toInt(); double aDistance = vals[1].toFloat(); vtkFloatingPointType anAngle[2]; @@ -4903,8 +5295,43 @@ void SMESHGUI::restoreVisualParameters (int savePoint) if (viewIndex >= 0 && viewIndex < lst.count()) { SUIT_ViewManager* vman = lst.at(viewIndex); SVTK_ViewWindow* vtkView = (SVTK_ViewWindow*) vman->getActiveView(); - SMESHGUI_ClippingDlg::AddPlane(aSmeshActor, vtkView, - anOrientation, aDistance, anAngle); + + SMESHGUI_ClippingPlaneInfoList& aClippingPlaneInfoList = myClippingPlaneInfoMap[ vman ]; + + SMESH::TActorList anActorList; + anActorList.push_back( aSmeshActor ); + SMESH::OrientedPlane* aPlane = + SMESHGUI_ClippingDlg::AddPlane(anActorList, vtkView, anOrientation, aDistance, anAngle); + if( aPlane ) { + SMESH::ClippingPlaneInfo aClippingPlaneInfo; + aClippingPlaneInfo.Plane = aPlane; + aClippingPlaneInfo.ActorList = anActorList; + aClippingPlaneInfoList.push_back( aClippingPlaneInfo ); + } + } + } + } + else { + bool ok = false; + int aPlaneId = val.toInt( &ok ); + if( ok && aPlaneId >= 0 ) { + bool anIsDefinedPlane = false; + TPlaneInfoList& aPlaneInfoList = aPlaneInfoMap[ viewIndex ]; + TPlaneInfoList::iterator anIter = aPlaneInfoList.begin(); + for( ; anIter != aPlaneInfoList.end(); anIter++ ) { + TPlaneInfo& aPlaneInfo = *anIter; + if( aPlaneInfo.PlaneId == aPlaneId ) { + aPlaneInfo.ActorList.push_back( aSmeshActor ); + anIsDefinedPlane = true; + break; + } + } + if( !anIsDefinedPlane ) { + TPlaneInfo aPlaneInfo; + aPlaneInfo.PlaneId = aPlaneId; + aPlaneInfo.ActorList.push_back( aSmeshActor ); + aPlaneInfo.ViewManager = vman; + aPlaneInfoList.push_back( aPlaneInfo ); } } } @@ -4915,6 +5342,55 @@ void SMESHGUI::restoreVisualParameters (int savePoint) } // for names/parameters iterator } // for entries iterator + // add clipping planes to actors according to the restored parameters + // and update the clipping plane map + TPlaneInfoMap::const_iterator anIter1 = aPlaneInfoMap.begin(); + for( ; anIter1 != aPlaneInfoMap.end(); anIter1++ ) { + int aViewId = anIter1->first; + const TPlaneInfoList& aPlaneInfoList = anIter1->second; + + TPlaneDataMap::const_iterator anIter2 = aPlaneDataMap.find( aViewId ); + if( anIter2 == aPlaneDataMap.end() ) + continue; + const TPlaneDataList& aPlaneDataList = anIter2->second; + + TPlaneInfoList::const_iterator anIter3 = aPlaneInfoList.begin(); + for( ; anIter3 != aPlaneInfoList.end(); anIter3++ ) { + const TPlaneInfo& aPlaneInfo = *anIter3; + int aPlaneId = aPlaneInfo.PlaneId; + const TActorList& anActorList = aPlaneInfo.ActorList; + SUIT_ViewManager* aViewManager = aPlaneInfo.ViewManager; + if( !aViewManager ) + continue; + + SVTK_ViewWindow* aViewWindow = dynamic_cast( aViewManager->getActiveView() ); + if( !aViewWindow ) + continue; + + SMESHGUI_ClippingPlaneInfoList& aClippingPlaneInfoList = myClippingPlaneInfoMap[ aViewManager ]; + + TPlaneDataList::const_iterator anIter4 = aPlaneDataList.begin(); + for( ; anIter4 != aPlaneDataList.end(); anIter4++ ) { + const TPlaneData& aPlaneData = *anIter4; + if( aPlaneData.Id == aPlaneId ) { + SMESH::OrientedPlane* aPlane = + SMESHGUI_ClippingDlg::AddPlane( anActorList, + aViewWindow, + (SMESH::Orientation)aPlaneData.Orientation, + aPlaneData.Distance, + aPlaneData.Angle ); + if( aPlane ) { + SMESH::ClippingPlaneInfo aClippingPlaneInfo; + aClippingPlaneInfo.Plane = aPlane; + aClippingPlaneInfo.ActorList = anActorList; + aClippingPlaneInfoList.push_back( aClippingPlaneInfo ); + } + break; + } + } + } + } + // update all VTK views QList lst; getApp()->viewManagers(lst); diff --git a/src/SMESHGUI/SMESHGUI.h b/src/SMESHGUI/SMESHGUI.h index bb2b29c04..7aa14367f 100644 --- a/src/SMESHGUI/SMESHGUI.h +++ b/src/SMESHGUI/SMESHGUI.h @@ -39,6 +39,14 @@ #include #include CORBA_SERVER_HEADER(SMESH_Gen) +// VTK includes +#include +#include + +class vtkActor; +class vtkCallbackCommand; +class vtkObject; + class QDialog; class SUIT_Desktop; @@ -52,10 +60,24 @@ class SalomeApp_Study; class LightApp_Selection; class LightApp_SelectionMgr; +class SMESH_Actor; class SMESHGUI_FilterLibraryDlg; typedef std::map SMESHGUI_StudyId2MarkerMap; +namespace SMESH +{ + class OrientedPlane; + struct ClippingPlaneInfo + { + OrientedPlane* Plane; + std::list ActorList; + }; +} + +typedef std::list SMESHGUI_ClippingPlaneInfoList; +typedef std::map SMESHGUI_ClippingPlaneInfoMap; + //================================================================================= // class : SMESHGUI // purpose : @@ -122,6 +144,10 @@ public : virtual void storeVisualParameters (int savePoint); virtual void restoreVisualParameters(int savePoint); + virtual void addActorAsObserver( SMESH_Actor* theActor ); + + SMESHGUI_ClippingPlaneInfoMap& getClippingPlaneInfoMap() { return myClippingPlaneInfoMap; } + public slots: virtual bool deactivateModule( SUIT_Study* ); virtual bool activateModule( SUIT_Study* ); @@ -130,6 +156,7 @@ public slots: private slots: void OnGUIEvent(); void onViewManagerActivated( SUIT_ViewManager* ); + void onViewManagerRemoved( SUIT_ViewManager* ); void onOperationCommited( SUIT_Operation* ); void onOperationAborted( SUIT_Operation* ); void onHypothesisEdit( int result ); @@ -159,6 +186,11 @@ protected: virtual bool reusableOperation( const int id ); + static void ProcessEvents( vtkObject* theObject, + unsigned long theEvent, + void* theClientData, + void* theCallData ); + private: void OnEditDelete(); int addVtkFontPref( const QString& label, @@ -175,6 +207,10 @@ private : SMESHGUI_FilterLibraryDlg* myFilterLibraryDlg; SMESHGUI_StudyId2MarkerMap myMarkerMap; + SMESHGUI_ClippingPlaneInfoMap myClippingPlaneInfoMap; + + vtkSmartPointer myEventCallbackCommand; + vtkFloatingPointType myPriority; }; #endif // SMESHGUI_H diff --git a/src/SMESHGUI/SMESHGUI_ClippingDlg.cxx b/src/SMESHGUI/SMESHGUI_ClippingDlg.cxx index 13bdc8eb4..ac190be77 100644 --- a/src/SMESHGUI/SMESHGUI_ClippingDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ClippingDlg.cxx @@ -41,11 +41,15 @@ #include #include #include +#include #include +#include + #include -#include + +#include #include @@ -59,139 +63,138 @@ #include #include #include +#include // VTK includes #include -#include #include #include #include #include +#include #define SPACING 6 #define MARGIN 11 -class OrientedPlane: public vtkPlane +//================================================================================= +// class : OrientedPlane +// purpose : +//================================================================================= +SMESH::OrientedPlane* SMESH::OrientedPlane::New() { - QPointer myViewWindow; - - vtkDataSetMapper* myMapper; - -public: - static OrientedPlane *New() - { - return new OrientedPlane(); - } - static OrientedPlane *New(SVTK_ViewWindow* theViewWindow) - { - return new OrientedPlane(theViewWindow); - } - vtkTypeMacro (OrientedPlane, vtkPlane); - - SMESH::Orientation myOrientation; - float myDistance; - double myAngle[2]; + return new OrientedPlane(); +} - vtkPlaneSource* myPlaneSource; - SALOME_Actor *myActor; +SMESH::OrientedPlane* SMESH::OrientedPlane::New(SVTK_ViewWindow* theViewWindow) +{ + return new OrientedPlane(theViewWindow); +} - void SetOrientation (SMESH::Orientation theOrientation) { myOrientation = theOrientation; } - SMESH::Orientation GetOrientation() { return myOrientation; } +void SMESH::OrientedPlane::ShallowCopy(SMESH::OrientedPlane* theOrientedPlane) +{ + SetNormal(theOrientedPlane->GetNormal()); + SetOrigin(theOrientedPlane->GetOrigin()); - void SetDistance (float theDistance) { myDistance = theDistance; } - float GetDistance() { return myDistance; } + myOrientation = theOrientedPlane->GetOrientation(); + myDistance = theOrientedPlane->GetDistance(); - void ShallowCopy (OrientedPlane* theOrientedPlane) - { - SetNormal(theOrientedPlane->GetNormal()); - SetOrigin(theOrientedPlane->GetOrigin()); + myAngle[0] = theOrientedPlane->myAngle[0]; + myAngle[1] = theOrientedPlane->myAngle[1]; - myOrientation = theOrientedPlane->GetOrientation(); - myDistance = theOrientedPlane->GetDistance(); + myPlaneSource->SetNormal(theOrientedPlane->myPlaneSource->GetNormal()); + myPlaneSource->SetOrigin(theOrientedPlane->myPlaneSource->GetOrigin()); + myPlaneSource->SetPoint1(theOrientedPlane->myPlaneSource->GetPoint1()); + myPlaneSource->SetPoint2(theOrientedPlane->myPlaneSource->GetPoint2()); +} - myAngle[0] = theOrientedPlane->myAngle[0]; - myAngle[1] = theOrientedPlane->myAngle[1]; +SMESH::OrientedPlane::OrientedPlane(SVTK_ViewWindow* theViewWindow): + myViewWindow(theViewWindow), + myOrientation(SMESH::XY), + myDistance(0.5) +{ + Init(); + myViewWindow->AddActor(myActor); +} - myPlaneSource->SetNormal(theOrientedPlane->myPlaneSource->GetNormal()); - myPlaneSource->SetOrigin(theOrientedPlane->myPlaneSource->GetOrigin()); - myPlaneSource->SetPoint1(theOrientedPlane->myPlaneSource->GetPoint1()); - myPlaneSource->SetPoint2(theOrientedPlane->myPlaneSource->GetPoint2()); - } +SMESH::OrientedPlane::OrientedPlane(): + myOrientation(SMESH::XY), + myViewWindow(NULL), + myDistance(0.5) +{ + Init(); +} -protected: - OrientedPlane(SVTK_ViewWindow* theViewWindow): - myViewWindow(theViewWindow), - myOrientation(SMESH::XY), - myDistance(0.5) - { - Init(); - myViewWindow->AddActor(myActor); - } +void SMESH::OrientedPlane::Init() +{ + myPlaneSource = vtkPlaneSource::New(); + + myAngle[0] = myAngle[1] = 0.0; + + // Create and display actor + myMapper = vtkDataSetMapper::New(); + myMapper->SetInput(myPlaneSource->GetOutput()); + + myActor = SALOME_Actor::New(); + myActor->VisibilityOff(); + myActor->PickableOff(); + myActor->SetInfinitive(true); + myActor->SetMapper(myMapper); + + vtkFloatingPointType anRGB[3]; + vtkProperty* aProp = vtkProperty::New(); + SMESH::GetColor( "SMESH", "fill_color", anRGB[0], anRGB[1], anRGB[2], QColor( 0, 170, 255 ) ); + aProp->SetColor(anRGB[0],anRGB[1],anRGB[2]); + aProp->SetOpacity(0.75); + myActor->SetProperty(aProp); + aProp->Delete(); + + vtkProperty* aBackProp = vtkProperty::New(); + SMESH::GetColor( "SMESH", "backface_color", anRGB[0], anRGB[1], anRGB[2], QColor( 0, 0, 255 ) ); + aBackProp->SetColor(anRGB[0],anRGB[1],anRGB[2]); + aBackProp->SetOpacity(0.75); + myActor->SetBackfaceProperty(aBackProp); + aBackProp->Delete(); +} - OrientedPlane(): - myOrientation(SMESH::XY), - myViewWindow(NULL), - myDistance(0.5) - { - Init(); - } +SMESH::OrientedPlane::~OrientedPlane() +{ + if (myViewWindow) + myViewWindow->RemoveActor(myActor); + myActor->Delete(); + + myMapper->RemoveAllInputs(); + myMapper->Delete(); - void Init() - { - myPlaneSource = vtkPlaneSource::New(); - - myAngle[0] = myAngle[1] = 0.0; - - // Create and display actor - myMapper = vtkDataSetMapper::New(); - myMapper->SetInput(myPlaneSource->GetOutput()); - - myActor = SALOME_Actor::New(); - myActor->VisibilityOff(); - myActor->PickableOff(); - myActor->SetInfinitive(true); - myActor->SetMapper(myMapper); - - vtkFloatingPointType anRGB[3]; - vtkProperty* aProp = vtkProperty::New(); - SMESH::GetColor( "SMESH", "fill_color", anRGB[0], anRGB[1], anRGB[2], QColor( 0, 170, 255 ) ); - aProp->SetColor(anRGB[0],anRGB[1],anRGB[2]); - aProp->SetOpacity(0.75); - myActor->SetProperty(aProp); - aProp->Delete(); - - vtkProperty* aBackProp = vtkProperty::New(); - SMESH::GetColor( "SMESH", "backface_color", anRGB[0], anRGB[1], anRGB[2], QColor( 0, 0, 255 ) ); - aBackProp->SetColor(anRGB[0],anRGB[1],anRGB[2]); - aBackProp->SetOpacity(0.75); - myActor->SetBackfaceProperty(aBackProp); - aBackProp->Delete(); - } + // commented: porting to vtk 5.0 + // myPlaneSource->UnRegisterAllOutputs(); + myPlaneSource->Delete(); +} - ~OrientedPlane(){ - if (myViewWindow) - myViewWindow->RemoveActor(myActor); - myActor->Delete(); - - myMapper->RemoveAllInputs(); - myMapper->Delete(); +//================================================================================= +// class : ActorItem +// purpose : +//================================================================================= +class ActorItem : public QListWidgetItem +{ +public: + ActorItem( SMESH_Actor* theActor, const QString& theName, QListWidget* theListWidget ) : + QListWidgetItem( theName, theListWidget ), + myActor( theActor ) {} - // commented: porting to vtk 5.0 - // myPlaneSource->UnRegisterAllOutputs(); - myPlaneSource->Delete(); - }; + SMESH_Actor* getActor() const { return myActor; } private: - // Not implemented. - OrientedPlane (const OrientedPlane&); - void operator= (const OrientedPlane&); - + SMESH_Actor* myActor; }; -struct TSetVisiblity { - TSetVisiblity(int theIsVisible): myIsVisible(theIsVisible){} - void operator()(SMESH::TVTKPlane& theOrientedPlane){ - theOrientedPlane->myActor->SetVisibility(myIsVisible); +//================================================================================= +// class : TSetVisibility +// purpose : +//================================================================================= +struct TSetVisibility { + TSetVisibility(int theIsVisible): myIsVisible(theIsVisible){} + void operator()(SMESH::TPlaneData& thePlaneData){ + thePlaneData.Plane.GetPointer()->myActor->SetVisibility(myIsVisible); } int myIsVisible; }; @@ -200,13 +203,13 @@ struct TSetVisiblity { // used in SMESHGUI::restoreVisualParameters() to avoid // declaration of OrientedPlane outside of SMESHGUI_ClippingDlg.cxx //================================================================================= -void SMESHGUI_ClippingDlg::AddPlane (SMESH_Actor* theActor, - SVTK_ViewWindow* theViewWindow, - SMESH::Orientation theOrientation, - double theDistance, - vtkFloatingPointType theAngle[2]) +SMESH::OrientedPlane* SMESHGUI_ClippingDlg::AddPlane (SMESH::TActorList theActorList, + SVTK_ViewWindow* theViewWindow, + SMESH::Orientation theOrientation, + double theDistance, + const vtkFloatingPointType theAngle[2]) { - OrientedPlane* aPlane = OrientedPlane::New(theViewWindow); + SMESH::OrientedPlane* aPlane = SMESH::OrientedPlane::New(theViewWindow); aPlane->myAngle[0] = theAngle[0]; aPlane->myAngle[1] = theAngle[1]; @@ -256,14 +259,26 @@ void SMESHGUI_ClippingDlg::AddPlane (SMESH_Actor* theActor, vtkMath::Cross(aNormal,aDir[1],aDir[0]); } - // ??? - theActor->SetPlaneParam(aNormal, theDistance, aPlane); + vtkFloatingPointType aBounds[6]; + vtkFloatingPointType anOrigin[3]; + bool anIsOk = SMESH::ComputeClippingPlaneParameters( theActorList, + aNormal, + theDistance, + aBounds, + anOrigin ); + if( !anIsOk ) + return NULL; - vtkDataSet* aDataSet = theActor->GetInput(); - vtkFloatingPointType *aPnt = aDataSet->GetCenter(); + aPlane->SetNormal( aNormal ); + aPlane->SetOrigin( anOrigin ); - vtkFloatingPointType* anOrigin = aPlane->GetOrigin(); - vtkFloatingPointType aDel = aDataSet->GetLength()/2.0; + vtkFloatingPointType aPnt[3] = { ( aBounds[0] + aBounds[1] ) / 2., + ( aBounds[2] + aBounds[3] ) / 2., + ( aBounds[4] + aBounds[5] ) / 2. }; + + vtkFloatingPointType aDel = pow( pow( aBounds[1] - aBounds[0], 2 ) + + pow( aBounds[3] - aBounds[2], 2 ) + + pow( aBounds[5] - aBounds[4], 2 ), 0.5 ); vtkFloatingPointType aDelta[2][3] = {{aDir[0][0]*aDel, aDir[0][1]*aDel, aDir[0][2]*aDel}, {aDir[1][0]*aDel, aDir[1][1]*aDel, aDir[1][2]*aDel}}; @@ -299,28 +314,13 @@ void SMESHGUI_ClippingDlg::AddPlane (SMESH_Actor* theActor, aPlaneSource->SetPoint1(aPnt1[0],aPnt1[1],aPnt1[2]); aPlaneSource->SetPoint2(aPnt2[0],aPnt2[1],aPnt2[2]); - theActor->AddClippingPlane(aPlane); - aPlane->Delete(); -} + SMESH::TActorList::iterator anIter = theActorList.begin(); + for ( ; anIter != theActorList.end(); anIter++ ) + if( vtkActor* aVTKActor = *anIter ) + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( aVTKActor ) ) + anActor->AddClippingPlane( aPlane ); -//================================================================================= -// used in SMESHGUI::restoreVisualParameters() to avoid -// declaration of OrientedPlane outside of SMESHGUI_ClippingDlg.cxx -//================================================================================= -void SMESHGUI_ClippingDlg::GetPlaneParam (SMESH_Actor* theActor, - int thePlaneIndex, - SMESH::Orientation& theOrientation, - double& theDistance, - vtkFloatingPointType* theAngle) -{ - if (vtkPlane* aPln = theActor->GetClippingPlane(thePlaneIndex)) { - if (OrientedPlane* aPlane = OrientedPlane::SafeDownCast(aPln)) { - theOrientation = aPlane->GetOrientation(); - theDistance = aPlane->GetDistance(); - theAngle[0] = aPlane->myAngle[0]; - theAngle[1] = aPlane->myAngle[1]; - } - } + return aPlane; } //================================================================================= @@ -328,11 +328,10 @@ void SMESHGUI_ClippingDlg::GetPlaneParam (SMESH_Actor* theActor, // purpose : // //================================================================================= -SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule ): +SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule, SVTK_ViewWindow* theViewWindow ): QDialog( SMESH::GetDesktop(theModule) ), - mySelector(SMESH::GetViewWindow(theModule)->GetSelector()), - mySelectionMgr(SMESH::GetSelectionMgr(theModule)), - mySMESHGUI(theModule) + mySMESHGUI(theModule), + myViewWindow(theViewWindow) { setModal( false ); setAttribute( Qt::WA_DeleteOnClose, true ); @@ -345,7 +344,7 @@ SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule ): // Controls for selecting, creating, deleting planes QGroupBox* GroupPlanes = new QGroupBox(tr("CLIP_PLANES"), this); - QHBoxLayout* GroupPlanesLayout = new QHBoxLayout(GroupPlanes); + QGridLayout* GroupPlanesLayout = new QGridLayout(GroupPlanes); GroupPlanesLayout->setSpacing(SPACING); GroupPlanesLayout->setMargin(MARGIN); @@ -355,10 +354,21 @@ SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule ): buttonDelete = new QPushButton(tr("SMESH_BUT_DELETE"), GroupPlanes); - GroupPlanesLayout->addWidget(ComboBoxPlanes); - GroupPlanesLayout->addStretch(); - GroupPlanesLayout->addWidget(buttonNew); - GroupPlanesLayout->addWidget(buttonDelete); + QLabel* aLabel = new QLabel(tr("MESHES_SUBMESHES_GROUPS"), GroupPlanes); + + ActorList = new QListWidget(GroupPlanes); + ActorList->setSelectionMode(QAbstractItemView::SingleSelection); + + SelectAllCheckBox = new QCheckBox(tr("SELECT_ALL"), GroupPlanes); + + GroupPlanesLayout->addWidget(ComboBoxPlanes, 0, 0); + GroupPlanesLayout->addWidget(new QWidget(), 0, 1); + GroupPlanesLayout->addWidget(buttonNew, 0, 2); + GroupPlanesLayout->addWidget(buttonDelete, 0, 3); + GroupPlanesLayout->addWidget(aLabel, 1, 0, 1, 4); + GroupPlanesLayout->addWidget(ActorList, 2, 0, 1, 4); + GroupPlanesLayout->addWidget(SelectAllCheckBox, 3, 0, 1, 4); + GroupPlanesLayout->setColumnStretch( 1, 1 ); // Controls for defining plane parameters QGroupBox* GroupParameters = new QGroupBox(tr("SMESH_PARAMETERS"), this); @@ -437,9 +447,10 @@ SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule ): SpinBoxDistance->SetValue(0.5); - myActor = 0; myIsSelectPlane = false; - onSelectionChanged(); + + initializePlaneData(); + synchronize(); myHelpFileName = "clipping_page.html"; @@ -447,6 +458,8 @@ SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule ): connect(ComboBoxPlanes, SIGNAL(activated(int)), this, SLOT(onSelectPlane(int))); connect(buttonNew, SIGNAL(clicked()), this, SLOT(ClickOnNew())); connect(buttonDelete, SIGNAL(clicked()), this, SLOT(ClickOnDelete())); + connect(ActorList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(onActorItemChanged(QListWidgetItem*))); + connect(SelectAllCheckBox, SIGNAL(stateChanged(int)), this, SLOT(onSelectAll(int))); connect(ComboBoxOrientation, SIGNAL(activated(int)), this, SLOT(onSelectOrientation(int))); connect(SpinBoxDistance, SIGNAL(valueChanged(double)), this, SLOT(SetCurrentPlaneParam())); connect(SpinBoxRot1, SIGNAL(valueChanged(double)), this, SLOT(SetCurrentPlaneParam())); @@ -458,7 +471,6 @@ SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule ): connect(buttonApply, SIGNAL(clicked()), this, SLOT(ClickOnApply())); connect(buttonHelp, SIGNAL(clicked()), this, SLOT(ClickOnHelp())); connect(mySMESHGUI, SIGNAL (SignalCloseAllDialogs()), this, SLOT(ClickOnCancel())); - connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(onSelectionChanged())); /* to close dialog if study frame change */ connect(mySMESHGUI, SIGNAL (SignalStudyFrameChanged()), this, SLOT(ClickOnCancel())); @@ -472,10 +484,9 @@ SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule ): SMESHGUI_ClippingDlg::~SMESHGUI_ClippingDlg() { // no need to delete child widgets, Qt does it all for us - std::for_each(myPlanes.begin(),myPlanes.end(),TSetVisiblity(false)); - if (mySMESHGUI) - if (SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(mySMESHGUI)) - SMESH::RenderViewWindow(aViewWindow); + std::for_each(myPlanes.begin(),myPlanes.end(),TSetVisibility(false)); + if (myViewWindow) + SMESH::RenderViewWindow(myViewWindow); } double SMESHGUI_ClippingDlg::getDistance() const @@ -504,27 +515,56 @@ double SMESHGUI_ClippingDlg::getRotation2() const //======================================================================= void SMESHGUI_ClippingDlg::ClickOnApply() { - if (!myActor) - return; - - if (SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(mySMESHGUI)) { + if (myViewWindow) { SUIT_OverrideCursor wc; QWidget *aCurrWid = this->focusWidget(); aCurrWid->clearFocus(); aCurrWid->setFocus(); - myActor->RemoveAllClippingPlanes(); - - SMESH::TPlanes::iterator anIter = myPlanes.begin(); - for ( ; anIter != myPlanes.end(); anIter++) { - OrientedPlane* anOrientedPlane = OrientedPlane::New(aViewWindow); - anOrientedPlane->ShallowCopy(anIter->GetPointer()); - myActor->AddClippingPlane(anOrientedPlane); - anOrientedPlane->Delete(); + SMESHGUI_ClippingPlaneInfoMap& aClippingPlaneInfoMap = mySMESHGUI->getClippingPlaneInfoMap(); + SMESHGUI_ClippingPlaneInfoList& aClippingPlaneInfoList = aClippingPlaneInfoMap[ myViewWindow->getViewManager() ]; + + // clean memory allocated for planes + SMESHGUI_ClippingPlaneInfoList::iterator anIter1 = aClippingPlaneInfoList.begin(); + for( ; anIter1 != aClippingPlaneInfoList.end(); anIter1++ ) + if( SMESH::OrientedPlane* aPlane = (*anIter1).Plane ) + aPlane->Delete(); + + aClippingPlaneInfoList.clear(); + + VTK::ActorCollectionCopy aCopy( myViewWindow->getRenderer()->GetActors() ); + vtkActorCollection* anAllActors = aCopy.GetActors(); + anAllActors->InitTraversal(); + while( vtkActor* aVTKActor = anAllActors->GetNextActor() ) + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( aVTKActor ) ) + anActor->RemoveAllClippingPlanes(); + + SMESH::TPlaneDataVector::iterator anIter2 = myPlanes.begin(); + for( ; anIter2 != myPlanes.end(); anIter2++ ) { + SMESH::TPlaneData aPlaneData = *anIter2; + SMESH::TPlane aPlane = aPlaneData.Plane; + SMESH::TActorList anActorList = aPlaneData.ActorList; + if( anActorList.empty() ) + continue; + + SMESH::OrientedPlane* anOrientedPlane = SMESH::OrientedPlane::New(myViewWindow); + anOrientedPlane->ShallowCopy(aPlane.GetPointer()); + + SMESH::TActorList::iterator anIter3 = anActorList.begin(); + for( ; anIter3 != anActorList.end(); anIter3++ ) + if( vtkActor* aVTKActor = *anIter3 ) + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( aVTKActor ) ) + anActor->AddClippingPlane(anOrientedPlane); + + SMESH::ClippingPlaneInfo aClippingPlaneInfo; + aClippingPlaneInfo.Plane = anOrientedPlane; + aClippingPlaneInfo.ActorList = anActorList; + + aClippingPlaneInfoList.push_back( aClippingPlaneInfo ); } - SMESH::RenderViewWindow(aViewWindow); + SMESH::RenderViewWindow( myViewWindow ); } } @@ -571,53 +611,17 @@ void SMESHGUI_ClippingDlg::ClickOnHelp() } } -//================================================================================= -// function : onSelectionChanged() -// purpose : Called when selection is changed -//================================================================================= -void SMESHGUI_ClippingDlg::onSelectionChanged() -{ - if (SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(mySMESHGUI)) { - const SALOME_ListIO& aList = mySelector->StoredIObjects(); - if (aList.Extent() > 0) { - Handle(SALOME_InteractiveObject) IOS = aList.First(); - myActor = SMESH::FindActorByEntry(IOS->getEntry()); - if (myActor) { - std::for_each(myPlanes.begin(),myPlanes.end(),TSetVisiblity(false)); - myPlanes.clear(); - - vtkIdType anId = 0, anEnd = myActor->GetNumberOfClippingPlanes(); - for ( ; anId < anEnd; anId++) { - if (vtkImplicitFunction* aFunction = myActor->GetClippingPlane(anId)) { - if(OrientedPlane* aPlane = OrientedPlane::SafeDownCast(aFunction)){ - OrientedPlane* anOrientedPlane = OrientedPlane::New(aViewWindow); - SMESH::TVTKPlane aTVTKPlane(anOrientedPlane); - anOrientedPlane->Delete(); - aTVTKPlane->ShallowCopy(aPlane); - myPlanes.push_back(aTVTKPlane); - } - } - } - - std::for_each(myPlanes.begin(),myPlanes.end(), - TSetVisiblity(PreviewCheckBox->isChecked())); - } - } - SMESH::RenderViewWindow(aViewWindow); - } - Sinchronize(); -} - //======================================================================= // function : onSelectPlane() // purpose : //======================================================================= void SMESHGUI_ClippingDlg::onSelectPlane (int theIndex) { - if (!myActor || myPlanes.empty()) + if (myPlanes.empty()) return; - OrientedPlane* aPlane = myPlanes[theIndex].GetPointer(); + SMESH::TPlaneData aPlaneData = myPlanes[theIndex]; + SMESH::OrientedPlane* aPlane = aPlaneData.Plane.GetPointer(); // Orientation SMESH::Orientation anOrientation = aPlane->GetOrientation(); @@ -644,6 +648,11 @@ void SMESHGUI_ClippingDlg::onSelectPlane (int theIndex) break; } myIsSelectPlane = false; + + // Actors + bool anIsBlocked = ActorList->blockSignals( true ); + updateActorList(); + ActorList->blockSignals( anIsBlocked ); } //======================================================================= @@ -652,19 +661,31 @@ void SMESHGUI_ClippingDlg::onSelectPlane (int theIndex) //======================================================================= void SMESHGUI_ClippingDlg::ClickOnNew() { - if (!myActor) - return; + if(myViewWindow){ + SMESH::OrientedPlane* aPlane = SMESH::OrientedPlane::New(myViewWindow); + SMESH::TPlane aTPlane(aPlane); + + SMESH::TActorList anActorList; + VTK::ActorCollectionCopy aCopy( myViewWindow->getRenderer()->GetActors() ); + vtkActorCollection* anAllActors = aCopy.GetActors(); + anAllActors->InitTraversal(); + while( vtkActor* aVTKActor = anAllActors->GetNextActor() ) + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( aVTKActor ) ) + anActorList.push_back( anActor ); - if(SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(mySMESHGUI)){ - OrientedPlane* aPlane = OrientedPlane::New(aViewWindow); - SMESH::TVTKPlane aTVTKPlane(aPlane); - myPlanes.push_back(aTVTKPlane); + SMESH::TPlaneData aPlaneData(aTPlane, anActorList); + + myPlanes.push_back(aPlaneData); if (PreviewCheckBox->isChecked()) - aTVTKPlane->myActor->VisibilityOn(); - - Sinchronize(); + aTPlane->myActor->VisibilityOn(); + + bool anIsBlocked = ActorList->blockSignals( true ); + + synchronize(); SetCurrentPlaneParam(); + + ActorList->blockSignals( anIsBlocked ); } } @@ -674,20 +695,105 @@ void SMESHGUI_ClippingDlg::ClickOnNew() //======================================================================= void SMESHGUI_ClippingDlg::ClickOnDelete() { - if (!myActor || myPlanes.empty()) + if (myPlanes.empty()) return; int aPlaneIndex = ComboBoxPlanes->currentIndex(); - SMESH::TPlanes::iterator anIter = myPlanes.begin() + aPlaneIndex; - anIter->GetPointer()->myActor->SetVisibility(false); + SMESH::TPlaneDataVector::iterator anIter = myPlanes.begin() + aPlaneIndex; + SMESH::TPlaneData aPlaneData = *anIter; + aPlaneData.Plane.GetPointer()->myActor->SetVisibility(false); myPlanes.erase(anIter); if(AutoApplyCheckBox->isChecked()) ClickOnApply(); - Sinchronize(); - SMESH::RenderViewWindow(SMESH::GetCurrentVtkView()); + synchronize(); + SMESH::RenderViewWindow( myViewWindow ); +} + +//======================================================================= +// function : updateActorItem() +// purpose : +//======================================================================= +void SMESHGUI_ClippingDlg::updateActorItem( QListWidgetItem* theItem, + bool theUpdateSelectAll, + bool theUpdateClippingPlaneMap ) +{ + // update Select All check box + if( theUpdateSelectAll ) { + int aNbItems = ActorList->count(), aNbChecked = 0; + for( int i = 0; i < aNbItems; i++ ) + if( QListWidgetItem* anItem = ActorList->item( i ) ) + if( anItem->checkState() == Qt::Checked ) + aNbChecked++; + + Qt::CheckState aCheckState = Qt::Unchecked; + if( aNbChecked == aNbItems ) + aCheckState = Qt::Checked; + else if( aNbChecked > 0 ) + aCheckState = Qt::PartiallyChecked; + + bool anIsBlocked = SelectAllCheckBox->blockSignals( true ); + SelectAllCheckBox->setCheckState( aCheckState ); + SelectAllCheckBox->blockSignals( anIsBlocked ); + } + + // update clipping plane map + if( theUpdateClippingPlaneMap ) { + int aCurPlaneIndex = ComboBoxPlanes->currentIndex(); + if( ActorItem* anItem = dynamic_cast( theItem ) ) { + if( SMESH_Actor* anActor = anItem->getActor() ) { + SMESH::TPlaneData& aPlaneData = myPlanes[ aCurPlaneIndex ]; + SMESH::TActorList& anActorList = aPlaneData.ActorList; + bool anIsPushed = false; + SMESH::TActorList::iterator anIter = anActorList.begin(); + for ( ; anIter != anActorList.end(); anIter++ ) { + if( anActor == *anIter ) { + anIsPushed = true; + break; + } + } + if( theItem->checkState() == Qt::Checked && !anIsPushed ) + anActorList.push_back( anActor ); + else if( theItem->checkState() == Qt::Unchecked && anIsPushed ) + anActorList.remove( anActor ); + } + } + } +} + +//======================================================================= +// function : onActorItemChanged() +// purpose : +//======================================================================= +void SMESHGUI_ClippingDlg::onActorItemChanged( QListWidgetItem* theItem ) +{ + updateActorItem( theItem, true, true ); + SetCurrentPlaneParam(); +} + +//======================================================================= +// function : onSelectAll() +// purpose : +//======================================================================= +void SMESHGUI_ClippingDlg::onSelectAll( int theState ) +{ + if( theState == Qt::PartiallyChecked ) { + SelectAllCheckBox->setCheckState( Qt::Checked ); + return; + } + + bool anIsBlocked = ActorList->blockSignals( true ); + for( int i = 0, n = ActorList->count(); i < n; i++ ) { + if( QListWidgetItem* anItem = ActorList->item( i ) ) { + anItem->setCheckState( theState == Qt::Checked ? Qt::Checked : Qt::Unchecked ); + updateActorItem( anItem, false, true ); + } + } + SelectAllCheckBox->setTristate( false ); + ActorList->blockSignals( anIsBlocked ); + SetCurrentPlaneParam(); } //======================================================================= @@ -717,10 +823,10 @@ void SMESHGUI_ClippingDlg::onSelectOrientation (int theItem) } //======================================================================= -// function : Sinchronize() +// function : synchronize() // purpose : //======================================================================= -void SMESHGUI_ClippingDlg::Sinchronize() +void SMESHGUI_ClippingDlg::synchronize() { int aNbPlanes = myPlanes.size(); ComboBoxPlanes->clear(); @@ -737,17 +843,22 @@ void SMESHGUI_ClippingDlg::Sinchronize() bool anIsControlsEnable = (aPos >= 0); if (anIsControlsEnable) { onSelectPlane(aPos); + updateActorList(); } else { ComboBoxPlanes->addItem(tr("NO_PLANES")); + ActorList->clear(); SpinBoxRot1->SetValue(0.0); SpinBoxRot2->SetValue(0.0); SpinBoxDistance->SetValue(0.5); } + ActorList->setEnabled(anIsControlsEnable); + SelectAllCheckBox->setEnabled(anIsControlsEnable); buttonDelete->setEnabled(anIsControlsEnable); - buttonApply->setEnabled(anIsControlsEnable); - PreviewCheckBox->setEnabled(anIsControlsEnable); - AutoApplyCheckBox->setEnabled(anIsControlsEnable); + // the following 3 controls should be enabled + //buttonApply->setEnabled(anIsControlsEnable); + //PreviewCheckBox->setEnabled(anIsControlsEnable); + //AutoApplyCheckBox->setEnabled(anIsControlsEnable); ComboBoxOrientation->setEnabled(anIsControlsEnable); SpinBoxDistance->setEnabled(anIsControlsEnable); SpinBoxRot1->setEnabled(anIsControlsEnable); @@ -775,7 +886,8 @@ void SMESHGUI_ClippingDlg::SetCurrentPlaneParam() int aCurPlaneIndex = ComboBoxPlanes->currentIndex(); - OrientedPlane* aPlane = myPlanes[aCurPlaneIndex].GetPointer(); + SMESH::TPlaneData aPlaneData = myPlanes[aCurPlaneIndex]; + SMESH::OrientedPlane* aPlane = aPlaneData.Plane.GetPointer(); vtkFloatingPointType aNormal[3]; SMESH::Orientation anOrientation; @@ -833,52 +945,69 @@ void SMESHGUI_ClippingDlg::SetCurrentPlaneParam() aPlane->SetOrientation(anOrientation); aPlane->SetDistance(getDistance()); - myActor->SetPlaneParam(aNormal, getDistance(), aPlane); - - vtkDataSet* aDataSet = myActor->GetInput(); - vtkFloatingPointType *aPnt = aDataSet->GetCenter(); - - vtkFloatingPointType* anOrigin = aPlane->GetOrigin(); - vtkFloatingPointType aDel = aDataSet->GetLength()/2.0; - - vtkFloatingPointType aDelta[2][3] = {{aDir[0][0]*aDel, aDir[0][1]*aDel, aDir[0][2]*aDel}, - {aDir[1][0]*aDel, aDir[1][1]*aDel, aDir[1][2]*aDel}}; - vtkFloatingPointType aParam, aPnt0[3], aPnt1[3], aPnt2[3]; - - vtkFloatingPointType aPnt01[3] = {aPnt[0] - aDelta[0][0] - aDelta[1][0], - aPnt[1] - aDelta[0][1] - aDelta[1][1], - aPnt[2] - aDelta[0][2] - aDelta[1][2]}; - vtkFloatingPointType aPnt02[3] = {aPnt01[0] + aNormal[0], - aPnt01[1] + aNormal[1], - aPnt01[2] + aNormal[2]}; - vtkPlane::IntersectWithLine(aPnt01,aPnt02,aNormal,anOrigin,aParam,aPnt0); - - vtkFloatingPointType aPnt11[3] = {aPnt[0] - aDelta[0][0] + aDelta[1][0], - aPnt[1] - aDelta[0][1] + aDelta[1][1], - aPnt[2] - aDelta[0][2] + aDelta[1][2]}; - vtkFloatingPointType aPnt12[3] = {aPnt11[0] + aNormal[0], - aPnt11[1] + aNormal[1], - aPnt11[2] + aNormal[2]}; - vtkPlane::IntersectWithLine(aPnt11,aPnt12,aNormal,anOrigin,aParam,aPnt1); - - vtkFloatingPointType aPnt21[3] = {aPnt[0] + aDelta[0][0] - aDelta[1][0], - aPnt[1] + aDelta[0][1] - aDelta[1][1], - aPnt[2] + aDelta[0][2] - aDelta[1][2]}; - vtkFloatingPointType aPnt22[3] = {aPnt21[0] + aNormal[0], - aPnt21[1] + aNormal[1], - aPnt21[2] + aNormal[2]}; - vtkPlane::IntersectWithLine(aPnt21,aPnt22,aNormal,anOrigin,aParam,aPnt2); - - vtkPlaneSource* aPlaneSource = aPlane->myPlaneSource; - aPlaneSource->SetNormal(aNormal[0],aNormal[1],aNormal[2]); - aPlaneSource->SetOrigin(aPnt0[0],aPnt0[1],aPnt0[2]); - aPlaneSource->SetPoint1(aPnt1[0],aPnt1[1],aPnt1[2]); - aPlaneSource->SetPoint2(aPnt2[0],aPnt2[1],aPnt2[2]); + SMESH::TActorList anActorList = aPlaneData.ActorList; + + vtkFloatingPointType aBounds[6]; + vtkFloatingPointType anOrigin[3]; + bool anIsOk = SMESH::ComputeClippingPlaneParameters( anActorList, + aNormal, + getDistance(), + aBounds, + anOrigin ); + + aPlane->myActor->SetVisibility( anIsOk && PreviewCheckBox->isChecked() ); + + if( anIsOk ) { + aPlane->SetNormal( aNormal ); + aPlane->SetOrigin( anOrigin ); + + vtkFloatingPointType aPnt[3] = { ( aBounds[0] + aBounds[1] ) / 2., + ( aBounds[2] + aBounds[3] ) / 2., + ( aBounds[4] + aBounds[5] ) / 2. }; + + vtkFloatingPointType aDel = pow( pow( aBounds[1] - aBounds[0], 2 ) + + pow( aBounds[3] - aBounds[2], 2 ) + + pow( aBounds[5] - aBounds[4], 2 ), 0.5 ); + + vtkFloatingPointType aDelta[2][3] = {{aDir[0][0]*aDel, aDir[0][1]*aDel, aDir[0][2]*aDel}, + {aDir[1][0]*aDel, aDir[1][1]*aDel, aDir[1][2]*aDel}}; + vtkFloatingPointType aParam, aPnt0[3], aPnt1[3], aPnt2[3]; + + vtkFloatingPointType aPnt01[3] = {aPnt[0] - aDelta[0][0] - aDelta[1][0], + aPnt[1] - aDelta[0][1] - aDelta[1][1], + aPnt[2] - aDelta[0][2] - aDelta[1][2]}; + vtkFloatingPointType aPnt02[3] = {aPnt01[0] + aNormal[0], + aPnt01[1] + aNormal[1], + aPnt01[2] + aNormal[2]}; + vtkPlane::IntersectWithLine(aPnt01,aPnt02,aNormal,anOrigin,aParam,aPnt0); + + vtkFloatingPointType aPnt11[3] = {aPnt[0] - aDelta[0][0] + aDelta[1][0], + aPnt[1] - aDelta[0][1] + aDelta[1][1], + aPnt[2] - aDelta[0][2] + aDelta[1][2]}; + vtkFloatingPointType aPnt12[3] = {aPnt11[0] + aNormal[0], + aPnt11[1] + aNormal[1], + aPnt11[2] + aNormal[2]}; + vtkPlane::IntersectWithLine(aPnt11,aPnt12,aNormal,anOrigin,aParam,aPnt1); + + vtkFloatingPointType aPnt21[3] = {aPnt[0] + aDelta[0][0] - aDelta[1][0], + aPnt[1] + aDelta[0][1] - aDelta[1][1], + aPnt[2] + aDelta[0][2] - aDelta[1][2]}; + vtkFloatingPointType aPnt22[3] = {aPnt21[0] + aNormal[0], + aPnt21[1] + aNormal[1], + aPnt21[2] + aNormal[2]}; + vtkPlane::IntersectWithLine(aPnt21,aPnt22,aNormal,anOrigin,aParam,aPnt2); + + vtkPlaneSource* aPlaneSource = aPlane->myPlaneSource; + aPlaneSource->SetNormal(aNormal[0],aNormal[1],aNormal[2]); + aPlaneSource->SetOrigin(aPnt0[0],aPnt0[1],aPnt0[2]); + aPlaneSource->SetPoint1(aPnt1[0],aPnt1[1],aPnt1[2]); + aPlaneSource->SetPoint2(aPnt2[0],aPnt2[1],aPnt2[2]); + } if(AutoApplyCheckBox->isChecked()) ClickOnApply(); - SMESH::RenderViewWindow(SMESH::GetCurrentVtkView()); + SMESH::RenderViewWindow( myViewWindow ); } //======================================================================= @@ -887,8 +1016,8 @@ void SMESHGUI_ClippingDlg::SetCurrentPlaneParam() //======================================================================= void SMESHGUI_ClippingDlg::OnPreviewToggle (bool theIsToggled) { - std::for_each(myPlanes.begin(),myPlanes.end(),TSetVisiblity(theIsToggled)); - SMESH::RenderViewWindow(SMESH::GetCurrentVtkView()); + std::for_each(myPlanes.begin(),myPlanes.end(),TSetVisibility(theIsToggled)); + SMESH::RenderViewWindow( myViewWindow ); } //================================================================================= @@ -906,3 +1035,124 @@ void SMESHGUI_ClippingDlg::keyPressEvent( QKeyEvent* e ) ClickOnHelp(); } } + +//================================================================================= +// function : initializePlaneData() +// purpose : +//================================================================================= +void SMESHGUI_ClippingDlg::initializePlaneData() +{ + const SMESHGUI_ClippingPlaneInfoMap& aClippingPlaneInfoMap = mySMESHGUI->getClippingPlaneInfoMap(); + SMESHGUI_ClippingPlaneInfoMap::const_iterator anIter1 = aClippingPlaneInfoMap.find( myViewWindow->getViewManager() ); + if( anIter1 != aClippingPlaneInfoMap.end() ) { + const SMESHGUI_ClippingPlaneInfoList& aClippingPlaneInfoList = anIter1->second; + SMESHGUI_ClippingPlaneInfoList::const_iterator anIter2 = aClippingPlaneInfoList.begin(); + for( ; anIter2 != aClippingPlaneInfoList.end(); anIter2++ ) { + const SMESH::ClippingPlaneInfo& aClippingPlaneInfo = *anIter2; + SMESH::TPlane aTPlane( aClippingPlaneInfo.Plane ); + SMESH::TPlaneData aPlaneData( aTPlane, aClippingPlaneInfo.ActorList ); + myPlanes.push_back( aPlaneData ); + } + } + std::for_each( myPlanes.begin(),myPlanes.end(), TSetVisibility( PreviewCheckBox->isChecked() ) ); +} + +//================================================================================= +// function : updateActorList() +// purpose : +//================================================================================= +void SMESHGUI_ClippingDlg::updateActorList() +{ + ActorList->clear(); + + SalomeApp_Study* anAppStudy = SMESHGUI::activeStudy(); + if( !anAppStudy ) + return; + + _PTR(Study) aStudy = anAppStudy->studyDS(); + if( !aStudy ) + return; + + if( !myViewWindow ) + return; + + int aCurPlaneIndex = ComboBoxPlanes->currentIndex(); + const SMESH::TPlaneData& aPlaneData = myPlanes[ aCurPlaneIndex ]; + const SMESH::TActorList& anActorList = aPlaneData.ActorList; + + VTK::ActorCollectionCopy aCopy( myViewWindow->getRenderer()->GetActors() ); + vtkActorCollection* anAllActors = aCopy.GetActors(); + anAllActors->InitTraversal(); + while( vtkActor* aVTKActor = anAllActors->GetNextActor() ) { + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( aVTKActor ) ) { + if( anActor->hasIO() ) { + Handle(SALOME_InteractiveObject) anIO = anActor->getIO(); + if( _PTR(SObject) aSObj = aStudy->FindObjectID( anIO->getEntry() ) ) { + bool anIsChecked = false; + SMESH::TActorList::const_iterator anIter = anActorList.begin(); + for ( ; anIter != anActorList.end(); anIter++ ) { + if( vtkActor* aVTKActorRef = *anIter ) { + if( SMESH_Actor* anActorRef = SMESH_Actor::SafeDownCast( aVTKActorRef ) ) { + if( anActorRef == anActor ) { + anIsChecked = true; + break; + } + } + } + } + QString aName = QString( aSObj->GetName().c_str() ); + QListWidgetItem* anItem = new ActorItem( anActor, aName, ActorList ); + anItem->setCheckState( anIsChecked ? Qt::Checked : Qt::Unchecked ); + updateActorItem( anItem, true, false ); + } + } + } + } +} + +//================================================================================= +// function : getCurrentActors() +// purpose : +//================================================================================= +SMESH::TActorList SMESHGUI_ClippingDlg::getCurrentActors() +{ + SMESH::TActorList anActorList; + for( int i = 0, n = ActorList->count(); i < n; i++ ) + if( ActorItem* anItem = dynamic_cast( ActorList->item( i ) ) ) + if( anItem->checkState() == Qt::Checked ) + if( SMESH_Actor* anActor = anItem->getActor() ) + anActorList.push_back( anActor ); + return anActorList; +} + +//================================================================================= +// function : dumpPlaneData() +// purpose : +//================================================================================= +void SMESHGUI_ClippingDlg::dumpPlaneData() const +{ + printf( "----------- Plane Data -----------\n" ); + int anId = 1; + SMESH::TPlaneDataVector::const_iterator anIter1 = myPlanes.begin(); + for ( ; anIter1 != myPlanes.end(); anIter1++, anId++ ) { + SMESH::TPlaneData aPlaneData = *anIter1; + SMESH::TPlane aPlane = aPlaneData.Plane; + vtkFloatingPointType* aNormal = aPlane->GetNormal(); + vtkFloatingPointType* anOrigin = aPlane->GetOrigin(); + printf( "Plane N%d:\n", anId ); + printf( " Normal = ( %f, %f, %f )\n", aNormal[0], aNormal[1], aNormal[2] ); + printf( " Origin = ( %f, %f, %f )\n", anOrigin[0], anOrigin[1], anOrigin[2] ); + + SMESH::TActorList anActorList = aPlaneData.ActorList; + SMESH::TActorList::const_iterator anIter2 = anActorList.begin(); + for ( ; anIter2 != anActorList.end(); anIter2++ ) { + if( vtkActor* aVTKActor = *anIter2 ) { + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( aVTKActor ) ) + printf( " - Actor: '%s'\n", anActor->getName() ); + } + else + printf( " - Actor: NULL\n"); + } + } + printf( "----------------------------------\n" ); +} diff --git a/src/SMESHGUI/SMESHGUI_ClippingDlg.h b/src/SMESHGUI/SMESHGUI_ClippingDlg.h index 0c70ca9c2..87a4b7b9d 100644 --- a/src/SMESHGUI/SMESHGUI_ClippingDlg.h +++ b/src/SMESHGUI/SMESHGUI_ClippingDlg.h @@ -35,31 +35,91 @@ // Qt includes #include +#include // VTK includes +#include #include // STL includes +#include +#include #include class QLabel; class QPushButton; class QCheckBox; class QComboBox; -class LightApp_SelectionMgr; -class SVTK_Selector; +class QListWidget; +class QListWidgetItem; +class SALOME_Actor; class SMESHGUI; class SMESH_Actor; -class OrientedPlane; class SMESHGUI_SpinBox; +class vtkActor; +class vtkDataSetMapper; +class vtkPlaneSource; namespace SMESH { - typedef vtkSmartPointer TVTKPlane; - typedef std::vector TPlanes; enum Orientation { XY, YZ, ZX }; -}; + class OrientedPlane: public vtkPlane + { + QPointer myViewWindow; + vtkDataSetMapper* myMapper; + + public: + static OrientedPlane *New(); + static OrientedPlane *New(SVTK_ViewWindow* theViewWindow); + vtkTypeMacro (OrientedPlane, vtkPlane); + + SMESH::Orientation myOrientation; + float myDistance; + double myAngle[2]; + + vtkPlaneSource* myPlaneSource; + SALOME_Actor *myActor; + + void SetOrientation (SMESH::Orientation theOrientation) { myOrientation = theOrientation; } + SMESH::Orientation GetOrientation() { return myOrientation; } + + void SetDistance (float theDistance) { myDistance = theDistance; } + float GetDistance() { return myDistance; } + + void ShallowCopy (OrientedPlane* theOrientedPlane); + + protected: + OrientedPlane(SVTK_ViewWindow* theViewWindow); + OrientedPlane(); + + void Init(); + + ~OrientedPlane(); + private: + // Not implemented. + OrientedPlane (const OrientedPlane&); + void operator= (const OrientedPlane&); + }; + + typedef vtkSmartPointer TPlane; + typedef std::list TActorList; + + struct TPlaneData + { + TPlaneData( TPlane thePlane, + TActorList theActorList ) + { + Plane = thePlane; + ActorList = theActorList; + } + TPlane Plane; + TActorList ActorList; + }; + + typedef std::vector TPlaneVector; + typedef std::vector TPlaneDataVector; +}; //================================================================================= // class : SMESHGUI_ClippingDlg @@ -70,7 +130,7 @@ class SMESHGUI_EXPORT SMESHGUI_ClippingDlg : public QDialog Q_OBJECT public: - SMESHGUI_ClippingDlg( SMESHGUI* ); + SMESHGUI_ClippingDlg( SMESHGUI*, SVTK_ViewWindow* ); ~SMESHGUI_ClippingDlg(); double getDistance() const; @@ -78,35 +138,42 @@ public: double getRotation1() const; double getRotation2() const; void setRotation( const double, const double ); - void Sinchronize(); // used in SMESHGUI::restoreVisualParameters() to avoid // declaration of OrientedPlane outside of SMESHGUI_ClippingDlg.cxx - static void AddPlane (SMESH_Actor* theActor, - SVTK_ViewWindow* theViewWindow, - SMESH::Orientation theOrientation, - double theDistance, - vtkFloatingPointType theAngle[2]); - - static void GetPlaneParam (SMESH_Actor* theActor, - int thePlaneIndex, - SMESH::Orientation& theOrientation, - double& theDistance, - vtkFloatingPointType* theAngle); + static SMESH::OrientedPlane* AddPlane (SMESH::TActorList theActorList, + SVTK_ViewWindow* theViewWindow, + SMESH::Orientation theOrientation, + double theDistance, + const vtkFloatingPointType theAngle[2]); protected: void keyPressEvent( QKeyEvent* ); private: - LightApp_SelectionMgr* mySelectionMgr; - SVTK_Selector* mySelector; + void initializePlaneData(); + + void synchronize(); + + void updateActorList(); + SMESH::TActorList getCurrentActors(); + + void updateActorItem( QListWidgetItem* theItem, + bool theUpdateSelectAll, + bool theUpdateClippingPlaneMap ); + + void dumpPlaneData() const; + +private: SMESHGUI* mySMESHGUI; - SMESH_Actor* myActor; - SMESH::TPlanes myPlanes; + SVTK_ViewWindow* myViewWindow; + SMESH::TPlaneDataVector myPlanes; QComboBox* ComboBoxPlanes; QPushButton* buttonNew; QPushButton* buttonDelete; + QListWidget* ActorList; + QCheckBox* SelectAllCheckBox; QLabel* TextLabelOrientation; QComboBox* ComboBoxOrientation; QLabel* TextLabelDistance; @@ -129,9 +196,10 @@ public slots: void onSelectPlane( int ); void ClickOnNew(); void ClickOnDelete(); + void onActorItemChanged( QListWidgetItem* ); + void onSelectAll( int ); void onSelectOrientation( int ); void SetCurrentPlaneParam(); - void onSelectionChanged(); void OnPreviewToggle( bool ); void ClickOnOk(); void ClickOnCancel(); diff --git a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx index 99da50cf2..ee88f7662 100755 --- a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx @@ -1379,6 +1379,8 @@ const char* SMESHGUI_FilterTable::getPrecision( const int aType ) retval = "len_tol_precision"; break; case SMESH::FT_Length: case SMESH::FT_Length2D: + case SMESH::FT_MaxElementLength2D: + case SMESH::FT_MaxElementLength3D: retval = "length_precision"; break; case SMESH::FT_Volume3D: retval = "vol_precision"; break; @@ -1795,6 +1797,7 @@ const QMap& SMESHGUI_FilterTable::getCriteria (const int theType) aCriteria[ SMESH::FT_Taper ] = tr("TAPER"); aCriteria[ SMESH::FT_Skew ] = tr("SKEW"); aCriteria[ SMESH::FT_Area ] = tr("AREA"); + aCriteria[ SMESH::FT_MaxElementLength2D ] = tr("MAX_ELEMENT_LENGTH_2D"); aCriteria[ SMESH::FT_FreeEdges ] = tr("FREE_EDGES"); aCriteria[ SMESH::FT_RangeOfIds ] = tr("RANGE_OF_IDS"); aCriteria[ SMESH::FT_BelongToGeom ] = tr("BELONG_TO_GEOM"); @@ -1817,14 +1820,15 @@ const QMap& SMESHGUI_FilterTable::getCriteria (const int theType) static QMap aCriteria; if (aCriteria.isEmpty()) { - aCriteria[ SMESH::FT_AspectRatio3D ] = tr("ASPECT_RATIO_3D"); - aCriteria[ SMESH::FT_RangeOfIds ] = tr("RANGE_OF_IDS"); - aCriteria[ SMESH::FT_BelongToGeom ] = tr("BELONG_TO_GEOM"); - aCriteria[ SMESH::FT_LyingOnGeom ] = tr("LYING_ON_GEOM"); - aCriteria[ SMESH::FT_BadOrientedVolume ] = tr("BAD_ORIENTED_VOLUME"); - aCriteria[ SMESH::FT_Volume3D ] = tr("VOLUME_3D"); - aCriteria[ SMESH::FT_LinearOrQuadratic ] = tr("LINEAR"); - aCriteria[ SMESH::FT_GroupColor ] = tr("GROUP_COLOR"); + aCriteria[ SMESH::FT_AspectRatio3D ] = tr("ASPECT_RATIO_3D"); + aCriteria[ SMESH::FT_RangeOfIds ] = tr("RANGE_OF_IDS"); + aCriteria[ SMESH::FT_BelongToGeom ] = tr("BELONG_TO_GEOM"); + aCriteria[ SMESH::FT_LyingOnGeom ] = tr("LYING_ON_GEOM"); + aCriteria[ SMESH::FT_BadOrientedVolume ] = tr("BAD_ORIENTED_VOLUME"); + aCriteria[ SMESH::FT_Volume3D ] = tr("VOLUME_3D"); + aCriteria[ SMESH::FT_MaxElementLength3D ] = tr("MAX_ELEMENT_LENGTH_3D"); + aCriteria[ SMESH::FT_LinearOrQuadratic ] = tr("LINEAR"); + aCriteria[ SMESH::FT_GroupColor ] = tr("GROUP_COLOR"); aCriteria[ SMESH::FT_ElemGeomType ] = tr("GEOM_TYPE"); } return aCriteria; diff --git a/src/SMESHGUI/SMESHGUI_Measurements.cxx b/src/SMESHGUI/SMESHGUI_Measurements.cxx new file mode 100644 index 000000000..b07c08dc4 --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_Measurements.cxx @@ -0,0 +1,1231 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 : SMESHGUI_Measurements.cxx +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) + +#include "SMESHGUI_Measurements.h" + +#include "SMESH_Actor.h" +#include "SMESHGUI.h" +#include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_Utils.h" +#include "SMESHGUI_VTKUtils.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 CORBA_SERVER_HEADER(SMESH_MeshEditor) +#include CORBA_SERVER_HEADER(SMESH_Measurements) + +const int SPACING = 6; // layout spacing +const int MARGIN = 9; // layout margin +const int MAX_NB_FOR_EDITOR = 40; // max nb of items in the ID list editor field + +// Uncomment as soon as elements are supported by Min Distance operation +//#define MINDIST_ENABLE_ELEMENT + +// Uncomment as soon as objects are supported by Min Distance operation +//#define MINDIST_ENABLE_OBJECT + +/*! + \class SMESHGUI_MinDistance + \brief Minimum distance measurement widget. + + Widget to calculate minimum distance between two objects. +*/ + +/*! + \brief Constructor. + \param parent parent widget +*/ +SMESHGUI_MinDistance::SMESHGUI_MinDistance( QWidget* parent ) +: QWidget( parent ), myCurrentTgt( FirstTgt ), myFirstActor( 0 ), mySecondActor( 0 ), myPreview( 0 ) +{ + QGroupBox* aFirstTgtGrp = new QGroupBox( tr( "FIRST_TARGET" ), this ); + QRadioButton* aFNode = new QRadioButton( tr( "NODE" ), aFirstTgtGrp ); + QRadioButton* aFElem = new QRadioButton( tr( "ELEMENT" ), aFirstTgtGrp ); + QRadioButton* aFObject = new QRadioButton( tr( "OBJECT" ), aFirstTgtGrp ); + myFirstTgt = new QLineEdit( aFirstTgtGrp ); + + QGridLayout* fl = new QGridLayout( aFirstTgtGrp ); + fl->setMargin( MARGIN ); + fl->setSpacing( SPACING ); + fl->addWidget( aFNode, 0, 0 ); + fl->addWidget( aFElem, 0, 1 ); + fl->addWidget( aFObject, 0, 2 ); + fl->addWidget( myFirstTgt, 1, 0, 1, 3 ); + + myFirst = new QButtonGroup( this ); + myFirst->addButton( aFNode, NodeTgt ); + myFirst->addButton( aFElem, ElementTgt ); + myFirst->addButton( aFObject, ObjectTgt ); + + QGroupBox* aSecondTgtGrp = new QGroupBox( tr( "SECOND_TARGET" ), this ); + QRadioButton* aSOrigin = new QRadioButton( tr( "ORIGIN" ), aSecondTgtGrp ); + QRadioButton* aSNode = new QRadioButton( tr( "NODE" ), aSecondTgtGrp ); + QRadioButton* aSElem = new QRadioButton( tr( "ELEMENT" ), aSecondTgtGrp ); + QRadioButton* aSObject = new QRadioButton( tr( "OBJECT" ), aSecondTgtGrp ); + mySecondTgt = new QLineEdit( aSecondTgtGrp ); + + QGridLayout* sl = new QGridLayout( aSecondTgtGrp ); + sl->setMargin( MARGIN ); + sl->setSpacing( SPACING ); + sl->addWidget( aSOrigin, 0, 0 ); + sl->addWidget( aSNode, 0, 1 ); + sl->addWidget( aSElem, 0, 2 ); + sl->addWidget( aSObject, 0, 3 ); + sl->addWidget( mySecondTgt, 1, 0, 1, 4 ); + + mySecond = new QButtonGroup( this ); + mySecond->addButton( aSOrigin, OriginTgt ); + mySecond->addButton( aSNode, NodeTgt ); + mySecond->addButton( aSElem, ElementTgt ); + mySecond->addButton( aSObject, ObjectTgt ); + + QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this ); + + QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this ); + QLabel* aDxLab = new QLabel( "dX", aResults ); + myDX = new QLineEdit( aResults ); + QLabel* aDyLab = new QLabel( "dY", aResults ); + myDY = new QLineEdit( aResults ); + QLabel* aDzLab = new QLabel( "dZ", aResults ); + myDZ = new QLineEdit( aResults ); + QLabel* aDistLab = new QLabel( tr( "DISTANCE" ), aResults ); + myDistance = new QLineEdit( aResults ); + + QGridLayout* rl = new QGridLayout( aResults ); + rl->setMargin( MARGIN ); + rl->setSpacing( SPACING ); + rl->addWidget( aDxLab, 0, 0 ); + rl->addWidget( myDX, 0, 1 ); + rl->addWidget( aDyLab, 1, 0 ); + rl->addWidget( myDY, 1, 1 ); + rl->addWidget( aDzLab, 2, 0 ); + rl->addWidget( myDZ, 2, 1 ); + rl->addWidget( aDistLab, 0, 2 ); + rl->addWidget( myDistance, 0, 3 ); + + QGridLayout* l = new QGridLayout( this ); + l->setMargin( MARGIN ); + l->setSpacing( SPACING ); + + l->addWidget( aFirstTgtGrp, 0, 0, 1, 2 ); + l->addWidget( aSecondTgtGrp, 1, 0, 1, 2 ); + l->addWidget( aCompute, 2, 0 ); + l->addWidget( aResults, 3, 0, 1, 2 ); + l->setColumnStretch( 1, 5 ); + l->setRowStretch( 4, 5 ); + + aFNode->setChecked( true ); + aSOrigin->setChecked( true ); +#ifndef MINDIST_ENABLE_ELEMENT + aFElem->setEnabled( false ); // NOT AVAILABLE YET + aSElem->setEnabled( false ); // NOT AVAILABLE YET +#endif +#ifndef MINDIST_ENABLE_OBJECT + aFObject->setEnabled( false ); // NOT AVAILABLE YET + aSObject->setEnabled( false ); // NOT AVAILABLE YET +#endif + myDX->setReadOnly( true ); + myDY->setReadOnly( true ); + myDZ->setReadOnly( true ); + myDistance->setReadOnly( true ); + + myValidator = new SMESHGUI_IdValidator( this, 1 ); + + myFirstTgt->installEventFilter( this ); + mySecondTgt->installEventFilter( this ); + + connect( myFirst, SIGNAL( buttonClicked( int ) ), this, SLOT( firstChanged() ) ); + connect( mySecond, SIGNAL( buttonClicked( int ) ), this, SLOT( secondChanged() ) ); + connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ) ); + connect( myFirstTgt, SIGNAL( textEdited( QString ) ), this, SLOT( firstEdited() ) ); + connect( mySecondTgt, SIGNAL( textEdited( QString ) ), this, SLOT( secondEdited() ) ); + + QList filters; + filters.append( new SMESH_TypeFilter( MESHorSUBMESH ) ); + filters.append( new SMESH_TypeFilter( GROUP ) ); + myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR ); + + mySecondTgt->setEnabled( mySecond->checkedId() != OriginTgt ); + clear(); + + //setTarget( FirstTgt ); +} + +/*! + \brief Destructor +*/ +SMESHGUI_MinDistance::~SMESHGUI_MinDistance() +{ + erasePreview(); + if ( myPreview ) + myPreview->Delete(); +} + +/*! + \brief Event filter + \param o object + \param o event + \return \c true if event is filtered or \c false otherwise +*/ +bool SMESHGUI_MinDistance::eventFilter( QObject* o, QEvent* e ) +{ + if ( e->type() == QEvent::FocusIn ) { + if ( o == myFirstTgt ) + setTarget( FirstTgt ); + else if ( o == mySecondTgt ) + setTarget( SecondTgt ); + } + return QWidget::eventFilter( o, e ); +} + +/*! + \brief Setup selection mode depending on the current widget state +*/ +void SMESHGUI_MinDistance::updateSelection() +{ + LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); + + disconnect( selMgr, 0, this, 0 ); + selMgr->clearFilters(); + + bool nodeMode = ( myCurrentTgt == FirstTgt && myFirst->checkedId() == NodeTgt ) || + ( myCurrentTgt == SecondTgt && mySecond->checkedId() == NodeTgt ); + bool elemMode = ( myCurrentTgt == FirstTgt && myFirst->checkedId() == ElementTgt ) || + ( myCurrentTgt == SecondTgt && mySecond->checkedId() == ElementTgt ); + bool objMode = ( myCurrentTgt == FirstTgt && myFirst->checkedId() == ObjectTgt ) || + ( myCurrentTgt == SecondTgt && mySecond->checkedId() == ObjectTgt ) || + ( myCurrentTgt == NoTgt ); + + if ( nodeMode ) { + SMESH::SetPointRepresentation( true ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( NodeSelection ); + } + else if ( elemMode ) { + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( CellSelection ); + } + else if ( objMode ) { + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( ActorSelection ); + selMgr->installFilter( myFilter ); + } + + connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) ); + + if ( myCurrentTgt == FirstTgt ) + firstEdited(); + else if ( myCurrentTgt == SecondTgt ) + secondEdited(); + + //selectionChanged(); +} + +/*! + \brief Deactivate widget +*/ +void SMESHGUI_MinDistance::deactivate() +{ + disconnect( SMESHGUI::selectionMgr(), 0, this, 0 ); +} + +/*! + \brief Set current target for selection + \param target new target ID +*/ +void SMESHGUI_MinDistance::setTarget( int target ) +{ + if ( myCurrentTgt != target ) { + myCurrentTgt = target; + updateSelection(); + } +} + +/*! + \brief Erase preview actor +*/ +void SMESHGUI_MinDistance::erasePreview() +{ + SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(); + if ( aViewWindow && myPreview ) { + aViewWindow->RemoveActor( myPreview ); + aViewWindow->Repaint(); + } +} + +/*! + \brief Display preview actor +*/ +void SMESHGUI_MinDistance::displayPreview() +{ + SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(); + if ( aViewWindow && myPreview ) { + aViewWindow->AddActor( myPreview ); + aViewWindow->Repaint(); + } +} + +/*! + \brief Create preview actor + \param x1 X coordinate of first point + \param y1 X coordinate of first point + \param z1 Y coordinate of first point + \param x2 Y coordinate of second point + \param y2 Z coordinate of second point + \param z2 Z coordinate of second point +*/ +void SMESHGUI_MinDistance::createPreview( double x1, double y1, double z1, double x2, double y2, double z2 ) +{ + if ( myPreview ) + myPreview->Delete(); + + vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New(); + // create points + vtkPoints* aPoints = vtkPoints::New(); + aPoints->SetNumberOfPoints( 2 ); + aPoints->SetPoint( 0, x1, y1, z1 ); + aPoints->SetPoint( 1, x2, y2, z2 ); + aGrid->SetPoints( aPoints ); + aPoints->Delete(); + // create cells + vtkIdList* anIdList = vtkIdList::New(); + anIdList->SetNumberOfIds( 2 ); + vtkCellArray* aCells = vtkCellArray::New(); + aCells->Allocate( 2, 0); + vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New(); + aCellTypesArray->SetNumberOfComponents( 1 ); + aCellTypesArray->Allocate( 1 ); + anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 1 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->Delete(); + VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New(); + aCellLocationsArray->SetNumberOfComponents( 1 ); + aCellLocationsArray->SetNumberOfTuples( 1 ); + aCells->InitTraversal(); + for( vtkIdType idType = 0, *pts, npts; aCells->GetNextCell( npts, pts ); idType++ ) + aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) ); + aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells ); + aCellLocationsArray->Delete(); + aCellTypesArray->Delete(); + aCells->Delete(); + // create actor + vtkDataSetMapper* aMapper = vtkDataSetMapper::New(); + aMapper->SetInput( aGrid ); + aGrid->Delete(); + myPreview = SALOME_Actor::New(); + myPreview->PickableOff(); + myPreview->SetMapper( aMapper ); + aMapper->Delete(); + vtkProperty* aProp = vtkProperty::New(); + aProp->SetRepresentationToWireframe(); + aProp->SetColor( 250, 0, 250 ); + aProp->SetPointSize( 5 ); + aProp->SetLineWidth( 3 ); + myPreview->SetProperty( aProp ); + aProp->Delete(); +} + +/*! + \brief Called when selection is changed +*/ +void SMESHGUI_MinDistance::selectionChanged() +{ + SUIT_OverrideCursor wc; + + SALOME_ListIO selected; + SMESHGUI::selectionMgr()->selectedObjects( selected ); + + if ( selected.Extent() == 1 ) { + Handle(SALOME_InteractiveObject) IO = selected.First(); + SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface( IO ); + if ( !CORBA::is_nil( obj ) ) { + if ( myCurrentTgt == FirstTgt ) { + myFirstSrc = obj; + myFirstActor = SMESH::FindActorByEntry( IO->getEntry() ); + if ( myFirst->checkedId() == ObjectTgt ) { + QString aName; + SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName ); + myFirstTgt->setText( aName ); + } + else { + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + QString ID; + int nb = 0; + if ( myFirstActor && selector ) { + nb = myFirst->checkedId() == NodeTgt ? + SMESH::GetNameOfSelectedElements( selector, IO, ID ) : + SMESH::GetNameOfSelectedNodes( selector, IO, ID ); + } + if ( nb == 1 ) + myFirstTgt->setText( ID.trimmed() ); + else + myFirstTgt->clear(); + } + } + else if ( myCurrentTgt == SecondTgt ) { + mySecondSrc = obj; + mySecondActor = SMESH::FindActorByEntry( IO->getEntry() ); + if ( mySecond->checkedId() == ObjectTgt ) { + QString aName; + SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName ); + mySecondTgt->setText( aName ); + } + else { + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + QString ID; + int nb = 0; + if ( mySecondActor && selector ) { + nb = mySecond->checkedId() == NodeTgt ? + SMESH::GetNameOfSelectedElements( selector, IO, ID ) : + SMESH::GetNameOfSelectedNodes( selector, IO, ID ); + } + if ( nb == 1 ) + mySecondTgt->setText( ID.trimmed() ); + else + mySecondTgt->clear(); + } + } + } + } + clear(); +} + +/*! + \brief Called when first target mode is changed by the user +*/ +void SMESHGUI_MinDistance::firstChanged() +{ + myFirstSrc = SMESH::SMESH_IDSource::_nil(); + myFirstTgt->clear(); + myFirstTgt->setReadOnly( myFirst->checkedId() == ObjectTgt ); + myFirstTgt->setValidator( myFirst->checkedId() == ObjectTgt ? 0 : myValidator ); + setTarget( FirstTgt ); + updateSelection(); + clear(); +} + +/*! + \brief Called when second target mode is changed by the user +*/ +void SMESHGUI_MinDistance::secondChanged() +{ + mySecondSrc = SMESH::SMESH_IDSource::_nil(); + mySecondTgt->setEnabled( mySecond->checkedId() != OriginTgt ); + mySecondTgt->setReadOnly( mySecond->checkedId() == ObjectTgt ); + mySecondTgt->setValidator( mySecond->checkedId() == ObjectTgt ? 0 : myValidator ); + mySecondTgt->clear(); + setTarget( mySecond->checkedId() != OriginTgt ? SecondTgt : NoTgt ); + updateSelection(); + clear(); +} + +/*! + \brief Called when first target is edited by the user +*/ +void SMESHGUI_MinDistance::firstEdited() +{ + setTarget( FirstTgt ); + if ( sender() == myFirstTgt ) + clear(); + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + if ( myFirstActor && selector ) { + Handle(SALOME_InteractiveObject) IO = myFirstActor->getIO(); + if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) { + TColStd_MapOfInteger ID; + ID.Add( myFirstTgt->text().toLong() ); + selector->AddOrRemoveIndex( IO, ID, false ); + } + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->highlight( IO, true, true ); + } +} + +/*! + \brief Called when second target is edited by the user +*/ +void SMESHGUI_MinDistance::secondEdited() +{ + setTarget( SecondTgt ); + if ( sender() == mySecondTgt ) + clear(); + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + if ( mySecondActor && selector ) { + Handle(SALOME_InteractiveObject) IO = mySecondActor->getIO(); + if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) { + TColStd_MapOfInteger ID; + ID.Add( mySecondTgt->text().toLong() ); + selector->AddOrRemoveIndex( IO, ID, false ); + } + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->highlight( IO, true, true ); + } +} + +/*! + \brief Compute the minimum distance between targets +*/ +void SMESHGUI_MinDistance::compute() +{ + SUIT_OverrideCursor wc; + SMESH::SMESH_IDSource_var s1; + SMESH::SMESH_IDSource_var s2; + bool isOrigin = mySecond->checkedId() == OriginTgt; + + // process first target + if ( !CORBA::is_nil( myFirstSrc ) ) { + if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) { + SMESH::SMESH_Mesh_var m = myFirstSrc->GetMesh(); + long id = myFirstTgt->text().toLong(); + if ( !CORBA::is_nil( m ) && id ) { + SMESH::long_array_var ids = new SMESH::long_array(); + ids->length( 1 ); + ids[0] = id; + SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor(); + s1 = me->MakeIDSource( ids.in(), myFirst->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE ); + } + } + else { + s1 = myFirstSrc; + } + } + + // process second target + if ( !CORBA::is_nil( mySecondSrc ) ) { + if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) { + SMESH::SMESH_Mesh_var m = mySecondSrc->GetMesh(); + long id = mySecondTgt->text().toLong(); + if ( !CORBA::is_nil( m ) && id ) { + SMESH::long_array_var ids = new SMESH::long_array(); + ids->length( 1 ); + ids[0] = id; + SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor(); + s2 = me->MakeIDSource( ids.in(), mySecond->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE ); + } + } + else { + s2 = mySecondSrc; + } + } + + if ( !CORBA::is_nil( s1 ) && ( !CORBA::is_nil( s2 ) || isOrigin ) ) { + // compute min distance + int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); + SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements(); + SMESH::Measure result = measure->MinDistance( s1.in(), s2.in() ); + measure->Destroy(); + myDX->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myDY->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myDZ->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myDistance->setText( QString::number( result.value, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + // update preview actor + erasePreview(); + double x1, y1, z1, x2, y2, z2; + SMESH::double_array_var coord = s1->GetMesh()->GetNodeXYZ( result.node1 ); + x1 = coord[0]; y1 = coord[1]; z1 = coord[2]; + if ( isOrigin ) { + x2 = y2 = z2 = 0.; + } + else { + coord = s2->GetMesh()->GetNodeXYZ( result.node2 ); + x2 = coord[0]; y2 = coord[1]; z2 = coord[2]; + } + createPreview( x1, y1, z1, x2, y2, z2 ); + displayPreview(); + } + else { + clear(); + } +} + +/*! + \brief Reset the widget to the initial state (nullify result fields) +*/ +void SMESHGUI_MinDistance::clear() +{ + myDX->clear(); + myDY->clear(); + myDZ->clear(); + myDistance->clear(); + erasePreview(); +} + +/*! + \class SMESHGUI_BoundingBox + \brief Bounding box measurement widget. + + Widget to calculate bounding box of the selected object(s). +*/ + +/*! + \brief Constructor. + \param parent parent widget +*/ +SMESHGUI_BoundingBox::SMESHGUI_BoundingBox( QWidget* parent ) +: QWidget( parent ), myActor( 0 ), myPreview( 0 ) +{ + QGroupBox* aSourceGrp = new QGroupBox( tr( "SOURCE" ), this ); + QRadioButton* aObjects = new QRadioButton( tr( "OBJECTS" ), aSourceGrp ); + QRadioButton* aNodes = new QRadioButton( tr( "NODES" ), aSourceGrp ); + QRadioButton* aElements = new QRadioButton( tr( "ELEMENTS" ), aSourceGrp ); + mySource = new QLineEdit( aSourceGrp ); + + QGridLayout* fl = new QGridLayout( aSourceGrp ); + fl->setMargin( MARGIN ); + fl->setSpacing( SPACING ); + fl->addWidget( aObjects, 0, 0 ); + fl->addWidget( aNodes, 0, 1 ); + fl->addWidget( aElements, 0, 2 ); + fl->addWidget( mySource, 1, 0, 1, 3 ); + + mySourceMode = new QButtonGroup( this ); + mySourceMode->addButton( aObjects, ObjectsSrc ); + mySourceMode->addButton( aNodes, NodesSrc ); + mySourceMode->addButton( aElements, ElementsSrc ); + + QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this ); + + QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this ); + QLabel* aXminLab = new QLabel( "Xmin", aResults ); + myXmin = new QLineEdit( aResults ); + QLabel* aXmaxLab = new QLabel( "Xmax", aResults ); + myXmax = new QLineEdit( aResults ); + QLabel* aDxLab = new QLabel( "dX", aResults ); + myDX = new QLineEdit( aResults ); + QLabel* aYminLab = new QLabel( "Ymin", aResults ); + myYmin = new QLineEdit( aResults ); + QLabel* aYmaxLab = new QLabel( "Ymax", aResults ); + myYmax = new QLineEdit( aResults ); + QLabel* aDyLab = new QLabel( "dY", aResults ); + myDY = new QLineEdit( aResults ); + QLabel* aZminLab = new QLabel( "Zmin", aResults ); + myZmin = new QLineEdit( aResults ); + QLabel* aZmaxLab = new QLabel( "Zmax", aResults ); + myZmax = new QLineEdit( aResults ); + QLabel* aDzLab = new QLabel( "dZ", aResults ); + myDZ = new QLineEdit( aResults ); + + QGridLayout* rl = new QGridLayout( aResults ); + rl->setMargin( MARGIN ); + rl->setSpacing( SPACING ); + rl->addWidget( aXminLab, 0, 0 ); + rl->addWidget( myXmin, 0, 1 ); + rl->addWidget( aXmaxLab, 0, 2 ); + rl->addWidget( myXmax, 0, 3 ); + rl->addWidget( aDxLab, 0, 4 ); + rl->addWidget( myDX, 0, 5 ); + rl->addWidget( aYminLab, 1, 0 ); + rl->addWidget( myYmin, 1, 1 ); + rl->addWidget( aYmaxLab, 1, 2 ); + rl->addWidget( myYmax, 1, 3 ); + rl->addWidget( aDyLab, 1, 4 ); + rl->addWidget( myDY, 1, 5 ); + rl->addWidget( aZminLab, 2, 0 ); + rl->addWidget( myZmin, 2, 1 ); + rl->addWidget( aZmaxLab, 2, 2 ); + rl->addWidget( myZmax, 2, 3 ); + rl->addWidget( aDzLab, 2, 4 ); + rl->addWidget( myDZ, 2, 5 ); + + QGridLayout* l = new QGridLayout( this ); + l->setMargin( MARGIN ); + l->setSpacing( SPACING ); + + l->addWidget( aSourceGrp, 0, 0, 1, 2 ); + l->addWidget( aCompute, 1, 0 ); + l->addWidget( aResults, 2, 0, 1, 2 ); + l->setColumnStretch( 1, 5 ); + l->setRowStretch( 3, 5 ); + + aObjects->setChecked( true ); + myXmin->setReadOnly( true ); + myXmax->setReadOnly( true ); + myDX->setReadOnly( true ); + myYmin->setReadOnly( true ); + myYmax->setReadOnly( true ); + myDY->setReadOnly( true ); + myZmin->setReadOnly( true ); + myZmax->setReadOnly( true ); + myDZ->setReadOnly( true ); + + myValidator = new SMESHGUI_IdValidator( this ); + + connect( mySourceMode, SIGNAL( buttonClicked( int ) ), this, SLOT( sourceChanged() ) ); + connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ) ); + connect( mySource, SIGNAL( textEdited( QString ) ), this, SLOT( sourceEdited() ) ); + + QList filters; + filters.append( new SMESH_TypeFilter( MESHorSUBMESH ) ); + filters.append( new SMESH_TypeFilter( GROUP ) ); + myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR ); + + clear(); +} + +/*! + \brief Destructor +*/ +SMESHGUI_BoundingBox::~SMESHGUI_BoundingBox() +{ + erasePreview(); + if ( myPreview ) + myPreview->Delete(); +} + +/*! + \brief Setup selection mode depending on the current widget state +*/ +void SMESHGUI_BoundingBox::updateSelection() +{ + LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); + + disconnect( selMgr, 0, this, 0 ); + selMgr->clearFilters(); + + bool nodeMode = mySourceMode->checkedId() == NodesSrc; + bool elemMode = mySourceMode->checkedId() == ElementsSrc; + bool objMode = mySourceMode->checkedId() == ObjectsSrc; + + if ( nodeMode ) { + SMESH::SetPointRepresentation( true ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( NodeSelection ); + } + else if ( elemMode ) { + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( CellSelection ); + } + else if ( objMode ) { + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( ActorSelection ); + selMgr->installFilter( myFilter ); + } + + connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) ); + + sourceEdited(); + + //selectionChanged(); +} + +/*! + \brief Deactivate widget +*/ +void SMESHGUI_BoundingBox::deactivate() +{ + disconnect( SMESHGUI::selectionMgr(), 0, this, 0 ); +} + +/*! + \brief Erase preview actor +*/ +void SMESHGUI_BoundingBox::erasePreview() +{ + SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(); + if ( aViewWindow && myPreview ) { + aViewWindow->RemoveActor( myPreview ); + aViewWindow->Repaint(); + } +} + +/*! + \brief Display preview actor +*/ +void SMESHGUI_BoundingBox::displayPreview() +{ + SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(); + if ( aViewWindow && myPreview ) { + aViewWindow->AddActor( myPreview ); + aViewWindow->Repaint(); + } +} + +/*! + \brief Create preview actor + \param minX min X coordinate of bounding box + \param maxX max X coordinate of bounding box + \param minY min Y coordinate of bounding box + \param maxY max Y coordinate of bounding box + \param minZ min Z coordinate of bounding box + \param maxZ max Z coordinate of bounding box +*/ +void SMESHGUI_BoundingBox::createPreview( double minX, double maxX, double minY, double maxY, double minZ, double maxZ ) +{ + if ( myPreview ) + myPreview->Delete(); + + vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New(); + // create points + vtkPoints* aPoints = vtkPoints::New(); + aPoints->SetNumberOfPoints( 8 ); + aPoints->SetPoint( 0, minX, minY, minZ ); + aPoints->SetPoint( 1, maxX, minY, minZ ); + aPoints->SetPoint( 2, minX, maxY, minZ ); + aPoints->SetPoint( 3, maxX, maxY, minZ ); + aPoints->SetPoint( 4, minX, minY, maxZ ); + aPoints->SetPoint( 5, maxX, minY, maxZ ); + aPoints->SetPoint( 6, minX, maxY, maxZ ); + aPoints->SetPoint( 7, maxX, maxY, maxZ ); + aGrid->SetPoints( aPoints ); + aPoints->Delete(); + // create cells + // connectivity: 0-1 0-4 0-2 1-5 1-3 2-6 2-3 3-7 4-6 4-5 5-7 6-7 + vtkIdList* anIdList = vtkIdList::New(); + anIdList->SetNumberOfIds( 2 ); + vtkCellArray* aCells = vtkCellArray::New(); + aCells->Allocate( 2*12, 0); + vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New(); + aCellTypesArray->SetNumberOfComponents( 1 ); + aCellTypesArray->Allocate( 12 ); + anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 1 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 4 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 2 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 5 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 3 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 6 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 3 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 3 ); anIdList->SetId( 1, 7 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 6 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 5 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 5 ); anIdList->SetId( 1, 7 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 6 ); anIdList->SetId( 1, 7 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->Delete(); + VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New(); + aCellLocationsArray->SetNumberOfComponents( 1 ); + aCellLocationsArray->SetNumberOfTuples( 12 ); + aCells->InitTraversal(); + for( vtkIdType idType = 0, *pts, npts; aCells->GetNextCell( npts, pts ); idType++ ) + aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) ); + aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells ); + aCellLocationsArray->Delete(); + aCellTypesArray->Delete(); + aCells->Delete(); + // create actor + vtkDataSetMapper* aMapper = vtkDataSetMapper::New(); + aMapper->SetInput( aGrid ); + aGrid->Delete(); + myPreview = SALOME_Actor::New(); + myPreview->PickableOff(); + myPreview->SetMapper( aMapper ); + aMapper->Delete(); + vtkProperty* aProp = vtkProperty::New(); + aProp->SetRepresentationToWireframe(); + aProp->SetColor( 250, 0, 250 ); + aProp->SetPointSize( 5 ); + aProp->SetLineWidth( 3 ); + myPreview->SetProperty( aProp ); + aProp->Delete(); +} + +/*! + \brief Called when selection is changed +*/ +void SMESHGUI_BoundingBox::selectionChanged() +{ + SUIT_OverrideCursor wc; + + SALOME_ListIO selected; + SMESHGUI::selectionMgr()->selectedObjects( selected ); + + if ( selected.Extent() == 1 ) { + Handle(SALOME_InteractiveObject) IO = selected.First(); + SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface( IO ); + if ( !CORBA::is_nil( obj ) ) { + mySrc.clear(); + mySrc.append( obj ); + myActor = SMESH::FindActorByEntry( IO->getEntry() ); + if ( mySourceMode->checkedId() == ObjectsSrc ) { + QString aName; + SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName ); + mySource->setText( aName ); + } + else { + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + QString ID; + int nb = 0; + if ( myActor && selector ) { + nb = mySourceMode->checkedId() == NodesSrc ? + SMESH::GetNameOfSelectedElements( selector, IO, ID ) : + SMESH::GetNameOfSelectedNodes( selector, IO, ID ); + } + if ( nb > 0 ) { + myIDs = ID.trimmed(); + if ( nb < MAX_NB_FOR_EDITOR ) { + mySource->setReadOnly( false ); + if ( mySource->validator() != myValidator ) + mySource->setValidator( myValidator ); + mySource->setText( ID.trimmed() ); + } + else { + mySource->setReadOnly( true ); + mySource->setValidator( 0 ); + mySource->setText( tr( "SELECTED_NB_OBJ" ).arg( nb ) + .arg( mySourceMode->checkedId() == NodesSrc ? tr( "NB_NODES" ) : tr( "NB_ELEMENTS") ) ); + } + } + else { + myIDs = ""; + mySource->clear(); + mySource->setReadOnly( false ); + mySource->setValidator( myValidator ); + } + } + } + } + else if ( selected.Extent() > 1 ) { + myIDs = ""; + SALOME_ListIteratorOfListIO It( selected ); + mySrc.clear(); + myActor = 0; + if ( mySourceMode->checkedId() == ObjectsSrc ) { + for( ; It.More(); It.Next()){ + Handle(SALOME_InteractiveObject) IO = It.Value(); + SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface( IO ); + if ( !CORBA::is_nil( obj ) ) { + mySrc.append( obj ); + } + } + QString aName; + SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName ); + mySource->setText( aName ); + } + else { + mySource->clear(); + } + } + clear(); +} + +/*! + \brief Called when source mode is changed by the user +*/ +void SMESHGUI_BoundingBox::sourceChanged() +{ + myIDs = ""; + mySource->clear(); + mySource->setReadOnly( mySourceMode->checkedId() == ObjectsSrc ); + mySource->setValidator( mySourceMode->checkedId() == ObjectsSrc ? 0 : myValidator ); + updateSelection(); + clear(); +} + +/*! + \brief Called when source mode is edited by the user +*/ +void SMESHGUI_BoundingBox::sourceEdited() +{ + if ( sender() == mySource ) + clear(); + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + if ( myActor && selector ) { + Handle(SALOME_InteractiveObject) IO = myActor->getIO(); + if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) { + TColStd_MapOfInteger ID; + if ( !mySource->isReadOnly() ) + myIDs = mySource->text(); + QStringList ids = myIDs.split( " ", QString::SkipEmptyParts ); + foreach ( QString id, ids ) + ID.Add( id.trimmed().toLong() ); + selector->AddOrRemoveIndex( IO, ID, false ); + } + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->highlight( IO, true, true ); + } +} + +/*! + \brief Calculate bounding box of the selected object(s) +*/ +void SMESHGUI_BoundingBox::compute() +{ + SUIT_OverrideCursor wc; + SMESH::ListOfIDSources_var srcList = new SMESH::ListOfIDSources(); + if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) { + if ( mySrc.count() > 0 && !CORBA::is_nil( mySrc[0] ) ) { + SMESH::SMESH_Mesh_var m = mySrc[0]->GetMesh(); + QStringList ids = myIDs.split( " ", QString::SkipEmptyParts ); + if ( !CORBA::is_nil( m ) && ids.count() > 0 ) { + SMESH::long_array_var ids_in = new SMESH::long_array(); + ids_in->length( ids.count() ); + for( int i = 0; i < ids.count(); i++ ) + ids_in[i] = ids[i].trimmed().toLong(); + SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor(); + SMESH::SMESH_IDSource_var s = me->MakeIDSource( ids_in.in(), mySourceMode->checkedId() == NodesSrc ? SMESH::NODE : SMESH::FACE ); + srcList->length( 1 ); + srcList[0] = s; + } + } + } + else { + srcList->length( mySrc.count() ); + for( int i = 0; i < mySrc.count(); i++ ) + srcList[i] = mySrc[i]; + } + if ( srcList->length() > 0 ) { + // compute bounding box + int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); + SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements(); + SMESH::Measure result = measure->BoundingBox( srcList.in() ); + measure->Destroy(); + myXmin->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myXmax->setText( QString::number( result.maxX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myDX->setText( QString::number( result.maxX-result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myYmin->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myYmax->setText( QString::number( result.maxY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myDY->setText( QString::number( result.maxY-result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myZmin->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myZmax->setText( QString::number( result.maxZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myDZ->setText( QString::number( result.maxZ-result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + // update preview actor + erasePreview(); + createPreview( result.minX, result.maxX, result.minY, result.maxY, result.minZ, result.maxZ ); + displayPreview(); + } + else { + clear(); + } +} + +/*! + \brief Reset the widget to the initial state (nullify result fields) +*/ +void SMESHGUI_BoundingBox::clear() +{ + myXmin->clear(); + myXmax->clear(); + myDX->clear(); + myYmin->clear(); + myYmax->clear(); + myDY->clear(); + myZmin->clear(); + myZmax->clear(); + myDZ->clear(); + erasePreview(); +} + +/*! + \class SMESHGUI_MeshInfoDlg + \brief Centralized dialog box for the measurements +*/ + +/*! + \brief Constructor + \param parent parent widget + \param page specifies the dialog page to be shown at the start-up +*/ +SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page ) +: QDialog( parent ) +{ + setModal( false ); + setAttribute( Qt::WA_DeleteOnClose, true ); + setWindowTitle( tr( "MEASUREMENTS" ) ); + setSizeGripEnabled( true ); + + SUIT_ResourceMgr* resMgr = SMESHGUI::resourceMgr(); + + myTabWidget = new QTabWidget( this ); + + // min distance + + myMinDist = new SMESHGUI_MinDistance( myTabWidget ); + myTabWidget->addTab( myMinDist, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_MIN_DIST" ) ), tr( "MIN_DIST" ) ); + + // bounding box + + myBndBox = new SMESHGUI_BoundingBox( myTabWidget ); + myTabWidget->addTab( myBndBox, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BND_BOX" ) ), tr( "BND_BOX" ) ); + + // buttons + QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this ); + okBtn->setAutoDefault( true ); + okBtn->setDefault( true ); + okBtn->setFocus(); + QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this ); + helpBtn->setAutoDefault( true ); + + QHBoxLayout* btnLayout = new QHBoxLayout; + btnLayout->setSpacing( SPACING ); + btnLayout->setMargin( 0 ); + btnLayout->addWidget( okBtn ); + btnLayout->addStretch( 10 ); + btnLayout->addWidget( helpBtn ); + + QVBoxLayout* l = new QVBoxLayout ( this ); + l->setMargin( MARGIN ); + l->setSpacing( SPACING ); + l->addWidget( myTabWidget ); + l->addStretch(); + l->addLayout( btnLayout ); + + myTabWidget->setCurrentIndex( qMax( (int)MinDistance, qMin( (int)BoundingBox, page ) ) ); + + connect( okBtn, SIGNAL( clicked() ), this, SLOT( reject() ) ); + connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) ); + connect( myTabWidget, SIGNAL( currentChanged( int ) ), this, SLOT( updateSelection() ) ); + connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) ); + connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ), this, SLOT( reject() ) ); + + updateSelection(); +} + +/*! + \brief Destructor +*/ +SMESHGUI_MeasureDlg::~SMESHGUI_MeasureDlg() +{ +} + +/*! + \brief Perform clean-up actions on the dialog box closing. +*/ +void SMESHGUI_MeasureDlg::reject() +{ + LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); + selMgr->clearFilters(); + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( ActorSelection ); + QDialog::reject(); +} + +/*! + \brief Process keyboard event + \param e key press event +*/ +void SMESHGUI_MeasureDlg::keyPressEvent( QKeyEvent* e ) +{ + QDialog::keyPressEvent( e ); + if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) { + e->accept(); + help(); + } +} + +/*! + \brief Reactivate dialog box, when mouse pointer goes into it. +*/ +void SMESHGUI_MeasureDlg::enterEvent( QEvent* ) +{ + activate(); +} + +/*! + \brief Setup selection mode depending on the current dialog box state. +*/ +void SMESHGUI_MeasureDlg::updateSelection() +{ + if ( myTabWidget->currentIndex() == MinDistance ) + myMinDist->updateSelection(); + else if ( myTabWidget->currentIndex() == BoundingBox ) + myBndBox->updateSelection(); + +} + +/*! + \brief Show help page +*/ +void SMESHGUI_MeasureDlg::help() +{ + SMESH::ShowHelpFile( myTabWidget->currentIndex() == MinDistance ? + "measurements_page.html#min_distance_anchor" : + "measurements_page.html#bounding_box_anchor" ); +} + +/*! + \brief Activate dialog box +*/ +void SMESHGUI_MeasureDlg::activate() +{ + SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog(); + SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this ); + myTabWidget->setEnabled( true ); + updateSelection(); +} + +/*! + \brief Deactivate dialog box +*/ +void SMESHGUI_MeasureDlg::deactivate() +{ + myMinDist->deactivate(); + myBndBox->deactivate(); + myTabWidget->setEnabled( false ); + disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) ); +} diff --git a/src/SMESHGUI/SMESHGUI_Measurements.h b/src/SMESHGUI/SMESHGUI_Measurements.h new file mode 100644 index 000000000..b9b58c8be --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_Measurements.h @@ -0,0 +1,172 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 : SMESHGUI_Measurements.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) + +#ifndef SMESHGUI_MEASUREMENTS_H +#define SMESHGUI_MEASUREMENTS_H + +#include "SMESH_SMESHGUI.hxx" + +#include + +class QButtonGroup; +class QLineEdit; +class QTabWidget; +class SUIT_SelectionFilter; +class SALOME_Actor; +class SMESH_Actor; +class SMESHGUI_IdValidator; + +#include +#include CORBA_SERVER_HEADER(SMESH_Mesh) + +class SMESHGUI_EXPORT SMESHGUI_MinDistance : public QWidget +{ + Q_OBJECT; + + enum { NoTgt, FirstTgt, SecondTgt }; + enum { OriginTgt, NodeTgt, ElementTgt, ObjectTgt }; + +public: + SMESHGUI_MinDistance( QWidget* = 0 ); + ~SMESHGUI_MinDistance(); + + bool eventFilter( QObject*, QEvent* ); + void updateSelection(); + void deactivate(); + +private: + void setTarget( int ); + void erasePreview(); + void displayPreview(); + void createPreview( double, double, double, double, double, double ); + +private slots: + void selectionChanged(); + void firstChanged(); + void secondChanged(); + void firstEdited(); + void secondEdited(); + void compute(); + void clear(); + +private: + QButtonGroup* myFirst; + QButtonGroup* mySecond; + QLineEdit* myFirstTgt; + QLineEdit* mySecondTgt; + QLineEdit* myDX; + QLineEdit* myDY; + QLineEdit* myDZ; + QLineEdit* myDistance; + int myCurrentTgt; + SMESH::SMESH_IDSource_var myFirstSrc; + SMESH::SMESH_IDSource_var mySecondSrc; + SMESH_Actor* myFirstActor; + SMESH_Actor* mySecondActor; + SMESHGUI_IdValidator* myValidator; + SUIT_SelectionFilter* myFilter; + SALOME_Actor* myPreview; +}; + +class SMESHGUI_EXPORT SMESHGUI_BoundingBox : public QWidget +{ + Q_OBJECT; + + enum { ObjectsSrc, NodesSrc, ElementsSrc }; + +public: + SMESHGUI_BoundingBox( QWidget* = 0 ); + ~SMESHGUI_BoundingBox(); + + void updateSelection(); + void deactivate(); + +private: + void erasePreview(); + void displayPreview(); + void createPreview( double, double, double, double, double, double ); + +private slots: + void selectionChanged(); + void sourceChanged(); + void sourceEdited(); + void compute(); + void clear(); + +private: + typedef QList SourceList; + QButtonGroup* mySourceMode; + QLineEdit* mySource; + QLineEdit* myXmin; + QLineEdit* myXmax; + QLineEdit* myDX; + QLineEdit* myYmin; + QLineEdit* myYmax; + QLineEdit* myDY; + QLineEdit* myZmin; + QLineEdit* myZmax; + QLineEdit* myDZ; + SourceList mySrc; + SMESH_Actor* myActor; + SMESHGUI_IdValidator* myValidator; + QString myIDs; + SUIT_SelectionFilter* myFilter; + SALOME_Actor* myPreview; +}; + +class SMESHGUI_EXPORT SMESHGUI_MeasureDlg : public QDialog +{ + Q_OBJECT; + + enum { NodeMode, ElemMode }; + +public: + //! Measurement type + enum { + MinDistance, //!< minimum distance + BoundingBox //!< bounding box + }; + + SMESHGUI_MeasureDlg( QWidget* = 0, int = MinDistance ); + ~SMESHGUI_MeasureDlg(); + + void reject(); + +protected: + void keyPressEvent( QKeyEvent* ); + void enterEvent( QEvent* ); + +private slots: + void help(); + void updateSelection(); + void activate(); + void deactivate(); + +private: + QTabWidget* myTabWidget; + SMESHGUI_MinDistance* myMinDist; + SMESHGUI_BoundingBox* myBndBox; +}; + +#endif // SMESHGUI_MEASUREMENTS_H diff --git a/src/SMESHGUI/SMESHGUI_MeshInfo.cxx b/src/SMESHGUI/SMESHGUI_MeshInfo.cxx new file mode 100644 index 000000000..16a33b199 --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_MeshInfo.cxx @@ -0,0 +1,1335 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 : SMESHGUI_MeshInfo.cxx +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) + +#include "SMESHGUI_MeshInfo.h" + +#include "SMESH_Actor.h" +#include "SMESHGUI.h" +#include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_Utils.h" +#include "SMESHGUI_VTKUtils.h" +#include "SMDSAbs_ElementType.hxx" +#include "SMDS_Mesh.hxx" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include CORBA_SERVER_HEADER(SMESH_Group) + +const int SPACING = 6; +const int MARGIN = 9; + +/*! + \class SMESHGUI_MeshInfo + \brief Base mesh information widget + + Displays the base information about mesh object: mesh, sub-mesh, group or arbitrary ID source. +*/ + +/*! + \brief Constructor. + \param parent parent widget +*/ +SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent ) + : QFrame( parent ), myWidgets( iElementsEnd ) +{ + setFrameStyle( StyledPanel | Sunken ); + + QGridLayout* l = new QGridLayout( this ); + l->setMargin( MARGIN ); + l->setSpacing( SPACING ); + + // object + QLabel* aNameLab = new QLabel( tr( "NAME_LAB" ), this ); + QLabel* aName = createField(); + aName->setMinimumWidth( 150 ); + QLabel* aObjLab = new QLabel( tr( "OBJECT_LAB" ), this ); + QLabel* aObj = createField(); + aObj->setMinimumWidth( 150 ); + myWidgets[0] << aNameLab << aName; + myWidgets[1] << aObjLab << aObj; + + // nodes + QWidget* aNodesLine = createLine(); + QLabel* aNodesLab = new QLabel( tr( "NODES_LAB" ), this ); + QLabel* aNodes = createField(); + myWidgets[2] << aNodesLine; + myWidgets[3] << aNodesLab << aNodes; + + // elements + QWidget* aElemLine = createLine(); + QLabel* aElemLab = new QLabel( tr( "ELEMENTS_LAB" ), this ); + QLabel* aElemTotal = new QLabel( tr( "TOTAL_LAB" ), this ); + QLabel* aElemLin = new QLabel( tr( "LINEAR_LAB" ), this ); + QLabel* aElemQuad = new QLabel( tr( "QUADRATIC_LAB" ), this ); + myWidgets[4] << aElemLine; + myWidgets[5] << aElemLab << aElemTotal << aElemLin << aElemQuad; + + // ... 0D elements + QWidget* a0DLine = createLine(); + QLabel* a0DLab = new QLabel( tr( "0D_LAB" ), this ); + QLabel* a0DTotal = createField(); + myWidgets[6] << a0DLine; + myWidgets[7] << a0DLab << a0DTotal; + + // ... 1D elements + QWidget* a1DLine = createLine(); + QLabel* a1DLab = new QLabel( tr( "1D_LAB" ), this ); + QLabel* a1DTotal = createField(); + QLabel* a1DLin = createField(); + QLabel* a1DQuad = createField(); + myWidgets[8] << a1DLine; + myWidgets[9] << a1DLab << a1DTotal << a1DLin << a1DQuad; + + // ... 2D elements + QWidget* a2DLine = createLine(); + QLabel* a2DLab = new QLabel( tr( "2D_LAB" ), this ); + QLabel* a2DTotal = createField(); + QLabel* a2DLin = createField(); + QLabel* a2DQuad = createField(); + QLabel* a2DTriLab = new QLabel( tr( "TRIANGLES_LAB" ), this ); + QLabel* a2DTriTotal = createField(); + QLabel* a2DTriLin = createField(); + QLabel* a2DTriQuad = createField(); + QLabel* a2DQuaLab = new QLabel( tr( "QUADRANGLES_LAB" ), this ); + QLabel* a2DQuaTotal = createField(); + QLabel* a2DQuaLin = createField(); + QLabel* a2DQuaQuad = createField(); + QLabel* a2DPolLab = new QLabel( tr( "POLYGONS_LAB" ), this ); + QLabel* a2DPolTotal = createField(); + myWidgets[10] << a2DLine; + myWidgets[11] << a2DLab << a2DTotal << a2DLin << a2DQuad; + myWidgets[12] << a2DTriLab << a2DTriTotal << a2DTriLin << a2DTriQuad; + myWidgets[13] << a2DQuaLab << a2DQuaTotal << a2DQuaLin << a2DQuaQuad; + myWidgets[14] << a2DPolLab << a2DPolTotal; + + // ... 3D elements + QWidget* a3DLine = createLine(); + QLabel* a3DLab = new QLabel( tr( "3D_LAB" ), this ); + QLabel* a3DTotal = createField(); + QLabel* a3DLin = createField(); + QLabel* a3DQuad = createField(); + QLabel* a3DTetLab = new QLabel( tr( "TETRAHEDRONS_LAB" ), this ); + QLabel* a3DTetTotal = createField(); + QLabel* a3DTetLin = createField(); + QLabel* a3DTetQuad = createField(); + QLabel* a3DHexLab = new QLabel( tr( "HEXAHEDONRS_LAB" ), this ); + QLabel* a3DHexTotal = createField(); + QLabel* a3DHexLin = createField(); + QLabel* a3DHexQuad = createField(); + QLabel* a3DPyrLab = new QLabel( tr( "PYRAMIDS_LAB" ), this ); + QLabel* a3DPyrTotal = createField(); + QLabel* a3DPyrLin = createField(); + QLabel* a3DPyrQuad = createField(); + QLabel* a3DPriLab = new QLabel( tr( "PRISMS_LAB" ), this ); + QLabel* a3DPriTotal = createField(); + QLabel* a3DPriLin = createField(); + QLabel* a3DPriQuad = createField(); + QLabel* a3DPolLab = new QLabel( tr( "POLYHEDRONS_LAB" ), this ); + QLabel* a3DPolTotal = createField(); + myWidgets[15] << a3DLine; + myWidgets[16] << a3DLab << a3DTotal << a3DLin << a3DQuad; + myWidgets[17] << a3DTetLab << a3DTetTotal << a3DTetLin << a3DTetQuad; + myWidgets[18] << a3DHexLab << a3DHexTotal << a3DHexLin << a3DHexQuad; + myWidgets[19] << a3DPyrLab << a3DPyrTotal << a3DPyrLin << a3DPyrQuad; + myWidgets[20] << a3DPriLab << a3DPriTotal << a3DPriLin << a3DPriQuad; + myWidgets[21] << a3DPolLab << a3DPolTotal; + + setFontAttributes( aNameLab, Bold ); + setFontAttributes( aObjLab, Bold ); + setFontAttributes( aNodesLab, Bold ); + setFontAttributes( aElemLab, Bold ); + setFontAttributes( aElemTotal, Italic ); + setFontAttributes( aElemLin, Italic ); + setFontAttributes( aElemQuad, Italic ); + setFontAttributes( a0DLab, Bold ); + setFontAttributes( a1DLab, Bold ); + setFontAttributes( a2DLab, Bold ); + setFontAttributes( a3DLab, Bold ); + + l->addWidget( aNameLab, 0, 0 ); + l->addWidget( aName, 0, 1, 1, 3 ); + l->addWidget( aObjLab, 1, 0 ); + l->addWidget( aObj, 1, 1, 1, 3 ); + l->addWidget( aNodesLine, 2, 0, 1, 4 ); + l->addWidget( aNodesLab, 3, 0 ); + l->addWidget( aNodes, 3, 1 ); + l->addWidget( aElemLine, 4, 0, 1, 4 ); + l->addWidget( aElemLab, 5, 0 ); + l->addWidget( aElemTotal, 5, 1 ); + l->addWidget( aElemLin, 5, 2 ); + l->addWidget( aElemQuad, 5, 3 ); + l->addWidget( a0DLine, 6, 1, 1, 3 ); + l->addWidget( a0DLab, 7, 0 ); + l->addWidget( a0DTotal, 7, 1 ); + l->addWidget( a1DLine, 8, 1, 1, 3 ); + l->addWidget( a1DLab, 9, 0 ); + l->addWidget( a1DTotal, 9, 1 ); + l->addWidget( a1DLin, 9, 2 ); + l->addWidget( a1DQuad, 9, 3 ); + l->addWidget( a2DLine, 10, 1, 1, 3 ); + l->addWidget( a2DLab, 11, 0 ); + l->addWidget( a2DTotal, 11, 1 ); + l->addWidget( a2DLin, 11, 2 ); + l->addWidget( a2DQuad, 11, 3 ); + l->addWidget( a2DTriLab, 12, 0 ); + l->addWidget( a2DTriTotal, 12, 1 ); + l->addWidget( a2DTriLin, 12, 2 ); + l->addWidget( a2DTriQuad, 12, 3 ); + l->addWidget( a2DQuaLab, 13, 0 ); + l->addWidget( a2DQuaTotal, 13, 1 ); + l->addWidget( a2DQuaLin, 13, 2 ); + l->addWidget( a2DQuaQuad, 13, 3 ); + l->addWidget( a2DPolLab, 14, 0 ); + l->addWidget( a2DPolTotal, 14, 1 ); + l->addWidget( a3DLine, 15, 1, 1, 3 ); + l->addWidget( a3DLab, 16, 0 ); + l->addWidget( a3DTotal, 16, 1 ); + l->addWidget( a3DLin, 16, 2 ); + l->addWidget( a3DQuad, 16, 3 ); + l->addWidget( a3DTetLab, 17, 0 ); + l->addWidget( a3DTetTotal, 17, 1 ); + l->addWidget( a3DTetLin, 17, 2 ); + l->addWidget( a3DTetQuad, 17, 3 ); + l->addWidget( a3DHexLab, 18, 0 ); + l->addWidget( a3DHexTotal, 18, 1 ); + l->addWidget( a3DHexLin, 18, 2 ); + l->addWidget( a3DHexQuad, 18, 3 ); + l->addWidget( a3DPyrLab, 19, 0 ); + l->addWidget( a3DPyrTotal, 19, 1 ); + l->addWidget( a3DPyrLin, 19, 2 ); + l->addWidget( a3DPyrQuad, 19, 3 ); + l->addWidget( a3DPriLab, 20, 0 ); + l->addWidget( a3DPriTotal, 20, 1 ); + l->addWidget( a3DPriLin, 20, 2 ); + l->addWidget( a3DPriQuad, 20, 3 ); + l->addWidget( a3DPolLab, 21, 0 ); + l->addWidget( a3DPolTotal, 21, 1 ); + l->setColumnStretch( 0, 0 ); + l->setColumnStretch( 1, 5 ); + l->setColumnStretch( 2, 5 ); + l->setColumnStretch( 3, 5 ); + l->setRowStretch( 22, 5 ); + + clear(); +} + +/*! + \brief Destructor +*/ +SMESHGUI_MeshInfo::~SMESHGUI_MeshInfo() +{ +} + +/*! + \brief Show information on the mesh object. + \param obj object being processed (mesh, sub-mesh, group, ID source) +*/ +void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj ) +{ + clear(); + if ( !CORBA::is_nil( obj ) ) { + _PTR(SObject) sobj = ObjectToSObject( obj ); + if ( sobj ) + myWidgets[iName][iSingle]->setProperty( "text", sobj->GetName().c_str() ); + SMESH::SMESH_Mesh_var aMesh = SMESH::SMESH_Mesh::_narrow( obj ); + SMESH::SMESH_subMesh_var aSubMesh = SMESH::SMESH_subMesh::_narrow( obj ); + SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_narrow( obj ); + if ( !aMesh->_is_nil() ) { + myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_MESH" ) ); + } + else if ( !aSubMesh->_is_nil() ) { + myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_SUBMESH" ) ); + } + else if ( !aGroup->_is_nil() ) { + QString objType; + switch( aGroup->GetType() ) { + case SMESH::NODE: + objType = tr( "OBJECT_GROUP_NODES" ); + break; + case SMESH::EDGE: + objType = tr( "OBJECT_GROUP_EDGES" ); + break; + case SMESH::FACE: + objType = tr( "OBJECT_GROUP_FACES" ); + break; + case SMESH::VOLUME: + objType = tr( "OBJECT_GROUP_VOLUMES" ); + break; + case SMESH::ELEM0D: + objType = tr( "OBJECT_GROUP_0DELEMS" ); + break; + default: + objType = tr( "OBJECT_GROUP" ); + break; + } + myWidgets[iObject][iSingle]->setProperty( "text", objType ); + } + SMESH::long_array_var info = obj->GetMeshInfo(); + myWidgets[iNodes][iTotal]->setProperty( "text", QString::number( info[SMDSEntity_Node] ) ); + myWidgets[i0D][iTotal]->setProperty( "text", QString::number( info[SMDSEntity_0D] ) ); + long nbEdges = info[SMDSEntity_Edge] + info[SMDSEntity_Quad_Edge]; + myWidgets[i1D][iTotal]->setProperty( "text", QString::number( nbEdges ) ); + myWidgets[i1D][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Edge] ) ); + myWidgets[i1D][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Edge] ) ); + long nbTriangles = info[SMDSEntity_Triangle] + info[SMDSEntity_Quad_Triangle]; + long nbQuadrangles = info[SMDSEntity_Quadrangle] + info[SMDSEntity_Quad_Quadrangle]; + long nb2DLinear = info[SMDSEntity_Triangle] + info[SMDSEntity_Quadrangle] + info[SMDSEntity_Polygon]; + long nb2DQuadratic = info[SMDSEntity_Quad_Triangle] + info[SMDSEntity_Quad_Quadrangle]; + myWidgets[i2D][iTotal]->setProperty( "text", QString::number( nb2DLinear + nb2DQuadratic ) ); + myWidgets[i2D][iLinear]->setProperty( "text", QString::number( nb2DLinear ) ); + myWidgets[i2D][iQuadratic]->setProperty( "text", QString::number( nb2DQuadratic ) ); + myWidgets[i2DTriangles][iTotal]->setProperty( "text", QString::number( nbTriangles ) ); + myWidgets[i2DTriangles][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Triangle] ) ); + myWidgets[i2DTriangles][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Triangle] ) ); + myWidgets[i2DQuadrangles][iTotal]->setProperty( "text", QString::number( nbQuadrangles ) ); + myWidgets[i2DQuadrangles][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Quadrangle] ) ); + myWidgets[i2DQuadrangles][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Quadrangle] ) ); + myWidgets[i2DPolygons][iTotal]->setProperty( "text", QString::number( info[SMDSEntity_Polygon] ) ); + long nbTetrahedrons = info[SMDSEntity_Tetra] + info[SMDSEntity_Quad_Tetra]; + long nbHexahedrons = info[SMDSEntity_Hexa] + info[SMDSEntity_Quad_Hexa]; + long nbPyramids = info[SMDSEntity_Pyramid] + info[SMDSEntity_Quad_Pyramid]; + long nbPrisms = info[SMDSEntity_Penta] + info[SMDSEntity_Quad_Penta]; + long nb3DLinear = info[SMDSEntity_Tetra] + info[SMDSEntity_Hexa] + info[SMDSEntity_Pyramid] + info[SMDSEntity_Penta] + info[SMDSEntity_Polyhedra]; + long nb3DQuadratic = info[SMDSEntity_Quad_Tetra] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_Quad_Pyramid] + info[SMDSEntity_Quad_Penta]; + myWidgets[i3D][iTotal]->setProperty( "text", QString::number( nb3DLinear + nb3DQuadratic ) ); + myWidgets[i3D][iLinear]->setProperty( "text", QString::number( nb3DLinear ) ); + myWidgets[i3D][iQuadratic]->setProperty( "text", QString::number( nb3DQuadratic ) ); + myWidgets[i3DTetrahedrons][iTotal]->setProperty( "text", QString::number( nbTetrahedrons ) ); + myWidgets[i3DTetrahedrons][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Tetra] ) ); + myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Tetra] ) ); + myWidgets[i3DHexahedrons][iTotal]->setProperty( "text", QString::number( nbHexahedrons ) ); + myWidgets[i3DHexahedrons][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Hexa] ) ); + myWidgets[i3DHexahedrons][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Hexa] ) ); + myWidgets[i3DPyramids][iTotal]->setProperty( "text", QString::number( nbPyramids ) ); + myWidgets[i3DPyramids][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Pyramid] ) ); + myWidgets[i3DPyramids][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Pyramid] ) ); + myWidgets[i3DPrisms][iTotal]->setProperty( "text", QString::number( nbPrisms ) ); + myWidgets[i3DPrisms][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Penta] ) ); + myWidgets[i3DPrisms][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Penta] ) ); + myWidgets[i3DPolyhedrons][iTotal]->setProperty( "text", QString::number( info[SMDSEntity_Polyhedra] ) ); + } +} + +/*! + \brief Reset the widget to the initial state (nullify all fields). +*/ +void SMESHGUI_MeshInfo::clear() +{ + myWidgets[iName][iSingle]->setProperty( "text", QString() ); + myWidgets[iObject][iSingle]->setProperty( "text", QString() ); + myWidgets[iNodes][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i0D][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i1D][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i1D][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i1D][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2D][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2D][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2D][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DTriangles][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DTriangles][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DTriangles][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DQuadrangles][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DQuadrangles][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DQuadrangles][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DPolygons][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3D][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3D][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3D][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DTetrahedrons][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DTetrahedrons][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DHexahedrons][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DHexahedrons][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DHexahedrons][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DPyramids][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DPyramids][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DPyramids][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DPrisms][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DPrisms][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DPrisms][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DPolyhedrons][iTotal]->setProperty( "text", QString::number( 0 ) ); +} + +/*! + \brief Create info field + \return new info field +*/ +QLabel* SMESHGUI_MeshInfo::createField() +{ + QLabel* lab = new QLabel( this ); + lab->setFrameStyle( StyledPanel | Sunken ); + lab->setAlignment( Qt::AlignCenter ); + lab->setAutoFillBackground( true ); + QPalette pal = lab->palette(); + pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ) ); + lab->setPalette( pal ); + lab->setMinimumWidth( 70 ); + return lab; +} + +/*! + \brief Create horizontal rule. + \return new line object +*/ +QWidget* SMESHGUI_MeshInfo::createLine() +{ + QFrame* line = new QFrame( this ); + line->setFrameStyle( HLine | Sunken ); + return line; +} + +/*! + \brief Change widget font attributes (bold, italic, ...). + \param w widget + \param attr font attributes (XORed flags) + \param val value to be set to attributes +*/ +void SMESHGUI_MeshInfo::setFontAttributes( QWidget* w, int attr, bool val ) +{ + if ( w && attr ) { + QFont f = w->font(); + if ( attr & Bold ) f.setBold( val ); + if ( attr & Italic ) f.setItalic( val ); + w->setFont( f ); + } +} + +/*! + \brief Show/hide group(s) of fields. + \param start beginning of the block + \param end end of the block + \param on visibility flag +*/ +void SMESHGUI_MeshInfo::setFieldsVisible( int start, int end, bool on ) +{ + start = qMax( 0, start ); + end = qMin( end, (int)iElementsEnd ); + for ( int i = start; i < end; i++ ) { + wlist wl = myWidgets[i]; + foreach ( QWidget* w, wl ) w->setVisible( on ); + } +} + +/*! + \class SMESHGUI_ElemInfo + \brief Base class for the mesh element information widget. +*/ + +/*! + \brief Constructor + \param parent parent widget +*/ +SMESHGUI_ElemInfo::SMESHGUI_ElemInfo( QWidget* parent ) +: QWidget( parent ), myActor( 0 ), myID( 0 ), myIsElement( -1 ) +{ +} + +/*! + \brief Destructor +*/ +SMESHGUI_ElemInfo::~SMESHGUI_ElemInfo() +{ +} + +/*! + \brief Set mesh data source (actor) + \param actor mesh object actor +*/ +void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor ) +{ + if ( myActor != actor ) { + myActor = actor; + myID = 0; + myIsElement = -1; + clear(); + } +} + +/*! + \brief Show mesh element information + \param long id mesh node / element ID + \param isElem show mesh element information if \c true or mesh node information if \c false +*/ +void SMESHGUI_ElemInfo::showInfo( long id, bool isElem ) +{ + myID = id; + myIsElement = isElem; +} + +/*! + \fn void SMESHGUI_ElemInfo::clear() + \brief Clear mesh element information widget +*/ + +/*! + \brief Get node connectivity + \param node mesh node + \return node connectivity map +*/ +SMESHGUI_ElemInfo::Connectivity SMESHGUI_ElemInfo::nodeConnectivity( const SMDS_MeshNode* node ) +{ + Connectivity elmap; + if ( node ) { + SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); + while ( it && it->more() ) { + const SMDS_MeshElement* ne = it->next(); + elmap[ ne->GetType() ] << ne->GetID(); + } + } + return elmap; +} + +/*! + \brief Format connectivity data to string representation + \param connectivity connetivity map + \param type element type + \return string representation of the connectivity +*/ +QString SMESHGUI_ElemInfo::formatConnectivity( Connectivity connectivity, int type ) +{ + QStringList str; + if ( connectivity.contains( type ) ) { + QList elements = connectivity[ type ]; + qSort( elements ); + foreach( int id, elements ) + str << QString::number( id ); + } + return str.join( " " ); +} + +/*! + \brief Calculate gravity center of the mesh element + \param element mesh element +*/ +SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::gravityCenter( const SMDS_MeshElement* element ) +{ + XYZ xyz; + if ( element ) { + SMDS_ElemIteratorPtr nodeIt = element->nodesIterator(); + while ( nodeIt->more() ) { + const SMDS_MeshNode* node = static_cast( nodeIt->next() ); + xyz.add( node->X(), node->Y(), node->Z() ); + } + xyz.divide( element->NbNodes() ); + } + return xyz; +} + +/*! + \class SMESHGUI_SimpleElemInfo + \brief Represents mesh element information in the simple text area. +*/ + +/*! + \brief Constructor + \param parent parent widget +*/ +SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent ) +: SMESHGUI_ElemInfo( parent ) +{ + myInfo = new QTextBrowser( this ); + QVBoxLayout* l = new QVBoxLayout( this ); + l->setMargin( 0 ); + l->addWidget( myInfo ); +} + +/*! + \brief Show mesh element information + \param long id mesh node / element ID + \param isElem show mesh element information if \c true or mesh node information if \c false +*/ +void SMESHGUI_SimpleElemInfo::showInfo( long id, bool isElem ) +{ + if ( myID == id && myIsElement == isElem ) return; + + SMESHGUI_ElemInfo::showInfo( id, isElem ); + + clear(); + + if ( myActor ) { + int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); + if ( !isElem ) { + // + // show node info + // + const SMDS_MeshElement* e = myActor->GetObject()->GetMesh()->FindNode( id ); + if ( !e ) return; + const SMDS_MeshNode* node = static_cast( e ); + + // node ID + myInfo->append( QString( "%1 #%2" ).arg( tr( "NODE" ) ).arg( id ) ); + // separator + myInfo->append( "" ); + // coordinates + myInfo->append( QString( "%1: (%2, %3, %4)" ).arg( tr( "COORDINATES" ) ). + arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ). + arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ). + arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + // separator + myInfo->append( "" ); + // connectivity + Connectivity connectivity = nodeConnectivity( node ); + if ( !connectivity.isEmpty() ) { + myInfo->append( QString( "%1:" ).arg( tr( "CONNECTIVITY" ) ) ); + QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "0D_ELEMENTS" ) ).arg( con ) ); + con = formatConnectivity( connectivity, SMDSAbs_Edge ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "EDGES" ) ).arg( con ) ); + con = formatConnectivity( connectivity, SMDSAbs_Face ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "FACES" ) ).arg( con ) ); + con = formatConnectivity( connectivity, SMDSAbs_Volume ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "VOLUMES" ) ).arg( con ) ); + } + else { + myInfo->append( QString( "%1" ).arg( tr( "FREE_NODE" ) ).arg( id ) ); + } + } + else { + // + // show element info + // + const SMDS_MeshElement* e = myActor->GetObject()->GetMesh()->FindElement( id ); + if ( !e ) return; + + // element ID && type + QString stype; + switch( e->GetType() ) { + case SMDSAbs_0DElement: + stype = tr( "0D ELEMENT" ); break; + case SMDSAbs_Edge: + stype = tr( "EDGE" ); break; + case SMDSAbs_Face: + stype = tr( "FACE" ); break; + case SMDSAbs_Volume: + stype = tr( "VOLUME" ); break; + default: + break; + } + if ( stype.isEmpty() ) return; + myInfo->append( QString( "%1 #%2" ).arg( stype ).arg( id ) ); + // separator + myInfo->append( "" ); + // geometry type + QString gtype; + switch( e->GetEntityType() ) { + case SMDSEntity_Triangle: + case SMDSEntity_Quad_Triangle: + gtype = tr( "TRIANGLE" ); break; + case SMDSEntity_Quadrangle: + case SMDSEntity_Quad_Quadrangle: + gtype = tr( "QUADRANGLE" ); break; + case SMDSEntity_Polygon: + case SMDSEntity_Quad_Polygon: + gtype = tr( "QUADRANGLE" ); break; + case SMDSEntity_Tetra: + case SMDSEntity_Quad_Tetra: + gtype = tr( "TETRAHEDRON" ); break; + case SMDSEntity_Pyramid: + case SMDSEntity_Quad_Pyramid: + gtype = tr( "PYRAMID" ); break; + case SMDSEntity_Hexa: + case SMDSEntity_Quad_Hexa: + gtype = tr( "HEXAHEDRON" ); break; + case SMDSEntity_Penta: + case SMDSEntity_Quad_Penta: + gtype = tr( "PRISM" ); break; + case SMDSEntity_Polyhedra: + case SMDSEntity_Quad_Polyhedra: + gtype = tr( "POLYHEDRON" ); break; + default: + break; + } + if ( !gtype.isEmpty() ) + myInfo->append( QString( "%1: %2" ).arg( tr( "TYPE" ) ).arg( gtype ) ); + // quadratic flag and gravity center (any element except 0D) + if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Last ) { + // quadratic flag + myInfo->append( QString( "%1? %2" ).arg( tr( "QUADRATIC" ) ).arg( e->IsQuadratic() ? tr( "YES" ) : tr( "NO" ) ) ); + // separator + myInfo->append( "" ); + // gravity center + XYZ gc = gravityCenter( e ); + myInfo->append( QString( "%1: (%2, %3, %4)" ).arg( tr( "GRAVITY_CENTER" ) ).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ) ); + } + // separator + myInfo->append( "" ); + // connectivity + SMDS_ElemIteratorPtr nodeIt = e->nodesIterator(); + for ( int idx = 1; nodeIt->more(); idx++ ) { + const SMDS_MeshNode* node = static_cast( nodeIt->next() ); + // node number and ID + myInfo->append( QString( "%1 %2/%3 - #%4" ).arg( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ).arg( node->GetID() ) ); + // node coordinates + myInfo->append( QString( "%1: (%2, %3, %4)" ).arg( tr( "COORDINATES" ) ). + arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ). + arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ). + arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + // node connectivity + Connectivity connectivity = nodeConnectivity( node ); + if ( !connectivity.isEmpty() ) { + myInfo->append( QString( "%1:" ).arg( tr( "CONNECTIVITY" ) ) ); + QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "0D_ELEMENTS" ) ).arg( con ) ); + con = formatConnectivity( connectivity, SMDSAbs_Edge ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "EDGES" ) ).arg( con ) ); + con = formatConnectivity( connectivity, SMDSAbs_Face ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "FACES" ) ).arg( con ) ); + con = formatConnectivity( connectivity, SMDSAbs_Volume ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "VOLUMES" ) ).arg( con ) ); + } + else { + myInfo->append( QString( "%1" ).arg( tr( "FREE_NODE" ) ).arg( id ) ); + } + // separator + myInfo->append( "" ); + } + } + } +} + +/*! + \brief Clear mesh element information widget +*/ +void SMESHGUI_SimpleElemInfo::clear() +{ + myInfo->clear(); +} + +/*! + \class SMESHGUI_TreeElemInfo::ItemDelegate + \brief Item delegate for tree mesh info widget + \internal +*/ +class SMESHGUI_TreeElemInfo::ItemDelegate : public QItemDelegate +{ +public: + ItemDelegate( QObject* ); + QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const; +}; + +/*! + \brief Constructor + \internal +*/ +SMESHGUI_TreeElemInfo::ItemDelegate::ItemDelegate( QObject* parent ) : QItemDelegate( parent ) +{ +} + +/*! + \brief Create item editor widget + \internal +*/ +QWidget* SMESHGUI_TreeElemInfo::ItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + QWidget* w = index.column() == 0 ? 0: QItemDelegate::createEditor( parent, option, index ); + if ( qobject_cast( w ) ) qobject_cast( w )->setReadOnly( true ); + return w; +} + +/*! + \class SMESHGUI_TreeElemInfo + \brief Represents mesh element information in the tree-like form. +*/ + +/*! + \brief Constructor + \param parent parent widget +*/ +SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent ) +: SMESHGUI_ElemInfo( parent ) +{ + myInfo = new QTreeWidget( this ); + myInfo->setColumnCount( 2 ); + myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ) ); + myInfo->header()->setStretchLastSection( true ); + myInfo->header()->setResizeMode( 0, QHeaderView::ResizeToContents ); + myInfo->setItemDelegate( new ItemDelegate( myInfo ) ); + QVBoxLayout* l = new QVBoxLayout( this ); + l->setMargin( 0 ); + l->addWidget( myInfo ); +} + +/*! + \brief Show mesh element information + \param long id mesh node / element ID + \param isElem show mesh element information if \c true or mesh node information if \c false +*/ +void SMESHGUI_TreeElemInfo::showInfo( long id, bool isElem ) +{ + if ( myID == id && myIsElement == isElem ) return; + + SMESHGUI_ElemInfo::showInfo( id, isElem ); + + clear(); + + if ( myActor ) { + int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); + if ( !isElem ) { + // + // show node info + // + const SMDS_MeshElement* e = myActor->GetObject()->GetMesh()->FindNode( id ); + if ( !e ) return; + const SMDS_MeshNode* node = static_cast( e ); + + // node ID + QTreeWidgetItem* nodeItem = createItem( 0, -1 ); + nodeItem->setText( 0, tr( "NODE" ) ); + nodeItem->setText( 1, QString( "#%1" ).arg( id ) ); + nodeItem->setExpanded( true ); + // coordinates + QTreeWidgetItem* coordItem = createItem( nodeItem, 0 ); + coordItem->setText( 0, tr( "COORDINATES" ) ); + coordItem->setExpanded( true ); + QTreeWidgetItem* xItem = createItem( coordItem ); + xItem->setText( 0, "X" ); + xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + QTreeWidgetItem* yItem = createItem( coordItem ); + yItem->setText( 0, "Y" ); + yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + QTreeWidgetItem* zItem = createItem( coordItem ); + zItem->setText( 0, "Z" ); + zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + // connectivity + QTreeWidgetItem* conItem = createItem( nodeItem, 0 ); + conItem->setText( 0, tr( "CONNECTIVITY" ) ); + conItem->setExpanded( true ); + Connectivity connectivity = nodeConnectivity( node ); + if ( !connectivity.isEmpty() ) { + QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); + if ( !con.isEmpty() ) { + QTreeWidgetItem* i = createItem( conItem ); + i->setText( 0, tr( "0D_ELEMENTS" ) ); + i->setText( 1, con ); + } + con = formatConnectivity( connectivity, SMDSAbs_Edge ); + if ( !con.isEmpty() ) { + QTreeWidgetItem* i = createItem( conItem ); + i->setText( 0, tr( "EDGES" ) ); + i->setText( 1, con ); + } + con = formatConnectivity( connectivity, SMDSAbs_Face ); + if ( !con.isEmpty() ) { + QTreeWidgetItem* i = createItem( conItem ); + i->setText( 0, tr( "FACES" ) ); + i->setText( 1, con ); + } + con = formatConnectivity( connectivity, SMDSAbs_Volume ); + if ( !con.isEmpty() ) { + QTreeWidgetItem* i = createItem( conItem ); + i->setText( 0, tr( "VOLUMES" ) ); + i->setText( 1, con ); + } + } + else { + conItem->setText( 1, tr( "FREE_NODE" ) ); + } + } + else { + // + // show element info + // + const SMDS_MeshElement* e = myActor->GetObject()->GetMesh()->FindElement( id ); + if ( !e ) return; + + // element ID && type + QString stype; + switch( e->GetType() ) { + case SMDSAbs_0DElement: + stype = tr( "0D ELEMENT" ); break; + case SMDSAbs_Edge: + stype = tr( "EDGE" ); break; + case SMDSAbs_Face: + stype = tr( "FACE" ); break; + case SMDSAbs_Volume: + stype = tr( "VOLUME" ); break; + default: + break; + } + if ( stype.isEmpty() ) return; + QTreeWidgetItem* elemItem = createItem( 0, -1 ); + elemItem->setText( 0, stype ); + elemItem->setText( 1, QString( "#%1" ).arg( id ) ); + elemItem->setExpanded( true ); + // geometry type + QString gtype; + switch( e->GetEntityType() ) { + case SMDSEntity_Triangle: + case SMDSEntity_Quad_Triangle: + gtype = tr( "TRIANGLE" ); break; + case SMDSEntity_Quadrangle: + case SMDSEntity_Quad_Quadrangle: + gtype = tr( "QUADRANGLE" ); break; + case SMDSEntity_Polygon: + case SMDSEntity_Quad_Polygon: + gtype = tr( "QUADRANGLE" ); break; + case SMDSEntity_Tetra: + case SMDSEntity_Quad_Tetra: + gtype = tr( "TETRAHEDRON" ); break; + case SMDSEntity_Pyramid: + case SMDSEntity_Quad_Pyramid: + gtype = tr( "PYRAMID" ); break; + case SMDSEntity_Hexa: + case SMDSEntity_Quad_Hexa: + gtype = tr( "HEXAHEDRON" ); break; + case SMDSEntity_Penta: + case SMDSEntity_Quad_Penta: + gtype = tr( "PRISM" ); break; + case SMDSEntity_Polyhedra: + case SMDSEntity_Quad_Polyhedra: + gtype = tr( "POLYHEDRON" ); break; + default: + break; + } + if ( !gtype.isEmpty() ) { + QTreeWidgetItem* typeItem = createItem( elemItem, 0 ); + typeItem->setText( 0, tr( "TYPE" ) ); + typeItem->setText( 1, gtype ); + } + // quadratic flag and gravity center (any element except 0D) + if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Last ) { + // quadratic flag + QTreeWidgetItem* quadItem = createItem( elemItem, 0 ); + quadItem->setText( 0, tr( "QUADRATIC" ) ); + quadItem->setText( 1, e->IsQuadratic() ? tr( "YES" ) : tr( "NO" ) ); + // gravity center + XYZ gc = gravityCenter( e ); + QTreeWidgetItem* gcItem = createItem( elemItem, 0 ); + gcItem->setText( 0, tr( "GRAVITY_CENTER" ) ); + gcItem->setExpanded( true ); + QTreeWidgetItem* xItem = createItem( gcItem ); + xItem->setText( 0, "X" ); + xItem->setText( 1, QString::number( gc.x(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + QTreeWidgetItem* yItem = createItem( gcItem ); + yItem->setText( 0, "Y" ); + yItem->setText( 1, QString::number( gc.y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + QTreeWidgetItem* zItem = createItem( gcItem ); + zItem->setText( 0, "Z" ); + zItem->setText( 1, QString::number( gc.z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + } + // connectivity + QTreeWidgetItem* conItem = createItem( elemItem, 0 ); + conItem->setText( 0, tr( "CONNECTIVITY" ) ); + conItem->setExpanded( true ); + SMDS_ElemIteratorPtr nodeIt = e->nodesIterator(); + for ( int idx = 1; nodeIt->more(); idx++ ) { + const SMDS_MeshNode* node = static_cast( nodeIt->next() ); + // node number and ID + QTreeWidgetItem* nodeItem = createItem( conItem, 0 ); + nodeItem->setText( 0, QString( "%1 %2/%3" ).arg( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ) ); + nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ) ); + //nodeItem->setExpanded( true ); + // node coordinates + QTreeWidgetItem* coordItem = createItem( nodeItem ); + coordItem->setText( 0, tr( "COORDINATES" ) ); + coordItem->setExpanded( true ); + QTreeWidgetItem* xItem = createItem( coordItem ); + xItem->setText( 0, "X" ); + xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + QTreeWidgetItem* yItem = createItem( coordItem ); + yItem->setText( 0, "Y" ); + yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + QTreeWidgetItem* zItem = createItem( coordItem ); + zItem->setText( 0, "Z" ); + zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + // node connectivity + QTreeWidgetItem* nconItem = createItem( nodeItem ); + nconItem->setText( 0, tr( "CONNECTIVITY" ) ); + nconItem->setExpanded( true ); + Connectivity connectivity = nodeConnectivity( node ); + if ( !connectivity.isEmpty() ) { + QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); + if ( !con.isEmpty() ) { + QTreeWidgetItem* i = createItem( nconItem ); + i->setText( 0, tr( "0D_ELEMENTS" ) ); + i->setText( 1, con ); + } + con = formatConnectivity( connectivity, SMDSAbs_Edge ); + if ( !con.isEmpty() ) { + QTreeWidgetItem* i = createItem( nconItem ); + i->setText( 0, tr( "EDGES" ) ); + i->setText( 1, con ); + } + con = formatConnectivity( connectivity, SMDSAbs_Face ); + if ( !con.isEmpty() ) { + QTreeWidgetItem* i = createItem( nconItem ); + i->setText( 0, tr( "FACES" ) ); + i->setText( 1, con ); + } + con = formatConnectivity( connectivity, SMDSAbs_Volume ); + if ( !con.isEmpty() ) { + QTreeWidgetItem* i = createItem( nconItem ); + i->setText( 0, tr( "VOLUMES" ) ); + i->setText( 1, con ); + } + } + } + } + } +} + +/*! + \brief Clear mesh element information widget +*/ +void SMESHGUI_TreeElemInfo::clear() +{ + myInfo->clear(); + myInfo->repaint(); +} + +/*! + \brief Create new tree item. + \param parnt parent tree widget item + \param column item column to be set bold, if it is -1, bold font will be set for all columns + \return new tree widget item +*/ +QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int column ) +{ + QTreeWidgetItem* item; + if ( parent ) + item = new QTreeWidgetItem( parent ); + else + item = new QTreeWidgetItem( myInfo ); + + item->setFlags( item->flags() | Qt::ItemIsEditable ); + + QFont f = item->font( 0 ); + f.setBold( true ); + if ( column >= 0 && column < myInfo->columnCount() ) { + item->setFont( column, f ); + } + else if ( column == -1 ) { + for ( int i = 0; i < myInfo->columnCount(); i++ ) + item->setFont( i, f ); + } + return item; +} + +/*! + \class SMESHGUI_MeshInfoDlg + \brief Mesh information dialog box +*/ + +/*! + \brief Constructor + \param parent parent widget + \param page specifies the dialog page to be shown at the start-up +*/ +SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page ) +: QDialog( parent ), myActor( 0 ) +{ + setModal( false ); + setAttribute( Qt::WA_DeleteOnClose, true ); + setWindowTitle( tr( "MESH_INFO" ) ); + setSizeGripEnabled( true ); + + myTabWidget = new QTabWidget( this ); + + // base info + + myBaseInfo = new SMESHGUI_MeshInfo( myTabWidget ); + myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) ); + + // elem info + + QWidget* w = new QWidget( myTabWidget ); + + myMode = new QButtonGroup( this ); + myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode ); + myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode ); + myMode->button( NodeMode )->setChecked( true ); + myID = new QLineEdit( w ); + myID->setValidator( new SMESHGUI_IdValidator( this, 1 ) ); + + int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 ); + mode = qMin( 1, qMax( 0, mode ) ); + + if ( mode == 0 ) + myElemInfo = new SMESHGUI_SimpleElemInfo( w ); + else + myElemInfo = new SMESHGUI_TreeElemInfo( w ); + + QGridLayout* elemLayout = new QGridLayout( w ); + elemLayout->setMargin( MARGIN ); + elemLayout->setSpacing( SPACING ); + elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 ); + elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 ); + elemLayout->addWidget( myID, 0, 2 ); + elemLayout->addWidget( myElemInfo, 1, 0, 1, 3 ); + + myTabWidget->addTab( w, tr( "ELEM_INFO" ) ); + + QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this ); + okBtn->setAutoDefault( true ); + okBtn->setDefault( true ); + okBtn->setFocus(); + QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this ); + helpBtn->setAutoDefault( true ); + + QHBoxLayout* btnLayout = new QHBoxLayout; + btnLayout->setSpacing( SPACING ); + btnLayout->setMargin( 0 ); + + btnLayout->addWidget( okBtn ); + btnLayout->addStretch( 10 ); + btnLayout->addWidget( helpBtn ); + + QVBoxLayout* l = new QVBoxLayout ( this ); + l->setMargin( MARGIN ); + l->setSpacing( SPACING ); + l->addWidget( myTabWidget ); + l->addStretch(); + l->addLayout( btnLayout ); + + myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) ); + + connect( okBtn, SIGNAL( clicked() ), this, SLOT( reject() ) ); + connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) ); + connect( myTabWidget, SIGNAL( currentChanged( int ) ), this, SLOT( updateSelection() ) ); + connect( myMode, SIGNAL( buttonClicked( int ) ), this, SLOT( modeChanged() ) ); + connect( myID, SIGNAL( textEdited( QString ) ), this, SLOT( idChanged() ) ); + connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) ); + connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ), this, SLOT( reject() ) ); + + updateSelection(); +} + +/*! + \brief Destructor +*/ +SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg() +{ +} + +/*! + \brief Show mesh information + \param IO interactive object +*/ +void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO ) +{ + SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface( IO ); + if ( !CORBA::is_nil( obj ) ) { + myBaseInfo->showInfo( obj ); + + myActor = SMESH::FindActorByEntry( IO->getEntry() ); + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + QString ID; + int nb = 0; + if ( myActor && selector ) { + nb = myMode->checkedId() == NodeMode ? + SMESH::GetNameOfSelectedElements( selector, IO, ID ) : + SMESH::GetNameOfSelectedNodes( selector, IO, ID ); + } + if ( nb == 1 ) { + myID->setText( ID.trimmed() ); + myElemInfo->setSource( myActor ) ; + myElemInfo->showInfo( ID.toLong(), myMode->checkedId() == ElemMode ); + } + else { + myID->clear(); + myElemInfo->clear(); + } + } +} + +/*! + \brief Perform clean-up actions on the dialog box closing. +*/ +void SMESHGUI_MeshInfoDlg::reject() +{ + LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); + selMgr->clearFilters(); + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( ActorSelection ); + QDialog::reject(); +} + +/*! + \brief Process keyboard event + \param e key press event +*/ +void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e ) +{ + QDialog::keyPressEvent( e ); + if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) { + e->accept(); + help(); + } +} + +/*! + \brief Reactivate dialog box, when mouse pointer goes into it. +*/ +void SMESHGUI_MeshInfoDlg::enterEvent( QEvent* ) +{ + activate(); +} + +/*! + \brief Setup selection mode depending on the current dialog box state. +*/ +void SMESHGUI_MeshInfoDlg::updateSelection() +{ + LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); + + disconnect( selMgr, 0, this, 0 ); + selMgr->clearFilters(); + + if ( myTabWidget->currentIndex() == BaseInfo ) { + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( ActorSelection ); + } + else { + if ( myMode->checkedId() == NodeMode ) { + SMESH::SetPointRepresentation( true ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( NodeSelection ); + } + else { + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( CellSelection ); + } + } + + int oldID = myID->text().toLong(); + SMESH_Actor* oldActor = myActor; + myID->clear(); + + connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) ); + updateInfo(); + + if ( oldActor == myActor && myActor && oldID ) { + myID->setText( QString::number( oldID ) ); + idChanged(); + } +} + +/*! + \brief Show help page +*/ +void SMESHGUI_MeshInfoDlg::help() +{ + SMESH::ShowHelpFile( myTabWidget->currentIndex() == BaseInfo ? + "mesh_infos_page.html#advanced_mesh_infos_anchor" : + "mesh_infos_page.html#mesh_element_info_anchor" ); +} + +/*! + \brief Show mesh information +*/ +void SMESHGUI_MeshInfoDlg::updateInfo() +{ + SUIT_OverrideCursor wc; + + SALOME_ListIO selected; + SMESHGUI::selectionMgr()->selectedObjects( selected ); + + if ( selected.Extent() == 1 ) { + Handle(SALOME_InteractiveObject) IO = selected.First(); + showInfo( IO ); + } +// else { +// myBaseInfo->clear(); +// myElemInfo->clear(); +// } +} + +/*! + \brief Activate dialog box +*/ +void SMESHGUI_MeshInfoDlg::activate() +{ + SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog(); + SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this ); + myTabWidget->setEnabled( true ); + updateSelection(); +} + +/*! + \brief Deactivate dialog box +*/ +void SMESHGUI_MeshInfoDlg::deactivate() +{ + myTabWidget->setEnabled( false ); + disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) ); +} + +/*! + \brief Called when users switches between node / element modes. +*/ +void SMESHGUI_MeshInfoDlg::modeChanged() +{ + myID->clear(); + updateSelection(); +} + +/*! + \brief Caled when users prints mesh element ID in the corresponding field. +*/ +void SMESHGUI_MeshInfoDlg::idChanged() +{ + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + if ( myActor && selector ) { + Handle(SALOME_InteractiveObject) IO = myActor->getIO(); + TColStd_MapOfInteger ID; + ID.Add( myID->text().toLong() ); + selector->AddOrRemoveIndex( IO, ID, false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->highlight( IO, true, true ); + myElemInfo->showInfo( myID->text().toLong(), myMode->checkedId() == ElemMode ); + } +} diff --git a/src/SMESHGUI/SMESHGUI_MeshInfo.h b/src/SMESHGUI/SMESHGUI_MeshInfo.h new file mode 100644 index 000000000..ae22e5ac0 --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_MeshInfo.h @@ -0,0 +1,220 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 : SMESHGUI_MeshInfo.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) + +#ifndef SMESHGUI_MESHINFO_H +#define SMESHGUI_MESHINFO_H + +#include "SMESH_SMESHGUI.hxx" +#include + +#include +#include +#include +#include +#include + +#include +#include CORBA_SERVER_HEADER(SMESH_Mesh) + +class QButtonGroup; +class QLabel; +class QLineEdit; +class QTabWidget; +class QTextBrowser; +class QTreeWidget; +class QTreeWidgetItem; +class SMESH_Actor; +class SMDS_MeshNode; +class SMDS_MeshElement; + +class SMESHGUI_EXPORT SMESHGUI_MeshInfo : public QFrame +{ + Q_OBJECT; + + enum { + iName, + iObject, + iNodesStart, + iNodes, + iNodesEnd, + iElementsStart = iNodesEnd, + iElements, + i0DStart, + i0D, + i0DEnd, + i1DStart = i0DEnd, + i1D, + i1DEnd, + i2DStart = i1DEnd, + i2D, + i2DTriangles, + i2DQuadrangles, + i2DPolygons, + i2DEnd, + i3DStart = i2DEnd, + i3D, + i3DTetrahedrons, + i3DHexahedrons, + i3DPyramids, + i3DPrisms, + i3DPolyhedrons, + i3DEnd, + iElementsEnd = i3DEnd + }; + + enum { + iSingle = 1, + iTotal = iSingle, + iLinear, + iQuadratic + }; + + typedef QList wlist; + typedef QVector iwlist; + +public: + SMESHGUI_MeshInfo( QWidget* = 0 ); + ~SMESHGUI_MeshInfo(); + + void showInfo( SMESH::SMESH_IDSource_ptr ); + void clear(); + +private: + enum { Bold = 0x01, Italic = 0x02 }; + + QLabel* createField(); + QWidget* createLine(); + void setFontAttributes( QWidget*, int, bool = true ); + void setFieldsVisible( int, int, bool ); + +private: + iwlist myWidgets; +}; + +class SMESHGUI_EXPORT SMESHGUI_ElemInfo : public QWidget +{ + Q_OBJECT; + +public: + SMESHGUI_ElemInfo( QWidget* = 0 ); + ~SMESHGUI_ElemInfo(); + + void setSource( SMESH_Actor* ); + virtual void showInfo( long, bool ); + virtual void clear() = 0; + +protected: + struct XYZ + { + double myX, myY, myZ; + XYZ() { myX = myY = myZ = 0.0; } + void add( double x, double y, double z ) { myX += x; myY += y; myZ += z; } + void divide( double a ) { if ( a != 0.) { myX /= a; myY /= a; myZ /= a; } } + double x() const { return myX; } + double y() const { return myY; } + double z() const { return myZ; } + }; + typedef QMap< int, QList > Connectivity; + + Connectivity nodeConnectivity( const SMDS_MeshNode* ); + QString formatConnectivity( Connectivity, int ); + XYZ gravityCenter( const SMDS_MeshElement* ); + +protected: + SMESH_Actor* myActor; + long myID; + int myIsElement; +}; + +class SMESHGUI_EXPORT SMESHGUI_SimpleElemInfo : public SMESHGUI_ElemInfo +{ +public: + SMESHGUI_SimpleElemInfo( QWidget* = 0 ); + + void showInfo( long, bool ); + void clear(); + +private: + QTextBrowser* myInfo; +}; + +class SMESHGUI_EXPORT SMESHGUI_TreeElemInfo : public SMESHGUI_ElemInfo +{ + class ItemDelegate; + +public: + SMESHGUI_TreeElemInfo( QWidget* = 0 ); + + void showInfo( long, bool ); + void clear(); + +private: + QTreeWidgetItem* createItem( QTreeWidgetItem* = 0, int = 100 ); + +private: + QTreeWidget* myInfo; +}; + +class SMESHGUI_EXPORT SMESHGUI_MeshInfoDlg : public QDialog +{ + Q_OBJECT; + + enum { NodeMode, ElemMode }; + +public: + //! Information type + enum { + BaseInfo, //!< base mesh information + ElemInfo //!< mesh element information + }; + + SMESHGUI_MeshInfoDlg( QWidget* = 0, int = BaseInfo ); + ~SMESHGUI_MeshInfoDlg(); + + void showInfo( const Handle(SALOME_InteractiveObject)& ); + void reject(); + +protected: + void keyPressEvent( QKeyEvent* ); + void enterEvent( QEvent* ); + +private slots: + void help(); + void updateSelection(); + void updateInfo(); + void activate(); + void deactivate(); + void modeChanged(); + void idChanged(); + +private: + QTabWidget* myTabWidget; + SMESHGUI_MeshInfo* myBaseInfo; + QButtonGroup* myMode; + QLineEdit* myID; + SMESHGUI_ElemInfo* myElemInfo; + SMESH_Actor* myActor; +}; + +#endif // SMESHGUI_MESHINFO_H diff --git a/src/SMESHGUI/SMESHGUI_MeshOp.cxx b/src/SMESHGUI/SMESHGUI_MeshOp.cxx index 84107dc27..48b4fae6e 100644 --- a/src/SMESHGUI/SMESHGUI_MeshOp.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshOp.cxx @@ -860,6 +860,7 @@ void SMESHGUI_MeshOp::existingHyps( const int theDim, if ( !aHypVar->_is_nil() ) { HypothesisData* aData = SMESH::GetHypothesisData( aHypVar->GetName() ); + if ( !aData) continue; if ( ( theDim == -1 || aData->Dim.contains( theDim ) ) && ( isCompatible ( theAlgoData, aData, theHypType )) && ( isAux == aData->IsAux )) @@ -1858,7 +1859,7 @@ SMESH::SMESH_Hypothesis_var SMESHGUI_MeshOp::getAlgo( const int theDim ) { // Call hypothesis creation server method (without GUI) SMESH::SMESH_Hypothesis_var aHyp = - SMESH::CreateHypothesis(aHypName, aHypData->Label, true); + SMESH::CreateHypothesis(aHypName, aHypName, true); #ifdef WITHGENERICOBJ if (!CORBA::is_nil(aHyp)) aHyp->Destroy(); @@ -1876,7 +1877,7 @@ SMESH::SMESH_Hypothesis_var SMESHGUI_MeshOp::getAlgo( const int theDim ) aCreator->create(true, aHypName, myDlg, 0, QString::null ); else { SMESH::SMESH_Hypothesis_var aHyp = - SMESH::CreateHypothesis(aHypName, aHypData->Label, true); + SMESH::CreateHypothesis(aHypName, aHypName, true); #ifdef WITHGENERICOBJ if (!CORBA::is_nil(aHyp)) aHyp->Destroy(); diff --git a/src/SMESHGUI/SMESHGUI_MeshUtils.cxx b/src/SMESHGUI/SMESHGUI_MeshUtils.cxx index bf53ecd7f..7d48093e2 100644 --- a/src/SMESHGUI/SMESHGUI_MeshUtils.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshUtils.cxx @@ -27,6 +27,7 @@ // #include "SMESHGUI_MeshUtils.h" +#include "SMESHGUI.h" #include "SMESHGUI_Utils.h" // SALOME KERNEL includes @@ -38,6 +39,7 @@ // IDL includes #include #include CORBA_SERVER_HEADER(SMESH_Group) +#include CORBA_SERVER_HEADER(SMESH_Measurements) namespace SMESH { @@ -122,4 +124,13 @@ namespace SMESH } return name; } + + SMESH::Measurements_var& GetMeasurements() + { + static SMESH::Measurements_var aMeasurements; + if (CORBA::is_nil(aMeasurements)) { + aMeasurements = SMESHGUI::GetSMESHGen()->CreateMeasurements(); + } + return aMeasurements; + } } // end of namespace SMESH diff --git a/src/SMESHGUI/SMESHGUI_MeshUtils.h b/src/SMESHGUI/SMESHGUI_MeshUtils.h index 5a959cb39..a5371f56b 100644 --- a/src/SMESHGUI/SMESHGUI_MeshUtils.h +++ b/src/SMESHGUI/SMESHGUI_MeshUtils.h @@ -42,6 +42,7 @@ // IDL includes #include #include CORBA_SERVER_HEADER(SMESH_Mesh) +#include CORBA_SERVER_HEADER(SMESH_Measurements) class SALOMEDSClient_SObject; @@ -54,6 +55,8 @@ namespace SMESH QString UniqueMeshName( const QString&, const QString& = QString() ); SMESHGUI_EXPORT QString UniqueName( const QString&, _PTR(SObject) = _PTR(SObject)(), const QString& = QString() ); + + SMESHGUI_EXPORT SMESH::Measurements_var& GetMeasurements(); } #endif // SMESHGUI_MESHUTILS_H diff --git a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx index ec3a4d14f..43640501e 100644 --- a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx @@ -33,6 +33,8 @@ #include "SMESHGUI_Utils.h" #include +#include +#include // SALOME GUI includes #include @@ -63,7 +65,6 @@ // VTK includes #include -#include #include #define MINIMUM_WIDTH 70 @@ -279,8 +280,35 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* myOriginDimGrpLayout->addWidget( myHeightSpin, 1, 3 ); aTopLayout->addWidget( myOriginDimGrp ); + /******************************************************************************/ - /***************************************************************/ + // Destribution + myDistributionGrp = new QGroupBox ( tr( "SMESH_DISTRIBUTION_SCALARBAR" ), this ); + myDistributionGrp->setCheckable(true); + QHBoxLayout* aDistributionGrpLayout = new QHBoxLayout( myDistributionGrp ); + aDistributionGrpLayout->setSpacing( SPACING_SIZE ); aDistributionGrpLayout->setMargin( MARGIN_SIZE ); + + myDistribColorGrp = new QButtonGroup( this ); + + myDMonoColor = new QRadioButton( tr( "SMESH_MONOCOLOR" ) , myDistributionGrp ); + myDMultiColor = new QRadioButton( tr( "SMESH_MULTICOLOR" ), myDistributionGrp ); + myDMonoColor->setChecked( true ); + + myDistribColorGrp->addButton(myDMonoColor);myDistribColorGrp->setId(myDMonoColor,1); + myDistribColorGrp->addButton(myDMultiColor);myDistribColorGrp->setId(myDMultiColor,2); + + aDistributionGrpLayout->addWidget( myDMultiColor ); + aDistributionGrpLayout->addWidget( myDMonoColor ); + + //Color of the Distribution in monocolor case: + myDistributionColorLbl = new QLabel( tr( "SMESH_DISTRIBUTION_COLOR" ), myDistributionGrp ); + aDistributionGrpLayout->addWidget( myDistributionColorLbl ); + myMonoColorBtn = new QtxColorButton( myDistributionGrp ); + aDistributionGrpLayout->addWidget(myMonoColorBtn); + + aTopLayout->addWidget(myDistributionGrp); + + /******************************************************************************/ // Common buttons myButtonGrp = new QGroupBox( this ); QHBoxLayout* myButtonGrpLayout = new QHBoxLayout( myButtonGrp ); @@ -376,6 +404,25 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* setOriginAndSize(myIniX, myIniY, myIniW, myIniH); + + bool distributionVisibility = mgr->booleanValue("SMESH","distribution_visibility"); + myDistributionGrp->setChecked(distributionVisibility); + + int coloringType = mgr->integerValue("SMESH", "distribution_coloring_type", 0); + if( coloringType == SMESH_MONOCOLOR_TYPE ) { + myDMultiColor->setChecked(true); + onDistributionChanged(myDistribColorGrp->id(myDMultiColor)); + } else { + myDMonoColor->setChecked(true); + onDistributionChanged(myDistribColorGrp->id(myDMonoColor)); + } + + QColor distributionColor = mgr->colorValue("SMESH", "distribution_color", + QColor(255, 255, 255)); + myMonoColorBtn->setColor(distributionColor); + + + // --> then init from selection if necessary onSelectionChanged(); @@ -388,10 +435,11 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* connect( myXSpin, SIGNAL( valueChanged( double ) ), this, SLOT( onXYChanged() ) ); connect( myYSpin, SIGNAL( valueChanged( double ) ), this, SLOT( onXYChanged() ) ); connect( aOrientationGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( onOrientationChanged() ) ); + connect( myDistribColorGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( onDistributionChanged( int ) ) ); connect( mySelectionMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( onSelectionChanged() ) ); connect( mySMESHGUI, SIGNAL( SignalCloseAllDialogs() ), this, SLOT( onCancel() ) ); - myHelpFileName = "about_quality_controls_page.html"; + myHelpFileName = "quality_page.html"; } //================================================================================================= @@ -430,7 +478,7 @@ bool SMESHGUI_Preferences_ScalarBarDlg::onApply() // Scalar Bar properties if (!myActor) return false; - vtkScalarBarActor* myScalarBarActor = myActor->GetScalarBarActor(); + SMESH_ScalarBarActor* myScalarBarActor = myActor->GetScalarBarActor(); vtkTextProperty* aTitleTextPrp = myScalarBarActor->GetTitleTextProperty(); QColor aTColor = myTitleColorBtn->color(); @@ -461,7 +509,18 @@ bool SMESHGUI_Preferences_ScalarBarDlg::onApply() myScalarBarActor->SetLabelTextProperty( aLabelsTextPrp ); myScalarBarActor->SetNumberOfLabels( myLabelsSpin->value() ); - myScalarBarActor->SetMaximumNumberOfColors( myColorsSpin->value() ); + if( myColorsSpin->value() != myScalarBarActor->GetMaximumNumberOfColors() ) { + myScalarBarActor->SetMaximumNumberOfColors( myColorsSpin->value() ); + SMESH::Controls::FunctorPtr fn = myActor->GetFunctor(); + SMESH::Controls::NumericalFunctor* aNumericalFunctor = dynamic_cast(fn.get()); + if( aNumericalFunctor ) { + int nbIntervals = myColorsSpin->value(); + std::vector nbEvents; + std::vector funValues; + aNumericalFunctor->GetHistogram(nbIntervals, nbEvents, funValues); + myScalarBarActor->SetDistribution(nbEvents); + } + } if ( myHorizRadioBtn->isChecked() ) myScalarBarActor->SetOrientationToHorizontal(); @@ -472,6 +531,21 @@ bool SMESHGUI_Preferences_ScalarBarDlg::onApply() myScalarBarActor->SetWidth( myWidthSpin->value() ); myScalarBarActor->SetHeight( myHeightSpin->value() ); + // Distribution + myScalarBarActor->SetDistributionVisibility((int)myDistributionGrp->isChecked()); + if( myDistributionGrp->isChecked() ) { + int ColoringType = myDMultiColor->isChecked() ? SMESH_MULTICOLOR_TYPE : SMESH_MONOCOLOR_TYPE; + myScalarBarActor->SetDistributionColoringType(ColoringType); + if( !myDMultiColor->isChecked() ) { + QColor aTColor = myMonoColorBtn->color(); + double rgb[3]; + rgb [0] = aTColor.red()/255.; + rgb [1] = aTColor.green()/255.; + rgb [2] = aTColor.blue()/255.; + myScalarBarActor->SetDistributionColor(rgb); + } + } + double aMin = myMinEdit->text().toDouble(); double aMax = myMaxEdit->text().toDouble(); vtkLookupTable* myLookupTable = @@ -540,7 +614,7 @@ void SMESHGUI_Preferences_ScalarBarDlg::onSelectionChanged() SMESH_Actor* anActor = SMESH::FindActorByEntry(anIO->getEntry()); if ( anActor && anActor->GetScalarBarActor() && anActor->GetControlMode() != SMESH_Actor::eNone ) { myActor = anActor; - vtkScalarBarActor* myScalarBarActor = myActor->GetScalarBarActor(); + SMESH_ScalarBarActor* myScalarBarActor = myActor->GetScalarBarActor(); if ( myScalarBarActor->GetLookupTable() ) { vtkFloatingPointType *range = myScalarBarActor->GetLookupTable()->GetRange(); @@ -581,6 +655,17 @@ void SMESHGUI_Preferences_ScalarBarDlg::onSelectionChanged() myIniH = myScalarBarActor->GetHeight(); setOriginAndSize( myIniX, myIniY, myIniW, myIniH ); + myDistributionGrp->setChecked((bool)myScalarBarActor->GetDistributionVisibility()); + int coloringType = myScalarBarActor->GetDistributionColoringType(); + myScalarBarActor->GetDistributionColor( aTColor ); + myMonoColorBtn->setColor( QColor( (int)( aTColor[0]*255 ), (int)( aTColor[1]*255 ), (int)( aTColor[2]*255 ) ) ); + if ( coloringType == SMESH_MONOCOLOR_TYPE ) { + myDMonoColor->setChecked(true); + onDistributionChanged(myDistribColorGrp->id(myDMonoColor)); + } else { + myDMultiColor->setChecked(true); + onDistributionChanged(myDistribColorGrp->id(myDMultiColor)); + } myRangeGrp->setEnabled( true ); myFontGrp->setEnabled( true ); myLabColorGrp->setEnabled( true ); @@ -651,6 +736,19 @@ void SMESHGUI_Preferences_ScalarBarDlg::setOriginAndSize( const double x, onXYChanged(); } + +//================================================================================================= +/*! + * SMESHGUI_Preferences_ScalarBarDlg::onDistributionChanged + * + * Called when coloring type of the distribution is changed + */ +//================================================================================================= +void SMESHGUI_Preferences_ScalarBarDlg::onDistributionChanged( int id ) { + myMonoColorBtn->setEnabled(myDistribColorGrp->id(myDMonoColor) == id); + myDistributionColorLbl->setEnabled(myDistribColorGrp->id(myDMonoColor) == id); +} + //================================================================================================= /*! * SMESHGUI_Preferences_ScalarBarDlg::onOrientationChanged diff --git a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.h b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.h index c71c43cda..42058ee2b 100644 --- a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.h +++ b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.h @@ -40,6 +40,8 @@ class QLineEdit; class QPushButton; class QToolButton; class QRadioButton; +class QButtonGroup; +class QLabel; class SMESHGUI; class SMESH_Actor; @@ -77,6 +79,7 @@ protected slots: void onSelectionChanged(); void onXYChanged(); void onOrientationChanged(); + void onDistributionChanged( int ); private: SMESHGUI* mySMESHGUI; @@ -117,7 +120,14 @@ private: SMESHGUI_SpinBox* myWidthSpin; SMESHGUI_SpinBox* myHeightSpin; + QGroupBox* myDistributionGrp; + QRadioButton* myDMonoColor; + QRadioButton* myDMultiColor; + QtxColorButton* myMonoColorBtn; + QLabel* myDistributionColorLbl; + QGroupBox* myButtonGrp; + QButtonGroup* myDistribColorGrp; QPushButton* myOkBtn; QPushButton* myApplyBtn; QPushButton* myCancelBtn; diff --git a/src/SMESHGUI/SMESHGUI_Selection.cxx b/src/SMESHGUI/SMESHGUI_Selection.cxx index 887cdea08..df7c9c1c6 100644 --- a/src/SMESHGUI/SMESHGUI_Selection.cxx +++ b/src/SMESHGUI/SMESHGUI_Selection.cxx @@ -34,6 +34,7 @@ #include #include +#include // SALOME GUI includes #include @@ -114,6 +115,7 @@ QVariant SMESHGUI_Selection::parameter( const int ind, const QString& p ) const else if ( p=="shrinkMode" ) val = QVariant( shrinkMode( ind ) ); else if ( p=="entityMode" ) val = QVariant( entityMode( ind ) ); else if ( p=="controlMode" ) val = QVariant( controlMode( ind ) ); + else if ( p=="isNumFunctor" ) val = QVariant( isNumFunctor( ind ) ); else if ( p=="displayMode" ) val = QVariant( displayMode( ind ) ); else if ( p=="isComputable" ) val = QVariant( isComputable( ind ) ); else if ( p=="isPreComputable" ) val = QVariant( isPreComputable( ind ) ); @@ -122,6 +124,7 @@ QVariant SMESHGUI_Selection::parameter( const int ind, const QString& p ) const else if ( p=="facesOrientationMode" ) val = QVariant( facesOrientationMode( ind ) ); else if ( p=="groupType" ) val = QVariant( groupType( ind ) ); else if ( p=="quadratic2DMode") val = QVariant(quadratic2DMode(ind)); + else if ( p=="isDistributionVisible") val = QVariant(isDistributionVisible(ind)); if( val.isValid() ) return val; @@ -216,6 +219,16 @@ QString SMESHGUI_Selection::quadratic2DMode( int ind ) const return "Unknown"; } +//======================================================================= +//function : isDistributionVisible +//purpose : Visible/Invisible distribution of the ScalarBar Actor +//======================================================================= + +bool SMESHGUI_Selection::isDistributionVisible(int ind) const { + SMESH_Actor* actor = getActor( ind ); + return (actor && actor->GetScalarBarActor() && actor->GetScalarBarActor()->GetDistributionVisibility()); +} + //======================================================================= //function : shrinkMode //purpose : return either 'IsSrunk', 'IsNotShrunk' or 'IsNotShrinkable' @@ -271,6 +284,8 @@ QString SMESHGUI_Selection::controlMode( int ind ) const case SMESH_Actor::eMultiConnection2D: return "eMultiConnection2D"; case SMESH_Actor::eArea: return "eArea"; case SMESH_Actor::eVolume3D: return "eVolume3D"; + case SMESH_Actor::eMaxElementLength2D: return "eMaxElementLength2D"; + case SMESH_Actor::eMaxElementLength3D: return "eMaxElementLength3D"; case SMESH_Actor::eTaper: return "eTaper"; case SMESH_Actor::eAspectRatio: return "eAspectRatio"; case SMESH_Actor::eAspectRatio3D: return "eAspectRatio3D"; @@ -283,6 +298,35 @@ QString SMESHGUI_Selection::controlMode( int ind ) const return "eNone"; } +bool SMESHGUI_Selection::isNumFunctor( int ind ) const +{ + bool result = false; + SMESH_Actor* actor = getActor( ind ); + if ( actor ) { + switch( actor->GetControlMode() ) { + case SMESH_Actor::eLength: + case SMESH_Actor::eLength2D: + case SMESH_Actor::eMultiConnection: + case SMESH_Actor::eMultiConnection2D: + case SMESH_Actor::eArea: + case SMESH_Actor::eVolume3D: + case SMESH_Actor::eMaxElementLength2D: + case SMESH_Actor::eMaxElementLength3D: + case SMESH_Actor::eTaper: + case SMESH_Actor::eAspectRatio: + case SMESH_Actor::eAspectRatio3D: + case SMESH_Actor::eMinimumAngle: + case SMESH_Actor::eWarping: + case SMESH_Actor::eSkew: + result = true; + break; + default: + break; + } + } + return result; +} + //======================================================================= //function : facesOrientationMode //purpose : @@ -590,4 +634,3 @@ QString SMESHGUI_Selection::groupType( int ind ) const } return type; } - diff --git a/src/SMESHGUI/SMESHGUI_Selection.h b/src/SMESHGUI/SMESHGUI_Selection.h index 2320041de..2ad545d98 100644 --- a/src/SMESHGUI/SMESHGUI_Selection.h +++ b/src/SMESHGUI/SMESHGUI_Selection.h @@ -61,6 +61,8 @@ public: virtual QString quadratic2DMode(int ) const; + virtual bool isDistributionVisible(int ) const; + // parameters got from actor return nothing if an actor is not visible virtual QList elemTypes( int ) const; virtual QList labeledTypes( int ) const; @@ -68,6 +70,7 @@ public: virtual QString shrinkMode( int ) const; virtual QList entityMode( int ) const; virtual QString controlMode( int ) const; + virtual bool isNumFunctor( int ) const; virtual QString facesOrientationMode( int ) const; virtual QString groupType( int ) const; diff --git a/src/SMESHGUI/SMESHGUI_Utils.cxx b/src/SMESHGUI/SMESHGUI_Utils.cxx index 6f921cd22..dfe778831 100644 --- a/src/SMESHGUI/SMESHGUI_Utils.cxx +++ b/src/SMESHGUI/SMESHGUI_Utils.cxx @@ -205,6 +205,20 @@ namespace SMESH return SObjectToObject(theSObject,aStudy); } + _PTR(SObject) ObjectToSObject( CORBA::Object_ptr theObject ) + { + _PTR(SObject) res; + SalomeApp_Application* app = dynamic_cast + (SUIT_Session::session()->activeApplication()); + if ( app ) { + QString IOR = app->orb()->object_to_string( theObject ); + SalomeApp_Study* study = dynamic_cast( app->activeStudy() ); + if ( study && !IOR.isEmpty() ) + res = study->studyDS()->FindObjectIOR( IOR.toLatin1().constData() ); + } + return res; + } + CORBA::Object_var IObjectToObject (const Handle(SALOME_InteractiveObject)& theIO) { if (!theIO.IsNull()) { diff --git a/src/SMESHGUI/SMESHGUI_Utils.h b/src/SMESHGUI/SMESHGUI_Utils.h index 555d23382..996a34761 100644 --- a/src/SMESHGUI/SMESHGUI_Utils.h +++ b/src/SMESHGUI/SMESHGUI_Utils.h @@ -129,6 +129,9 @@ SMESHGUI_EXPORT return TInterface::_nil(); } +SMESHGUI_EXPORT + _PTR(SObject) ObjectToSObject( CORBA::Object_ptr ); + SMESHGUI_EXPORT CORBA::Object_var IObjectToObject( const Handle(SALOME_InteractiveObject)& ); diff --git a/src/SMESHGUI/SMESHGUI_VTKUtils.cxx b/src/SMESHGUI/SMESHGUI_VTKUtils.cxx index 72ce1e852..c663c74da 100644 --- a/src/SMESHGUI/SMESHGUI_VTKUtils.cxx +++ b/src/SMESHGUI/SMESHGUI_VTKUtils.cxx @@ -65,6 +65,7 @@ #include CORBA_CLIENT_HEADER(SMESH_Group) // VTK includes +#include #include #include #include @@ -605,6 +606,9 @@ namespace SMESH } } } + if( anActor ) + if( SMESHGUI* aSMESHGUI = SMESHGUI::GetSMESHGUI() ) + aSMESHGUI->addActorAsObserver( anActor ); return anActor; } @@ -1167,4 +1171,108 @@ namespace SMESH } } + + //---------------------------------------------------------------------------- + // internal function + void ComputeBoundsParam( vtkFloatingPointType theBounds[6], + vtkFloatingPointType theDirection[3], + vtkFloatingPointType theMinPnt[3], + vtkFloatingPointType& theMaxBoundPrj, + vtkFloatingPointType& theMinBoundPrj ) + { + //Enlarge bounds in order to avoid conflicts of precision + for(int i = 0; i < 6; i += 2){ + static double EPS = 1.0E-3; + vtkFloatingPointType aDelta = (theBounds[i+1] - theBounds[i])*EPS; + theBounds[i] -= aDelta; + theBounds[i+1] += aDelta; + } + + vtkFloatingPointType aBoundPoints[8][3] = { {theBounds[0],theBounds[2],theBounds[4]}, + {theBounds[1],theBounds[2],theBounds[4]}, + {theBounds[0],theBounds[3],theBounds[4]}, + {theBounds[1],theBounds[3],theBounds[4]}, + {theBounds[0],theBounds[2],theBounds[5]}, + {theBounds[1],theBounds[2],theBounds[5]}, + {theBounds[0],theBounds[3],theBounds[5]}, + {theBounds[1],theBounds[3],theBounds[5]}}; + + int aMaxId = 0, aMinId = aMaxId; + theMaxBoundPrj = vtkMath::Dot(theDirection,aBoundPoints[aMaxId]); + theMinBoundPrj = theMaxBoundPrj; + for(int i = 1; i < 8; i++){ + vtkFloatingPointType aTmp = vtkMath::Dot(theDirection,aBoundPoints[i]); + if(theMaxBoundPrj < aTmp){ + theMaxBoundPrj = aTmp; + aMaxId = i; + } + if(theMinBoundPrj > aTmp){ + theMinBoundPrj = aTmp; + aMinId = i; + } + } + vtkFloatingPointType *aMinPnt = aBoundPoints[aMaxId]; + theMinPnt[0] = aMinPnt[0]; + theMinPnt[1] = aMinPnt[1]; + theMinPnt[2] = aMinPnt[2]; + } + + // internal function + void DistanceToPosition( vtkFloatingPointType theBounds[6], + vtkFloatingPointType theDirection[3], + vtkFloatingPointType theDist, + vtkFloatingPointType thePos[3] ) + { + vtkFloatingPointType aMaxBoundPrj, aMinBoundPrj, aMinPnt[3]; + ComputeBoundsParam(theBounds,theDirection,aMinPnt,aMaxBoundPrj,aMinBoundPrj); + vtkFloatingPointType aLength = (aMaxBoundPrj-aMinBoundPrj)*theDist; + thePos[0] = aMinPnt[0]-theDirection[0]*aLength; + thePos[1] = aMinPnt[1]-theDirection[1]*aLength; + thePos[2] = aMinPnt[2]-theDirection[2]*aLength; + } + + // internal function (currently unused, left just in case) + void PositionToDistance( vtkFloatingPointType theBounds[6], + vtkFloatingPointType theDirection[3], + vtkFloatingPointType thePos[3], + vtkFloatingPointType& theDist ) + { + vtkFloatingPointType aMaxBoundPrj, aMinBoundPrj, aMinPnt[3]; + ComputeBoundsParam(theBounds,theDirection,aMinPnt,aMaxBoundPrj,aMinBoundPrj); + vtkFloatingPointType aPrj = vtkMath::Dot(theDirection,thePos); + theDist = (aPrj-aMinBoundPrj)/(aMaxBoundPrj-aMinBoundPrj); + } + + bool ComputeClippingPlaneParameters( std::list theActorList, + vtkFloatingPointType theNormal[3], + vtkFloatingPointType theDist, + vtkFloatingPointType theBounds[6], + vtkFloatingPointType theOrigin[3] ) + { + bool anIsOk = false; + theBounds[0] = theBounds[2] = theBounds[4] = VTK_DOUBLE_MAX; + theBounds[1] = theBounds[3] = theBounds[5] = -VTK_DOUBLE_MAX; + std::list::iterator anIter = theActorList.begin(); + for( ; anIter != theActorList.end(); anIter++ ) { + if( vtkActor* aVTKActor = *anIter ) { + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( aVTKActor ) ) { + vtkFloatingPointType aBounds[6]; + anActor->GetUnstructuredGrid()->GetBounds( aBounds ); + theBounds[0] = std::min( theBounds[0], aBounds[0] ); + theBounds[1] = std::max( theBounds[1], aBounds[1] ); + theBounds[2] = std::min( theBounds[2], aBounds[2] ); + theBounds[3] = std::max( theBounds[3], aBounds[3] ); + theBounds[4] = std::min( theBounds[4], aBounds[4] ); + theBounds[5] = std::max( theBounds[5], aBounds[5] ); + anIsOk = true; + } + } + } + + if( !anIsOk ) + return false; + + DistanceToPosition( theBounds, theNormal, theDist, theOrigin ); + return true; + } } // end of namespace SMESH diff --git a/src/SMESHGUI/SMESHGUI_VTKUtils.h b/src/SMESHGUI/SMESHGUI_VTKUtils.h index 508ce767e..5a9b09c25 100644 --- a/src/SMESHGUI/SMESHGUI_VTKUtils.h +++ b/src/SMESHGUI/SMESHGUI_VTKUtils.h @@ -57,6 +57,8 @@ class SMESHGUI; class SMESH_Actor; class SALOME_Actor; +class vtkActor; + namespace SMESH { //---------------------------------------------------------------------------- @@ -185,6 +187,14 @@ SMESHGUI_EXPORT SMESHGUI_EXPORT void SetControlsPrecision( const long ); + + //---------------------------------------------------------------------------- +SMESHGUI_EXPORT + bool ComputeClippingPlaneParameters( std::list theActorList, + vtkFloatingPointType theNormal[3], + vtkFloatingPointType theDist, + vtkFloatingPointType theBounds[6], + vtkFloatingPointType theOrigin[3] ); }; #endif // SMESHGUI_VTKUTILS_H diff --git a/src/SMESHGUI/SMESH_images.ts b/src/SMESHGUI/SMESH_images.ts index c22f4e96e..856e88f32 100644 --- a/src/SMESHGUI/SMESH_images.ts +++ b/src/SMESHGUI/SMESH_images.ts @@ -289,6 +289,14 @@ ICON_MAP mesh_pattern.png + + ICON_MAX_ELEMENT_LENGTH_2D + mesh_max_element_length_2d.png + + + ICON_MAX_ELEMENT_LENGTH_3D + mesh_max_element_length_3d.png + ICON_OBJBROWSER_SMESH mesh.png @@ -455,7 +463,7 @@ ICON_WHAT_IS - mesh_whatis.png + mesh_elem_info.png ICON_WIRE @@ -477,5 +485,13 @@ ICON_SPLIT_TO_TETRA split_into_tetra.png + + ICON_MEASURE_MIN_DIST + mesh_min_dist.png + + + ICON_MEASURE_BND_BOX + mesh_bounding_box.png + diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index a42af7217..8ea5465e1 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -3,6 +3,42 @@ @default + + SMESH_EXPORT_MESH + Export mesh + + + MED_FILES_FILTER + MED files + + + IDEAS_FILES_FILTER + IDEAS files + + + DAT_FILES_FILTER + DAT files + + + TEXT_FILES_FILTER + TXT files + + + MED_VX_FILES_FILTER + MED %1 files + + + STL_ASCII_FILES_FILTER + STL ASCII files + + + STL_BIN_FILES_FILTER + STL binary files + + + ALL_FILES_FILTER + All files + AREA_ELEMENTS Area @@ -107,13 +143,21 @@ LOCAL_ALGO Local + + MAX_ELEMENT_LENGTH_2D + Max Element Length 2D + + + MAX_ELEMENT_LENGTH_3D + Max Element Length 3D + MEN_ADD Add MEN_ADV_INFO - Advanced Mesh Infos + Mesh Information MEN_ALL @@ -207,6 +251,22 @@ MEN_CTRL Controls + + MEN_NODE_CTRL + Node Controls + + + MEN_EDGE_CTRL + Edge Controls + + + MEN_FACE_CTRL + Face Controls + + + MEN_VOLUME_CTRL + Volume Controls + MEN_CUT Cutting of Quadrangles @@ -387,6 +447,14 @@ MEN_MAP Pattern Mapping + + MEN_MAX_ELEMENT_LENGTH_2D + Max Element Length 2D + + + MEN_MAX_ELEMENT_LENGTH_3D + Max Element Length 3D + MEN_MED MED file @@ -419,6 +487,34 @@ MEN_MODIFY Modification + + MEN_MEASURE + Measurements + + + MEN_MEASURE_MIN_DIST + Minimum Distance + + + STB_MEASURE_MIN_DIST + Calculate minimum distance between two objects + + + TOP_MEASURE_MIN_DIST + Minimum distance + + + MEN_MEASURE_BND_BOX + Bounding Box + + + STB_MEASURE_BND_BOX + Calculate bounding box for the selected object(s) + + + TOP_MEASURE_BND_BOX + Bounding box + MEN_MOVE Move Node @@ -535,6 +631,14 @@ MEN_RESET Reset + + MEN_SAVE_DISTRIBUTION + Export Distribution... + + + MEN_SHOW_DISTRIBUTION + Show Distribution + MEN_REVOLUTION Revolution @@ -689,7 +793,7 @@ MEN_WHAT_IS - Mesh Element Info + Mesh Element Information MEN_WIRE @@ -1741,6 +1845,14 @@ add the exported data to its contents? SMESH_POSITION_SIZE_SCALARBAR Origin && Size + + SMESH_DISTRIBUTION_SCALARBAR + Distribution + + + SMESH_SHOW_DISTRIBUTION_SCALARBAR + Show Distribution + SMESH_PRECISION Precision @@ -1985,6 +2097,22 @@ add the exported data to its contents? SMESH_VERTICAL Vertical + + + SMESH_DISTRIBUTION_COLORING_TYPE + Coloring Type + + + SMESH_MONOCOLOR + Monocolor + + + SMESH_DISTRIBUTION_COLOR + Distribution color: + + + SMESH_MULTICOLOR + Multicolor SMESH_VISU_PROBLEM @@ -2112,7 +2240,7 @@ Please check preferences of Mesh module. STB_ADV_INFO - Advanced Mesh Infos + Show base information about the mesh object STB_ALL @@ -2350,6 +2478,14 @@ Please check preferences of Mesh module. STB_MAP Pattern mapping + + STB_MAX_ELEMENT_LENGTH_2D + Max Element Length 2D + + + STB_MAX_ELEMENT_LENGTH_3D + Max Element Length 3D + STB_MED Import MED file @@ -2470,6 +2606,14 @@ Please check preferences of Mesh module. STB_RESET Reset + + STB_SAVE_DISTRIBUTION + Save distribution to the file + + + STB_SHOW_DISTRIBUTION + Show Distribution + STB_REVOLUTION Revolution @@ -2596,7 +2740,7 @@ Please check preferences of Mesh module. STB_WHAT_IS - Mesh Element Info + Show information about the mesh node or element STB_WIRE @@ -2632,7 +2776,7 @@ Please check preferences of Mesh module. TOP_ADV_INFO - Advanced Mesh Infos + Mesh Information TOP_ALL @@ -2870,6 +3014,14 @@ Please check preferences of Mesh module. TOP_MAP Pattern mapping + + TOP_MAX_ELEMENT_LENGTH_2D + Max Element Length 2D + + + TOP_MAX_ELEMENT_LENGTH_3D + Max Element Length 3D + TOP_MED Import MED file @@ -2990,6 +3142,14 @@ Please check preferences of Mesh module. TOP_RESET Reset + + TOP_SAVE_DISTRIBUTION + Export distribution + + + TOP_SHOW_DISTRIBUTION + Show Distribution + TOP_REVOLUTION Revolution @@ -3116,15 +3276,19 @@ Please check preferences of Mesh module. TOP_WHAT_IS - Mesh Element Info + Mesh Element Information TOP_WIRE Wireframe + + UNKNOWN_CONTROL + Unknown + VOLUME_3D_ELEMENTS - Area + Volume WARP_ELEMENTS @@ -3224,6 +3388,10 @@ Input value precision can be adjusted using NB_NODES_REMOVED Removed %1 node(s). + + SMESH_SAVE_DISTRIBUTION + Export Distribution + SMESHGUI @@ -3312,6 +3480,30 @@ Please, create VTK viewer and try again PREF_NOTIFY_MODE Show a computation result notification + + PREF_NOTIFY_NEVER + Never + + + PREF_NOTIFY_ERROR + Errors only + + + PREF_NOTIFY_ALWAYS + Always + + + PREF_ELEM_INFO + Mesh element information + + + PREF_ELEM_INFO_SIMPLE + Simple + + + PREF_ELEM_INFO_TREE + Tree + SMESH_PREF_GROUP_PRECISION Input fields precision @@ -3361,7 +3553,11 @@ Please, create VTK viewer and try again Selection - PREF_HIGHLIGHT_COLOR + PREF_GROUP_INFO + Mesh information + + + PREF_HIGHLIGHT_COLOR Highlight color @@ -4221,6 +4417,14 @@ Please enter correct value and try again LYING_ON_GEOM Lying on Geom + + MAX_ELEMENT_LENGTH_2D + Max Element Length 2D + + + MAX_ELEMENT_LENGTH_3D + Max Element Length 3D + MINIMUM_ANGLE Minimum angle @@ -5169,6 +5373,14 @@ It is impossible to read point coordinates from file CLIP_PLANES Clipping planes + + MESHES_SUBMESHES_GROUPS + Meshes, sub-meshes and groups + + + SELECT_ALL + Select all + ROTATION_AROUND_X_Y2Z Rotation around X (Y to Z): @@ -5339,4 +5551,346 @@ It is impossible to read point coordinates from file Group name is not specified + + SMESHGUI_MeshInfo + + NAME_LAB + Name: + + + OBJECT_LAB + Object: + + + NODES_LAB + Nodes: + + + ELEMENTS_LAB + Elements: + + + TOTAL_LAB + Total + + + LINEAR_LAB + Linear + + + QUADRATIC_LAB + Quadratic + + + 0D_LAB + 0D: + + + 1D_LAB + 1D (edges): + + + 2D_LAB + 2D (faces): + + + TRIANGLES_LAB + Triangles: + + + QUADRANGLES_LAB + Quadrandgles: + + + POLYGONS_LAB + Polygons: + + + 3D_LAB + 3D (volumes): + + + TETRAHEDRONS_LAB + Tetrahedrons: + + + HEXAHEDONRS_LAB + Hexahedrons: + + + PYRAMIDS_LAB + Pyramids: + + + PRISMS_LAB + Prisms: + + + POLYHEDRONS_LAB + Polyhedrons: + + + OBJECT_MESH + Mesh + + + OBJECT_SUBMESH + Sub-mesh + + + OBJECT_GROUP + Group + + + OBJECT_GROUP_NODES + Group of nodes + + + OBJECT_GROUP_EDGES + Group of edges + + + OBJECT_GROUP_FACES + Group of faces + + + OBJECT_GROUP_VOLUMES + Group of volumes + + + OBJECT_GROUP_0DELEMS + Group of 0D elements + + + + SMESHGUI_MeshInfoDlg + + MESH_INFO + Mesh Information + + + BASE_INFO + Base Info + + + ELEM_INFO + Element Info + + + NODE_MODE + Node + + + ELEM_MODE + Element + + + + SMESHGUI_ElemInfo + + COORDINATES + COORDINATES + + + CONNECTIVITY + CONNECTIVITY + + + GRAVITY_CENTER + GRAVITY CENTER + + + NODE + NODE + + + 0D_ELEMENT + 0D ELEMENT + + + 0D_ELEMENTS + 0D ELEMENTS + + + EDGE + EDGE + + + EDGES + EDGES + + + FACE + FACE + + + FACES + FACES + + + VOLUME + VOLUME + + + VOLUMES + VOLUMES + + + FREE_NODE + Free node (no connectivity) + + + TYPE + TYPE + + + TRIANGLE + Triangle + + + QUADRANGLE + Quadrangle + + + POLYGON + Polygon + + + TETRAHEDRON + Tetrahedron + + + HEXAHEDRON + Hexahedron + + + PYRAMID + Pyramid + + + PRISM + Prism + + + POLYHEDRON + Polyhedron + + + QUADRATIC + QUADRATIC + + + YES + Yes + + + NO + No + + + GRAVITY_CENTER + GRAVITY CENTER + + + PROPERTY + Property + + + VALUE + Value + + + + SMESHGUI_MinDistance + + FIRST_TARGET + First target + + + SECOND_TARGET + Second target + + + NODE + Node + + + ELEMENT + Element + + + OBJECT + Object + + + ORIGIN + Origin + + + COMPUTE + Compute + + + RESULT + Distance between targets + + + DISTANCE + Distance + + + + SMESHGUI_MeasureDlg + + MEASUREMENTS + Measurements + + + MIN_DIST + Minimum Distance + + + BND_BOX + Bounding Box + + + + SMESHGUI_BoundingBox + + SOURCE + Source + + + OBJECTS + Objects + + + NODES + Nodes + + + ELEMENTS + Elements + + + COMPUTE + Compute + + + RESULT + Bounding Box + + + SELECTED_NB_OBJ + %1 %2 selected + + + NB_NODES + nodes + + + NB_ELEMENTS + elements + + diff --git a/src/SMESH_I/Makefile.am b/src/SMESH_I/Makefile.am index 9a2a3c6a4..53f285528 100644 --- a/src/SMESH_I/Makefile.am +++ b/src/SMESH_I/Makefile.am @@ -46,6 +46,7 @@ salomeinclude_HEADERS = \ SMESH_Pattern_i.hxx \ SMESH_2smeshpy.hxx \ SMESH_NoteBook.hxx \ + SMESH_Measurements_i.hxx \ SMESH.hxx # Scripts to be installed. @@ -76,7 +77,8 @@ dist_libSMESHEngine_la_SOURCES = \ SMESH_Group_i.cxx \ SMESH_Pattern_i.cxx \ SMESH_2smeshpy.cxx \ - SMESH_NoteBook.cxx + SMESH_NoteBook.cxx \ + SMESH_Measurements_i.cxx # Executables targets bin_PROGRAMS = SMESHEngine diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx index 1f4a1de14..dfb378f24 100644 --- a/src/SMESH_I/SMESH_2smeshpy.cxx +++ b/src/SMESH_I/SMESH_2smeshpy.cxx @@ -342,6 +342,7 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand ) // Concatenate( [mesh1, ...], ... ) // CreateHypothesis( theHypType, theLibName ) // Compute( mesh, geom ) + // Evaluate( mesh, geom ) // mesh creation TCollection_AsciiString method = theCommand->GetMethod(); @@ -395,6 +396,20 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand ) } } + // smeshgen.Evaluate( mesh, geom ) --> mesh.Evaluate(geom) + if ( method == "Evaluate" ) + { + const _pyID& meshID = theCommand->GetArg( 1 ); + map< _pyID, Handle(_pyMesh) >::iterator id_mesh = myMeshes.find( meshID ); + if ( id_mesh != myMeshes.end() ) { + theCommand->SetObject( meshID ); + _pyID geom = theCommand->GetArg( 2 ); + theCommand->RemoveArgs(); + theCommand->SetArg( 1, geom ); + return; + } + } + // objects erasing creation command if no more it's commands invoked: // SMESH_Pattern, FilterManager if ( method == "GetPattern" || method == "CreateFilterManager" ) { diff --git a/src/SMESH_I/SMESH_DumpPython.cxx b/src/SMESH_I/SMESH_DumpPython.cxx index 4bc9f1aa2..3fd8ff22f 100644 --- a/src/SMESH_I/SMESH_DumpPython.cxx +++ b/src/SMESH_I/SMESH_DumpPython.cxx @@ -274,6 +274,8 @@ namespace SMESH case FT_Skew: myStream<< "aSkew"; break; case FT_Area: myStream<< "aArea"; break; case FT_Volume3D: myStream<< "aVolume3D"; break; + case FT_MaxElementLength2D:myStream<< "aMaxElementLength2D";break; + case FT_MaxElementLength3D:myStream<< "aMaxElementLength3D";break; case FT_FreeBorders: myStream<< "aFreeBorders"; break; case FT_FreeEdges: myStream<< "aFreeEdges"; break; case FT_FreeNodes: myStream<< "aFreeNodes"; break; @@ -307,6 +309,15 @@ namespace SMESH return *this; } + TPythonDump& + TPythonDump:: + operator<<(SMESH::Measurements_i* theArg) + { + myStream<<"aMeasurements"; + return *this; + } + + TPythonDump& TPythonDump:: operator<<(SMESH_Gen_i* theArg) { myStream << SMESHGenName(); return *this; @@ -684,6 +695,7 @@ TCollection_AsciiString SMESH_Gen_i::DumpPython_impl TCollection_AsciiString aScript; aScript = "def RebuildData(theStudy):\n\t"; aScript += helper + "aFilterManager = " + aSMESHGen + ".CreateFilterManager()\n\t"; + aScript += helper + "aMeasurements = " + aSMESHGen + ".CreateMeasurements()\n\t"; if ( isPublished ) aScript += aSMESHGen + ".SetCurrentStudy(theStudy)"; else diff --git a/src/SMESH_I/SMESH_Filter_i.cxx b/src/SMESH_I/SMESH_Filter_i.cxx index 477e92a13..d2a7ae648 100644 --- a/src/SMESH_I/SMESH_Filter_i.cxx +++ b/src/SMESH_I/SMESH_Filter_i.cxx @@ -596,6 +596,28 @@ CORBA::Double NumericalFunctor_i::GetValue( CORBA::Long theId ) return myNumericalFunctorPtr->GetValue( theId ); } +SMESH::Histogram* NumericalFunctor_i::GetHistogram(CORBA::Short nbIntervals) +{ + std::vector nbEvents; + std::vector funValues; + myNumericalFunctorPtr->GetHistogram(nbIntervals,nbEvents,funValues); + + nbIntervals = CORBA::Short( std::min( nbEvents.size(), funValues.size() - 1)); + SMESH::Histogram_var histogram = new SMESH::Histogram; + if ( nbIntervals > 0 ) + { + histogram->length( nbIntervals ); + for ( int i = 0; i < nbIntervals; ++i ) + { + HistogramRectangle& rect = histogram[i]; + rect.nbEvents = nbEvents[i]; + rect.min = funValues[i]; + rect.max = funValues[i+1]; + } + } + return histogram._retn(); +} + void NumericalFunctor_i::SetPrecision( CORBA::Long thePrecision ) { myNumericalFunctorPtr->SetPrecision( thePrecision ); @@ -738,6 +760,36 @@ FunctorType Volume3D_i::GetFunctorType() return SMESH::FT_Volume3D; } +/* + Class : MaxElementLength2D_i + Description : Functor for calculating maximum length of 2D element +*/ +MaxElementLength2D_i::MaxElementLength2D_i() +{ + myNumericalFunctorPtr.reset( new Controls::MaxElementLength2D() ); + myFunctorPtr = myNumericalFunctorPtr; +} + +FunctorType MaxElementLength2D_i::GetFunctorType() +{ + return SMESH::FT_MaxElementLength2D; +} + +/* + Class : MaxElementLength3D_i + Description : Functor for calculating maximum length of 3D element +*/ +MaxElementLength3D_i::MaxElementLength3D_i() +{ + myNumericalFunctorPtr.reset( new Controls::MaxElementLength3D() ); + myFunctorPtr = myNumericalFunctorPtr; +} + +FunctorType MaxElementLength3D_i::GetFunctorType() +{ + return SMESH::FT_MaxElementLength3D; +} + /* Class : Length_i Description : Functor for calculating length off edge @@ -1838,6 +1890,24 @@ Volume3D_ptr FilterManager_i::CreateVolume3D() } +MaxElementLength2D_ptr FilterManager_i::CreateMaxElementLength2D() +{ + SMESH::MaxElementLength2D_i* aServant = new SMESH::MaxElementLength2D_i(); + SMESH::MaxElementLength2D_var anObj = aServant->_this(); + TPythonDump()<_this(); + TPythonDump()<CreateVolume3D(); break; + case SMESH::FT_MaxElementLength2D: + aFunctor = aFilterMgr->CreateMaxElementLength2D(); + break; + case SMESH::FT_MaxElementLength3D: + aFunctor = aFilterMgr->CreateMaxElementLength3D(); + break; // Predicates @@ -2870,6 +2956,8 @@ static inline LDOMString toString( CORBA::Long theType ) case FT_Skew : return "Skew"; case FT_Area : return "Area"; case FT_Volume3D : return "Volume3D"; + case FT_MaxElementLength2D: return "Max element length 2D"; + case FT_MaxElementLength3D: return "Max element length 3D"; case FT_BelongToGeom : return "Belong to Geom"; case FT_BelongToPlane : return "Belong to Plane"; case FT_BelongToCylinder: return "Belong to Cylinder"; @@ -2912,6 +3000,8 @@ static inline SMESH::FunctorType toFunctorType( const LDOMString& theStr ) else if ( theStr.equals( "Skew" ) ) return FT_Skew; else if ( theStr.equals( "Area" ) ) return FT_Area; else if ( theStr.equals( "Volume3D" ) ) return FT_Volume3D; + else if ( theStr.equals( "Max element length 2D" ) ) return FT_MaxElementLength2D; + else if ( theStr.equals( "Max element length 3D" ) ) return FT_MaxElementLength3D; else if ( theStr.equals( "Belong to Geom" ) ) return FT_BelongToGeom; else if ( theStr.equals( "Belong to Plane" ) ) return FT_BelongToPlane; else if ( theStr.equals( "Belong to Cylinder" ) ) return FT_BelongToCylinder; diff --git a/src/SMESH_I/SMESH_Filter_i.hxx b/src/SMESH_I/SMESH_Filter_i.hxx index aefc71ef6..bef8c2252 100644 --- a/src/SMESH_I/SMESH_Filter_i.hxx +++ b/src/SMESH_I/SMESH_Filter_i.hxx @@ -157,6 +157,7 @@ namespace SMESH { public: CORBA::Double GetValue( CORBA::Long theElementId ); + SMESH::Histogram* GetHistogram(CORBA::Short nbIntervals); void SetPrecision( CORBA::Long thePrecision ); CORBA::Long GetPrecision(); Controls::NumericalFunctorPtr GetNumericalFunctor(); @@ -270,6 +271,32 @@ namespace SMESH }; + /* + Class : MaxElementLength2D_i + Description : Functor for calculating maximum length of 2D element + */ + class SMESH_I_EXPORT MaxElementLength2D_i: public virtual POA_SMESH::MaxElementLength2D, + public virtual NumericalFunctor_i + { + public: + MaxElementLength2D_i(); + FunctorType GetFunctorType(); + }; + + + /* + Class : MaxElementLength3D_i + Description : Functor for calculating maximum length of 3D element + */ + class SMESH_I_EXPORT MaxElementLength3D_i: public virtual POA_SMESH::MaxElementLength3D, + public virtual NumericalFunctor_i + { + public: + MaxElementLength3D_i(); + FunctorType GetFunctorType(); + }; + + /* Class : Length_i Description : Functor for calculating length of edge @@ -802,18 +829,6 @@ namespace SMESH void SetMesh( SMESH_Mesh_ptr ); - virtual - SMESH::long_array* - GetIDs(); - - virtual - SMESH::long_array* - GetMeshInfo(); - - virtual - SMESH::array_of_ElementType* - GetTypes(); - static void GetElementsId( Predicate_i*, @@ -847,6 +862,14 @@ namespace SMESH Predicate_i* GetPredicate_i(); + // ========================= + // SMESH_IDSource interface + // ========================= + virtual SMESH::long_array* GetIDs(); + virtual SMESH::long_array* GetMeshInfo(); + virtual SMESH::array_of_ElementType* GetTypes(); + virtual SMESH::SMESH_Mesh_ptr GetMesh(); + private: Controls::Filter myFilter; Predicate_i* myPredicate; @@ -910,6 +933,8 @@ namespace SMESH Skew_ptr CreateSkew(); Area_ptr CreateArea(); Volume3D_ptr CreateVolume3D(); + MaxElementLength2D_ptr CreateMaxElementLength2D(); + MaxElementLength3D_ptr CreateMaxElementLength3D(); Length_ptr CreateLength(); Length2D_ptr CreateLength2D(); MultiConnection_ptr CreateMultiConnection(); diff --git a/src/SMESH_I/SMESH_Gen_i.cxx b/src/SMESH_I/SMESH_Gen_i.cxx index 08ce77e36..a0ce885aa 100644 --- a/src/SMESH_I/SMESH_Gen_i.cxx +++ b/src/SMESH_I/SMESH_Gen_i.cxx @@ -932,7 +932,6 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMED( const char* theFileName, // Python Dump TPythonDump aPythonDump; aPythonDump << "(["; - //TCollection_AsciiString aStr ("(["); if (theStatus == SMESH::DRS_OK) { SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder(); @@ -943,7 +942,6 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMED( const char* theFileName, // Iterate through all meshes and create mesh objects for ( list::iterator it = aNames.begin(); it != aNames.end(); it++ ) { // Python Dump - //if (i > 0) aStr += ", "; if (i > 0) aPythonDump << ", "; // create mesh @@ -956,12 +954,9 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMED( const char* theFileName, if ( !aSO->_is_nil() ) { // Python Dump aPythonDump << aSO; - //aStr += aSO->GetID(); } else { // Python Dump aPythonDump << "mesh_" << i; -// aStr += "mesh_"; -// aStr += TCollection_AsciiString(i); } // Read mesh data (groups are published automatically by ImportMEDFile()) @@ -1431,7 +1426,9 @@ CORBA::Boolean SMESH_Gen_i::Compute( SMESH::SMESH_Mesh_ptr theMesh, myLocShape = SMESH_Mesh::PseudoShape(); // call implementation compute ::SMESH_Mesh& myLocMesh = meshServant->GetImpl(); - return myGen.Compute( myLocMesh, myLocShape); + bool ok = myGen.Compute( myLocMesh, myLocShape); + meshServant->CreateGroupServants(); // algos can create groups (issue 0020918) + return ok; } } catch ( std::bad_alloc ) { @@ -2323,6 +2320,38 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, DriverMED_W_SMESHDS_Mesh myWriter; myWriter.SetFile( meshfile.ToCString() ); + // IMP issue 20918 + // SetStoreName() to groups before storing hypotheses to let them refer to + // groups using "store name", which is "Group " + { + SALOMEDS::ChildIterator_var itBig = myCurrentStudy->NewChildIterator( theComponent ); + for ( ; itBig->More(); itBig->Next() ) { + SALOMEDS::SObject_var gotBranch = itBig->Value(); + if ( gotBranch->Tag() > GetAlgorithmsRootTag() ) { + CORBA::Object_var anObject = SObjectToObject( gotBranch ); + if ( !CORBA::is_nil( anObject ) ) { + SMESH::SMESH_Mesh_var myMesh = SMESH::SMESH_Mesh::_narrow( anObject ) ; + if ( !myMesh->_is_nil() ) { + SMESH::ListOfGroups_var groups = myMesh->GetGroups(); + for ( int i = 0; i < groups->length(); ++i ) + { + SMESH_GroupBase_i* grImpl = SMESH::DownCast( groups[i]); + if ( grImpl ) + { + CORBA::String_var objStr = GetORB()->object_to_string( grImpl->_this() ); + int anId = myStudyContext->findId( string( objStr.in() ) ); + char grpName[ 30 ]; + sprintf( grpName, "Group %d", anId ); + SMESHDS_GroupBase* aGrpBaseDS = grImpl->GetGroupDS(); + aGrpBaseDS->SetStoreName( grpName ); + } + } + } + } + } + } + } + // Write data // ---> create HDF file aFile = new HDFfile( (char*) filename.ToCString() ); @@ -2519,13 +2548,21 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, aDataset->CloseOnDisk(); // issue 0020693. Store _isModified flag - int isModified = myImpl->GetImpl().GetIsModified(); + int isModified = myLocMesh.GetIsModified(); aSize[ 0 ] = 1; aDataset = new HDFdataset( "_isModified", aTopGroup, HDF_INT32, aSize, 1 ); aDataset->CreateOnDisk(); aDataset->WriteOnDisk( &isModified ); aDataset->CloseOnDisk(); + // issue 20918. Store Persistent Id of SMESHDS_Mesh + int meshPersistentId = mySMESHDSMesh->GetPersistentId(); + aSize[ 0 ] = 1; + aDataset = new HDFdataset( "meshPersistentId", aTopGroup, HDF_INT32, aSize, 1 ); + aDataset->CreateOnDisk(); + aDataset->WriteOnDisk( &meshPersistentId ); + aDataset->CloseOnDisk(); + // write reference on a shape if exists SALOMEDS::SObject_var myRef; bool shapeRefFound = false; @@ -2869,17 +2906,19 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, dynamic_cast( GetServant( aSubObject ).in() ); if ( !myGroupImpl ) continue; + SMESHDS_GroupBase* aGrpBaseDS = myGroupImpl->GetGroupDS(); + if ( !aGrpBaseDS ) + continue; CORBA::String_var objStr = GetORB()->object_to_string( aSubObject ); int anId = myStudyContext->findId( string( objStr.in() ) ); - + // For each group, create a dataset named "Group " // and store the group's user name into it - char grpName[ 30 ]; - sprintf( grpName, "Group %d", anId ); + const char* grpName = aGrpBaseDS->GetStoreName(); char* aUserName = myGroupImpl->GetName(); aSize[ 0 ] = strlen( aUserName ) + 1; - + aDataset = new HDFdataset( grpName, aGroup, HDF_STRING, aSize, 1 ); aDataset->CreateOnDisk(); aDataset->WriteOnDisk( aUserName ); @@ -2901,46 +2940,36 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, aDataset->WriteOnDisk( anRGB ); aDataset->CloseOnDisk(); - // Store the group contents into MED file - if ( myLocMesh.GetGroup( myGroupImpl->GetLocalID() ) ) { - - if(MYDEBUG) MESSAGE( "VSR - SMESH_Gen_i::Save(): saving group with StoreName = " - << grpName << " to MED file" ); - SMESHDS_GroupBase* aGrpBaseDS = - myLocMesh.GetGroup( myGroupImpl->GetLocalID() )->GetGroupDS(); - aGrpBaseDS->SetStoreName( grpName ); - - // Pass SMESHDS_Group to MED writer - SMESHDS_Group* aGrpDS = dynamic_cast( aGrpBaseDS ); - if ( aGrpDS ) - myWriter.AddGroup( aGrpDS ); - - // write reference on a shape if exists - SMESHDS_GroupOnGeom* aGeomGrp = - dynamic_cast( aGrpBaseDS ); - if ( aGeomGrp ) { - SALOMEDS::SObject_var mySubRef, myShape; - if (mySObject->FindSubObject( GetRefOnShapeTag(), mySubRef ) && - mySubRef->ReferencedObject( myShape ) && - !CORBA::is_nil( myShape->GetObject() )) - { - string myRefOnObject = myShape->GetID(); - if ( myRefOnObject.length() > 0 ) { - char aRefName[ 30 ]; - sprintf( aRefName, "Ref on shape %d", anId); - aSize[ 0 ] = myRefOnObject.length() + 1; - aDataset = new HDFdataset(aRefName, aGroup, HDF_STRING, aSize, 1); - aDataset->CreateOnDisk(); - aDataset->WriteOnDisk( ( char* )( myRefOnObject.c_str() ) ); - aDataset->CloseOnDisk(); - } - } - else // shape ref is invalid: - { - // save a group on geometry as ordinary group - myWriter.AddGroup( aGeomGrp ); + // Pass SMESHDS_Group to MED writer + SMESHDS_Group* aGrpDS = dynamic_cast( aGrpBaseDS ); + if ( aGrpDS ) + myWriter.AddGroup( aGrpDS ); + + // write reference on a shape if exists + SMESHDS_GroupOnGeom* aGeomGrp = + dynamic_cast( aGrpBaseDS ); + if ( aGeomGrp ) { + SALOMEDS::SObject_var mySubRef, myShape; + if (mySObject->FindSubObject( GetRefOnShapeTag(), mySubRef ) && + mySubRef->ReferencedObject( myShape ) && + !CORBA::is_nil( myShape->GetObject() )) + { + string myRefOnObject = myShape->GetID(); + if ( myRefOnObject.length() > 0 ) { + char aRefName[ 30 ]; + sprintf( aRefName, "Ref on shape %d", anId); + aSize[ 0 ] = myRefOnObject.length() + 1; + aDataset = new HDFdataset(aRefName, aGroup, HDF_STRING, aSize, 1); + aDataset->CreateOnDisk(); + aDataset->WriteOnDisk( ( char* )( myRefOnObject.c_str() ) ); + aDataset->CloseOnDisk(); } } + else // shape ref is invalid: + { + // save a group on geometry as ordinary group + myWriter.AddGroup( aGeomGrp ); + } } } } @@ -3630,6 +3659,18 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, aDataset->CloseOnDisk(); myNewMeshImpl->GetImpl().SetIsModified( bool(*isModified)); } + + // issue 20918. Restore Persistent Id of SMESHDS_Mesh + if( aTopGroup->ExistInternalObject( "meshPersistentId" ) ) + { + aDataset = new HDFdataset( "meshPersistentId", aTopGroup ); + aDataset->OpenOnDisk(); + size = aDataset->GetSize(); + int* meshPersistentId = new int[ size ]; + aDataset->ReadFromDisk( meshPersistentId ); + aDataset->CloseOnDisk(); + myNewMeshImpl->GetImpl().GetMeshDS()->SetPersistentId( *meshPersistentId ); + } } } } @@ -3944,7 +3985,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, aGroup = new HDFgroup( "Submeshes", aTopGroup ); aGroup->OpenOnDisk(); - int maxID = mySMESHDSMesh->MaxShapeIndex(); + int maxID = Max( mySMESHDSMesh->MaxSubMeshIndex(), mySMESHDSMesh->MaxShapeIndex() ); vector< SMESHDS_SubMesh * > subMeshes( maxID + 1, (SMESHDS_SubMesh*) 0 ); vector< TopAbs_ShapeEnum > smType ( maxID + 1, TopAbs_SHAPE ); @@ -4132,20 +4173,6 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, } // if ( aTopGroup->ExistInternalObject( "Node Positions" ) ) } // if ( hasData ) - // Recompute State (as computed sub-meshes are restored from MED) - if ( !aShapeObject->_is_nil() || !myNewMeshImpl->HasShapeToMesh()) { - MESSAGE("Compute State Engine ..."); - TopoDS_Shape myLocShape; - if(myNewMeshImpl->HasShapeToMesh()) - myLocShape = GeomObjectToShape( aShapeObject ); - else - myLocShape = SMESH_Mesh::PseudoShape(); - - myNewMeshImpl->GetImpl().GetSubMesh(myLocShape)->ComputeStateEngine - (SMESH_subMesh::SUBMESH_RESTORED); - MESSAGE("Compute State Engine finished"); - } - // try to get groups for ( int ii = GetNodeGroupsTag(); ii <= GetVolumeGroupsTag(); ii++ ) { char name_group[ 30 ]; @@ -4252,6 +4279,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, aGroup->CloseOnDisk(); } } + // read submeh order if any if( aTopGroup->ExistInternalObject( "Mesh Order" ) ) { aDataset = new HDFdataset( "Mesh Order", aTopGroup ); @@ -4270,7 +4298,30 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, myNewMeshImpl->GetImpl().SetMeshOrder( anOrderIds ); } + } // loop on meshes + + // notify algos on completed restoration + for ( meshi_group = meshGroupList.begin(); meshi_group != meshGroupList.end(); ++meshi_group ) + { + SMESH_Mesh_i* myNewMeshImpl = meshi_group->first; + ::SMESH_Mesh& myLocMesh = myNewMeshImpl->GetImpl(); + + TopoDS_Shape myLocShape; + if(myLocMesh.HasShapeToMesh()) + myLocShape = myLocMesh.GetShapeToMesh(); + else + myLocShape = SMESH_Mesh::PseudoShape(); + + myLocMesh.GetSubMesh(myLocShape)-> + ComputeStateEngine (SMESH_subMesh::SUBMESH_RESTORED); } + + for ( hyp_data = hypDataList.begin(); hyp_data != hypDataList.end(); ++hyp_data ) + { + SMESH_Hypothesis_i* hyp = hyp_data->first; + hyp->UpdateAsMeshesRestored(); // for hyps needing full mesh data restored (issue 20918) + } + // close mesh group if(aTopGroup) aTopGroup->CloseOnDisk(); diff --git a/src/SMESH_I/SMESH_Gen_i.hxx b/src/SMESH_I/SMESH_Gen_i.hxx index 89cf79ca7..b2c90805c 100644 --- a/src/SMESH_I/SMESH_Gen_i.hxx +++ b/src/SMESH_I/SMESH_Gen_i.hxx @@ -223,7 +223,7 @@ public: SMESH::SMESH_Mesh_ptr CreateEmptyMesh() throw ( SALOME::SALOME_Exception ); - // Create mesh(es) and import data from UNV file + // Create mesh(es) and import data from UNV fileter SMESH::SMESH_Mesh_ptr CreateMeshesFromUNV( const char* theFileName ) throw ( SALOME::SALOME_Exception ); @@ -357,6 +357,9 @@ public: // Return a pattern mesher SMESH::SMESH_Pattern_ptr GetPattern(); + // Create measurement instance + SMESH::Measurements_ptr CreateMeasurements(); + // Clears study-connected data when it is closed void Close( SALOMEDS::SComponent_ptr theComponent ); diff --git a/src/SMESH_I/SMESH_Hypothesis_i.cxx b/src/SMESH_I/SMESH_Hypothesis_i.cxx index 19d436ff6..8875e4d1f 100644 --- a/src/SMESH_I/SMESH_Hypothesis_i.cxx +++ b/src/SMESH_I/SMESH_Hypothesis_i.cxx @@ -279,4 +279,17 @@ void SMESH_Hypothesis_i::LoadFrom( const char* theStream ) MESSAGE( "SMESH_Hypothesis_i::LoadFrom" ); std::istringstream is( theStream ); myBaseImpl->LoadFrom( is ); + // let listeners know about loading (issue 0020918) + myBaseImpl->NotifySubMeshesHypothesisModification(); +} + +//================================================================================ +/*! + * \brief This mesthod is called after completion of loading a study + */ +//================================================================================ + +void SMESH_Hypothesis_i::UpdateAsMeshesRestored() +{ + // for hyps needing full data restored } diff --git a/src/SMESH_I/SMESH_Hypothesis_i.hxx b/src/SMESH_I/SMESH_Hypothesis_i.hxx index 24c01d46a..99eba89ca 100644 --- a/src/SMESH_I/SMESH_Hypothesis_i.hxx +++ b/src/SMESH_I/SMESH_Hypothesis_i.hxx @@ -91,7 +91,8 @@ public: // Persistence virtual char* SaveTo(); virtual void LoadFrom( const char* theStream ); - + virtual void UpdateAsMeshesRestored(); // for hyps needing full data restored + protected: ::SMESH_Hypothesis* myBaseImpl; // base hypothesis implementation }; diff --git a/src/SMESH_I/SMESH_Measurements_i.cxx b/src/SMESH_I/SMESH_Measurements_i.cxx new file mode 100644 index 000000000..1397a4c39 --- /dev/null +++ b/src/SMESH_I/SMESH_Measurements_i.cxx @@ -0,0 +1,259 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 : SMESH_Measurements_i.cxx +// Author : Pavel TELKOV, Open CASCADE S.A.S. (pavel.telkov@opencascade.com) + +#include "SMESH_Measurements_i.hxx" + +#include "SMESH_Gen_i.hxx" +#include "SMESH_PythonDump.hxx" + +#include "SMDS_Mesh.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMDS_MeshElement.hxx" +#include "SMDS_ElemIterator.hxx" + +#include "SMESHDS_Mesh.hxx" + + +using namespace SMESH; + +/** + * this local function to avoid uninitialized fields + */ +static void initMeasure( SMESH::Measure& theMeasure) +{ + + theMeasure.minX = theMeasure.minY = theMeasure.minZ = 0.; + theMeasure.maxX = theMeasure.maxY = theMeasure.maxZ = 0.; + theMeasure.node1 = theMeasure.node2 = -1; + theMeasure.elem1 = theMeasure.elem2 = -1; + theMeasure.value = 0.; +} + +//============================================================================= +/*! + * SMESH_Gen_i::CreateMeasurements + * + * Create measurement instance + */ +//============================================================================= + +SMESH::Measurements_ptr SMESH_Gen_i::CreateMeasurements() +{ + SMESH::Measurements_i* aMeasure = new SMESH::Measurements_i(); + SMESH::Measurements_var anObj = aMeasure->_this(); + return anObj._retn(); +} + + +/* + Class : Measurements + Description : make measure of mesh qunatities +*/ + +//======================================================================= +// name : Measurements_i +// Purpose : Constructor +//======================================================================= +Measurements_i::Measurements_i() +: SALOME::GenericObj_i( SMESH_Gen_i::GetPOA() ) +{ + //Base class Salome_GenericObject do it inmplicitly by overriding PortableServer::POA_ptr _default_POA() method + //PortableServer::ObjectId_var anObjectId = + // SMESH_Gen_i::GetPOA()->activate_object( this ); +} + +//======================================================================= +// name : ~Measurements_i +// Purpose : Destructor +//======================================================================= +Measurements_i::~Measurements_i() +{ + //TPythonDump()<X(); if (theNode2) dd -= theNode2->X(); theMeasure.minX = dd; dd *= dd; dist += dd; + dd = theNode1->Y(); if (theNode2) dd -= theNode2->Y(); theMeasure.minY = dd; dd *= dd; dist += dd; + dd = theNode1->Z(); if (theNode2) dd -= theNode2->Z(); theMeasure.minZ = dd; dd *= dd; dist += dd; + + if (dist < 0) + return false; + + theMeasure.value = sqrt(dist); + theMeasure.node1 = theNode1->GetID(); + theMeasure.node2 = theNode2 ? theNode2->GetID() : 0; + + return true; +} + +static SMESHDS_Mesh* getMesh(SMESH::SMESH_IDSource_ptr theSource) +{ + if (!CORBA::is_nil( theSource )) + { + SMESH_Mesh_i* anImplPtr = DownCast(theSource->GetMesh()); + if (anImplPtr) + return anImplPtr->GetImpl().GetMeshDS(); + } + return 0; +} + +static bool isNodeType (SMESH::array_of_ElementType_var theTypes) +{ + return theTypes->length() > 0 && theTypes[0] == SMESH::NODE; +} + +//======================================================================= +// name : MinDistance +// Purpose : minimal distance between two given entities +//======================================================================= +SMESH::Measure Measurements_i::MinDistance + (SMESH::SMESH_IDSource_ptr theSource1, + SMESH::SMESH_IDSource_ptr theSource2) +{ + SMESH::Measure aMeasure; + initMeasure(aMeasure); + + if (CORBA::is_nil( theSource1 )) + return aMeasure; + + // if second source is null, min distance from theSource1 to the origin is calculated + bool isOrigin = CORBA::is_nil( theSource2 ); + + // calculate minimal distance between two mesh entities + SMESH::array_of_ElementType_var types1 = theSource1->GetTypes(); + SMESH::array_of_ElementType_var types2; + if ( !isOrigin ) types2 = theSource2->GetTypes(); + + // here we assume that type of all IDs defined by first type in array + bool isNode1 = isNodeType(types1); + bool isNode2 = isOrigin || isNodeType(types2); + + SMESH::long_array_var aElementsId1 = theSource1->GetIDs(); + SMESH::long_array_var aElementsId2; + if ( !isOrigin ) aElementsId2 = theSource2->GetIDs(); + + // compute distance between two entities + /* NOTE: currently only node-to-node case is implemented + * all other cases will be implemented later + * below IF should be replaced by complete switch + * on mesh entities types + */ + if (isNode1 && isNode2) + { + // node - node + const SMESHDS_Mesh* aMesh1 = getMesh( theSource1 ); + const SMESHDS_Mesh* aMesh2 = isOrigin ? 0 : getMesh( theSource2 ); + const SMDS_MeshNode* theNode1 = aMesh1 ? aMesh1->FindNode( aElementsId1[0] ) : 0; + const SMDS_MeshNode* theNode2 = aMesh2 ? aMesh2->FindNode( aElementsId2[0] ) : 0; + getNodeNodeDistance( aMeasure, theNode1, theNode2 ); + } + else + { + // NOT_IMPLEMENTED + } + + return aMeasure; +} + +//======================================================================= +// name : enlargeBoundingBox +// Purpose : +//======================================================================= +static void enlargeBoundingBox(const SMDS_MeshNode* theNode, + SMESH::Measure& theMeasure) +{ + if (!theNode) + return; + if ( theMeasure.node1 == -1 ) { + // we use this attribute as a flag that it is the first node added to the bnd box + theMeasure.minX = theMeasure.maxX = theNode->X(); + theMeasure.minY = theMeasure.maxY = theNode->Y(); + theMeasure.minZ = theMeasure.maxZ = theNode->Z(); + theMeasure.node1 = theNode->GetID(); + } + else { + theMeasure.minX = min( theMeasure.minX, theNode->X() ); + theMeasure.maxX = max( theMeasure.maxX, theNode->X() ); + theMeasure.minY = min( theMeasure.minY, theNode->Y() ); + theMeasure.maxY = max( theMeasure.maxY, theNode->Y() ); + theMeasure.minZ = min( theMeasure.minZ, theNode->Z() ); + theMeasure.maxZ = max( theMeasure.maxZ, theNode->Z() ); + } +} + +//======================================================================= +// name : enlargeBoundingBox +// Purpose : +//======================================================================= +static void enlargeBoundingBox(const SMESH::SMESH_IDSource_ptr theObject, + SMESH::Measure& theMeasure) +{ + if ( CORBA::is_nil( theObject ) ) + return; + const SMESHDS_Mesh* aMesh = getMesh( theObject ); + if ( !aMesh ) + return; + SMESH::array_of_ElementType_var types = theObject->GetTypes(); + SMESH::long_array_var aElementsId = theObject->GetIDs(); + // here we assume that type of all IDs defined by first type in array + const bool isNode = isNodeType( types ); + for(int i = 0, n = aElementsId->length(); i < n; i++) + { + if (isNode) + enlargeBoundingBox( aMesh->FindNode( aElementsId[i] ), theMeasure); + else + { + const SMDS_MeshElement* elem = aMesh->FindElement( aElementsId[i] ); + if (!elem) + continue; + SMDS_ElemIteratorPtr aNodeIter = elem->nodesIterator(); + while( aNodeIter->more() ) + enlargeBoundingBox( dynamic_cast( aNodeIter->next() ), theMeasure); + } + } +} + +//======================================================================= +// name : BoundingBox +// Purpose : compute common bounding box of entities +//======================================================================= +SMESH::Measure Measurements_i::BoundingBox (const SMESH::ListOfIDSources& theSources) +{ + SMESH::Measure aMeasure; + initMeasure(aMeasure); + + // calculate bounding box on sources + for ( int i = 0, n = theSources.length(); i < n ; ++i ) + enlargeBoundingBox( theSources[i], aMeasure ); + + return aMeasure; +} diff --git a/src/SMESH_I/SMESH_Measurements_i.hxx b/src/SMESH_I/SMESH_Measurements_i.hxx new file mode 100644 index 000000000..0e1d77dcf --- /dev/null +++ b/src/SMESH_I/SMESH_Measurements_i.hxx @@ -0,0 +1,63 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 : SMESH_Measurements_i.hxx +// Author : Pavel TELKOV, Open CASCADE S.A.S. (pavel.telkov@opencascade.com) + +#ifndef _SMESH_MEASUREMENTS_I_HXX_ +#define _SMESH_MEASUREMENTS_I_HXX_ + +#include "SMESH.hxx" + +#include +#include CORBA_SERVER_HEADER(SMESH_Measurements) + +#include "SALOME_GenericObj_i.hh" + +class SMESHDS_Mesh; + +namespace SMESH +{ + + /* + Measurements + */ + class SMESH_I_EXPORT Measurements_i: public virtual POA_SMESH::Measurements, + public virtual SALOME::GenericObj_i + { + public: + Measurements_i(); + ~Measurements_i(); + + /*! + * minimal distance between two given entities + */ + SMESH::Measure MinDistance(SMESH::SMESH_IDSource_ptr theSource1, + SMESH::SMESH_IDSource_ptr theSource2); + + /*! + * common bounding box of entities + */ + SMESH::Measure BoundingBox(const SMESH::ListOfIDSources& theSources); + }; +} + +#endif diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index 5da4f5ceb..d442601d5 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -369,10 +369,12 @@ void SMESH_MeshEditor_i::initData(bool deleteSearchers) struct _IDSource : public POA_SMESH::SMESH_IDSource { - SMESH::long_array _ids; - SMESH::ElementType _type; + SMESH::long_array _ids; + SMESH::ElementType _type; + SMESH::SMESH_Mesh_ptr _mesh; SMESH::long_array* GetIDs() { return new SMESH::long_array( _ids ); } SMESH::long_array* GetMeshInfo() { return 0; } + SMESH::SMESH_Mesh_ptr GetMesh() { return SMESH::SMESH_Mesh::_duplicate( _mesh ); } SMESH::array_of_ElementType* GetTypes() { SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType; @@ -388,6 +390,7 @@ SMESH::SMESH_IDSource_ptr SMESH_MeshEditor_i::MakeIDSource(const SMESH::long_arr _IDSource* anIDSource = new _IDSource; anIDSource->_ids = ids; anIDSource->_type = type; + anIDSource->_mesh = myMesh_i->_this(); SMESH::SMESH_IDSource_var anIDSourceVar = anIDSource->_this(); return anIDSourceVar._retn(); diff --git a/src/SMESH_I/SMESH_Mesh_i.cxx b/src/SMESH_I/SMESH_Mesh_i.cxx index de07a09f7..c3be622ae 100644 --- a/src/SMESH_I/SMESH_Mesh_i.cxx +++ b/src/SMESH_I/SMESH_Mesh_i.cxx @@ -858,8 +858,7 @@ void SMESH_Mesh_i::RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup SMESH::long_array_var anIds = aGroup->GetListOfID(); SMESH::SMESH_MeshEditor_var aMeshEditor = SMESH_Mesh_i::GetMeshEditor(); - // Update Python script - TPythonDump() << _this() << ".RemoveGroupWithContents( " << theGroup << " )"; + TPythonDump pyDump; // Supress dump from RemoveNodes/Elements() and RemoveGroup() // Remove contents if ( aGroup->GetType() == SMESH::NODE ) @@ -870,12 +869,10 @@ void SMESH_Mesh_i::RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup // Remove group RemoveGroup( theGroup ); - // Clear python lines, created by RemoveNodes/Elements() and RemoveGroup() - _gen_i->RemoveLastFromPythonScript(_gen_i->GetCurrentStudy()->StudyId()); - _gen_i->RemoveLastFromPythonScript(_gen_i->GetCurrentStudy()->StudyId()); + // Update Python script + pyDump << _this() << ".RemoveGroupWithContents( " << theGroup << " )"; } - //================================================================================ /*! * \brief Get the list of groups existing in the mesh @@ -918,6 +915,7 @@ SMESH::ListOfGroups * SMESH_Mesh_i::GetGroups() throw(SALOME::SALOME_Exception) return aList._retn(); } + //============================================================================= /*! * Get number of groups existing in the mesh @@ -2110,13 +2108,17 @@ void SMESH_Mesh_i::removeGroup( const int theId ) { if(MYDEBUG) MESSAGE("SMESH_Mesh_i::removeGroup()" ); if ( _mapGroups.find( theId ) != _mapGroups.end() ) { - removeGeomGroupData( _mapGroups[theId] ); + SMESH::SMESH_GroupBase_ptr group = _mapGroups[theId]; _mapGroups.erase( theId ); - _impl->RemoveGroup( theId ); + removeGeomGroupData( group ); + if (! _impl->RemoveGroup( theId )) + { + // it seems to be a call up from _impl caused by hyp modification (issue 0020918) + RemoveGroup( group ); + } } } - //============================================================================= /*! * @@ -2213,6 +2215,19 @@ CORBA::Long SMESH_Mesh_i::GetStudyId()throw(SALOME::SALOME_Exception) return _studyId; } +//============================================================================= +namespace +{ + //!< implementation of struct used to call SMESH_Mesh_i::removeGroup() from + // SMESH_Mesh::RemoveGroup() (issue 0020918) + struct TRmGroupCallUp_i : public SMESH_Mesh::TRmGroupCallUp + { + SMESH_Mesh_i* _mesh; + TRmGroupCallUp_i(SMESH_Mesh_i* mesh):_mesh(mesh) {} + virtual void RemoveGroup (const int theGroupID) { _mesh->removeGroup( theGroupID ); } + }; +} + //============================================================================= /*! * @@ -2223,6 +2238,8 @@ void SMESH_Mesh_i::SetImpl(::SMESH_Mesh * impl) { if(MYDEBUG) MESSAGE("SMESH_Mesh_i::SetImpl"); _impl = impl; + if ( _impl ) + _impl->SetRemoveGroupCallUp( new TRmGroupCallUp_i(this)); } //============================================================================= @@ -3390,6 +3407,7 @@ void SMESH_Mesh_i::CreateGroupServants() { SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); + set addedIDs; ::SMESH_Mesh::GroupIteratorPtr groupIt = _impl->GetGroups(); while ( groupIt->more() ) { @@ -3399,6 +3417,7 @@ void SMESH_Mesh_i::CreateGroupServants() map::iterator it = _mapGroups.find(anId); if ( it != _mapGroups.end() && !CORBA::is_nil( it->second )) continue; + addedIDs.insert( anId ); SMESH_GroupBase_i* aGroupImpl; TopoDS_Shape shape; @@ -3424,12 +3443,23 @@ void SMESH_Mesh_i::CreateGroupServants() int nextId = _gen_i->RegisterObject( groupVar ); if(MYDEBUG) MESSAGE( "Add group to map with id = "<< nextId); - // publishing of the groups in the study + // publishing the groups in the study if ( !aStudy->_is_nil() ) { GEOM::GEOM_Object_var shapeVar = _gen_i->ShapeToGeomObject( shape ); _gen_i->PublishGroup( aStudy, _this(), groupVar, shapeVar, groupVar->GetName()); } } + if ( !addedIDs.empty() ) + { + // python dump + set::iterator id = addedIDs.begin(); + for ( ; id != addedIDs.end(); ++id ) + { + map::iterator it = _mapGroups.find(*id); + int i = std::distance( _mapGroups.begin(), it ); + TPythonDump() << it->second << " = " << _this() << ".GetGroups()[ "<< i << " ]"; + } + } } //============================================================================= @@ -3581,6 +3611,16 @@ SMESH::array_of_ElementType* SMESH_Mesh_i::GetTypes() return types._retn(); } +//======================================================================= +//function : GetMesh +//purpose : Returns self +//======================================================================= + +SMESH::SMESH_Mesh_ptr SMESH_Mesh_i::GetMesh() +{ + return SMESH::SMESH_Mesh::_duplicate( _this() ); +} + //============================================================================= /*! * \brief Returns statistic of mesh elements @@ -3925,10 +3965,9 @@ SMESH::submesh_array_array* SMESH_Mesh_i::GetMeshOrder() */ //============================================================================= -static void findCommonSubMesh - (list& theSubMeshList, - const SMESH_subMesh* theSubMesh, - set& theCommon ) +static void findCommonSubMesh (list& theSubMeshList, + const SMESH_subMesh* theSubMesh, + set& theCommon ) { if ( !theSubMesh ) return; diff --git a/src/SMESH_I/SMESH_Mesh_i.hxx b/src/SMESH_I/SMESH_Mesh_i.hxx index d3f550ecd..ea33ec9fa 100644 --- a/src/SMESH_I/SMESH_Mesh_i.hxx +++ b/src/SMESH_I/SMESH_Mesh_i.hxx @@ -521,18 +521,20 @@ public: // ========================= virtual SMESH::long_array* GetIDs(); - /*! * Returns statistic of mesh elements * Result array of number enityties * Inherited from SMESH_IDSource */ virtual SMESH::long_array* GetMeshInfo(); - /*! * Returns types of elements it contains */ virtual SMESH::array_of_ElementType* GetTypes(); + /*! + * Returns self + */ + virtual SMESH::SMESH_Mesh_ptr GetMesh(); std::map _mapSubMesh_i; //NRI diff --git a/src/SMESH_I/SMESH_PythonDump.hxx b/src/SMESH_I/SMESH_PythonDump.hxx index 031b3c415..f1ee26581 100644 --- a/src/SMESH_I/SMESH_PythonDump.hxx +++ b/src/SMESH_I/SMESH_PythonDump.hxx @@ -73,6 +73,7 @@ namespace SMESH class FilterManager_i; class Filter_i; class Functor_i; + class Measurements_i; // =========================================================================================== /*! @@ -142,6 +143,9 @@ namespace SMESH TPythonDump& operator<<(SMESH::Functor_i* theArg); + TPythonDump& + operator<<(SMESH::Measurements_i* theArg); + TPythonDump& operator<<(SMESH_Gen_i* theArg); diff --git a/src/SMESH_I/SMESH_subMesh_i.cxx b/src/SMESH_I/SMESH_subMesh_i.cxx index faa7aa1ca..45d486733 100644 --- a/src/SMESH_I/SMESH_subMesh_i.cxx +++ b/src/SMESH_I/SMESH_subMesh_i.cxx @@ -578,3 +578,13 @@ SMESH::array_of_ElementType* SMESH_subMesh_i::GetTypes() } return types._retn(); } + +//======================================================================= +//function : GetMesh +//purpose : interface SMESH_IDSource +//======================================================================= + +SMESH::SMESH_Mesh_ptr SMESH_subMesh_i::GetMesh() +{ + return GetFather(); +} diff --git a/src/SMESH_I/SMESH_subMesh_i.hxx b/src/SMESH_I/SMESH_subMesh_i.hxx index 3f90a8cb8..f5fd559d4 100644 --- a/src/SMESH_I/SMESH_subMesh_i.hxx +++ b/src/SMESH_I/SMESH_subMesh_i.hxx @@ -85,19 +85,28 @@ public: SALOME_MED::FAMILY_ptr GetFamily() throw (SALOME::SALOME_Exception); - virtual SMESH::long_array* GetIDs(); + // ========================= + // interface SMESH_IDSource + // ========================= + /*! + * Returns a sequence of all element IDs + */ + virtual SMESH::long_array* GetIDs(); /*! * Returns statistic of mesh elements * Result array of number enityties * Inherited from SMESH_IDSource */ virtual SMESH::long_array* GetMeshInfo(); - /*! * Returns types of elements it contains */ virtual SMESH::array_of_ElementType* GetTypes(); + /*! + * Returns the mesh + */ + SMESH::SMESH_Mesh_ptr GetMesh(); SMESH_Mesh_i* _mesh_i; //NRI diff --git a/src/SMESH_SWIG/SMESH_BelongToGeom.py b/src/SMESH_SWIG/SMESH_BelongToGeom.py index 02047a1cf..af6c98420 100644 --- a/src/SMESH_SWIG/SMESH_BelongToGeom.py +++ b/src/SMESH_SWIG/SMESH_BelongToGeom.py @@ -40,6 +40,7 @@ def CheckBelongToGeomFilterOld(theMeshGen, theMesh, theShape, theSubShape, theEl aBelongToGeom.SetElementType(theElemType) aFilter.SetPredicate(aBelongToGeom) + aFilterMgr.Destroy() return aFilter.GetElementsId(theMesh) ## Current style diff --git a/src/SMESH_SWIG/SMESH_GroupLyingOnGeom.py b/src/SMESH_SWIG/SMESH_GroupLyingOnGeom.py index e0cbb6404..c90a3bd89 100644 --- a/src/SMESH_SWIG/SMESH_GroupLyingOnGeom.py +++ b/src/SMESH_SWIG/SMESH_GroupLyingOnGeom.py @@ -36,6 +36,7 @@ def BuildGroupLyingOn(theMesh, theElemType, theName, theShape): aFilter.SetPredicate(aLyingOnGeom) anIds = aFilter.GetElementsId(theMesh) + aFilterMgr.Destroy() aGroup = theMesh.CreateGroup(theElemType, theName) aGroup.Add(anIds) diff --git a/src/SMESH_SWIG/SMESH_controls.py b/src/SMESH_SWIG/SMESH_controls.py index 43c1b5874..8cde5ac61 100644 --- a/src/SMESH_SWIG/SMESH_controls.py +++ b/src/SMESH_SWIG/SMESH_controls.py @@ -128,4 +128,16 @@ print "Criterion: Borders at multi-connections = 2 Nb = ", len( anIds ) #print anIds[ i ] +# Criterion : Max Element Length 2D > 10 + +# create group +aGroup = mesh.MakeGroup("Max Element Length 2D > 10", smesh.FACE, smesh.FT_MaxElementLength2D, smesh.FT_MoreThan, 10 ) + +# print result +anIds = aGroup.GetIDs() +print "Criterion: Max Element Length 2D > 10 Nb = ", len( anIds ) +#for i in range( len( anIds ) ): + #print anIds[ i ] + + salome.sg.updateObjBrowser(1) diff --git a/src/SMESH_SWIG/smeshDC.py b/src/SMESH_SWIG/smeshDC.py index 1e01d2ac0..2ea857466 100644 --- a/src/SMESH_SWIG/smeshDC.py +++ b/src/SMESH_SWIG/smeshDC.py @@ -88,6 +88,7 @@ ## @defgroup l2_modif_tofromqu Convert to/from Quadratic Mesh ## @} +## @defgroup l1_measurements Measurements import salome import geompyDC @@ -857,6 +858,7 @@ class smeshDC(SMESH._objref_SMESH_Gen): aCriteria = [] aCriteria.append(aCriterion) aFilter.SetCriteria(aCriteria) + aFilterMgr.Destroy() return aFilter ## Creates a numerical functor by its type @@ -881,6 +883,10 @@ class smeshDC(SMESH._objref_SMESH_Gen): return aFilterMgr.CreateArea() elif theCriterion == FT_Volume3D: return aFilterMgr.CreateVolume3D() + elif theCriterion == FT_MaxElementLength2D: + return aFilterMgr.CreateMaxElementLength2D() + elif theCriterion == FT_MaxElementLength3D: + return aFilterMgr.CreateMaxElementLength3D() elif theCriterion == FT_MultiConnection: return aFilterMgr.CreateMultiConnection() elif theCriterion == FT_MultiConnection2D: @@ -913,6 +919,110 @@ class smeshDC(SMESH._objref_SMESH_Gen): pass return d + ## Get minimum distance between two objects + # + # If @a src2 is None, and @a id2 = 0, distance from @a src1 / @a id1 to the origin is computed. + # If @a src2 is None, and @a id2 != 0, it is assumed that both @a id1 and @a id2 belong to @a src1. + # + # @param src1 first source object + # @param src2 second source object + # @param id1 node/element id from the first source + # @param id2 node/element id from the second (or first) source + # @param isElem1 @c True if @a id1 is element id, @c False if it is node id + # @param isElem2 @c True if @a id2 is element id, @c False if it is node id + # @return minimum distance value + # @sa GetMinDistance() + # @ingroup l1_measurements + def MinDistance(self, src1, src2=None, id1=0, id2=0, isElem1=False, isElem2=False): + result = self.GetMinDistance(src1, src2, id1, id2, isElem1, isElem2) + if result is None: + result = 0.0 + else: + result = result.value + return result + + ## Get measure structure specifying minimum distance data between two objects + # + # If @a src2 is None, and @a id2 = 0, distance from @a src1 / @a id1 to the origin is computed. + # If @a src2 is None, and @a id2 != 0, it is assumed that both @a id1 and @a id2 belong to @a src1. + # + # @param src1 first source object + # @param src2 second source object + # @param id1 node/element id from the first source + # @param id2 node/element id from the second (or first) source + # @param isElem1 @c True if @a id1 is element id, @c False if it is node id + # @param isElem2 @c True if @a id2 is element id, @c False if it is node id + # @return Measure structure or None if input data is invalid + # @sa MinDistance() + # @ingroup l1_measurements + def GetMinDistance(self, src1, src2=None, id1=0, id2=0, isElem1=False, isElem2=False): + if isinstance(src1, Mesh): src1 = src1.mesh + if isinstance(src2, Mesh): src2 = src2.mesh + if src2 is None and id2 != 0: src2 = src1 + if not hasattr(src1, "_narrow"): return None + src1 = src1._narrow(SMESH.SMESH_IDSource) + if not src1: return None + if id1 != 0: + m = src1.GetMesh() + e = m.GetMeshEditor() + if isElem1: + src1 = e.MakeIDSource([id1], SMESH.FACE) + else: + src1 = e.MakeIDSource([id1], SMESH.NODE) + pass + if hasattr(src2, "_narrow"): + src2 = src2._narrow(SMESH.SMESH_IDSource) + if src2 and id2 != 0: + m = src2.GetMesh() + e = m.GetMeshEditor() + if isElem2: + src2 = e.MakeIDSource([id2], SMESH.FACE) + else: + src2 = e.MakeIDSource([id2], SMESH.NODE) + pass + pass + aMeasurements = self.CreateMeasurements() + result = aMeasurements.MinDistance(src1, src2) + aMeasurements.Destroy() + return result + + ## Get bounding box of the specified object(s) + # @param objects single source object or list of source objects + # @return tuple of six values (minX, minY, minZ, maxX, maxY, maxZ) + # @sa GetBoundingBox() + # @ingroup l1_measurements + def BoundingBox(self, objects): + result = self.GetBoundingBox(objects) + if result is None: + result = (0.0,)*6 + else: + result = (result.minX, result.minY, result.minZ, result.maxX, result.maxY, result.maxZ) + return result + + ## Get measure structure specifying bounding box data of the specified object(s) + # @param objects single source object or list of source objects + # @return Measure structure + # @sa BoundingBox() + # @ingroup l1_measurements + def GetBoundingBox(self, objects): + if isinstance(objects, tuple): + objects = list(objects) + if not isinstance(objects, list): + objects = [objects] + srclist = [] + for o in objects: + if isinstance(o, Mesh): + srclist.append(o.mesh) + elif hasattr(o, "_narrow"): + src = o._narrow(SMESH.SMESH_IDSource) + if src: srclist.append(src) + pass + pass + aMeasurements = self.CreateMeasurements() + result = aMeasurements.BoundingBox(srclist) + aMeasurements.Destroy() + return result + import omniORB #Registering the new proxy for SMESH_Gen omniORB.registerObjref(SMESH._objref_SMESH_Gen._NP_RepositoryId, smeshDC) @@ -1078,6 +1188,24 @@ class Mesh: else: return Mesh_Segment(self, geom) + ## Creates 1D algorithm importing segments conatined in groups of other mesh. + # If the optional \a geom parameter is not set, this algorithm is global. + # Otherwise, this algorithm defines a submesh based on \a geom subshape. + # @param geom If defined the subshape is to be meshed + # @return an instance of Mesh_UseExistingElements class + # @ingroup l3_algos_basic + def UseExisting1DElements(self, geom=0): + return Mesh_UseExistingElements(1,self, geom) + + ## Creates 2D algorithm importing faces conatined in groups of other mesh. + # If the optional \a geom parameter is not set, this algorithm is global. + # Otherwise, this algorithm defines a submesh based on \a geom subshape. + # @param geom If defined the subshape is to be meshed + # @return an instance of Mesh_UseExistingElements class + # @ingroup l3_algos_basic + def UseExisting2DElements(self, geom=0): + return Mesh_UseExistingElements(2,self, geom) + ## Enables creation of nodes and segments usable by 2D algoritms. # The added nodes and segments must be bound to edges and vertices by # SetNodeOnVertex(), SetNodeOnEdge() and SetMeshElementOnShape() @@ -1209,7 +1337,9 @@ class Mesh: return Mesh_RadialPrism3D(self, geom) ## Evaluates size of prospective mesh on a shape - # @return True or False + # @return a list where i-th element is a number of elements of i-th SMESH.EntityType + # To know predicted number of e.g. edges, inquire it this way + # Evaluate()[ EnumToLong( Entity_Edge )] def Evaluate(self, geom=0): if geom == 0 or not isinstance(geom, geompyDC.GEOM._objref_GEOM_Object): if self.geom == 0: @@ -1639,6 +1769,7 @@ class Mesh: aCriteria.append(Criterion) aFilter.SetCriteria(aCriteria) group = self.MakeGroupByFilter(groupName, aFilter) + aFilterMgr.Destroy() return group ## Creates a mesh group by the given criteria (list of criteria) @@ -1651,6 +1782,7 @@ class Mesh: aFilter = aFilterMgr.CreateFilter() aFilter.SetCriteria(theCriteria) group = self.MakeGroupByFilter(groupName, aFilter) + aFilterMgr.Destroy() return group ## Creates a mesh group by the given filter @@ -1681,6 +1813,7 @@ class Mesh: aPredicate = aFilterMgr.CreateFreeEdges() aPredicate.SetMesh(self.mesh) aBorders = aPredicate.GetBorders() + aFilterMgr.Destroy() return aBorders ## Removes a group @@ -2200,6 +2333,95 @@ class Mesh: return self.mesh.BaryCenter(id) + # Get mesh measurements information: + # ------------------------------------ + + ## Get minimum distance between two nodes, elements or distance to the origin + # @param id1 first node/element id + # @param id2 second node/element id (if 0, distance from @a id1 to the origin is computed) + # @param isElem1 @c True if @a id1 is element id, @c False if it is node id + # @param isElem2 @c True if @a id2 is element id, @c False if it is node id + # @return minimum distance value + # @sa GetMinDistance() + def MinDistance(self, id1, id2=0, isElem1=False, isElem2=False): + aMeasure = self.GetMinDistance(id1, id2, isElem1, isElem2) + return aMeasure.value + + ## Get measure structure specifying minimum distance data between two objects + # @param id1 first node/element id + # @param id2 second node/element id (if 0, distance from @a id1 to the origin is computed) + # @param isElem1 @c True if @a id1 is element id, @c False if it is node id + # @param isElem2 @c True if @a id2 is element id, @c False if it is node id + # @return Measure structure + # @sa MinDistance() + def GetMinDistance(self, id1, id2=0, isElem1=False, isElem2=False): + if isElem1: + id1 = self.editor.MakeIDSource([id1], SMESH.FACE) + else: + id1 = self.editor.MakeIDSource([id1], SMESH.NODE) + if id2 != 0: + if isElem2: + id2 = self.editor.MakeIDSource([id2], SMESH.FACE) + else: + id2 = self.editor.MakeIDSource([id2], SMESH.NODE) + pass + else: + id2 = None + + aMeasurements = self.smeshpyD.CreateMeasurements() + aMeasure = aMeasurements.MinDistance(id1, id2) + aMeasurements.Destroy() + return aMeasure + + ## Get bounding box of the specified object(s) + # @param objects single source object or list of source objects or list of nodes/elements IDs + # @param isElem if @a objects is a list of IDs, @c True value in this parameters specifies that @a objects are elements, + # @c False specifies that @a objects are nodes + # @return tuple of six values (minX, minY, minZ, maxX, maxY, maxZ) + # @sa GetBoundingBox() + def BoundingBox(self, objects=None, isElem=False): + result = self.GetBoundingBox(objects, isElem) + if result is None: + result = (0.0,)*6 + else: + result = (result.minX, result.minY, result.minZ, result.maxX, result.maxY, result.maxZ) + return result + + ## Get measure structure specifying bounding box data of the specified object(s) + # @param objects single source object or list of source objects or list of nodes/elements IDs + # @param isElem if @a objects is a list of IDs, @c True value in this parameters specifies that @a objects are elements, + # @c False specifies that @a objects are nodes + # @return Measure structure + # @sa BoundingBox() + def GetBoundingBox(self, IDs=None, isElem=False): + if IDs is None: + IDs = [self.mesh] + elif isinstance(IDs, tuple): + IDs = list(IDs) + if not isinstance(IDs, list): + IDs = [IDs] + if len(IDs) > 0 and isinstance(IDs[0], int): + IDs = [IDs] + srclist = [] + for o in IDs: + if isinstance(o, Mesh): + srclist.append(o.mesh) + elif hasattr(o, "_narrow"): + src = o._narrow(SMESH.SMESH_IDSource) + if src: srclist.append(src) + pass + elif isinstance(o, list): + if isElem: + srclist.append(self.editor.MakeIDSource(o, SMESH.FACE)) + else: + srclist.append(self.editor.MakeIDSource(o, SMESH.NODE)) + pass + pass + aMeasurements = self.smeshpyD.CreateMeasurements() + aMeasure = aMeasurements.BoundingBox(srclist) + aMeasurements.Destroy() + return aMeasure + # Mesh edition (SMESH_MeshEditor functionality): # --------------------------------------------- @@ -3838,6 +4060,86 @@ class Mesh: def DoubleNodeElemGroupsInRegion(self, theElems, theNodesNot, theShape): return self.editor.DoubleNodeElemGroupsInRegion(theElems, theNodesNot, theShape) + def _valueFromFunctor(self, funcType, elemId): + fn = self.smeshpyD.GetFunctor(funcType) + fn.SetMesh(self.mesh) + if fn.GetElementType() == self.GetElementType(elemId, True): + val = fn.GetValue(elemId) + else: + val = 0 + return val + + ## Get length of 1D element. + # @param elemId mesh element ID + # @return element's length value + # @ingroup l1_measurements + def GetLength(self, elemId): + return self._valueFromFunctor(SMESH.FT_Length, elemId) + + ## Get area of 2D element. + # @param elemId mesh element ID + # @return element's area value + # @ingroup l1_measurements + def GetArea(self, elemId): + return self._valueFromFunctor(SMESH.FT_Area, elemId) + + ## Get volume of 3D element. + # @param elemId mesh element ID + # @return element's volume value + # @ingroup l1_measurements + def GetVolume(self, elemId): + return self._valueFromFunctor(SMESH.FT_Volume3D, elemId) + + ## Get maximum element length. + # @param elemId mesh element ID + # @return element's maximum length value + # @ingroup l1_measurements + def GetMaxElementLength(self, elemId): + if self.GetElementType(elemId, True) == SMESH.VOLUME: + ftype = SMESH.FT_MaxElementLength3D + else: + ftype = SMESH.FT_MaxElementLength2D + return self._valueFromFunctor(ftype, elemId) + + ## Get aspect ratio of 2D or 3D element. + # @param elemId mesh element ID + # @return element's aspect ratio value + # @ingroup l1_measurements + def GetAspectRatio(self, elemId): + if self.GetElementType(elemId, True) == SMESH.VOLUME: + ftype = SMESH.FT_AspectRatio3D + else: + ftype = SMESH.FT_AspectRatio + return self._valueFromFunctor(ftype, elemId) + + ## Get warping angle of 2D element. + # @param elemId mesh element ID + # @return element's warping angle value + # @ingroup l1_measurements + def GetWarping(self, elemId): + return self._valueFromFunctor(SMESH.FT_Warping, elemId) + + ## Get minimum angle of 2D element. + # @param elemId mesh element ID + # @return element's minimum angle value + # @ingroup l1_measurements + def GetMinimumAngle(self, elemId): + return self._valueFromFunctor(SMESH.FT_MinimumAngle, elemId) + + ## Get taper of 2D element. + # @param elemId mesh element ID + # @return element's taper value + # @ingroup l1_measurements + def GetTaper(self, elemId): + return self._valueFromFunctor(SMESH.FT_Taper, elemId) + + ## Get skew of 2D element. + # @param elemId mesh element ID + # @return element's skew value + # @ingroup l1_measurements + def GetSkew(self, elemId): + return self._valueFromFunctor(SMESH.FT_Skew, elemId) + ## The mother class to define algorithm, it is not recommended to use it directly. # # More details. @@ -5462,6 +5764,73 @@ class Mesh_RadialQuadrangle1D2D(Mesh_Algorithm): return hyp +# Public class: Mesh_UseExistingElements +# -------------------------------------- +## Defines a Radial Quadrangle 1D2D algorithm +# @ingroup l3_algos_basic +# +class Mesh_UseExistingElements(Mesh_Algorithm): + + def __init__(self, dim, mesh, geom=0): + if dim == 1: + self.Create(mesh, geom, "Import_1D") + else: + self.Create(mesh, geom, "Import_1D2D") + return + + ## Defines "Source edges" hypothesis, specifying groups of edges to import + # @param groups list of groups of edges + # @param toCopyMesh if True, the whole mesh \a groups belong to is imported + # @param toCopyGroups if True, all groups of the mesh \a groups belong to are imported + # @param UseExisting if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + def SourceEdges(self, groups, toCopyMesh=False, toCopyGroups=False, UseExisting=False): + if self.algo.GetName() == "Import_2D": + raise ValueError, "algoritm dimension mismatch" + hyp = self.Hypothesis("ImportSource1D", [groups, toCopyMesh, toCopyGroups], + UseExisting=UseExisting, CompareMethod=self._compareHyp) + hyp.SetSourceEdges(groups) + hyp.SetCopySourceMesh(toCopyMesh, toCopyGroups) + return hyp + + ## Defines "Source faces" hypothesis, specifying groups of faces to import + # @param groups list of groups of faces + # @param toCopyMesh if True, the whole mesh \a groups belong to is imported + # @param toCopyGroups if True, all groups of the mesh \a groups belong to are imported + # @param UseExisting if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + def SourceFaces(self, groups, toCopyMesh=False, toCopyGroups=False, UseExisting=False): + if self.algo.GetName() == "Import_1D": + raise ValueError, "algoritm dimension mismatch" + hyp = self.Hypothesis("ImportSource2D", [groups, toCopyMesh, toCopyGroups], + UseExisting=UseExisting, CompareMethod=self._compareHyp) + hyp.SetSourceFaces(groups) + hyp.SetCopySourceMesh(toCopyMesh, toCopyGroups) + return hyp + + def _compareHyp(self,hyp,args): + if hasattr( hyp, "GetSourceEdges"): + entries = hyp.GetSourceEdges() + else: + entries = hyp.GetSourceFaces() + groups = args[0] + toCopyMesh,toCopyGroups = hyp.GetCopySourceMesh() + if len(entries)==len(groups) and toCopyMesh==args[1] and toCopyGroups==args[2]: + entries2 = [] + study = self.mesh.smeshpyD.GetCurrentStudy() + if study: + for g in groups: + ior = salome.orb.object_to_string(g) + sobj = study.FindObjectIOR(ior) + if sobj: entries2.append( sobj.GetID() ) + pass + pass + entries.sort() + entries2.sort() + return entries == entries2 + return False + + # Private class: Mesh_UseExisting # ------------------------------- class Mesh_UseExisting(Mesh_Algorithm): diff --git a/src/StdMeshers/Makefile.am b/src/StdMeshers/Makefile.am index 0312e1f78..08c312ead 100644 --- a/src/StdMeshers/Makefile.am +++ b/src/StdMeshers/Makefile.am @@ -72,7 +72,10 @@ salomeinclude_HEADERS = \ StdMeshers_MaxLength.hxx \ StdMeshers_QuadrangleParams.hxx \ StdMeshers_RadialQuadrangle_1D2D.hxx \ - StdMeshers_HexaFromSkin_3D.hxx + StdMeshers_HexaFromSkin_3D.hxx \ + StdMeshers_ImportSource.hxx \ + StdMeshers_Import_1D.hxx \ + StdMeshers_Import_1D2D.hxx # Libraries targets @@ -123,7 +126,10 @@ dist_libStdMeshers_la_SOURCES = \ StdMeshers_MaxLength.cxx \ StdMeshers_QuadrangleParams.cxx \ StdMeshers_RadialQuadrangle_1D2D.cxx \ - StdMeshers_HexaFromSkin_3D.cxx + StdMeshers_HexaFromSkin_3D.cxx \ + StdMeshers_ImportSource.cxx \ + StdMeshers_Import_1D.cxx \ + StdMeshers_Import_1D2D.cxx # additionnal information to compil and link file diff --git a/src/StdMeshers/StdMeshers_CompositeSegment_1D.hxx b/src/StdMeshers/StdMeshers_CompositeSegment_1D.hxx index 7f003f4ae..4812b4235 100644 --- a/src/StdMeshers/StdMeshers_CompositeSegment_1D.hxx +++ b/src/StdMeshers/StdMeshers_CompositeSegment_1D.hxx @@ -23,7 +23,6 @@ // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_CompositeSegment_1D.hxx // Module : SMESH -// $Header$ // #ifndef _SMESH_CompositeSegment_1D_HXX_ #define _SMESH_CompositeSegment_1D_HXX_ diff --git a/src/StdMeshers/StdMeshers_ImportSource.cxx b/src/StdMeshers/StdMeshers_ImportSource.cxx new file mode 100644 index 000000000..1ba39eacf --- /dev/null +++ b/src/StdMeshers/StdMeshers_ImportSource.cxx @@ -0,0 +1,443 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 StdMeshers_ImportSource1D : implementaion of SMESH idl descriptions +// File : StdMeshers_ImportSource1D.cxx +// Module : SMESH +// +#include "StdMeshers_ImportSource.hxx" + +#include "SMESHDS_GroupBase.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) + { + 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 ( 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 + */ +//============================================================================= + +const std::vector& StdMeshers_ImportSource1D::GetGroups() const +{ + // filter off deleted groups + vector okGroups = getValidGroups( _groups, + _gen->GetStudyContext(_studyId) ); + 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; +} + +//============================================================================= +/*! + * 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/StdMeshers/StdMeshers_ImportSource.hxx b/src/StdMeshers/StdMeshers_ImportSource.hxx new file mode 100644 index 000000000..13287cb2e --- /dev/null +++ b/src/StdMeshers/StdMeshers_ImportSource.hxx @@ -0,0 +1,97 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 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; + +//============================================================================== +/*! + * \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() 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); + 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; + +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/StdMeshers/StdMeshers_Import_1D.cxx b/src/StdMeshers/StdMeshers_Import_1D.cxx new file mode 100644 index 000000000..fe0f05476 --- /dev/null +++ b/src/StdMeshers/StdMeshers_Import_1D.cxx @@ -0,0 +1,959 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 : 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"); +} + +//============================================================================= +/*! + * 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 = SMESH_Hypothesis::HYP_OK; + return true; + } + + aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + return true; +} + +//================================================================================ +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 + 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): + SMESH_subMeshEventListenerData(/*isDeletable=*/true), _srcHyp(h) + { + myType = SRC_HYP; + } + }; + //================================================================================ + /*! + * \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*> _subM; // submeshes relating to this srcMesh + set< SMESH_subMesh*> _copyMeshSubM; // submeshes requesting mesh copying + set< SMESH_subMesh*> _copyGroupSubM; // submeshes requesting mesh copying + set< SMESH_subMesh*> _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(), _importMeshSubDS, /*fromGroups=*/false ); + SMDS_NodeIteratorPtr nIt = _importMeshSubDS->GetNodes(); + while ( nIt->more() ) + meshDS->RemoveFreeNode( nIt->next(), _importMeshSubDS, /*fromGroups=*/false ); + _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 ); + } + }; + //================================================================================ + /*! + * Listener notified on events of an imported submesh + */ + class _Listener : public SMESH_subMeshEventListener + { + typedef map< SMESH_Mesh*, list< _ImportData > > TMesh2ImpData; + TMesh2ImpData _tgtMesh2ImportData; + + _Listener():SMESH_subMeshEventListener(/*isDeletable=*/false){} + + public: + // return poiter to a static listener + static _Listener* get() { static _Listener theListener; return &theListener; } + + //-------------------------------------------------------------------------------- + /*! + * \brief Find or create ImportData for given meshes + */ + static _ImportData* 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 mesh and groups + * \param smDS - submesh DS holding the imported mesh + * \param sm - submesh computed by Import algo + * \param srcMeshDS - source mesh + * \param srcHyp - ImportSource hypothesis + */ + static _ImportData* 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 a listener to hear events of the source mesh + SMESH_subMesh* smToNotify = importSub; + SMESH_subMesh* smToListen = srcMesh->GetSubMeshContaining(1); + importSub->SetEventListener + ( new SMESH_subMeshEventListener(/*isDeletable=*/true), + SMESH_subMeshEventListenerData::MakeData( smToNotify ), + smToListen ); + + // remeber the submesh + _ImportData* iData = _Listener::getImportData( srcMesh, importSub->GetFather()); + iData->_subM.insert( importSub ); + iData->trackHypParams( importSub, srcHyp ); + if ( !importSub->IsEmpty() ) + iData->_computedSubM.insert( 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 ); + } + if ( !importSub->IsEmpty() ) + iData->_computedSubM.insert( importSub ); + + return iData; + } + //-------------------------------------------------------------------------------- + /*! + * \brief 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 Remove imported mesh and/or groups as soon as no more imported submeshes + * remain computed + * \param sm - submesh loosing Import algo + * \param data - data holding imported groups + */ + void 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 ) + d->removeGroups( sm, data->_srcHyp ); + } + } + //-------------------------------------------------------------------------------- + /*! + * \brief Remove imported mesh and/or groups and + * clear all submeshes with common source mesh + * \param sm - cleared submesh + * \param data - data holding imported groups + */ + void clearSubmesh( 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.count( sm )) continue; + if ( (*d)._computedSubM.erase( sm ) ) + { + bool copyMesh = !d->_copyMeshSubM.empty(); + if ( copyMesh ) + { + // clear submeshes + if ( !d->_computedSubM.empty() ) + { + set< SMESH_subMesh*> subs; + subs.swap( d->_computedSubM ); // avoid recursion via events + while ( !subs.empty() ) + { + SMESH_subMesh* subM = *subs.begin(); subs.erase( subs.begin() ); + _ListenerData* hypData = (_ListenerData*) subM->GetEventListenerData( get() ); + if ( hypData ) + d->removeGroups( sm, hypData->_srcHyp ); + + subM->ComputeStateEngine( SMESH_subMesh::CLEAN ); + } + } + // remove imported mesh and groups + d->removeImportedMesh( sm->GetFather()->GetMeshDS() ); + + if ( data ) + d->removeGroups( sm, data->_srcHyp ); + } + } + if ( data ) + d->trackHypParams( sm, data->_srcHyp ); + d->_n2n.clear(); + d->_e2e.clear(); + } + } + //-------------------------------------------------------------------------------- + /*! + * \brief Remove imported mesh and/or groups + */ + virtual void ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* subMesh, + SMESH_subMeshEventListenerData* data, + const SMESH_Hypothesis* /*hyp*/) + { + if ( data && data->myType == WAIT_HYP_MODIF ) + { + if ( SMESH_subMesh::MODIF_HYP == event && + SMESH_subMesh::ALGO_EVENT == eventType ) + { + SMESH_Gen* gen = subMesh->GetFather()->GetGen(); + if ( SMESH_Algo* algo = gen->GetAlgo(*subMesh->GetFather(), subMesh->GetSubShape())) + algo->SetEventListener( subMesh ); + } + } + else + { + SMESH_Gen* gen = subMesh->GetFather()->GetGen(); + SMESH_Algo* algo = gen->GetAlgo(*subMesh->GetFather(),subMesh->GetSubShape() ); + + if ( subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK || + strncmp( "Import", algo->GetName(), 6 ) != 0 ) + { + // treate removal of Import algo from subMesh + removeSubmesh( subMesh, (_ListenerData*) data ); + } + else if ( subMesh->IsEmpty() ) + { + // treate modification of ImportSource hypothesis + clearSubmesh( subMesh, (_ListenerData*) data ); + } + 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); + } + } + } + } + }; // class _Listener + + //================================================================================ + /*! + * \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 subshapes 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 = 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 ) + 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->_computedSubM.insert( 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 + + +//============================================================================= +/*! + * Import elements from the other mesh + */ +//============================================================================= + +bool StdMeshers_Import_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & theShape) +{ + if ( !_sourceHyp ) return false; + + const vector& srcGroups = _sourceHyp->GetGroups(); + 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_MeshEditor::TNodeXYZ > vertexNodes; + list < SMESH_MeshEditor::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 ); + if ( !n ) return false; // very strange + } + vertexNodes.push_back( SMESH_MeshEditor::TNodeXYZ( n )); + } + + // 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(0,0,0); + double u; + 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() ); + newNodes.back() = 0; + SMDS_MeshElement::iterator node = edge->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 ) + { + if ( !subShapeIDs.count( n2nIt->second->GetPosition()->GetShapeId() )) + break; + } + else + { + // find an existing vertex node + for ( vNIt = vertexNodes.begin(); vNIt != vertexNodes.end(); ++vNIt) + if ( vNIt->SquareDistance( *node ) < 10 * edgeTol * edgeTol) + { + (*n2nIt).second = vNIt->_node; + vertexNodes.erase( vNIt ); + break; + } + } + if ( !n2nIt->second ) + { + // find out if node lies on theShape + tmpNode.setXYZ( (*node)->X(), (*node)->Y(), (*node)->Z()); + if ( helper.CheckNodeU( geomEdge, &tmpNode, u, 10 * edgeTol, /*force=*/true )) + { + SMDS_MeshNode* newNode = tgtMesh->AddNode( (*node)->X(), (*node)->Y(), (*node)->Z()); + n2nIt->second = newNode; + tgtMesh->SetNodeOnEdge( newNode, shapeID, u ); + } + } + if ( !(newNodes[i] = n2nIt->second )) + break; + } + if ( !newNodes.back() ) + 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]); + tgtMesh->SetMeshElementOnShape( newEdge, shapeID ); + e2e->insert( make_pair( edge, newEdge )); + } + } + 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 + + 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, elem->GetType(), elem->IsPoly()); + 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. Store them in a hypothesis + // as it stores its values 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(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_MeshEditor::TNodeXYZ p1( edge->GetNode(0)); + SMESH_MeshEditor::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); + } + } + + 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(); + 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/StdMeshers/StdMeshers_Import_1D.hxx b/src/StdMeshers/StdMeshers_Import_1D.hxx new file mode 100644 index 000000000..a3ab382fb --- /dev/null +++ b/src/StdMeshers/StdMeshers_Import_1D.hxx @@ -0,0 +1,81 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 +// Module : SMESH +// +#ifndef _SMESH_Import_1D_HXX_ +#define _SMESH_Import_1D_HXX_ + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_1D_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/StdMeshers/StdMeshers_Import_1D2D.cxx b/src/StdMeshers/StdMeshers_Import_1D2D.cxx new file mode 100644 index 000000000..0062de31d --- /dev/null +++ b/src/StdMeshers/StdMeshers_Import_1D2D.cxx @@ -0,0 +1,642 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 : 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_subMesh.hxx" + +#include "Utils_SALOME_Exception.hxx" +#include "utilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +//============================================================================= +/*! + * 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"); + _requireDescretBoundary = false; +} + +//============================================================================= +/*! + * 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(); + if ( srcGroups.empty() ) + return error("Invalid 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 ); + if ( helper.GetSubShapeOri( tgtMesh->ShapeToMesh(), geomFace) == TopAbs_REVERSED ) + surface->UReverse(); + gp_Pnt p; gp_Vec du, dv; + + set subShapeIDs; + subShapeIDs.insert( shapeID ); + + // get nodes on vertices + list < SMESH_MeshEditor::TNodeXYZ > vertexNodes; + list < SMESH_MeshEditor::TNodeXYZ >::iterator vNIt; + 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 + } + vertexNodes.push_back( SMESH_MeshEditor::TNodeXYZ( n )); + } + + // to count now many times a link between nodes encounters + map linkCount; + map::iterator link2Nb; + + // ========================= + // Import faces from groups + // ========================= + + StdMeshers_Import_1D::TNodeNodeMap* n2n; + StdMeshers_Import_1D::TElemElemMap* e2e; + vector newNodes; + 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; + StdMeshers_Import_1D::getMaps( srcMesh, &theMesh, n2n, e2e ); + + SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements(); + SMDS_MeshNode tmpNode(0,0,0); + gp_XY uv; + while ( srcElems->more() ) // loop on group contents + { + const SMDS_MeshElement* face = srcElems->next(); + // find or create nodes of a new face + newNodes.resize( face->NbNodes() ); + newNodes.back() = 0; + int nbCreatedNodes = 0; + SMDS_MeshElement::iterator node = face->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 ) + { + if ( !subShapeIDs.count( n2nIt->second->GetPosition()->GetShapeId() )) + break; + } + else + { + // find an existing vertex node + for ( vNIt = vertexNodes.begin(); vNIt != vertexNodes.end(); ++vNIt) + if ( vNIt->SquareDistance( *node ) < 10 * faceTol * faceTol) + { + (*n2nIt).second = vNIt->_node; + vertexNodes.erase( vNIt ); + break; + } + } + if ( !n2nIt->second ) + { + // find out if node lies on theShape + tmpNode.setXYZ( (*node)->X(), (*node)->Y(), (*node)->Z()); + if ( helper.CheckNodeUV( geomFace, &tmpNode, uv, 10 * faceTol, /*force=*/true )) + { + SMDS_MeshNode* newNode = tgtMesh->AddNode( (*node)->X(), (*node)->Y(), (*node)->Z()); + n2nIt->second = newNode; + tgtMesh->SetNodeOnFace( newNode, shapeID, uv.X(), uv.Y() ); + nbCreatedNodes++; + } + } + if ( !(newNodes[i] = n2nIt->second )) + break; + } + if ( !newNodes.back() ) + continue; // not all nodes of the face lie on theShape + + // 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 + if ( toCheckOri ) + { + int iNode = -1; + gp_Vec geomNorm; + do + { + uv = helper.GetNodeUV( geomFace, newNodes[++iNode] ); + surface->D1( uv.X(),uv.Y(), p, du,dv ); + geomNorm = du ^ dv; + } + while ( geomNorm.SquareMagnitude() < 1e-6 && iNode+1 < face->NbCornerNodes()); + + int iNext = helper.WrapIndex( iNode+1, face->NbCornerNodes() ); + int iPrev = helper.WrapIndex( iNode-1, face->NbCornerNodes() ); + + gp_Vec n1n0( SMESH_MeshEditor::TNodeXYZ( newNodes[iPrev] ) - + SMESH_MeshEditor::TNodeXYZ( newNodes[iNode] )); + gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( newNodes[iNext] ) - + SMESH_MeshEditor::TNodeXYZ( newNodes[iNode] )); + gp_Vec meshNorm = n1n2 ^ n1n0; + + if ( geomNorm * meshNorm < 0 ) + std::reverse( newNodes.begin(), newNodes.end() ); + } + + // make a new face + 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 + int nbNodes = face->NbCornerNodes(); + const SMDS_MeshNode* medium = 0; + for ( int i = 0; i < nbNodes; ++i ) + { + const SMDS_MeshNode* n1 = newNodes[i]; + const SMDS_MeshNode* n2 = newNodes[ (i+1)%nbNodes ]; + if ( newFace->IsQuadratic() ) + medium = newNodes[i+nbNodes]; + link2Nb = linkCount.insert( make_pair( TLink( n1, n2, medium ), 0)).first; + ++link2Nb->second; + } + } + } + + // ========================================================== + // Put nodes on geom edges and create edges on them; + // check if the whole geom face is covered by imported faces + // ========================================================== + + vector< TopoDS_Edge > edges; + for ( exp.Init( theShape, TopAbs_EDGE ); exp.More(); exp.Next() ) + if ( subShapeIDs.insert( tgtMesh->ShapeToIndex( exp.Current() )).second ) + edges.push_back( TopoDS::Edge( exp.Current() )); + + bool isFaceMeshed = false; + if ( SMESHDS_SubMesh* tgtSM = tgtMesh->MeshElements( theShape )) + { + // 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 the link lie 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->GetPosition()->GetShapeId() )) + { + for ( unsigned iE = 0; iE < edges.size(); ++iE ) + if ( helper.CheckNodeU( edges[iE], n, u, 10 * faceTol, /*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"); + tgtMesh->SetNodeOnEdge( (SMDS_MeshNode*)n, edges[iE], u ); + break; + } + nodesOnBoundary = subShapeIDs.count( n->GetPosition()->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 ) + break; // free internal link + if ( bndShapes.front().ShapeType() == TopAbs_EDGE && + bndShapes.front() != bndShapes.back() ) + break; // link nodes on different geom edges + + // find geom edge the link is on + if ( bndShapes.back().ShapeType() != TopAbs_EDGE ) + { + // find geom edge by two vertices + TopoDS_Shape geomEdge; + PShapeIteratorPtr edgeIt = helper.GetAncestors( bndShapes.back(), theMesh, TopAbs_EDGE ); + while ( edgeIt->more() ) + { + geomEdge = *(edgeIt->next()); + if ( !helper.IsSubShape( bndShapes.front(), geomEdge )) + geomEdge.Nullify(); + } + if ( geomEdge.IsNull() ) + break; // vertices belong to different edges -> free internal link + 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 ) + { + newNodes.push_back( link._medium ); + edge = tgtMesh->AddEdge( newNodes[0], newNodes[1], newNodes[2] ); + + TopoDS_Edge geomEdge = TopoDS::Edge(bndShapes.back()); + helper.CheckNodeU( geomEdge, link._medium, u, 10*faceTol, /*force=*/true ); + tgtMesh->SetNodeOnEdge( (SMDS_MeshNode*)link._medium, geomEdge, u ); + } + else + { + edge = tgtMesh->AddEdge( newNodes[0], newNodes[1]); + } + // remove nodes from submesh of theShape + for ( unsigned i = 0; i < newNodes.size(); ++i ) + tgtSM->RemoveNode( newNodes[i], /*isNodeDeleted=*/false ); + if ( !edge ) + return false; + + tgtMesh->SetMeshElementOnShape( edge, bndShapes.back() ); + } + else if ( nbFaces > 2 ) + { + return error( "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 ) + return false; // weird + if ( nbEdges > 2 ) + return error( "Source elements overlap one another"); + } + } + } + if ( !isFaceMeshed ) + return error( "Source elements don't cover totally the geometrical face" ); + + // notify sub-meshes of edges on computation + for ( unsigned iE = 0; iE < edges.size(); ++iE ) + theMesh.GetSubMesh( edges[iE] )->ComputeStateEngine(SMESH_subMesh::CHECK_COMPUTE_STATE); + + // ============ + // Copy meshes + // ============ + + vector srcMeshes = _sourceHyp->GetSourceMeshes(); + for ( unsigned 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_MeshEditor::TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator; + + SMESH_MesherHelper helper(theMesh); + helper.SetSubShape(theShape); + + const TopoDS_Face& geomFace = TopoDS::Face( theShape ); + const double faceTol = helper.MaxTolerance( geomFace ); + + // 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; + for ( int iG = 0; iG < srcGroups.size(); ++iG ) + { + const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS(); + SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements(); + SMDS_MeshNode tmpNode(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, 10 * faceTol, /*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; + } + } + } + } + } + + 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, 10*faceTol, /*force=*/true )&& + helper.CheckNodeU( geomEdge, link.node2(), u, 10*faceTol, /*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/StdMeshers/StdMeshers_Import_1D2D.hxx b/src/StdMeshers/StdMeshers_Import_1D2D.hxx new file mode 100644 index 000000000..5733c2f48 --- /dev/null +++ b/src/StdMeshers/StdMeshers_Import_1D2D.hxx @@ -0,0 +1,60 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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 +// Module : SMESH +// +#ifndef _SMESH_Import_2D_HXX_ +#define _SMESH_Import_2D_HXX_ + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_2D_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/StdMeshers/StdMeshers_QuadToTriaAdaptor.cxx b/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.cxx index 39dfd2e13..8e2718dd0 100644 --- a/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.cxx +++ b/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.cxx @@ -46,7 +46,7 @@ using namespace std; enum EQuadNature { NOT_QUAD, QUAD, DEGEN_QUAD }; - // std-like iterator used to get coordinates of nodes of mesh element +// std-like iterator used to get coordinates of nodes of mesh element typedef SMDS_StdIterator< SMESH_MeshEditor::TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator; namespace @@ -183,7 +183,7 @@ namespace //================================================================================ /*! * \brief Return true if two adjacent pyramids are too close one to another - * so that a tetrahedron to built between them whoul have too poor quality + * so that a tetrahedron to built between them would have too poor quality */ //================================================================================ @@ -333,7 +333,7 @@ namespace //================================================================================ StdMeshers_QuadToTriaAdaptor::StdMeshers_QuadToTriaAdaptor(): - myElemSearcher(0) + myElemSearcher(0), myNbTriangles(0) { } @@ -580,9 +580,11 @@ int StdMeshers_QuadToTriaAdaptor::Preparation(const SMDS_MeshElement* face gp_Vec& VNorm, const SMDS_MeshElement** volumes) { - if( face->NbNodes() != ( face->IsQuadratic() ? 8 : 4 )) - if( face->NbNodes() != 4 ) - return NOT_QUAD; + if( face->NbCornerNodes() != 4 ) + { + myNbTriangles += int( face->NbCornerNodes() == 3 ); + return NOT_QUAD; + } int i = 0; gp_XYZ xyzC(0., 0., 0.); @@ -696,6 +698,8 @@ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape { myResMap.clear(); myPyramids.clear(); + myNbTriangles = 0; + myShape = aShape; SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); SMESH_MesherHelper helper(aMesh); @@ -1144,6 +1148,10 @@ bool StdMeshers_QuadToTriaAdaptor::Compute2ndPart(SMESH_Mesh& aMesh) nodesToMove.insert( aNode1 ); nodesToMove.insert( aNode2 ); } + // fix intersections that could appear after apex movement + MergeAdjacent( PrmI, aMesh, nodesToMove ); + MergeAdjacent( PrmJ, aMesh, nodesToMove ); + } // end if(hasInt) } // loop on suspectPyrams } // loop on 4 base nodes of PrmI @@ -1165,7 +1173,7 @@ bool StdMeshers_QuadToTriaAdaptor::Compute2ndPart(SMESH_Mesh& aMesh) if ( q2t->first == q2tPrev->first ) q2tPrev->second.splice( q2tPrev->second.end(), q2t->second ); } - // delete removed triangles + // delete removed triangles and count resulting nb of triangles for ( q2t = myResMap.begin(); q2t != myResMap.end(); ++q2t ) { TTriaList & trias = q2t->second; @@ -1173,7 +1181,7 @@ bool StdMeshers_QuadToTriaAdaptor::Compute2ndPart(SMESH_Mesh& aMesh) if ( ((const Q2TAdaptor_Triangle*) *tri)->IsRemoved() ) delete *tri, trias.erase( tri++ ); else - tri++; + tri++, myNbTriangles++; } myPyramids.clear(); // no more needed diff --git a/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.hxx b/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.hxx index 874fdc6a9..ceccb2542 100644 --- a/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.hxx +++ b/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.hxx @@ -33,7 +33,6 @@ class SMDS_MeshNode; class SMDS_MeshFace; class Handle_TColgp_HArray1OfPnt; class Handle_TColgp_HArray1OfVec; -class TopoDS_Shape; class gp_Pnt; class gp_Vec; @@ -42,6 +41,8 @@ class gp_Vec; #include #include +#include + /*! * \brief "Transforms" quadrilateral faces into triangular ones by creation of pyramids */ @@ -58,6 +59,13 @@ public: const std::list* GetTriangles(const SMDS_MeshElement* aFace); + /*! + * \brief Return sum of generated and already present triangles + */ + int TotalNbOfTriangles() const { return myNbTriangles; } + + TopoDS_Shape GetShape() const { return myShape; } + protected: //bool CheckDegenerate(const SMDS_MeshElement* aFace); @@ -77,17 +85,19 @@ protected: bool Compute2ndPart(SMESH_Mesh& aMesh); - typedef std::list TTriaList; - typedef std::multimap TQuad2Trias; - //typedef std::map TPyram2Trias; + typedef std::list TTriaList; + typedef std::multimap TQuad2Trias; TQuad2Trias myResMap; - //TPyram2Trias myPyram2Trias; std::vector myPyramids; std::list< const SMDS_MeshNode* > myDegNodes; const SMESH_ElementSearcher* myElemSearcher; + + int myNbTriangles; + + TopoDS_Shape myShape; }; #endif diff --git a/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.cxx b/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.cxx index 06f2431ec..e69489aeb 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.cxx @@ -35,9 +35,11 @@ #include #include #include +#include // SALOME KERNEL incldues #include +#include // Qt includes #include @@ -54,8 +56,8 @@ //================================================================================ StdMeshersGUI_ObjectReferenceParamWdg::StdMeshersGUI_ObjectReferenceParamWdg -( SUIT_SelectionFilter* f, QWidget* parent) - : QWidget( parent ) +( SUIT_SelectionFilter* f, QWidget* parent, bool multiSelection) + : QWidget( parent ), myMultiSelection( multiSelection ) { myFilter = f; init(); @@ -69,8 +71,8 @@ StdMeshersGUI_ObjectReferenceParamWdg::StdMeshersGUI_ObjectReferenceParamWdg //================================================================================ StdMeshersGUI_ObjectReferenceParamWdg::StdMeshersGUI_ObjectReferenceParamWdg -( MeshObjectType objType, QWidget* parent ) - : QWidget( parent ) +( MeshObjectType objType, QWidget* parent, bool multiSelection ) + : QWidget( parent ), myMultiSelection( multiSelection ) { myFilter = new SMESH_TypeFilter( objType ); init(); @@ -84,7 +86,10 @@ StdMeshersGUI_ObjectReferenceParamWdg::StdMeshersGUI_ObjectReferenceParamWdg StdMeshersGUI_ObjectReferenceParamWdg::~StdMeshersGUI_ObjectReferenceParamWdg() { if ( myFilter ) + { + mySelectionMgr->removeFilter( myFilter ); delete myFilter; + } } @@ -184,7 +189,7 @@ void StdMeshersGUI_ObjectReferenceParamWdg::AvoidSimultaneousSelection void StdMeshersGUI_ObjectReferenceParamWdg::SetObject(CORBA::Object_ptr obj) { - myObject = CORBA::Object::_nil(); + myObjects.clear(); myObjNameLineEdit->setText( "" ); myParamValue = ""; @@ -194,11 +199,43 @@ void StdMeshersGUI_ObjectReferenceParamWdg::SetObject(CORBA::Object_ptr obj) if ( sobj ) { std::string name = sobj->GetName(); myObjNameLineEdit->setText( name.c_str() ); - myObject = CORBA::Object::_duplicate( obj ); + myObjects.push_back( CORBA::Object::_duplicate( obj )); myParamValue = sobj->GetID().c_str(); } } +//================================================================================ +/*! + * \brief Initialize selected objects + * \param objects - entries of objects + */ +//================================================================================ + +void StdMeshersGUI_ObjectReferenceParamWdg::SetObjects(SMESH::string_array_var& objects) +{ + myObjects.clear(); + myObjNameLineEdit->setText( "" ); + myParamValue = ""; + + for ( unsigned i = 0; i < objects->length(); ++i ) + { + _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); + _PTR(SObject) aSObj = aStudy->FindObjectID(objects[i].in()); + CORBA::Object_var anObj = SMESH::SObjectToObject(aSObj,aStudy); + if ( !CORBA::is_nil( anObj )) { + std::string name = aSObj->GetName(); + QString text = myObjNameLineEdit->text(); + if ( !text.isEmpty() ) + text += " "; + text += name.c_str(); + myObjNameLineEdit->setText( text ); + myObjects.push_back( anObj ); + myParamValue += " "; + myParamValue += objects[i]; + } + } +} + //================================================================================ /*! * \brief Takes selected object @@ -212,7 +249,26 @@ void StdMeshersGUI_ObjectReferenceParamWdg::onSelectionDone() SALOME_ListIO aList; mySelectionMgr->selectedObjects(aList); if (aList.Extent() == 1) + { obj = SMESH::IObjectToObject( aList.First() ); - SetObject( obj.in() ); + SetObject( obj.in() ); + } + else if (myMultiSelection) + { + SMESH::string_array_var objIds = new SMESH::string_array; + objIds->length( aList.Extent()); + SALOME_ListIteratorOfListIO io( aList ); + int i = 0; + for ( ; io.More(); io.Next(), ++i ) + { + Handle(SALOME_InteractiveObject) anIO = io.Value(); + if ( anIO->hasEntry() ) + objIds[i] = anIO->getEntry(); + else + i--; + } + objIds->length(i); + SetObjects( objIds ); + } } } diff --git a/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.h b/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.h index c5fabc25e..e8c387194 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.h +++ b/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.h @@ -37,6 +37,8 @@ // CORBA includes #include +#include CORBA_SERVER_HEADER(SMESH_Mesh) + class SUIT_SelectionFilter; class SMESHGUI; class LightApp_SelectionMgr; @@ -52,22 +54,29 @@ class STDMESHERSGUI_EXPORT StdMeshersGUI_ObjectReferenceParamWdg : public QWidge public: StdMeshersGUI_ObjectReferenceParamWdg( SUIT_SelectionFilter* filter, - QWidget* parent); + QWidget* parent, + bool multiSelection=false); StdMeshersGUI_ObjectReferenceParamWdg( MeshObjectType objType, - QWidget* parent); + QWidget* parent, + bool multiSelection=false); ~StdMeshersGUI_ObjectReferenceParamWdg(); void SetObject(CORBA::Object_ptr obj); + void SetObjects(SMESH::string_array_var& objEntries); + template - typename TInterface::_var_type GetObject() const { - if ( IsObjectSelected() ) return TInterface::_narrow(myObject); + typename TInterface::_var_type GetObject(unsigned i=0) const { + if ( IsObjectSelected(i) ) return TInterface::_narrow(myObjects[i]); return TInterface::_nil(); } + int NbObjects() const { return myObjects.size(); } + QString GetValue() const { return myParamValue; } - bool IsObjectSelected() const { return !CORBA::is_nil(myObject); } + bool IsObjectSelected(unsigned i=0) const + { return i < myObjects.size() && !CORBA::is_nil(myObjects[i]); } void AvoidSimultaneousSelection( StdMeshersGUI_ObjectReferenceParamWdg* other); @@ -97,7 +106,10 @@ private: void init(); private: - CORBA::Object_var myObject; + + bool myMultiSelection; + std::vector myObjects; + SUIT_SelectionFilter* myFilter; bool mySelectionActivated; diff --git a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx index 3e8d13ee2..9595e67a0 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx @@ -48,6 +48,7 @@ #include #include CORBA_SERVER_HEADER(SMESH_BasicHypothesis) #include CORBA_SERVER_HEADER(SMESH_Mesh) +#include CORBA_SERVER_HEADER(SMESH_Group) // Qt includes #include @@ -261,6 +262,25 @@ namespace { return SMESH::SMESH_Mesh::_nil(); } //================================================================================ + /*! + * \brief Retrieve SMESH_Mesh held by widget + */ + //================================================================================ + + inline SMESH::ListOfGroups_var groupsFromWdg(const QWidget* wdg) + { + SMESH::ListOfGroups_var groups = new SMESH::ListOfGroups; + const StdMeshersGUI_ObjectReferenceParamWdg * objRefWdg = + dynamic_cast( wdg ); + if ( objRefWdg ) + { + groups->length( objRefWdg->NbObjects() ); + for ( unsigned i = 0; i < groups->length(); ++i ) + groups[i] = objRefWdg->GetObject< SMESH::SMESH_GroupBase >(i); + } + return groups; + } + //================================================================================ /*! * \brief creates a filter for selection of shapes of given dimension * \param dim - dimension @@ -317,6 +337,15 @@ namespace { w->SetObject( object.in() ); return w; } + QWidget* newObjRefParamWdg( SUIT_SelectionFilter* filter, + SMESH::string_array_var& objEntries) + { + StdMeshersGUI_ObjectReferenceParamWdg* w = + new StdMeshersGUI_ObjectReferenceParamWdg( filter, 0, /*multiSel=*/true); + w->SetObjects( objEntries ); + w->activateSelection(); + return w; + } //================================================================================ /*! @@ -382,6 +411,12 @@ bool StdMeshersGUI_StdHypothesisCreator::checkParams( QString& msg ) const if ( ok ) deactivateObjRefParamWdg( customWidgets() ); } + else if ( hypType().startsWith("ImportSource" )) + { + StdMeshersGUI_ObjectReferenceParamWdg* w = + widget< StdMeshersGUI_ObjectReferenceParamWdg >( 0 ); + ok = ( w->IsObjectSelected() ); + } else if ( hypType() == "LayerDistribution" || hypType() == "LayerDistribution2D" ) { StdMeshersGUI_LayerDistributionParamWdg* w = @@ -609,6 +644,28 @@ QString StdMeshersGUI_StdHypothesisCreator::storeParams() const geomFromWdg ( getWidgetForParam( 3 )), // tgt1 geomFromWdg ( getWidgetForParam( 5 ))); // tgt2 } + else if( hypType()=="ImportSource1D" ) + { + StdMeshers::StdMeshers_ImportSource1D_var h = + StdMeshers::StdMeshers_ImportSource1D::_narrow( hypothesis() ); + + SMESH::ListOfGroups_var groups = groupsFromWdg( getWidgetForParam( 0 )); + h->SetSourceEdges( groups.in() ); + QCheckBox* toCopyMesh = widget< QCheckBox >( 1 ); + QCheckBox* toCopyGroups = widget< QCheckBox >( 2 ); + h->SetCopySourceMesh( toCopyMesh->isChecked(), toCopyGroups->isChecked()); + } + else if( hypType()=="ImportSource2D" ) + { + StdMeshers::StdMeshers_ImportSource2D_var h = + StdMeshers::StdMeshers_ImportSource2D::_narrow( hypothesis() ); + + SMESH::ListOfGroups_var groups = groupsFromWdg( getWidgetForParam( 0 )); + h->SetSourceFaces( groups.in() ); + QCheckBox* toCopyMesh = widget< QCheckBox >( 1 ); + QCheckBox* toCopyGroups = widget< QCheckBox >( 2 ); + h->SetCopySourceMesh( toCopyMesh->isChecked(), toCopyGroups->isChecked()); + } else if( hypType()=="QuadrangleParams" ) { StdMeshers::StdMeshers_QuadrangleParams_var h = @@ -992,6 +1049,56 @@ bool StdMeshersGUI_StdHypothesisCreator::stdParams( ListOfStdParams& p ) const customWidgets()->append( newObjRefParamWdg( filterForShapeOfDim( 0 ), h->GetTargetVertex( 2 ))); } + else if( hypType()=="ImportSource1D" ) + { + StdMeshers::StdMeshers_ImportSource1D_var h = + StdMeshers::StdMeshers_ImportSource1D::_narrow( hyp ); + + SMESH::string_array_var groupEntries = h->GetSourceEdges(); + CORBA::Boolean toCopyMesh, toCopyGroups; + h->GetCopySourceMesh(toCopyMesh, toCopyGroups); + + item.myName = tr( "SMESH_SOURCE_EDGES" ); p.append( item ); + customWidgets()->append( newObjRefParamWdg( new SMESH_TypeFilter( GROUP_EDGE ), + groupEntries)); + + item.myName = tr( "SMESH_COPY_MESH" ); p.append( item ); + QCheckBox* aQCheckBox = new QCheckBox(dlg()); + aQCheckBox->setChecked( toCopyMesh ); + connect( aQCheckBox, SIGNAL( stateChanged(int) ), this, SLOT( onValueChanged() )); + customWidgets()->append( aQCheckBox ); + + item.myName = tr( "SMESH_TO_COPY_GROUPS" ); p.append( item ); + aQCheckBox = new QCheckBox(dlg()); + aQCheckBox->setChecked( toCopyGroups ); + aQCheckBox->setEnabled( toCopyMesh ); + customWidgets()->append( aQCheckBox ); + } + else if( hypType()=="ImportSource2D" ) + { + StdMeshers::StdMeshers_ImportSource2D_var h = + StdMeshers::StdMeshers_ImportSource2D::_narrow( hyp ); + + SMESH::string_array_var groupEntries = h->GetSourceFaces(); + CORBA::Boolean toCopyMesh, toCopyGroups; + h->GetCopySourceMesh(toCopyMesh, toCopyGroups); + + item.myName = tr( "SMESH_SOURCE_FACES" ); p.append( item ); + customWidgets()->append( newObjRefParamWdg( new SMESH_TypeFilter( GROUP_FACE ), + groupEntries)); + + item.myName = tr( "SMESH_COPY_MESH" ); p.append( item ); + QCheckBox* aQCheckBox = new QCheckBox(dlg()); + aQCheckBox->setChecked( toCopyMesh ); + connect( aQCheckBox, SIGNAL( stateChanged(int) ), this, SLOT( onValueChanged() )); + customWidgets()->append( aQCheckBox ); + + item.myName = tr( "SMESH_COPY_GROUPS" ); p.append( item ); + aQCheckBox = new QCheckBox(dlg()); + aQCheckBox->setChecked( toCopyGroups ); + aQCheckBox->setEnabled( toCopyMesh ); + customWidgets()->append( aQCheckBox ); + } else if (hypType() == "QuadrangleParams") { StdMeshers::StdMeshers_QuadrangleParams_var h = @@ -1150,6 +1257,8 @@ QString StdMeshersGUI_StdHypothesisCreator::hypTypeName( const QString& t ) cons types.insert( "ProjectionSource1D", "PROJECTION_SOURCE_1D" ); types.insert( "ProjectionSource2D", "PROJECTION_SOURCE_2D" ); types.insert( "ProjectionSource3D", "PROJECTION_SOURCE_3D" ); + types.insert( "ImportSource1D", "IMPORT_SOURCE_1D" ); + types.insert( "ImportSource2D", "IMPORT_SOURCE_2D" ); types.insert( "NumberOfLayers", "NUMBER_OF_LAYERS" ); types.insert( "LayerDistribution", "LAYER_DISTRIBUTION" ); types.insert( "NumberOfLayers2D", "NUMBER_OF_LAYERS_2D" ); @@ -1250,6 +1359,12 @@ bool StdMeshersGUI_StdHypothesisCreator::getParamFromCustomWidget( StdParam & pa param.myValue = w->GetValue(); return true; } + if ( widget->inherits( "QCheckBox" )) + { + //const QCheckBox * w = static_cast( widget ); + //param.myValue = w->isChecked(); + return true; + } return false; } @@ -1261,7 +1376,8 @@ bool StdMeshersGUI_StdHypothesisCreator::getParamFromCustomWidget( StdParam & pa void StdMeshersGUI_StdHypothesisCreator::onReject() { - if ( hypType().startsWith("ProjectionSource" )) + if ( hypType().startsWith("ProjectionSource" ) || + hypType().startsWith("ImportSource" )) { // Uninstall filters of StdMeshersGUI_ObjectReferenceParamWdg deactivateObjRefParamWdg( customWidgets() ); @@ -1270,13 +1386,14 @@ void StdMeshersGUI_StdHypothesisCreator::onReject() //================================================================================ /*! - * \brief + * \brief Update widgets dependent on paramWidget */ //================================================================================ void StdMeshersGUI_StdHypothesisCreator::valueChanged( QWidget* paramWidget) { - if ( hypType() == "MaxLength" && paramWidget == getWidgetForParam(1) ) { + if ( hypType() == "MaxLength" && paramWidget == getWidgetForParam(1) ) + { getWidgetForParam(0)->setEnabled( !widget< QCheckBox >( 1 )->isChecked() ); if ( !getWidgetForParam(0)->isEnabled() ) { StdMeshers::StdMeshers_MaxLength_var h = @@ -1284,6 +1401,20 @@ void StdMeshersGUI_StdHypothesisCreator::valueChanged( QWidget* paramWidget) widget< QtxDoubleSpinBox >( 0 )->setValue( h->GetPreestimatedLength() ); } } + else if ( hypType().startsWith("ImportSource") && paramWidget == getWidgetForParam(1) ) + { + QCheckBox* toCopyMesh = (QCheckBox*) paramWidget; + QCheckBox* toCopyGroups = widget< QCheckBox >( 2 ); + if ( !toCopyMesh->isChecked() ) + { + toCopyGroups->setChecked( false ); + toCopyGroups->setEnabled( false ); + } + else + { + toCopyGroups->setEnabled( true ); + } + } } //================================================================================ diff --git a/src/StdMeshersGUI/StdMeshers_images.ts b/src/StdMeshersGUI/StdMeshers_images.ts index 927a4c09b..87444b56a 100644 --- a/src/StdMeshersGUI/StdMeshers_images.ts +++ b/src/StdMeshersGUI/StdMeshers_images.ts @@ -93,6 +93,14 @@ ICON_DLG_QUADRANGLE_PARAMS mesh_hypo_length.png + + ICON_DLG_IMPORT_SOURCE_1D + mesh_hypo_source_edge.png + + + ICON_DLG_IMPORT_SOURCE_2D + mesh_hypo_source_face.png + ICON_DLG_SEGMENT_LENGTH_AROUND_VERTEX mesh_hypo_length.png diff --git a/src/StdMeshersGUI/StdMeshers_msg_en.ts b/src/StdMeshersGUI/StdMeshers_msg_en.ts index c04916750..75888dfa3 100644 --- a/src/StdMeshersGUI/StdMeshers_msg_en.ts +++ b/src/StdMeshersGUI/StdMeshers_msg_en.ts @@ -235,6 +235,22 @@ SMESH_PROJECTION_SOURCE_3D_TITLE Hypothesis Construction + + SMESH_IMPORT_SOURCE_1D_HYPOTHESIS + Source edges + + + SMESH_IMPORT_SOURCE_1D_TITLE + Hypothesis Construction + + + SMESH_IMPORT_SOURCE_2D_HYPOTHESIS + Source faces + + + SMESH_IMPORT_SOURCE_2D_TITLE + Hypothesis Construction + SMESH_REMOVE_ROW Remove row @@ -283,14 +299,30 @@ SMESH_SOURCE_EDGE Edge + + SMESH_SOURCE_EDGES + Groups of Edges + SMESH_SOURCE_FACE Face + + SMESH_SOURCE_FACES + Groups of Faces + SMESH_SOURCE_MESH Mesh + + SMESH_COPY_MESH + To copy mesh + + + SMESH_TO_COPY_GROUPS + To copy groups + SMESH_SOURCE_VERTEX Source Vertex diff --git a/src/StdMeshers_I/Makefile.am b/src/StdMeshers_I/Makefile.am index 3331c0b36..17d7c9f6f 100644 --- a/src/StdMeshers_I/Makefile.am +++ b/src/StdMeshers_I/Makefile.am @@ -63,7 +63,11 @@ salomeinclude_HEADERS = \ StdMeshers_MaxLength_i.hxx \ StdMeshers_QuadrangleParams_i.hxx \ StdMeshers_RadialQuadrangle_1D2D_i.hxx \ - SMESH_StdMeshers_I.hxx + SMESH_StdMeshers_I.hxx \ + StdMeshers_ImportSource1D_i.hxx \ + StdMeshers_ImportSource2D_i.hxx \ + StdMeshers_Import_1D_i.hxx \ + StdMeshers_Import_1D2D_i.hxx # Libraries targets lib_LTLIBRARIES = libStdMeshersEngine.la @@ -105,7 +109,11 @@ dist_libStdMeshersEngine_la_SOURCES = \ StdMeshers_TrianglePreference_i.cxx \ StdMeshers_MaxLength_i.cxx \ StdMeshers_QuadrangleParams_i.cxx \ - StdMeshers_RadialQuadrangle_1D2D_i.cxx + StdMeshers_RadialQuadrangle_1D2D_i.cxx \ + StdMeshers_ImportSource1D_i.cxx \ + StdMeshers_ImportSource2D_i.cxx \ + StdMeshers_Import_1D_i.cxx \ + StdMeshers_Import_1D2D_i.cxx # additionnal information to compil and link file libStdMeshersEngine_la_CPPFLAGS = \ diff --git a/src/StdMeshers_I/StdMeshers_Deflection1D_i.cxx b/src/StdMeshers_I/StdMeshers_Deflection1D_i.cxx index 3c0859e23..61416d23c 100644 --- a/src/StdMeshers_I/StdMeshers_Deflection1D_i.cxx +++ b/src/StdMeshers_I/StdMeshers_Deflection1D_i.cxx @@ -25,7 +25,6 @@ // Moved here from SMESH_LocalLength_i.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #include "StdMeshers_Deflection1D_i.hxx" #include "SMESH_Gen_i.hxx" diff --git a/src/StdMeshers_I/StdMeshers_ImportSource1D_i.cxx b/src/StdMeshers_I/StdMeshers_ImportSource1D_i.cxx new file mode 100644 index 000000000..4d33ec8bb --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_ImportSource1D_i.cxx @@ -0,0 +1,280 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_ImportSource1D_i.cxx +// Module : SMESH +// +#include "StdMeshers_ImportSource1D_i.hxx" + +#include "SMESH_Gen.hxx" +#include "SMESH_Gen_i.hxx" +#include "SMESH_Group_i.hxx" +#include "SMESH_PythonDump.hxx" +#include "StdMeshers_ObjRefUlils.hxx" + +#include "Utils_CorbaException.hxx" +#include "utilities.h" + +#include + +#include CORBA_SERVER_HEADER(SMESH_Group) + +using namespace std; + +//============================================================================= +/*! + * StdMeshers_ImportSource1D_i::StdMeshers_ImportSource1D_i + * + * Constructor + */ +//============================================================================= + +StdMeshers_ImportSource1D_i::StdMeshers_ImportSource1D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ) + : SALOME::GenericObj_i( thePOA ), + SMESH_Hypothesis_i( thePOA ) +{ + MESSAGE( "StdMeshers_ImportSource1D_i::StdMeshers_ImportSource1D_i" ); + myBaseImpl = new ::StdMeshers_ImportSource1D( theGenImpl->GetANewId(), + theStudyId, + theGenImpl ); + _groupEntries = new SMESH::string_array(); +} + +//============================================================================= +/*! + * StdMeshers_ImportSource1D_i::~StdMeshers_ImportSource1D_i + * + * Destructor + */ +//============================================================================= + +StdMeshers_ImportSource1D_i::~StdMeshers_ImportSource1D_i() +{ + MESSAGE( "StdMeshers_ImportSource1D_i::~StdMeshers_ImportSource1D_i" ); +} + +//============================================================================= +/*! + * SetSourceEdges + */ +//============================================================================= + +void StdMeshers_ImportSource1D_i::SetSourceEdges(const SMESH::ListOfGroups& groups) +{ + MESSAGE( "StdMeshers_ImportSource1D_i::SetSourceEdges" ); + ASSERT( myBaseImpl ); + try + { + std::vector smesh_groups; + std::vector entries; + SALOMEDS::Study_var study = SMESH_Gen_i::GetSMESHGen()->GetCurrentStudy(); + for ( int i = 0; i < groups.length(); ++i ) + if ( SMESH_GroupBase_i* gp_i = SMESH::DownCast( groups[i] )) + { + if ( gp_i->GetType() != SMESH::EDGE ) + THROW_SALOME_CORBA_EXCEPTION("Wrong group type", SALOME::BAD_PARAM); + smesh_groups.push_back( gp_i->GetSmeshGroup() ); + + SALOMEDS::SObject_var so = SMESH_Gen_i::GetSMESHGen()->ObjectToSObject(study, groups[i]); + if ( !so->_is_nil()) + { + CORBA::String_var entry = so->GetID(); + entries.push_back( entry.in() ); + } + } + this->GetImpl()->SetGroups( smesh_groups ); + + _groupEntries = new SMESH::string_array; + _groupEntries->length( entries.size ()); + for ( int i = 0; i < entries.size(); ++i ) + _groupEntries[i] = entries[i].c_str(); + } + catch ( SALOME_Exception& S_ex ) + { + THROW_SALOME_CORBA_EXCEPTION( S_ex.what(), SALOME::BAD_PARAM ); + } + + // Update Python script + SMESH::TPythonDump() << _this() << ".SetSourceEdges( " << groups << " )"; +} + +//============================================================================= +/*! + * Return entries of groups + */ +//============================================================================= + +SMESH::string_array* StdMeshers_ImportSource1D_i::GetSourceEdges() +{ + MESSAGE( "StdMeshers_ImportSource1D_i::GetImportSource" ); + SMESH::string_array_var res = new SMESH::string_array( _groupEntries ); + return res._retn(); +} + +//================================================================================ +/*! + * \brief Set to copy mesh and groups + */ +//================================================================================ + +void StdMeshers_ImportSource1D_i::SetCopySourceMesh(CORBA::Boolean toCopyMesh, + CORBA::Boolean toCopyGroups) +{ + GetImpl()->SetCopySourceMesh(toCopyMesh,toCopyGroups); + SMESH::TPythonDump() << _this() << ".SetCopySourceMesh( " + << toCopyMesh << ", " << toCopyGroups << " )"; +} + +//================================================================================ +/*! + * \brief Return "to copy mesh and groups" + */ +//================================================================================ + +void StdMeshers_ImportSource1D_i::GetCopySourceMesh(CORBA::Boolean& toCopyMesh, + CORBA::Boolean& toCopyGroups) +{ + GetImpl()->GetCopySourceMesh(toCopyMesh,toCopyGroups); +} + +//================================================================================ +/*! + * \brief Write parameters in a string + * \retval char* - resulting string + */ +//================================================================================ + +char* StdMeshers_ImportSource1D_i::SaveTo() +{ + std::ostringstream os; + os << " " << _groupEntries->length(); + + SALOMEDS::Study_var study = SMESH_Gen_i::GetSMESHGen()->GetCurrentStudy(); + for ( int i = 0; i < _groupEntries->length(); ++i ) + { + // entry + os << " " << _groupEntries[i]; + + // id + SALOMEDS::SObject_var groupSO = study->FindObjectID( _groupEntries[i] ); + CORBA::Object_var groupObj; + if ( !groupSO->_is_nil() ) + groupObj = groupSO->GetObject(); + StdMeshers_ObjRefUlils::SaveToStream( groupObj, os ); + } + + myBaseImpl->SaveTo( os ); + + return CORBA::string_dup( os.str().c_str() ); +} + +//================================================================================ +/*! + * \brief Retrieve parameters from the string + * \param theStream - the input string + */ +//================================================================================ + +void StdMeshers_ImportSource1D_i::LoadFrom( const char* theStream ) +{ + std::istringstream is( theStream ); + + int nbGroups; + is >> nbGroups; + + _groupEntries = new SMESH::string_array; + _groupEntries->length( nbGroups ); + std::string id, entry; + for ( int i = 0; i < _groupEntries->length(); ++i ) + { + if ( is >> entry ) + _groupEntries[i] = entry.c_str(); + else + { + _groupEntries->length( i ); + is.clear(ios::badbit | is.rdstate()); + break; + } + if ( is >> id ) + _groupIDs.push_back( id ); + else + { + is.clear(ios::badbit | is.rdstate()); + break; + } + } + + myBaseImpl->LoadFrom( is ); +} + +//================================================================================ +/*! + * \brief Retrieve groups by their ids loaded by LoadFrom() + * This is possible only when all meshes are fully loaded + */ +//================================================================================ + +void StdMeshers_ImportSource1D_i::UpdateAsMeshesRestored() +{ + std::vector smesh_groups; + for ( unsigned i = 0; i < _groupIDs.size(); ++i ) + { + std::istringstream is( _groupIDs[i].c_str() ); + SMESH::SMESH_GroupBase_var group = + StdMeshers_ObjRefUlils::LoadObjectFromStream( is ); + if ( SMESH_GroupBase_i* gp_i = SMESH::DownCast( group )) + smesh_groups.push_back( gp_i->GetSmeshGroup() ); + } + GetImpl()->RestoreGroups(smesh_groups); +} + +//============================================================================= +/*! + * StdMeshers_ImportSource1D_i::GetImpl + * + * Get implementation + */ +//============================================================================= + +::StdMeshers_ImportSource1D* StdMeshers_ImportSource1D_i::GetImpl() +{ + MESSAGE( "StdMeshers_ImportSource1D_i::GetImpl" ); + return ( ::StdMeshers_ImportSource1D* )myBaseImpl; +} + +//================================================================================ +/*! + * \brief Verify whether hypothesis supports given entity type + * \param type - dimension (see SMESH::Dimension enumeration) + * \retval CORBA::Boolean - TRUE if dimension is supported, FALSE otherwise + * + * Verify whether hypothesis supports given entity type (see SMESH::Dimension enumeration) + */ +//================================================================================ +CORBA::Boolean StdMeshers_ImportSource1D_i::IsDimSupported( SMESH::Dimension type ) +{ + return type == SMESH::DIM_1D; +} + diff --git a/src/StdMeshers_I/StdMeshers_ImportSource1D_i.hxx b/src/StdMeshers_I/StdMeshers_ImportSource1D_i.hxx new file mode 100644 index 000000000..216244a62 --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_ImportSource1D_i.hxx @@ -0,0 +1,74 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_ImportSource1D_i.hxx +// Module : SMESH +// +#ifndef _SMESH_ImportSource1D_I_HXX_ +#define _SMESH_ImportSource1D_I_HXX_ + +#include "SMESH_StdMeshers_I.hxx" + +#include +#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis) + +#include "SMESH_Hypothesis_i.hxx" +#include "StdMeshers_ImportSource.hxx" + +class SMESH_Gen; + +class STDMESHERS_I_EXPORT StdMeshers_ImportSource1D_i: + public virtual POA_StdMeshers::StdMeshers_ImportSource1D, + public virtual SMESH_Hypothesis_i +{ + public: + // Constructor + StdMeshers_ImportSource1D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~StdMeshers_ImportSource1D_i(); + + void SetSourceEdges(const ::SMESH::ListOfGroups& groups); + SMESH::string_array* GetSourceEdges(); + void SetCopySourceMesh(::CORBA::Boolean toCopyMesh, ::CORBA::Boolean toCopyGroups); + void GetCopySourceMesh(::CORBA::Boolean& toCopyMesh, ::CORBA::Boolean& toCopyGroups); + + // Get implementation + ::StdMeshers_ImportSource1D* GetImpl(); + + // Verify whether hypothesis supports given entity type + CORBA::Boolean IsDimSupported( SMESH::Dimension type ); + + // Redefined Persistence + virtual char* SaveTo(); + virtual void LoadFrom( const char* theStream ); + virtual void UpdateAsMeshesRestored(); + + private: + SMESH::string_array_var _groupEntries; + std::vector< std::string > _groupIDs; +}; + +#endif + diff --git a/src/StdMeshers_I/StdMeshers_ImportSource2D_i.cxx b/src/StdMeshers_I/StdMeshers_ImportSource2D_i.cxx new file mode 100644 index 000000000..b2221a426 --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_ImportSource2D_i.cxx @@ -0,0 +1,280 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_ImportSource2D_i.cxx +// Module : SMESH +// +#include "StdMeshers_ImportSource2D_i.hxx" + +#include "SMESH_Gen.hxx" +#include "SMESH_Gen_i.hxx" +#include "SMESH_Group_i.hxx" +#include "SMESH_PythonDump.hxx" +#include "StdMeshers_ObjRefUlils.hxx" + +#include "Utils_CorbaException.hxx" +#include "utilities.h" + +#include + +#include CORBA_SERVER_HEADER(SMESH_Group) + +using namespace std; + +//============================================================================= +/*! + * StdMeshers_ImportSource2D_i::StdMeshers_ImportSource2D_i + * + * Constructor + */ +//============================================================================= + +StdMeshers_ImportSource2D_i::StdMeshers_ImportSource2D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ) + : SALOME::GenericObj_i( thePOA ), + SMESH_Hypothesis_i( thePOA ) +{ + MESSAGE( "StdMeshers_ImportSource2D_i::StdMeshers_ImportSource2D_i" ); + myBaseImpl = new ::StdMeshers_ImportSource2D( theGenImpl->GetANewId(), + theStudyId, + theGenImpl ); + _groupEntries = new SMESH::string_array(); +} + +//============================================================================= +/*! + * StdMeshers_ImportSource2D_i::~StdMeshers_ImportSource2D_i + * + * Destructor + */ +//============================================================================= + +StdMeshers_ImportSource2D_i::~StdMeshers_ImportSource2D_i() +{ + MESSAGE( "StdMeshers_ImportSource2D_i::~StdMeshers_ImportSource2D_i" ); +} + +//============================================================================= +/*! + * SetSourceFaces + */ +//============================================================================= + +void StdMeshers_ImportSource2D_i::SetSourceFaces(const SMESH::ListOfGroups& groups) +{ + MESSAGE( "StdMeshers_ImportSource2D_i::SetSourceFaces" ); + ASSERT( myBaseImpl ); + try + { + std::vector smesh_groups; + std::vector entries; + SALOMEDS::Study_var study = SMESH_Gen_i::GetSMESHGen()->GetCurrentStudy(); + for ( int i = 0; i < groups.length(); ++i ) + if ( SMESH_GroupBase_i* gp_i = SMESH::DownCast( groups[i] )) + { + if ( gp_i->GetType() != SMESH::FACE ) + THROW_SALOME_CORBA_EXCEPTION("Wrong group type", SALOME::BAD_PARAM); + smesh_groups.push_back( gp_i->GetSmeshGroup() ); + + SALOMEDS::SObject_var so = SMESH_Gen_i::GetSMESHGen()->ObjectToSObject(study, groups[i]); + if ( !so->_is_nil()) + { + CORBA::String_var entry = so->GetID(); + entries.push_back( entry.in() ); + } + } + this->GetImpl()->SetGroups( smesh_groups ); + + _groupEntries = new SMESH::string_array; + _groupEntries->length( entries.size ()); + for ( int i = 0; i < entries.size(); ++i ) + _groupEntries[i] = entries[i].c_str(); + } + catch ( SALOME_Exception& S_ex ) + { + THROW_SALOME_CORBA_EXCEPTION( S_ex.what(), SALOME::BAD_PARAM ); + } + + // Update Python script + SMESH::TPythonDump() << _this() << ".SetSourceFaces( " << groups << " )"; +} + +//============================================================================= +/*! + * Return entries of groups + */ +//============================================================================= + +SMESH::string_array* StdMeshers_ImportSource2D_i::GetSourceFaces() +{ + MESSAGE( "StdMeshers_ImportSource2D_i::GetImportSource" ); + SMESH::string_array_var res = new SMESH::string_array( _groupEntries ); + return res._retn(); +} + +//================================================================================ +/*! + * \brief Set to copy mesh and groups + */ +//================================================================================ + +void StdMeshers_ImportSource2D_i::SetCopySourceMesh(CORBA::Boolean toCopyMesh, + CORBA::Boolean toCopyGroups) +{ + GetImpl()->SetCopySourceMesh(toCopyMesh,toCopyGroups); + SMESH::TPythonDump() << _this() << ".SetCopySourceMesh( " + << toCopyMesh << ", " << toCopyGroups << " )"; +} + +//================================================================================ +/*! + * \brief Return "to copy mesh and groups" + */ +//================================================================================ + +void StdMeshers_ImportSource2D_i::GetCopySourceMesh(CORBA::Boolean& toCopyMesh, + CORBA::Boolean& toCopyGroups) +{ + GetImpl()->GetCopySourceMesh(toCopyMesh,toCopyGroups); +} + +//================================================================================ +/*! + * \brief Write parameters in a string + * \retval char* - resulting string + */ +//================================================================================ + +char* StdMeshers_ImportSource2D_i::SaveTo() +{ + std::ostringstream os; + os << " " << _groupEntries->length(); + + SALOMEDS::Study_var study = SMESH_Gen_i::GetSMESHGen()->GetCurrentStudy(); + for ( int i = 0; i < _groupEntries->length(); ++i ) + { + // entry + os << " " << _groupEntries[i]; + + // id + SALOMEDS::SObject_var groupSO = study->FindObjectID( _groupEntries[i] ); + CORBA::Object_var groupObj; + if ( !groupSO->_is_nil() ) + groupObj = groupSO->GetObject(); + StdMeshers_ObjRefUlils::SaveToStream( groupObj, os ); + } + + myBaseImpl->SaveTo( os ); + + return CORBA::string_dup( os.str().c_str() ); +} + +//================================================================================ +/*! + * \brief Retrieve parameters from the string + * \param theStream - the input string + */ +//================================================================================ + +void StdMeshers_ImportSource2D_i::LoadFrom( const char* theStream ) +{ + std::istringstream is( theStream ); + + int nbGroups; + is >> nbGroups; + + _groupEntries = new SMESH::string_array; + _groupEntries->length( nbGroups ); + std::string id, entry; + for ( int i = 0; i < _groupEntries->length(); ++i ) + { + if ( is >> entry ) + _groupEntries[i] = entry.c_str(); + else + { + _groupEntries->length( i ); + is.clear(ios::badbit | is.rdstate()); + break; + } + if ( is >> id ) + _groupIDs.push_back( id ); + else + { + is.clear(ios::badbit | is.rdstate()); + break; + } + } + + myBaseImpl->LoadFrom( is ); +} + +//================================================================================ +/*! + * \brief Retrieve groups by their ids loaded by LoadFrom() + * This is possible only when all meshes are fully loaded + */ +//================================================================================ + +void StdMeshers_ImportSource2D_i::UpdateAsMeshesRestored() +{ + std::vector smesh_groups; + for ( unsigned i = 0; i < _groupIDs.size(); ++i ) + { + std::istringstream is( _groupIDs[i].c_str() ); + SMESH::SMESH_GroupBase_var group = + StdMeshers_ObjRefUlils::LoadObjectFromStream( is ); + if ( SMESH_GroupBase_i* gp_i = SMESH::DownCast( group )) + smesh_groups.push_back( gp_i->GetSmeshGroup() ); + } + GetImpl()->RestoreGroups(smesh_groups); +} + +//============================================================================= +/*! + * StdMeshers_ImportSource2D_i::GetImpl + * + * Get implementation + */ +//============================================================================= + +::StdMeshers_ImportSource2D* StdMeshers_ImportSource2D_i::GetImpl() +{ + MESSAGE( "StdMeshers_ImportSource2D_i::GetImpl" ); + return ( ::StdMeshers_ImportSource2D* )myBaseImpl; +} + +//================================================================================ +/*! + * \brief Verify whether hypothesis supports given entity type + * \param type - dimension (see SMESH::Dimension enumeration) + * \retval CORBA::Boolean - TRUE if dimension is supported, FALSE otherwise + * + * Verify whether hypothesis supports given entity type (see SMESH::Dimension enumeration) + */ +//================================================================================ +CORBA::Boolean StdMeshers_ImportSource2D_i::IsDimSupported( SMESH::Dimension type ) +{ + return type == SMESH::DIM_2D; +} + diff --git a/src/StdMeshers_I/StdMeshers_ImportSource2D_i.hxx b/src/StdMeshers_I/StdMeshers_ImportSource2D_i.hxx new file mode 100644 index 000000000..7f2d71217 --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_ImportSource2D_i.hxx @@ -0,0 +1,74 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_ImportSource2D_i.hxx +// Module : SMESH +// +#ifndef _SMESH_ImportSource2D_I_HXX_ +#define _SMESH_ImportSource2D_I_HXX_ + +#include "SMESH_StdMeshers_I.hxx" + +#include +#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis) + +#include "SMESH_Hypothesis_i.hxx" +#include "StdMeshers_ImportSource.hxx" + +class SMESH_Gen; + +class STDMESHERS_I_EXPORT StdMeshers_ImportSource2D_i: + public virtual POA_StdMeshers::StdMeshers_ImportSource2D, + public virtual SMESH_Hypothesis_i +{ + public: + // Constructor + StdMeshers_ImportSource2D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~StdMeshers_ImportSource2D_i(); + + void SetSourceFaces(const ::SMESH::ListOfGroups& groups); + SMESH::string_array* GetSourceFaces(); + void SetCopySourceMesh(::CORBA::Boolean toCopyMesh, ::CORBA::Boolean toCopyGroups); + void GetCopySourceMesh(::CORBA::Boolean& toCopyMesh, ::CORBA::Boolean& toCopyGroups); + + // Get implementation + ::StdMeshers_ImportSource2D* GetImpl(); + + // Verify whether hypothesis supports given entity type + CORBA::Boolean IsDimSupported( SMESH::Dimension type ); + + // Redefined Persistence + virtual char* SaveTo(); + virtual void LoadFrom( const char* theStream ); + virtual void UpdateAsMeshesRestored(); + + private: + SMESH::string_array_var _groupEntries; + std::vector< std::string > _groupIDs; +}; + +#endif + diff --git a/src/StdMeshers_I/StdMeshers_Import_1D2D_i.cxx b/src/StdMeshers_I/StdMeshers_Import_1D2D_i.cxx new file mode 100644 index 000000000..e2489e54d --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_Import_1D2D_i.cxx @@ -0,0 +1,67 @@ +// Copyright (C) 2007-2010 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 distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// 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 : StdMeshers_Import_1D2D_i.cxx +// Module : SMESH +// +#include "StdMeshers_Import_1D2D_i.hxx" +#include "SMESH_Gen.hxx" + +#include "Utils_CorbaException.hxx" +#include "utilities.h" + +using namespace std; + + +//============================================================================= +/*! + * StdMeshers_Import_1D2D_i::StdMeshers_Import_1D2D_i + */ +//============================================================================= + +StdMeshers_Import_1D2D_i::StdMeshers_Import_1D2D_i (PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl) + : SALOME::GenericObj_i( thePOA ), + SMESH_Hypothesis_i( thePOA ), + SMESH_Algo_i( thePOA ), + SMESH_2D_Algo_i( thePOA ) +{ + MESSAGE( "StdMeshers_Import_1D2D_i::StdMeshers_Import_1D2D_i" ); + myBaseImpl = new ::StdMeshers_Import_1D2D(theGenImpl->GetANewId(), + theStudyId, + theGenImpl ); +} + +//----------------------------------------------------------------------------- + +StdMeshers_Import_1D2D_i::~StdMeshers_Import_1D2D_i() +{ + MESSAGE( "StdMeshers_Import_1D2D_i::~StdMeshers_Import_1D2D_i" ); +} + +//----------------------------------------------------------------------------- + +::StdMeshers_Import_1D2D* StdMeshers_Import_1D2D_i::GetImpl() +{ + MESSAGE( "StdMeshers_Import_1D2D_i::GetImpl" ); + return ( ::StdMeshers_Import_1D2D* )myBaseImpl; +} + diff --git a/src/StdMeshers_I/StdMeshers_Import_1D2D_i.hxx b/src/StdMeshers_I/StdMeshers_Import_1D2D_i.hxx new file mode 100644 index 000000000..8e569661c --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_Import_1D2D_i.hxx @@ -0,0 +1,53 @@ +// Copyright (C) 2007-2010 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 distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// 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 : StdMeshers_Import_1D2D_i.hxx +// Module : SMESH +// +#ifndef _SMESH_Import_1D2D_I_HXX_ +#define _SMESH_Import_1D2D_I_HXX_ + +#include +#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis) + +#include "SMESH_2D_Algo_i.hxx" +#include "StdMeshers_Import_1D2D.hxx" + +class SMESH_Gen; + +class StdMeshers_Import_1D2D_i: + public virtual POA_StdMeshers::StdMeshers_Import_1D2D, + public virtual SMESH_2D_Algo_i +{ +public: + // Constructor + StdMeshers_Import_1D2D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ); + + // Destructor + virtual ~StdMeshers_Import_1D2D_i(); + + // Get implementation + ::StdMeshers_Import_1D2D* GetImpl(); +}; + + +#endif diff --git a/src/StdMeshers_I/StdMeshers_Import_1D_i.cxx b/src/StdMeshers_I/StdMeshers_Import_1D_i.cxx new file mode 100644 index 000000000..02b3e2951 --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_Import_1D_i.cxx @@ -0,0 +1,85 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_Import_1D_i.cxx +// Moved here from SMESH_Import_1D_i.cxx +// Author : Paul RASCLE, EDF +// Module : SMESH +// +#include "StdMeshers_Import_1D_i.hxx" +#include "SMESH_Gen.hxx" + +#include "Utils_CorbaException.hxx" +#include "utilities.h" + +using namespace std; + +//============================================================================= +/*! + * StdMeshers_Import_1D_i::StdMeshers_Import_1D_i + * + * Constructor + */ +//============================================================================= + +StdMeshers_Import_1D_i::StdMeshers_Import_1D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ) + : SALOME::GenericObj_i( thePOA ), + SMESH_Hypothesis_i( thePOA ), + SMESH_Algo_i( thePOA ), + SMESH_1D_Algo_i( thePOA ) +{ + MESSAGE( "StdMeshers_Import_1D_i::StdMeshers_Import_1D_i" ); + myBaseImpl = new ::StdMeshers_Import_1D( theGenImpl->GetANewId(), + theStudyId, + theGenImpl ); +} + +//============================================================================= +/*! + * StdMeshers_Import_1D_i::~StdMeshers_Import_1D_i + * + * Destructor + */ +//============================================================================= + +StdMeshers_Import_1D_i::~StdMeshers_Import_1D_i() +{ + MESSAGE( "StdMeshers_Import_1D_i::~StdMeshers_Import_1D_i" ); +} + +//============================================================================= +/*! + * StdMeshers_Import_1D_i::GetImpl + * + * Get implementation + */ +//============================================================================= + +::StdMeshers_Import_1D* StdMeshers_Import_1D_i::GetImpl() +{ + MESSAGE( "StdMeshers_Import_1D_i::GetImpl" ); + return ( ::StdMeshers_Import_1D* )myBaseImpl; +} + diff --git a/src/StdMeshers_I/StdMeshers_Import_1D_i.hxx b/src/StdMeshers_I/StdMeshers_Import_1D_i.hxx new file mode 100644 index 000000000..d0e1d9752 --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_Import_1D_i.hxx @@ -0,0 +1,54 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&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_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_Import_1D_i.hxx +// Module : SMESH +// +#ifndef _SMESH_Import_1D_I_HXX_ +#define _SMESH_Import_1D_I_HXX_ + +#include "SMESH_StdMeshers_I.hxx" + +#include +#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis) + +#include "SMESH_1D_Algo_i.hxx" +#include "StdMeshers_Import_1D.hxx" + +class STDMESHERS_I_EXPORT StdMeshers_Import_1D_i: + public virtual POA_StdMeshers::StdMeshers_Import_1D, + public virtual SMESH_1D_Algo_i +{ + public: + // Constructor + StdMeshers_Import_1D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~StdMeshers_Import_1D_i(); + + // Get implementation + ::StdMeshers_Import_1D* GetImpl(); +}; + +#endif diff --git a/src/StdMeshers_I/StdMeshers_ProjectionSource1D_i.hxx b/src/StdMeshers_I/StdMeshers_ProjectionSource1D_i.hxx index d416a5787..fbd8b1898 100644 --- a/src/StdMeshers_I/StdMeshers_ProjectionSource1D_i.hxx +++ b/src/StdMeshers_I/StdMeshers_ProjectionSource1D_i.hxx @@ -24,7 +24,6 @@ // File : StdMeshers_ProjectionSource1D_i.hxx // Author : Edward AGAPOV // Module : SMESH -// $Header$ // #ifndef _SMESH_ProjectionSource1D_I_HXX_ #define _SMESH_ProjectionSource1D_I_HXX_ diff --git a/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.cxx b/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.cxx index 090e00ee9..b58d9cbd5 100644 --- a/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.cxx +++ b/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.cxx @@ -19,7 +19,6 @@ // SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses // File : StdMeshers_RadialQuadrangle_1D2D_i.cxx -// Author : Paul RASCLE, EDF // Module : SMESH // #include "StdMeshers_RadialQuadrangle_1D2D_i.hxx" diff --git a/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.hxx b/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.hxx index 85a6e3ae0..1a9fb637c 100644 --- a/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.hxx +++ b/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.hxx @@ -19,9 +19,7 @@ // SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses // File : StdMeshers_RadialQuadrangle_1D2D_i.hxx -// Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #ifndef _SMESH_RadialQuadrangle_1D2D_I_HXX_ #define _SMESH_RadialQuadrangle_1D2D_I_HXX_ diff --git a/src/StdMeshers_I/StdMeshers_Regular_1D_i.cxx b/src/StdMeshers_I/StdMeshers_Regular_1D_i.cxx index 2b75cdc8a..d6fd3cf45 100644 --- a/src/StdMeshers_I/StdMeshers_Regular_1D_i.cxx +++ b/src/StdMeshers_I/StdMeshers_Regular_1D_i.cxx @@ -25,7 +25,6 @@ // Moved here from SMESH_Regular_1D_i.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #include "StdMeshers_Regular_1D_i.hxx" #include "SMESH_Gen.hxx" diff --git a/src/StdMeshers_I/StdMeshers_Regular_1D_i.hxx b/src/StdMeshers_I/StdMeshers_Regular_1D_i.hxx index bfc463de5..02006c455 100644 --- a/src/StdMeshers_I/StdMeshers_Regular_1D_i.hxx +++ b/src/StdMeshers_I/StdMeshers_Regular_1D_i.hxx @@ -25,7 +25,6 @@ // Moved here from SMESH_Regular_1D_i.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #ifndef _SMESH_REGULAR_1D_I_HXX_ #define _SMESH_REGULAR_1D_I_HXX_ diff --git a/src/StdMeshers_I/StdMeshers_i.cxx b/src/StdMeshers_I/StdMeshers_i.cxx index f50fae594..a8f6a9824 100644 --- a/src/StdMeshers_I/StdMeshers_i.cxx +++ b/src/StdMeshers_I/StdMeshers_i.cxx @@ -56,6 +56,8 @@ #include "StdMeshers_SegmentLengthAroundVertex_i.hxx" #include "StdMeshers_MaxLength_i.hxx" #include "StdMeshers_QuadrangleParams_i.hxx" +#include "StdMeshers_ImportSource1D_i.hxx" +#include "StdMeshers_ImportSource2D_i.hxx" #include "StdMeshers_Regular_1D_i.hxx" #include "StdMeshers_MEFISTO_2D_i.hxx" @@ -67,6 +69,8 @@ #include "StdMeshers_CompositeSegment_1D_i.hxx" #include "StdMeshers_UseExisting_1D2D_i.hxx" #include "StdMeshers_RadialQuadrangle_1D2D_i.hxx" +#include "StdMeshers_Import_1D_i.hxx" +#include "StdMeshers_Import_1D2D_i.hxx" template class StdHypothesisCreator_i:public HypothesisCreator_i @@ -141,6 +145,10 @@ STDMESHERS_I_EXPORT aCreator = new StdHypothesisCreator_i; else if (strcmp(aHypName, "QuadrangleParams") == 0) aCreator = new StdHypothesisCreator_i; + else if (strcmp(aHypName, "ImportSource1D") == 0) + aCreator = new StdHypothesisCreator_i; + else if (strcmp(aHypName, "ImportSource2D") == 0) + aCreator = new StdHypothesisCreator_i; // Algorithms else if (strcmp(aHypName, "Regular_1D") == 0) @@ -171,6 +179,10 @@ STDMESHERS_I_EXPORT aCreator = new StdHypothesisCreator_i; else if (strcmp(aHypName, "RadialQuadrangle_1D2D") == 0) aCreator = new StdHypothesisCreator_i; + else if (strcmp(aHypName, "Import_1D") == 0) + aCreator = new StdHypothesisCreator_i; + else if (strcmp(aHypName, "Import_1D2D") == 0) + aCreator = new StdHypothesisCreator_i; else ; return aCreator; -- 2.30.2