Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+15
@@ -0,0 +1,15 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# Small hack to provide the missing smybol to 'typeinfo for std::bad_array_new_length@Qt_5'
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
IF(UNIX)
|
||||
NGL_ADD_LIBRARY(WS SV AAR ArcGISQt5Hack SHARED arcgisqt5hack.cpp arcgisqt5hack.version) # SV,AAR for CES - expand polygon
|
||||
NGL_TARGET_LINK_LIBRARIES(ArcGISQt5Hack PRIVATE "-Wl,--version-script,${CMAKE_CURRENT_SOURCE_DIR}/arcgisqt5hack.version")
|
||||
ELSE()
|
||||
NGL_ADD_LIBRARY(WS SV AAR ArcGISQt5Hack STATIC arcgisqt5hack.cpp) # SV,AAR for CES - expand polygon
|
||||
ENDIF()
|
||||
NGL_INSTALL_TARGET(ArcGISQt5Hack)
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Small hack to provide the missing smybol to 'typeinfo for std::bad_array_new_length@Qt_5'
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#ifdef WIN32
|
||||
__declspec(dllexport) int foo42(int) { return 42;} // just a dummy to get windows build running
|
||||
#else
|
||||
#include <new>
|
||||
|
||||
extern "C++"
|
||||
{
|
||||
__attribute__((visibility("default"))) void operator delete(void* ptr, std::size_t) noexcept
|
||||
{
|
||||
::operator delete(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
Qt_5 {
|
||||
*;
|
||||
};
|
||||
Executable
+587
@@ -0,0 +1,587 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
FIND_PACKAGE(ArcGIS REQUIRED)
|
||||
ADD_SUBDIRECTORY(ArcGISQt5Hack)
|
||||
|
||||
# During development: (instead top CMakeLists.txt"
|
||||
IF(NOT MSVC)
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra")
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra")
|
||||
ENDIF()
|
||||
OPTION(BUILD_SITMAP_UNIT_TESTS "Build situation map unit tests" ON)
|
||||
|
||||
|
||||
SET(GraphicalObjects_SRCS
|
||||
GraphicalObjects/abstract_graphical_object.cpp
|
||||
GraphicalObjects/ellipse_parameters.cpp
|
||||
GraphicalObjects/graphical_object_attributes.h
|
||||
GraphicalObjects/graphical_object_attributes.cpp
|
||||
GraphicalObjects/graphical_object_ellipse.cpp
|
||||
GraphicalObjects/graphical_object_multi_path.cpp
|
||||
GraphicalObjects/graphical_object_path.cpp
|
||||
GraphicalObjects/graphical_object_picture_marker.cpp
|
||||
GraphicalObjects/graphical_object_range.cpp
|
||||
GraphicalObjects/graphical_object_text.cpp
|
||||
GraphicalObjects/tactical_appearance.cpp
|
||||
GraphicalObjects/graphical_object_cube.cpp
|
||||
|
||||
GraphicalObjects/graphical_object_scene_marker.cpp
|
||||
GraphicalObjects/graphical_object_model_scene_marker.cpp
|
||||
GraphicalObjects/graphical_object_renderer_attributes.cpp
|
||||
)
|
||||
SET(GraphicalObjects_HDRS
|
||||
GraphicalObjects/abstract_graphical_object.h
|
||||
GraphicalObjects/ellipse_parameters.h
|
||||
GraphicalObjects/graphical_object_ellipse.h
|
||||
GraphicalObjects/graphical_object_multi_path.h
|
||||
GraphicalObjects/graphical_object_picture_marker.h
|
||||
GraphicalObjects/graphical_object_path.h
|
||||
GraphicalObjects/graphical_object_range.h
|
||||
GraphicalObjects/graphical_object_text.h
|
||||
GraphicalObjects/stub_graphical_object.h
|
||||
GraphicalObjects/tactical_appearance.h
|
||||
GraphicalObjects/graphical_object_cube.h
|
||||
|
||||
GraphicalObjects/graphical_object_scene_marker.h
|
||||
GraphicalObjects/graphical_object_model_scene_marker.h
|
||||
GraphicalObjects/graphical_object_renderer_attributes.cpp
|
||||
)
|
||||
|
||||
QT5_ADD_RESOURCES(GraphicalObjects_SRCS Resources/situation_map.qrc)
|
||||
|
||||
SET(Map_SRCS
|
||||
Map/bounding_box.cpp
|
||||
Map/fill_style.cpp
|
||||
Map/line_style.cpp
|
||||
Map/map.cpp
|
||||
Map/map_notifier.cpp
|
||||
Map/map_settings.cpp
|
||||
Map/map_initializer.cpp
|
||||
Map/object_container.cpp
|
||||
Map/object_factory.cpp
|
||||
Map/operator_map_settings.cpp
|
||||
# Map/point3D.cpp
|
||||
Map/party_id_to_color_functor.cpp
|
||||
# Map/scene_marker_data.cpp
|
||||
Map/situation_map_utils.cpp
|
||||
Map/terrain_profile_parameter.cpp
|
||||
Map/text_style.cpp
|
||||
Map/geometry_model_renderer.cpp
|
||||
Map/viewshed_parameter.cpp
|
||||
)
|
||||
|
||||
SET(Map_HDRS
|
||||
Map/situation_map_ahtc.ini
|
||||
Map/situation_map_defaults.ini
|
||||
Map/situation_map_guez.ini
|
||||
Map/situation_map_qatar.ini
|
||||
Map/situation_map_guez_tablet.ini
|
||||
Map/situation_map_ahtc_tablet.ini
|
||||
Map/abstract_effect_simulation.h
|
||||
Map/abstract_map_object.h
|
||||
Map/bounding_box.h
|
||||
Map/camera.h
|
||||
Map/camera.cpp
|
||||
Map/coord_translation_functor.h
|
||||
# Map/drop_event_manager.h
|
||||
Map/fill_style.h
|
||||
Map/generic_object_factory.h
|
||||
Map/grid.h
|
||||
Map/map.h
|
||||
Map/map_notifier.h
|
||||
Map/map_settings.h
|
||||
Map/map_initializer.h
|
||||
Map/measurement.h
|
||||
Map/layer_factory.h
|
||||
Map/layer_parameter.h
|
||||
Map/layer_parameter.cpp
|
||||
Map/location_display.h
|
||||
Map/line_style.h
|
||||
Map/object_container.h
|
||||
Map/object_factory.h
|
||||
Map/object_indicator.h
|
||||
Map/operator_map_settings.h
|
||||
Map/overview_map_handler.h
|
||||
Map/party_id_to_color_functor.h
|
||||
Map/pixel_based_textbox_handler.h
|
||||
Map/point3D.h
|
||||
# Map/scene_marker_data.cpp
|
||||
Map/sidc_symbol.h
|
||||
Map/sight_fan.h
|
||||
Map/situation_map_utils.h
|
||||
Map/situation_map_types.h
|
||||
Map/terrain_profile_parameter.h
|
||||
Map/terrain_profile.h
|
||||
Map/text_style.h
|
||||
Map/viewpoint2D.h
|
||||
Map/viewpoint2D.cpp
|
||||
Map/viewshed_parameter.h
|
||||
Map/viewshed.h
|
||||
Map/camera.h
|
||||
Map/camera.cpp
|
||||
|
||||
Map/overlay_handler.h
|
||||
Map/geometry_model_renderer.h
|
||||
)
|
||||
|
||||
SET(MapImpl_SRCS
|
||||
MapImpl/abstract_effect_simulation_impl.cpp
|
||||
MapImpl/abstract_effect_simulation_impl.h
|
||||
MapImpl/abstract_map_object_impl.cpp
|
||||
MapImpl/abstract_map_object_impl.h
|
||||
MapImpl/coordinate_translation.cpp
|
||||
MapImpl/coordinate_translation_thread.cpp
|
||||
MapImpl/grid_impl.cpp
|
||||
MapImpl/jump_point_model.cpp
|
||||
MapImpl/jump_point_custom_view.cpp
|
||||
MapImpl/jump_point_widget.cpp
|
||||
MapImpl/logical_layer.cpp
|
||||
MapImpl/layer_factory_impl.cpp
|
||||
MapImpl/layer_control_widget.cpp
|
||||
MapImpl/screen_location_elevation_helper_base.cpp
|
||||
MapImpl/location_display_impl.cpp
|
||||
MapImpl/location_to_elevation_helper.cpp
|
||||
MapImpl/location_to_elevation_bulk.cpp
|
||||
MapImpl/map_impl.cpp
|
||||
MapImpl/map_layer.cpp
|
||||
MapImpl/measurement_impl.cpp
|
||||
MapImpl/object_container_impl.cpp
|
||||
MapImpl/object_indicator_impl.cpp
|
||||
MapImpl/overview_map_handler_impl.cpp
|
||||
MapImpl/pixel_based_textbox_handler_impl.cpp
|
||||
MapImpl/screen_to_location_helper.cpp
|
||||
MapImpl/sidc_symbol_impl.cpp
|
||||
MapImpl/sight_fan_impl.cpp
|
||||
MapImpl/terrain_profile_impl.cpp
|
||||
MapImpl/terrain_profile_processor.cpp
|
||||
# MapImpl/tms_layer.cpp
|
||||
MapImpl/viewshed_base.cpp
|
||||
MapImpl/viewshed_analysis.cpp
|
||||
MapImpl/viewshed_geo_processing.cpp
|
||||
MapImpl/viewshed_base.cpp
|
||||
MapImpl/viewshed_impl.cpp
|
||||
MapImpl/jump_point_namer.cpp
|
||||
|
||||
|
||||
MapImpl/geometry_model_renderer_esri.cpp
|
||||
MapImpl/overlay_handler_impl.cpp
|
||||
)
|
||||
|
||||
SET(MapImpl_HDRS
|
||||
MapImpl/abstract_effect_simulation_impl.h
|
||||
MapImpl/abstract_map_object_impl.h
|
||||
MapImpl/coordinate_translation.h
|
||||
MapImpl/coordinate_translation_thread.h
|
||||
MapImpl/coord_translation_functor_impl.h
|
||||
MapImpl/geometry_model_renderer_esri.h
|
||||
MapImpl/grid_impl.cpp
|
||||
MapImpl/grid_impl.h
|
||||
MapImpl/jump_point_model.h
|
||||
MapImpl/jump_point_custom_view.h
|
||||
MapImpl/jump_point_widget.h
|
||||
MapImpl/logical_layer.h
|
||||
MapImpl/layer_control_widget.h
|
||||
MapImpl/layer_factory_impl.h
|
||||
MapImpl/screen_location_elevation_helper_base.h
|
||||
MapImpl/location_display_impl.h
|
||||
MapImpl/location_to_elevation_helper.h
|
||||
MapImpl/location_to_elevation_bulk.h
|
||||
MapImpl/map_impl.h
|
||||
MapImpl/map_layer.h
|
||||
MapImpl/measurement_impl.h
|
||||
MapImpl/object_container_impl.h
|
||||
MapImpl/object_indicator_impl.h
|
||||
MapImpl/overview_map_handler_impl.h
|
||||
MapImpl/overlay_handler_impl.h
|
||||
MapImpl/pixel_based_textbox_handler_impl.h
|
||||
MapImpl/screen_to_location_helper.h
|
||||
MapImpl/sidc_symbol_impl.h
|
||||
MapImpl/sight_fan_impl.h
|
||||
MapImpl/terrain_profile_impl.h
|
||||
MapImpl/terrain_profile_processor.h
|
||||
# MapImpl/tms_layer.h
|
||||
MapImpl/viewshed_base.h
|
||||
MapImpl/viewshed_analysis.h
|
||||
MapImpl/viewshed_geo_processing.h
|
||||
MapImpl/viewshed_impl.h
|
||||
MapImpl/jump_point_namer.h
|
||||
)
|
||||
|
||||
|
||||
|
||||
SET(MapObj_SRCS
|
||||
MapObjects/geometry.cpp
|
||||
)
|
||||
|
||||
SET(MapObj_HDRS
|
||||
MapObjects/abstract_multi_point_map_object.h
|
||||
MapObjects/abstract_single_point_map_object.h
|
||||
MapObjects/air_support.h
|
||||
MapObjects/area_fire.h
|
||||
MapObjects/biological_agent.h
|
||||
MapObjects/building_outline.h
|
||||
MapObjects/chemical_agent.h
|
||||
MapObjects/cube.h
|
||||
MapObjects/danger_area.h
|
||||
MapObjects/functional_area.h
|
||||
MapObjects/geo_image.h
|
||||
MapObjects/geometry.h
|
||||
MapObjects/hit_line.h
|
||||
MapObjects/line_of_sight.h
|
||||
MapObjects/map_object_attributes.h
|
||||
MapObjects/map_object_indicator.h
|
||||
MapObjects/mine.h
|
||||
MapObjects/mine_field.h
|
||||
MapObjects/nuclear_agent.h
|
||||
MapObjects/participant.h
|
||||
MapObjects/polygon.h
|
||||
MapObjects/polyline.h
|
||||
MapObjects/single_fire.h
|
||||
# MapObjects/single_fire_central.h
|
||||
MapObjects/sound_area.h
|
||||
MapObjects/text.h
|
||||
MapObjects/virtual_mine.h
|
||||
#situation_map_objects_export.h
|
||||
)
|
||||
|
||||
|
||||
SET (LayerAggregation_SRCS
|
||||
LayerAggregation/layer_aggregation_widget.cpp
|
||||
LayerAggregation/participant_aggregation_dialog.cpp
|
||||
)
|
||||
|
||||
SET (LayerAggregation_HDRS
|
||||
LayerAggregation/layer_aggregation_widget.h
|
||||
LayerAggregation/participant_aggregation_dialog.h
|
||||
)
|
||||
|
||||
|
||||
SET(Rubberbands_SRCS
|
||||
Rubberbands/abstract_event_dispatcher.cpp
|
||||
Rubberbands/drawable_ellipse.cpp
|
||||
Rubberbands/drawable_line.cpp
|
||||
Rubberbands/drawable_painter_path.cpp
|
||||
Rubberbands/drawable_smooth_path.cpp
|
||||
Rubberbands/event_delegater.cpp
|
||||
Rubberbands/event_dispatcher.cpp
|
||||
Rubberbands/event_mouse_navigator.cpp
|
||||
Rubberbands/gestures.cpp
|
||||
Rubberbands/rubberband_base.cpp
|
||||
Rubberbands/rubberband.cpp
|
||||
Rubberbands/rubberband_3d.cpp
|
||||
Rubberbands/rubberband_arrow.cpp
|
||||
Rubberbands/rubberband_corridor.cpp
|
||||
Rubberbands/rubberband_drawable.cpp
|
||||
Rubberbands/rubberband_factory.cpp
|
||||
Rubberbands/rubberband_frame_handle.cpp
|
||||
Rubberbands/rubberband_free_hand.cpp
|
||||
Rubberbands/rubberband_ellipse.cpp
|
||||
Rubberbands/rubberband_ellipse_handle.cpp
|
||||
Rubberbands/rubberband_handle.cpp
|
||||
Rubberbands/rubberband_handle_proxy.cpp
|
||||
Rubberbands/rubberband_internal.cpp
|
||||
Rubberbands/rubberband_line_handle.cpp
|
||||
Rubberbands/rubberband_multi_point_feature.cpp
|
||||
Rubberbands/rubberband_multi_ellipse_feature.cpp
|
||||
Rubberbands/rubberband_multi_point_feature_3d.cpp
|
||||
Rubberbands/rubberband_point_handle.cpp
|
||||
Rubberbands/rubberband_point_cluster.cpp
|
||||
Rubberbands/rubberband_point_feature.cpp
|
||||
Rubberbands/rubberband_point_feature_3d.cpp
|
||||
Rubberbands/rubberband_polyline_width.cpp
|
||||
Rubberbands/rubberband_rectangle.cpp
|
||||
Rubberbands/rubberband_smooth_line.cpp
|
||||
Rubberbands/rubberband_state_select.cpp
|
||||
Rubberbands/rubberband_transform.cpp
|
||||
Rubberbands/rubberband_transform_move.cpp
|
||||
Rubberbands/rubberband_transform_rotate.cpp
|
||||
Rubberbands/rubberband_transform_scale.cpp
|
||||
Rubberbands/transient_tactical_symbol.cpp
|
||||
)
|
||||
|
||||
SET(Rubberbands_HDRS
|
||||
Rubberbands/abstract_event_dispatcher.h
|
||||
Rubberbands/drawable_ellipse.h
|
||||
Rubberbands/drawable_line.h
|
||||
Rubberbands/drawable_painter_path.h
|
||||
Rubberbands/drawable_smooth_path.h
|
||||
Rubberbands/event_delegater.h
|
||||
Rubberbands/event_dispatcher.h
|
||||
Rubberbands/event_mouse_navigator.h
|
||||
Rubberbands/gestures.h
|
||||
Rubberbands/rubberband_free_hand.h
|
||||
Rubberbands/rubberband_base.h
|
||||
Rubberbands/rubberband_base_internal.h
|
||||
Rubberbands/rubberband.h
|
||||
Rubberbands/rubberband_3d.h
|
||||
Rubberbands/rubberband_arrow.h
|
||||
Rubberbands/rubberband_corridor.h
|
||||
Rubberbands/rubberband_drawable.h
|
||||
Rubberbands/rubberband_ellipse.h
|
||||
Rubberbands/rubberband_ellipse_handle.h
|
||||
Rubberbands/rubberband_factory.h
|
||||
Rubberbands/rubberband_frame_handle.h
|
||||
Rubberbands/rubberband_handle.h
|
||||
Rubberbands/rubberband_handle_proxy.h
|
||||
Rubberbands/rubberband_internal.h
|
||||
Rubberbands/rubberband_line_handle.h
|
||||
Rubberbands/rubberband_multi_point_feature.h
|
||||
Rubberbands/rubberband_multi_ellipse_feature.h
|
||||
Rubberbands/rubberband_multi_point_feature_3d.h
|
||||
Rubberbands/rubberband_point_cluster.h
|
||||
Rubberbands/rubberband_point_feature.h
|
||||
Rubberbands/rubberband_point_feature_3d.h
|
||||
Rubberbands/rubberband_point_handle.h
|
||||
Rubberbands/rubberband_polyline_width.h
|
||||
Rubberbands/rubberband_rectangle.h
|
||||
Rubberbands/rubberband_smooth_line.h
|
||||
Rubberbands/rubberband_state_select.h
|
||||
Rubberbands/rubberband_transform.h
|
||||
Rubberbands/rubberband_transform_move.h
|
||||
Rubberbands/rubberband_transform_rotate.h
|
||||
Rubberbands/rubberband_transform_scale.h
|
||||
Rubberbands/transient_tactical_symbol.h
|
||||
)
|
||||
|
||||
SET(Utils_SRCS
|
||||
situation_map_export.h
|
||||
Utils/movement_track.cpp
|
||||
Utils/movement_track_manager.cpp
|
||||
Utils/terrain_profile_dialog.cpp
|
||||
)
|
||||
|
||||
SET(Utils_HDRS
|
||||
Utils/movement_track.h
|
||||
Utils/movement_track_manager.h
|
||||
Utils/terrain_profile_dialog.h
|
||||
)
|
||||
|
||||
|
||||
|
||||
SET(MathUtils_SRCS
|
||||
MathUtils/clipper.cpp
|
||||
MathUtils/curve.cpp
|
||||
MathUtils/geometry_engine.cpp
|
||||
MathUtils/matrix2d.cpp
|
||||
MathUtils/path_rasterer.cpp
|
||||
MathUtils/simple_helper.cpp
|
||||
)
|
||||
|
||||
SET(MathUtils_HDRS
|
||||
MathUtils/clipper.hpp
|
||||
MathUtils/curve.h
|
||||
MathUtils/geometry_engine.h
|
||||
MathUtils/matrix2d.h
|
||||
MathUtils/math_const.h
|
||||
MathUtils/path_rasterer.h
|
||||
MathUtils/simple_helper.h
|
||||
)
|
||||
|
||||
NGL_WRAP_UI(Utils_HDRS
|
||||
MapImpl/jump_point_custom_view.ui
|
||||
Utils/terrain_profile_dialog.ui
|
||||
)
|
||||
|
||||
NGL_WRAP_UI(MapImpl_SRCS
|
||||
MapImpl/jump_point_namer.ui
|
||||
)
|
||||
|
||||
|
||||
SOURCE_GROUP(GraphicalObjects FILES ${GraphicalObjects_SRCS} ${GraphicalObjects_HDRS})
|
||||
SOURCE_GROUP(Map FILES ${Map_SRCS} ${Map_HDRS} ${MapImpl_SRCS} ${MapImpl_HDRS})
|
||||
SOURCE_GROUP(MapObjects FILES ${MapObj_HDRS})
|
||||
SOURCE_GROUP(LayerAggregation FILES ${LayerAggregation_SRCS} ${LayerAggregation_HDRS})
|
||||
SOURCE_GROUP(Rubberband FILES ${Rubberbands_SRCS} ${Rubberbands_HDRS})
|
||||
SOURCE_GROUP(Utils FILES ${Utils_SRCS} ${Utils_HDRS})
|
||||
SOURCE_GROUP(MathUtils FILES ${MathUtils_SRCS} ${MathUtils_HDRS})
|
||||
SOURCE_GROUP(SideBar FILES ${SideBar_SRCS} ${SideBar_HDRS})
|
||||
|
||||
|
||||
NGL_ADD_LIBRARY(WS situationMap SHARED
|
||||
# ${FunctionDialog_SRCS}
|
||||
${Map_SRCS} ${Map_HDRS} ${MapImpl_SRCS}
|
||||
${MapObj_SRCS} ${MapObj_HDRS}
|
||||
${GraphicalObjects_SRCS} ${GraphicalObjects_HDRS}
|
||||
${LayerAggregation_SRCS} ${LayerAggregation_HDRS}
|
||||
${Rubberbands_SRCS}
|
||||
${Utils_SRCS} ${Utils_HDRS}
|
||||
${MathUtils_SRCS} ${MathUtils_HDRS}
|
||||
)
|
||||
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(situationMap
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
)
|
||||
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(situationMap
|
||||
PRIVATE
|
||||
NGLLogger
|
||||
ArcGIS::ArcGIS
|
||||
Qt5::Concurrent
|
||||
Qt5::Network
|
||||
Qt5::PrintSupport
|
||||
LtsCoordTrans
|
||||
ArcGISQt5Hack
|
||||
PUBLIC
|
||||
Qt5::Core
|
||||
Qt5::Widgets
|
||||
LtsUtilsCoreHeaderOnly # QPoint3D
|
||||
LtsWidgets
|
||||
LtsDataView
|
||||
situationMapCommon
|
||||
situationMapElevationMap
|
||||
situationMapSideBar
|
||||
advancedSymbology
|
||||
situationMapGeometryModel
|
||||
ngltools
|
||||
)
|
||||
|
||||
# Copy on LIBchanges:
|
||||
IF(TARGET situationMap)
|
||||
SET(SYMBOLE_CSV symbole2.csv)
|
||||
ADD_CUSTOM_COMMAND(TARGET situationMap POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
ARGS -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/FunctionDialog/${SYMBOLE_CSV} $<TARGET_FILE_DIR:situationMap>/${SYMBOLE_CSV}
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
# copy ini to build-dir/share/Lts/situation_map/:
|
||||
SET(INI_DEST_DIR ${CMAKE_BINARY_DIR}/share/Lts/situation_map)
|
||||
|
||||
SET(SITUATIONMAPSETTINGS_INI situation_map_defaults.ini)
|
||||
SET(SITUATIONMAPSETTINGS_INI_PATH Map/${SITUATIONMAPSETTINGS_INI})
|
||||
ADD_CUSTOM_COMMAND(TARGET situationMap POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
ARGS -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${SITUATIONMAPSETTINGS_INI_PATH} ${INI_DEST_DIR}/${SITUATIONMAPSETTINGS_INI}
|
||||
)
|
||||
|
||||
SET(SITUATIONMAPSETTINGS_INI situation_map_defaults.ini)
|
||||
SET(SITUATIONMAPSETTINGS_INI_PATH Map/${SITUATIONMAPSETTINGS_INI})
|
||||
|
||||
#check if we need to change it
|
||||
IF(BUILD_RPM AND DEFINED _pname)
|
||||
|
||||
IF(UNIX AND "${_pname}" STREQUAL "guez")
|
||||
MESSAGE("Install situationmap ini for GUEZ")
|
||||
SET(SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_guez.ini)
|
||||
|
||||
SET(TABLET_SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_guez_tablet.ini)
|
||||
|
||||
ElseIF(UNIX AND "${_pname}" STREQUAL "ahtc")
|
||||
MESSAGE("Install situationmap ini for AHTC")
|
||||
SET(SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_ahtc.ini)
|
||||
|
||||
SET(TABLET_SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_ahtc_tablet.ini)
|
||||
|
||||
ElseIF(UNIX AND "${_pname}" STREQUAL "l400p2")
|
||||
MESSAGE("Install situationmap ini for L400P2")
|
||||
SET(SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_land400.ini)
|
||||
|
||||
SET(TABLET_SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_l400p2_tablet.ini)
|
||||
|
||||
ElseIF(UNIX AND "${_pname}" STREQUAL "qatar")
|
||||
MESSAGE("Install situationmap ini for Qatar")
|
||||
SET(SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_qatar.ini)
|
||||
|
||||
SET(TABLET_SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_qatar_tablet.ini)
|
||||
|
||||
ElseIF(UNIX AND "${_pname}" STREQUAL "qatarmout")
|
||||
MESSAGE("Install situationmap ini for Qatar Mout")
|
||||
SET(SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_qatarmout.ini)
|
||||
|
||||
SET(TABLET_SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_qatar_tablet.ini)
|
||||
|
||||
ElseIF(UNIX AND "${_pname}" STREQUAL "commaster")
|
||||
MESSAGE("Install situationmap ini for ComMaster/Luxemburg")
|
||||
SET(SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_luxemburg.ini)
|
||||
|
||||
SET(TABLET_SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_luxemburg_tablet.ini)
|
||||
|
||||
|
||||
ENDIF()
|
||||
|
||||
|
||||
ENDIF()
|
||||
|
||||
#now that we set the situation map ini if neccecsary we install it depending of the tablet build or not
|
||||
IF(TABLET_MODE)
|
||||
NGL_INSTALL(WS FILES ${TABLET_SITUATIONMAPSETTINGS_INI_PATH} DESTINATION "./share/Lts/situation_map" RENAME ${SITUATIONMAPSETTINGS_INI})
|
||||
ELSE()
|
||||
NGL_INSTALL(WS FILES ${SITUATIONMAPSETTINGS_INI_PATH} DESTINATION "./share/Lts/situation_map" RENAME ${SITUATIONMAPSETTINGS_INI})
|
||||
ENDIF()
|
||||
|
||||
ENDIF()
|
||||
|
||||
IF(BUILD_TESTING AND BUILD_SITMAP_UNIT_TESTS)
|
||||
|
||||
NGL_ADD_LIBRARY(WS NO_TRANSLATION situationMap_static STATIC
|
||||
${FunctionDialog_SRCS}
|
||||
${Map_SRCS} ${Map_HDRS} ${MapImpl_SRCS}
|
||||
${MapObj_SRCS} ${MapObj_HDRS}
|
||||
${GraphicalObjects_SRCS}
|
||||
${Rubberbands_SRCS}
|
||||
${Utils_SRCS} ${Utils_HDRS}
|
||||
${MathUtils_SRCS} ${MathUtils_HDRS}
|
||||
)
|
||||
NGL_TARGET_COMPILE_DEFINITIONS(situationMap_static PUBLIC "SITUATIONMAP_EXPORT=")
|
||||
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(situationMap_static
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(situationMap_static
|
||||
PRIVATE
|
||||
NGLLogger
|
||||
Qt5::Concurrent
|
||||
Qt5::Network
|
||||
Qt5::PrintSupport
|
||||
LtsCoordTrans
|
||||
ArcGISQt5Hack
|
||||
PUBLIC
|
||||
Qt5::Core
|
||||
Qt5::Widgets
|
||||
LtsUtilsCoreHeaderOnly # QPoint3D
|
||||
LtsWidgets
|
||||
LtsDataView
|
||||
situationMapCommon
|
||||
situationMapElevationMap
|
||||
situationMapSideBar
|
||||
advancedSymbology_static
|
||||
situationMapGeometryModel
|
||||
ngltools
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
NGL_INSTALL_TARGET(situationMap)
|
||||
|
||||
|
||||
# Choose logical order instead of alphabetical.
|
||||
# UnitTest should be performed BEFORE ModuleTest
|
||||
ADD_SUBDIRECTORY(Common)
|
||||
ADD_SUBDIRECTORY(ElevationMap)
|
||||
ADD_SUBDIRECTORY(Symbology)
|
||||
ADD_SUBDIRECTORY(SymbologyGui)
|
||||
ADD_SUBDIRECTORY(SymbologyXML)
|
||||
ADD_SUBDIRECTORY(MapObjectsImpl)
|
||||
#ADD_SUBDIRECTORY(LocalSrv)
|
||||
|
||||
ADD_SUBDIRECTORY(SideBar)
|
||||
ADD_SUBDIRECTORY(FunctionDialog)
|
||||
ADD_SUBDIRECTORY(GeometryModel)
|
||||
ADD_SUBDIRECTORY(Portal)
|
||||
|
||||
ADD_SUBDIRECTORY(Tests)
|
||||
|
||||
IF(BUILD_SITMAP_UNIT_TESTS)
|
||||
ADD_SUBDIRECTORY(EvalApps)
|
||||
ADD_SUBDIRECTORY(UnitTests)
|
||||
ADD_SUBDIRECTORY(UnitTestsGeoModel)
|
||||
ADD_SUBDIRECTORY(ModuleTests)
|
||||
ENDIF()
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
# LIBRARY
|
||||
|
||||
SET(Common_SRCS
|
||||
id_handler.cpp
|
||||
referenced.cpp
|
||||
resource_path.cpp
|
||||
situation_map_logging.cpp
|
||||
)
|
||||
|
||||
SET (Common_HDRS
|
||||
exception.h
|
||||
id_handler.h
|
||||
ref_pointer.h
|
||||
referenced.h
|
||||
resource_path.h
|
||||
situation_map_common_export.h
|
||||
situation_map_logging.h
|
||||
simple_value.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Common FILES ${Common_SRCS} ${Common_HDRS})
|
||||
|
||||
NGL_ADD_LIBRARY(WS AAR HLA SV situationMapCommon SHARED ${Common_SRCS} ${Common_HDRS})
|
||||
NGL_TARGET_LINK_LIBRARIES(situationMapCommon
|
||||
PRIVATE
|
||||
ngltools
|
||||
PUBLIC
|
||||
NGLLogger
|
||||
Qt5::Core
|
||||
)
|
||||
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(situationMapCommon
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
)
|
||||
|
||||
|
||||
NGL_INSTALL_TARGET(situationMapCommon)
|
||||
Executable
+93
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Implementation of Splines
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Joerg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** 19.06.2012, JT : Urversion for use in VIntel project
|
||||
** 12.08.2015, JT : adapted to SituationMap
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <QtCore/QString>
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
/**
|
||||
\class Exception exception.h
|
||||
\brief Basisklasse for Exception-Handling
|
||||
|
||||
The class Exception defines a very simple exception handler, that will be able to return
|
||||
a string message when an exception is thrown
|
||||
*/
|
||||
|
||||
class Exception
|
||||
{
|
||||
public:
|
||||
|
||||
Exception()
|
||||
: _message(QLatin1String("Error"))
|
||||
{}
|
||||
|
||||
Exception(const Exception &) = default;
|
||||
|
||||
explicit Exception(const QString &msg)
|
||||
: _message(msg)
|
||||
{}
|
||||
|
||||
|
||||
// explicit is not used here because
|
||||
// throw SituationMap::Exception(__FILE__, __LINE__, "Message" );
|
||||
// will become more complicated
|
||||
|
||||
Exception(const char *Source
|
||||
, unsigned int lineNo
|
||||
, const char *msg)
|
||||
: Exception(QLatin1String(Source), lineNo, QLatin1String(msg))
|
||||
{}
|
||||
|
||||
Exception(const char *Source
|
||||
, unsigned int lineNo
|
||||
, const QString &msg)
|
||||
: Exception(QLatin1String(Source), lineNo, msg)
|
||||
{}
|
||||
|
||||
Exception(const QString &Source
|
||||
, unsigned int lineNo
|
||||
, const QString &msg)
|
||||
: _message(QStringLiteral("\"%1\" in %2 at %3").arg(msg, Source).arg(lineNo))
|
||||
{}
|
||||
|
||||
~Exception() = default;
|
||||
Exception &operator = (const Exception &e) = default;
|
||||
|
||||
|
||||
QString getMessage() const { return _message; } //!< returns a specific error message as QString
|
||||
|
||||
protected:
|
||||
|
||||
QString _message;
|
||||
|
||||
};
|
||||
|
||||
} // namespace SituationMap
|
||||
+345
@@ -0,0 +1,345 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Simple Id Handler
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Linux, Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** ??.??.1994, JT : First edition for use with Tcl/Tk in START Feature Editor fe
|
||||
** 16.08.2004, JT : Refactoring for use in Geo-Map Library GeISiR
|
||||
** 11.05.2015, JT : Refactoring for use with Qt5
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "id_handler.h"
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
#include "referenced.h"
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
const IdHandler::UniqueId IdHandler::BadId = static_cast<IdHandler::UniqueId>(-1);
|
||||
|
||||
|
||||
bool IdHandler::isIdValid(const UniqueId &id) { return id != BadId; }
|
||||
|
||||
|
||||
IdHandler::IdHandler(unsigned int maxItems, unsigned int blockS)
|
||||
: _blockSize(blockS)
|
||||
, _maxIds(maxItems)
|
||||
, _freeIds(maxItems)
|
||||
, _firstFree(BadId)
|
||||
, _lastAlloc(BadId)
|
||||
, _notify(getLogger("IdHandler"))
|
||||
, _idVector()
|
||||
{
|
||||
} // IdHandler::IdHandler
|
||||
|
||||
|
||||
IdHandler::~IdHandler()
|
||||
{
|
||||
if (!_idVector.isEmpty())
|
||||
{
|
||||
if (_lastAlloc != BadId)
|
||||
{
|
||||
for (UniqueId i = 0; i <= _lastAlloc; ++i)
|
||||
_idVector[i] = nullptr;
|
||||
}
|
||||
_maxIds = 0;
|
||||
_freeIds = 0;
|
||||
_firstFree = BadId;
|
||||
_lastAlloc = BadId;
|
||||
}
|
||||
} // IdHandler::~IdHandler
|
||||
|
||||
|
||||
bool IdHandler::initMemHandler()
|
||||
{
|
||||
if (_idVector.empty())
|
||||
{
|
||||
_idVector.resize(_maxIds);
|
||||
_freeIds = _maxIds;
|
||||
_firstFree = 0;
|
||||
_lastAlloc = BadId;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} // IdHandler::initMemHandler
|
||||
|
||||
|
||||
void IdHandler::lookForNextFreeId()
|
||||
{
|
||||
++_firstFree;
|
||||
|
||||
while (_firstFree < _lastAlloc)
|
||||
{
|
||||
if (!_idVector[_firstFree]) break;
|
||||
++_firstFree;
|
||||
}
|
||||
if (_firstFree >= _lastAlloc) _firstFree = _maxIds;
|
||||
|
||||
} //IdHandler::lookForNextFreeId
|
||||
|
||||
|
||||
bool IdHandler::valid() const
|
||||
{
|
||||
return ((static_cast<quint32>(_idVector.size()) == _maxIds) && (_firstFree != BadId));
|
||||
} // IdHandler::valid
|
||||
|
||||
|
||||
unsigned int IdHandler::countReservedIds() const { return _maxIds; }
|
||||
unsigned int IdHandler::countUsedIds() const { return _maxIds - _freeIds; }
|
||||
unsigned int IdHandler::countFreeIds() const { return _freeIds; }
|
||||
|
||||
bool IdHandler::resize(quint32 maxItems)
|
||||
{
|
||||
if (initMemHandler())
|
||||
{
|
||||
if (maxItems > static_cast<quint32>(_idVector.size()))
|
||||
{
|
||||
_freeIds += maxItems - _maxIds;
|
||||
_maxIds = maxItems;
|
||||
_idVector.resize(_maxIds);
|
||||
}
|
||||
}
|
||||
return (static_cast<quint32>(_idVector.size()) == _maxIds);
|
||||
} // IdHandler::resize
|
||||
|
||||
|
||||
IdHandler::UniqueId IdHandler::createId(AccessableId *idPtr)
|
||||
{
|
||||
initMemHandler();
|
||||
|
||||
UniqueId id((_lastAlloc == BadId) ? 0 : _lastAlloc + 1);
|
||||
|
||||
if (id < _maxIds)
|
||||
{
|
||||
_idVector[id] = idPtr;
|
||||
_lastAlloc = id;
|
||||
if (_firstFree == id) ++_firstFree;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_firstFree >= _maxIds)
|
||||
{
|
||||
resize(_maxIds + _blockSize);
|
||||
|
||||
if (id < _maxIds)
|
||||
{
|
||||
_idVector[id] = idPtr;
|
||||
_lastAlloc = id;
|
||||
if (_firstFree == id)
|
||||
++_firstFree;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(_notify)
|
||||
<< LOGFUNCTION
|
||||
<< QStringLiteral("Id table overflow, object <%1> of type <%2>, reserved Ids %3")
|
||||
.arg(reinterpret_cast<qulonglong>(idPtr), 0, 16)
|
||||
.arg(QLatin1String(typeid(idPtr).name()))
|
||||
.arg(_maxIds);
|
||||
|
||||
return BadId;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
id = _firstFree;
|
||||
_idVector[id] = idPtr;
|
||||
|
||||
lookForNextFreeId();
|
||||
}
|
||||
}
|
||||
_freeIds--;
|
||||
return (id);
|
||||
} // IdHandler::createId
|
||||
|
||||
|
||||
bool IdHandler::reserveId(UniqueId id, AccessableId *idPtr)
|
||||
{
|
||||
initMemHandler();
|
||||
|
||||
if (!valid())
|
||||
{
|
||||
ERROR_LOG(_notify)
|
||||
<< LOGFUNCTION
|
||||
<< QStringLiteral("IdHandler is not initialzed, object <%1> of type <%2> ")
|
||||
.arg(reinterpret_cast<qulonglong>(idPtr), 0, 16)
|
||||
.arg(QLatin1String(typeid(idPtr).name()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (id == BadId)
|
||||
{
|
||||
ERROR_LOG(_notify)
|
||||
<< LOGFUNCTION
|
||||
<< " Requested id is bad id <" << id << ">";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (id >= _maxIds)
|
||||
{
|
||||
if (!resize((((id + 1) / _blockSize) + 1) * _blockSize))
|
||||
{
|
||||
ERROR_LOG(_notify)
|
||||
<< LOGFUNCTION
|
||||
<< QStringLiteral("Requested id is to large, id <%1> object <%2> of type <%3>.")
|
||||
.arg(id)
|
||||
.arg(reinterpret_cast<qulonglong>(idPtr), 0, 16)
|
||||
.arg(QLatin1String(typeid(idPtr).name()));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (_idVector[id])
|
||||
{
|
||||
ERROR_LOG(_notify)
|
||||
<< LOGFUNCTION
|
||||
<< QStringLiteral("Requested id is already in use, object <%1> of type <%2>.")
|
||||
.arg(reinterpret_cast<qulonglong>(idPtr), 0, 16)
|
||||
.arg(QLatin1String(typeid(idPtr).name()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_idVector[id] = idPtr;
|
||||
|
||||
if ((_lastAlloc == BadId) || (id > _lastAlloc)) _lastAlloc = id;
|
||||
if (id == _firstFree)
|
||||
{
|
||||
++_firstFree;
|
||||
lookForNextFreeId();
|
||||
}
|
||||
_freeIds--;
|
||||
return true;
|
||||
} // IdHandler::reserveId
|
||||
|
||||
|
||||
bool IdHandler::freeId(UniqueId id)
|
||||
{
|
||||
if (valid() && (_lastAlloc != BadId) && (id != BadId))
|
||||
{
|
||||
if (id <= _lastAlloc)
|
||||
{
|
||||
if (_idVector[id])
|
||||
{
|
||||
_idVector[id] = nullptr;
|
||||
if (id < _firstFree) _firstFree = id;
|
||||
if (id == _lastAlloc)
|
||||
{
|
||||
/* ---------------------------------------------------------
|
||||
* Last allocated id is now free. Search new lastAlloc ...
|
||||
* ---------------------------------------------------------- */
|
||||
if (_lastAlloc > 0)
|
||||
{
|
||||
--_lastAlloc;
|
||||
|
||||
while (!_idVector[_lastAlloc])
|
||||
{
|
||||
if (_lastAlloc < 1)
|
||||
{
|
||||
_lastAlloc = BadId;
|
||||
break;
|
||||
}
|
||||
else --_lastAlloc;
|
||||
} // while
|
||||
}
|
||||
else _lastAlloc = BadId;
|
||||
}
|
||||
_freeIds++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(_notify)
|
||||
<< LOGFUNCTION
|
||||
<< "Id is not in use, id <" << id << ">";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (id != BadId)
|
||||
{
|
||||
ERROR_LOG(_notify)
|
||||
<< LOGFUNCTION
|
||||
<< "IdHandler is not initialzed.";
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(_notify)
|
||||
<< LOGFUNCTION
|
||||
<< "Bad id, id <" << id << ">";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} // IdHandler::freeId
|
||||
|
||||
|
||||
IdHandler::AccessableId *IdHandler::accessId(UniqueId id) const
|
||||
{
|
||||
if (valid())
|
||||
{
|
||||
if ((id != BadId) && (id <= _lastAlloc))
|
||||
return _idVector[id].get();
|
||||
else
|
||||
{
|
||||
ERROR_LOG(_notify)
|
||||
<< LOGFUNCTION
|
||||
<< "Bad id or id is not in use, id <" << id << ">";
|
||||
#ifdef UseDebugBreaks
|
||||
#ifdef WIN32
|
||||
#ifdef _DEBUG
|
||||
__asm int 3
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(_notify)
|
||||
<< LOGFUNCTION
|
||||
<< "IdHandler is not initialzed";
|
||||
}
|
||||
return nullptr;
|
||||
} // IdHandler::accessId
|
||||
|
||||
|
||||
bool IdHandler::isIdInUse(UniqueId id) const
|
||||
{
|
||||
if (valid())
|
||||
{
|
||||
if ((id != BadId) && (id <= _lastAlloc))
|
||||
return (_idVector[id].get() != nullptr);
|
||||
}
|
||||
return false;
|
||||
} // IdHandler::isIdInUse
|
||||
|
||||
|
||||
} // SituationMap
|
||||
|
||||
|
||||
|
||||
Executable
+120
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Simple Id Handler
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Linux, Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** ??.??.1994, JT : First edition for use with Tcl/Tk in START Feature Editor fe
|
||||
** 16.08.2004, JT : Refactoring for use in Geo-Map Library GeISiR
|
||||
** 11.05.2015, JT : Refactoring for use with Qt5
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include <Map/situation_map_types.h>
|
||||
#include "referenced.h"
|
||||
#include "ref_pointer.h"
|
||||
#include "situation_map_logging.h"
|
||||
|
||||
#include "situation_map_common_export.h"
|
||||
#include <QVector>
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
/**
|
||||
@class IdHandler id_handler.h
|
||||
@brief Simple IdHandler to map id's to data pointers
|
||||
|
||||
IdHandler is a class to manage integer ids and map them to data pointers. The IdHandler stores
|
||||
the data pointer in a vector container. The index of the data pointer in this vector is used as
|
||||
id value. If the vector gets out of size new vector elements will be added automaticaly. This
|
||||
will be done blockwises. The initial size of the vector and the block size can be set as
|
||||
parameter of IdHandler ctor. The default values are 10000 for the initial vector size and 1000
|
||||
for the block size.
|
||||
*/
|
||||
class SITUATIONMAPCOMMON_EXPORT IdHandler
|
||||
{
|
||||
public:
|
||||
|
||||
using AccessableId = Referenced;
|
||||
using UniqueId = quint32; // see UniqueMapId @ situation_map_types.h
|
||||
|
||||
static const UniqueId BadId;
|
||||
|
||||
static bool isIdValid(const UniqueId &id); //!< Checks if the \c id is not a BadId
|
||||
|
||||
IdHandler(const IdHandler &) = delete;
|
||||
IdHandler &operator = (const IdHandler &) = delete;
|
||||
|
||||
/**
|
||||
@brief Construction of IdHandler
|
||||
|
||||
Initialize IdHandler instances. The vector container to store data pointers is
|
||||
reserved with \c maxItems. If the vector gets out of size new vector elements
|
||||
will be added automaticaly
|
||||
|
||||
@param maxItems Initial size of the vector container to store the data pointer.
|
||||
@param blockS Block size is used when the vector container will be extended.
|
||||
*/
|
||||
IdHandler(unsigned int maxItems = 10000, unsigned int blockS = 1000);
|
||||
|
||||
/**
|
||||
@brief Destruction of IdHandler
|
||||
*/
|
||||
virtual ~IdHandler();
|
||||
|
||||
bool valid() const; //!< Checks if IdHandler is valid
|
||||
|
||||
quint32 countReservedIds() const; //!< Returns count of reserved ids.
|
||||
quint32 countUsedIds() const; //!< Returns count of used ids.
|
||||
quint32 countFreeIds() const; //!< Returnes count of free ids
|
||||
|
||||
bool resize(quint32 maxItems); //!< Resize idMem to store now maxItems ids. Returns true on success.
|
||||
|
||||
UniqueId createId(AccessableId *); //!< Create new \c id and returns this new id.
|
||||
bool reserveId(UniqueId id, AccessableId *); //!< Reserve \c id if the id is unused. Returns true if \c id is not already in use and reservation of \c id is successful elsewise false.
|
||||
bool freeId(UniqueId id); //!< Frees \c id. Returns true on success elsewise false.
|
||||
|
||||
AccessableId *accessId(UniqueId id) const; //!< Returns pointer to object for \c id. Returns pointer on success elsewise \c nullptr.
|
||||
bool isIdInUse(UniqueId id) const; //!< Checks if a id is already in use.
|
||||
|
||||
protected:
|
||||
|
||||
quint32 _blockSize;
|
||||
quint32 _maxIds;
|
||||
quint32 _freeIds;
|
||||
UniqueId _firstFree;
|
||||
UniqueId _lastAlloc;
|
||||
LOGGER_T _notify;
|
||||
|
||||
mutable QVector<RefPointer<AccessableId>> _idVector;
|
||||
|
||||
private:
|
||||
|
||||
bool initMemHandler();
|
||||
void lookForNextFreeId();
|
||||
|
||||
}; /* IdHandler */
|
||||
|
||||
} /* SituationMap */
|
||||
|
||||
Executable
+226
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Base class for reference counted objects
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Umgebung: Intel-PC
|
||||
** Software-Umgebung: Linux, Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Pgrm-Sprache ....: C++ 11
|
||||
**
|
||||
** HIER/SACHN ......: P: -- ---- - --- QE
|
||||
**
|
||||
** Version .........: $Revision$
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Autor ...........: Nikolaus Hanekamp, SEDG, Tel. 2906
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notizen .........:
|
||||
**
|
||||
** 18.08.2004, NH : Urversion
|
||||
** 13.05.2015, JT : Refactoring for use with Qt5, ArcGIS 10.2.5
|
||||
** adding methodes according to std::share_ptr like reset
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Copyright (C) 2004 Rheinmetall Defence Electronics GmbH, D-28309 BREMEN
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "referenced.h"
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
/**
|
||||
@class RefPointer ref_pointer.h
|
||||
@brief Smart pointer for handling referenced counted objects
|
||||
|
||||
Simple class template to implement reference counted pointers or smart pointers. The RefPointer class controls the
|
||||
reference counter of the object \c T the pointer points to. The class \c T have to be derived from class \c Referenced,
|
||||
where the reference counter member variable is located. In case of this reference counter gets zero delete will be called
|
||||
automatically.
|
||||
|
||||
@see Referenced
|
||||
|
||||
*/
|
||||
template<class T> class RefPointer
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
using ElementType = T;
|
||||
|
||||
/**
|
||||
@name Construction and Destruction
|
||||
@{
|
||||
*/
|
||||
RefPointer() : RefPointer(nullptr) {}
|
||||
RefPointer(const RefPointer &rp) : RefPointer(rp._ptr) {}
|
||||
|
||||
explicit RefPointer(ElementType *t)
|
||||
: _ptr(t)
|
||||
{
|
||||
static_assert(std::is_base_of<Referenced, T>::value
|
||||
, "Class of template SituationMap::RefPointer have to be derived from class SituationMap::Referenced");
|
||||
|
||||
if (_ptr) _ptr->ref();
|
||||
} /* RefPointer */
|
||||
|
||||
~RefPointer()
|
||||
{
|
||||
if (_ptr) _ptr->unref();
|
||||
_ptr = nullptr;
|
||||
} /* ~RefPointer */
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
Checks if pointer is valid.
|
||||
*/
|
||||
explicit inline operator bool() const { return (_ptr != nullptr); }
|
||||
|
||||
/**
|
||||
@name Casting
|
||||
@{
|
||||
*/
|
||||
/**
|
||||
To create reference pointer from a derived class directly this contructor template can be used.
|
||||
How to use it is shown in the following example:
|
||||
|
||||
\code
|
||||
|
||||
RefPointer<AbstractMapObject> objPtr = getAbstractMapObject();
|
||||
|
||||
RefPointer<Participant> participantObj( objPtr );
|
||||
if (participantObj != NULL)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
\endcode
|
||||
|
||||
Alternatively it is posible to create \b participantObj from example above as follows:
|
||||
|
||||
\code
|
||||
|
||||
RefPointer<Participant> participantObj = RefPointer<Participant>(dynamic_cast<Participant*>(objPtr.get()));
|
||||
|
||||
\endcode
|
||||
*/
|
||||
|
||||
template<class Y> explicit RefPointer(RefPointer<Y> assignPtr)
|
||||
{
|
||||
_ptr = dynamic_cast<T *>(assignPtr.get());
|
||||
if (_ptr) _ptr->ref();
|
||||
}
|
||||
|
||||
|
||||
template<class Y> explicit RefPointer(Y *assignPtr)
|
||||
{
|
||||
_ptr = dynamic_cast<T *>(assignPtr);
|
||||
if (_ptr) _ptr->ref();
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
inline RefPointer &operator = (const RefPointer &rp)
|
||||
{
|
||||
if (_ptr == rp._ptr) return *this;
|
||||
T *tmp_ptr = _ptr;
|
||||
_ptr = rp._ptr;
|
||||
if (_ptr) _ptr->ref();
|
||||
// unref second to prevent any deletion of any object which might
|
||||
// be referenced by the other object. i.e rp is child of the
|
||||
// original _ptr.
|
||||
if (tmp_ptr) tmp_ptr->unref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline RefPointer &operator = (ElementType *ptr)
|
||||
{
|
||||
if (_ptr == ptr) return *this;
|
||||
T *tmp_ptr = _ptr;
|
||||
_ptr = ptr;
|
||||
if (_ptr) _ptr->ref();
|
||||
// unref second to prevent any deletion of any object which might
|
||||
// be referenced by the other object. i.e rp is child of the
|
||||
// original _ptr.
|
||||
if (tmp_ptr) tmp_ptr->unref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void reset() { *this = nullptr; }
|
||||
inline void reset(T *ptr) { *this = ptr; }
|
||||
|
||||
/**
|
||||
@name Comparison Operators
|
||||
Compares the pointer element \c _ptr with other pointers.
|
||||
@{
|
||||
*/
|
||||
inline bool operator == (const RefPointer &rp) const { return (_ptr == rp._ptr); }
|
||||
inline bool operator != (const RefPointer &rp) const { return (_ptr != rp._ptr); }
|
||||
inline bool operator < (const RefPointer &rp) const { return (_ptr < rp._ptr); }
|
||||
inline bool operator > (const RefPointer &rp) const { return (_ptr > rp._ptr); }
|
||||
|
||||
inline bool operator == (const ElementType *ptr) const { return (_ptr == ptr); }
|
||||
inline bool operator != (const ElementType *ptr) const { return (_ptr != ptr); }
|
||||
inline bool operator < (const ElementType *ptr) const { return (_ptr < ptr); }
|
||||
inline bool operator > (const ElementType *ptr) const { return (_ptr > ptr); }
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@name Access Operators
|
||||
Get access to the pointer or the object it points to.
|
||||
@{
|
||||
*/
|
||||
inline ElementType &operator*() { return *_ptr; }
|
||||
inline const ElementType &operator*() const { return *_ptr; }
|
||||
|
||||
inline ElementType *operator->() { return _ptr; }
|
||||
inline const ElementType *operator->() const { return _ptr; }
|
||||
|
||||
inline ElementType *get() { return _ptr; }
|
||||
inline const ElementType *get() const { return _ptr; }
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@name Checks if the pointer is valid.
|
||||
@{
|
||||
*/
|
||||
inline bool valid() const { return _ptr != nullptr; }
|
||||
inline bool operator!() const { return _ptr == nullptr; }
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Control Over Object Pointer
|
||||
* Take control over the object pointed to by RefPointer, unreference but do not delete even if ref count goes to 0,
|
||||
* return the pointer to the object.
|
||||
* Note, do not use this unless you are 100% sure your code handles the deletion of the object correctly, and
|
||||
* only use when absolutely required.
|
||||
@{
|
||||
*/
|
||||
inline ElementType *take() { return release();}
|
||||
inline ElementType *release() { T *tmp = _ptr; if (_ptr) _ptr->unref_nodelete(); _ptr = nullptr; return tmp;}
|
||||
/** @} */
|
||||
|
||||
private:
|
||||
|
||||
ElementType *_ptr;
|
||||
};
|
||||
|
||||
} // SituationMap
|
||||
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Base class for reference counted objects
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Umgebung: Intel-PC
|
||||
** Software-Umgebung: Linux, Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Pgrm-Sprache ....: C++ 11
|
||||
**
|
||||
** HIER/SACHN ......: P: -- ---- - --- QE
|
||||
**
|
||||
** Version .........: $Revision$
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Autor ...........: Nikolaus Hanekamp, SEDG, Tel. 2906
|
||||
** Joerg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notizen .........:
|
||||
**
|
||||
** 18.08.2004, NH : Urversion
|
||||
** 13.05.2015, JT : Refactoring for use with Qt5, ArcGIS 10.2.5
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#include "referenced.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <typeinfo>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
std::shared_ptr<DeleteHandler> & s_deleteHandler()
|
||||
{
|
||||
static std::shared_ptr<DeleteHandler> deleteHandler(nullptr);
|
||||
return deleteHandler;
|
||||
} // std::shared_ptr<DeleteHandler> & s_deleteHandler()
|
||||
|
||||
|
||||
void Referenced::setDeleteHandler(DeleteHandler *handler)
|
||||
{
|
||||
s_deleteHandler().reset(handler);
|
||||
} // Referenced::setDeleteHandler
|
||||
|
||||
|
||||
DeleteHandler *Referenced::getDeleteHandler() { return s_deleteHandler().get(); }
|
||||
|
||||
|
||||
Referenced::~Referenced()
|
||||
{
|
||||
if (_refCount > 0)
|
||||
{
|
||||
qCritical() << "Deleting still referenced object < " << QString::number((qint64)this, 0, 16) << ">"
|
||||
<< "of type <" << typeid(this).name() << ">"
|
||||
<< "refCnt: <" << _refCount;
|
||||
|
||||
}
|
||||
} // Referenced::~Referenced
|
||||
|
||||
} // end of namespace SituationMap
|
||||
|
||||
|
||||
|
||||
Executable
+157
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Base class for reference counted objects
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Umgebung: Intel-PC
|
||||
** Software-Umgebung: Linux, Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Pgrm-Sprache ....: C++ 11
|
||||
**
|
||||
** HIER/SACHN ......: P: -- ---- - --- QE
|
||||
**
|
||||
** Version .........: $Revision$
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Autor ...........: Nikolaus Hanekamp, SEDG, Tel. 2906
|
||||
** Joerg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notizen .........:
|
||||
**
|
||||
** 18.08.2004, NH : Urversion
|
||||
** 13.05.2015, JT : Refactoring for use with Qt5, ArcGIS 10.2.5
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "situation_map_common_export.h"
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
// forward declar, declared after Refenced below.
|
||||
class DeleteHandler;
|
||||
|
||||
/**
|
||||
@class Referenced referenced.h
|
||||
@brief Base class for referenced counted object classes
|
||||
Base class from providing referencing counted objects. Objects from type "Referenced" should
|
||||
be used in combination with the class "RefPointer" for memory handling. In this case calling
|
||||
delete direcly for those objects will result in an error at runtime. Unfortunately there is
|
||||
no way to check this at compile time - to declare delete operator protected does not work.
|
||||
|
||||
@sa RefPointer
|
||||
*/
|
||||
class SITUATIONMAPCOMMON_EXPORT Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
@name Construction
|
||||
@{
|
||||
*/
|
||||
Referenced() { _refCount = 0; }
|
||||
Referenced(const Referenced &) { _refCount = 0; }
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
Assign operator has to do nothing because is is permitted to change _refCount during assignment operation.
|
||||
*/
|
||||
inline Referenced &operator = (const Referenced &) { return *this; }
|
||||
|
||||
friend class DeleteHandler;
|
||||
|
||||
/** Set a DeleteHandler to which deletion of all referenced counted objects
|
||||
* will be delegated to.*/
|
||||
static void setDeleteHandler(DeleteHandler *handler);
|
||||
|
||||
/** Get a DeleteHandler.*/
|
||||
static DeleteHandler *getDeleteHandler();
|
||||
|
||||
|
||||
/** Increment the reference count by one, indicating that
|
||||
this object has another pointer which is referencing it.*/
|
||||
inline void ref() const { ++_refCount; }
|
||||
|
||||
/** Decrement the reference count by one, indicating that
|
||||
a pointer to this object is referencing it. If the
|
||||
reference count goes to zero, it is assumed that this object
|
||||
is no longer referenced and is automatically deleted.*/
|
||||
inline void unref() const;
|
||||
|
||||
/** Decrement the reference count by one, indicating that
|
||||
a pointer to this object is referencing it. However, do
|
||||
not delete it, even if ref count goes to 0. Warning, unref_nodelete()
|
||||
should only be called if the user knows exactly who will
|
||||
be resonsible for, one should prefer unref() over unref_nodelete()
|
||||
as the later can lead to memory leaks.*/
|
||||
inline void unref_nodelete() const { --_refCount; }
|
||||
|
||||
/** Return the number pointers currently referencing this object. */
|
||||
inline int referenceCount() const { return _refCount; }
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
Declaration of destructor is protected because only methode unref() or the delete
|
||||
handler itself are allowed to destroy referenced objects.
|
||||
*/
|
||||
virtual ~Referenced();
|
||||
mutable int _refCount;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** Class for override the default delete behavior so that users can implement their own object
|
||||
* deletion schemes. This might be done to help implement protection of multiple threads from deleting
|
||||
* objects unintentionally.
|
||||
* Note, the DeleteHandler cannot itself be reference counted, otherwise it
|
||||
* would be responsible for deleting itself!
|
||||
* An static auto_ptr<> is used internally in Referenced.cpp to manage the
|
||||
* DeleteHandler's memory.*/
|
||||
class SITUATIONMAPCOMMON_EXPORT DeleteHandler
|
||||
{
|
||||
public:
|
||||
|
||||
DeleteHandler() = default;
|
||||
virtual ~DeleteHandler() = default;
|
||||
|
||||
/** Flush any cache of objects that need to be deleted by doing an actual delete.*/
|
||||
virtual void flush() {}
|
||||
|
||||
static inline void doDelete(const Referenced *object) { delete object; }
|
||||
|
||||
/** Request the deletion of an object.
|
||||
* Depending on users implementation of DeleteHandler, the delete of the object may occur
|
||||
* straight away or be delayed until doDelete is called.
|
||||
* The default implementation does a delete straight away.*/
|
||||
virtual void requestDelete(const Referenced *object) { doDelete(object); }
|
||||
|
||||
}; /* DeleteHandler */
|
||||
|
||||
|
||||
inline void Referenced::unref() const
|
||||
{
|
||||
--_refCount;
|
||||
if (_refCount == 0)
|
||||
{
|
||||
if (getDeleteHandler()) getDeleteHandler()->requestDelete(this);
|
||||
else delete this;
|
||||
}
|
||||
else if (_refCount < 0)
|
||||
throw 2325;
|
||||
} /* Referenced::unref */
|
||||
|
||||
} // SituationMap
|
||||
|
||||
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Helper function to get the resource path
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
|
||||
#include "resource_path.h"
|
||||
|
||||
|
||||
#include <ngltools/ngltools_filesystem.h> // for NGL::directories
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QDir>
|
||||
#include <QVector>
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
QString getResourcePath()
|
||||
{
|
||||
const QString resDir = NGL::directory(NGL::FileType::ConfigFile, QLatin1String("resources"));
|
||||
if (!resDir.isEmpty())
|
||||
return resDir;
|
||||
|
||||
QVector<QString> pathsToSearch;
|
||||
|
||||
// for old systems
|
||||
#ifdef Q_OS_WIN
|
||||
pathsToSearch += QLatin1String("C:/ExtFw/resources/");
|
||||
#else
|
||||
pathsToSearch += QLatin1String("/usr/share/arcgis/resources");
|
||||
#endif
|
||||
|
||||
for (const QString &path : qAsConst(pathsToSearch))
|
||||
{
|
||||
if (QDir(path).exists())
|
||||
return path + QLatin1Char('/');
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Helper function to get the resource path
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "situation_map_common_export.h"
|
||||
|
||||
// Qt
|
||||
#include <QString>
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
QString SITUATIONMAPCOMMON_EXPORT getResourcePath();
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Helper class for storing a simple value and an implizit changed flag
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Qt
|
||||
|
||||
#include <sstream>
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
/*! \class SimpleValue
|
||||
\brief Simple storing fo values
|
||||
*/
|
||||
template <class TYPE> class SimpleValue
|
||||
{
|
||||
protected:
|
||||
TYPE m_value = TYPE(); // '{}' to initialize the member (and avoid unconditional jumps@valgrind)
|
||||
bool m_changed = true;
|
||||
|
||||
public:
|
||||
SimpleValue() = default;
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
SimpleValue(const TYPE &value) // should not be declared explicit to avoid additional writing stuff to cast values
|
||||
: m_value(value)
|
||||
{}
|
||||
|
||||
SimpleValue<TYPE> &operator=(const TYPE &newValue)
|
||||
{
|
||||
if (this->m_value != newValue)
|
||||
{
|
||||
this->m_value = newValue;
|
||||
m_changed = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const TYPE &operator()() const
|
||||
{
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
const TYPE &value() const
|
||||
{
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
TYPE &refValue()
|
||||
{
|
||||
m_changed = true;
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
const TYPE &refValue() const
|
||||
{
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
|
||||
bool changed() const
|
||||
{
|
||||
return m_changed;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_changed = false;
|
||||
}
|
||||
|
||||
void setChanged()
|
||||
{
|
||||
m_changed = true;
|
||||
}
|
||||
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &stream,
|
||||
const SimpleValue &simpleVal)
|
||||
{
|
||||
stream << simpleVal.value();
|
||||
return stream;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Export definitions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <qglobal.h>
|
||||
|
||||
#ifndef SITUATIONMAPCOMMON_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define SITUATIONMAPCOMMON_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SITUATIONMAPCOMMON_LIB)
|
||||
# define SITUATIONMAPCOMMON_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define SITUATIONMAPCOMMON_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Logging within SituationMap
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "situation_map_logging.h"
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
#include <QUuid>
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
LOGGER_T getLogger(const char *name, int id)
|
||||
{
|
||||
static const QLatin1String prefix("SituationMap.");
|
||||
std::string loggerName;
|
||||
const size_t len = strlen(name);
|
||||
loggerName.reserve(prefix.size() + len);
|
||||
loggerName.append(prefix.data(), prefix.size());
|
||||
loggerName.append(name, len);
|
||||
|
||||
if (id > 0)
|
||||
{
|
||||
std::stringstream loggerStream;
|
||||
loggerStream << loggerName << "." << id;
|
||||
loggerName = loggerStream.str();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
|
||||
getNGLLogger(loggerName);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
fprintf(stderr, "Error retrieving logger: %s", ex.what());
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
std::ostream &operator<< (std::ostream &stream,
|
||||
const QUuid &value)
|
||||
{
|
||||
stream << "QUuid(" << value.toString() << ")";
|
||||
return stream;
|
||||
}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Logging within SituationMap
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include "situation_map_common_export.h"
|
||||
|
||||
class QUuid;
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
using LOGGER_T = NGL::INGLLogger&;
|
||||
|
||||
// export for executables within 'Tests'
|
||||
LOGGER_T SITUATIONMAPCOMMON_EXPORT getLogger(const char *name, int id = -1);
|
||||
} // namespace SituationMap
|
||||
|
||||
SITUATIONMAPCOMMON_EXPORT std::ostream &operator<< (std::ostream &stream,
|
||||
const QUuid &value);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
FIND_PACKAGE(GDAL REQUIRED)
|
||||
|
||||
SET(Elevation_SRCS
|
||||
elevation_map.cpp
|
||||
elevation_map.h
|
||||
elevation_map_manager.cpp
|
||||
elevation_map_manager.h
|
||||
line_of_sight_calculation.cpp
|
||||
line_of_sight_calculation.h
|
||||
)
|
||||
|
||||
NGL_ADD_LIBRARY2(AAR SV WS HLA situationMapElevationMap SHARED ${Elevation_SRCS})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(situationMapElevationMap
|
||||
PRIVATE
|
||||
${GDAL_INCLUDE_DIR}
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(situationMapElevationMap
|
||||
PRIVATE
|
||||
situationMapCommon
|
||||
Qt5::Concurrent
|
||||
Qt5::Gui
|
||||
NGLLogger
|
||||
${GDAL_LIBRARIES}
|
||||
LtsCoordTrans
|
||||
PUBLIC
|
||||
Qt5::Core
|
||||
LtsUtilsCoreHeaderOnly
|
||||
)
|
||||
+975
@@ -0,0 +1,975 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* adapting GeISiR source to SituationMap
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
|
||||
#include "elevation_map.h"
|
||||
|
||||
#include <QtConcurrent>
|
||||
#include <QPolygonF>
|
||||
#include <MathUtils/math_const.h>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include <gdal.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <math.h>
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
class BoundingRect
|
||||
{
|
||||
double m_top = 0.0;
|
||||
double m_bottom = 0.0;
|
||||
double m_left = 0.0;
|
||||
double m_right = 0.0;
|
||||
|
||||
void swapBounds()
|
||||
{
|
||||
if (m_top < m_bottom)
|
||||
std::swap(m_bottom, m_top);
|
||||
if (m_right < m_left)
|
||||
std::swap(m_left, m_right);
|
||||
} // void swapBounds()
|
||||
|
||||
public:
|
||||
|
||||
BoundingRect() = default;
|
||||
|
||||
BoundingRect(double left, double bottom, double right, double top)
|
||||
: m_top(top), m_bottom(bottom), m_left(left), m_right(right)
|
||||
{
|
||||
swapBounds();
|
||||
} // BoundingRect( double left, double bottom, double right, double top)
|
||||
|
||||
BoundingRect(const BoundingRect &) = default;
|
||||
BoundingRect &operator =(const BoundingRect &) = default;
|
||||
|
||||
~BoundingRect() = default;
|
||||
|
||||
inline void operator()(double left, double bottom, double right, double top)
|
||||
{
|
||||
m_top = top;
|
||||
m_bottom = bottom;
|
||||
m_left = left;
|
||||
m_right = right;
|
||||
|
||||
swapBounds();
|
||||
} // inline void operator() (double left, double bottom, double right, double top)
|
||||
|
||||
double top() const { return m_top; }
|
||||
double bottom() const { return m_bottom; }
|
||||
double left() const { return m_left; }
|
||||
double right() const { return m_right; }
|
||||
|
||||
bool contains(const QPointF &p) const { return ((p.x() >= m_left) && (p.x() <= m_right) && (p.y() >= m_bottom) && (p.y() <= m_top)); }
|
||||
|
||||
QRectF toQRectF() const
|
||||
{
|
||||
return QRectF(QPointF(m_left, m_top), QPointF(m_right, m_bottom));
|
||||
} // toQRectF
|
||||
}; // BoundingRect
|
||||
|
||||
|
||||
|
||||
struct ElevationMap::Internal
|
||||
{
|
||||
BoundingRect _location; // Lage der Karte in Lat/Lon
|
||||
|
||||
struct PointDouble
|
||||
{
|
||||
void setX(double x) { _x = x;}
|
||||
void setY(double y) { _y = y;}
|
||||
double x() { return _x;}
|
||||
double y() { return _y;}
|
||||
double _x{0.0};
|
||||
double _y{0.0};
|
||||
};
|
||||
PointDouble _elexelSize; // LatLon Size of 1 elevation sample, redundat
|
||||
|
||||
int _totalColumns = 0;
|
||||
int _totalRows = 0;
|
||||
|
||||
double _toMeterFactor = 1.0;
|
||||
std::vector<int> _elevationField;
|
||||
|
||||
template<class BufferType> bool copyBufferData(GDALRasterBandH hBand, int xBlkSize, int yBlkSize)
|
||||
{
|
||||
// NLDEVCTRL-804: Konsistenz d. Z-Werte zwischen 2D/3D (also ElevationMap vs. ESRI::BaseSurface)
|
||||
// This ElevationMap was using an approach similar to following.
|
||||
// Now it´s more or less identical and the difference using 'Altmark_dt1.tif'
|
||||
// are gone. AHTC is also fine :-)
|
||||
/*
|
||||
CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
|
||||
{
|
||||
memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
|
||||
|
||||
CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
|
||||
|
||||
int nXBlockSize, nYBlockSize;
|
||||
|
||||
poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
|
||||
int nXBlocks = (poBand->GetXSize() + nXBlockSize - 1) / nXBlockSize;
|
||||
int nYBlocks = (poBand->GetYSize() + nYBlockSize - 1) / nYBlockSize;
|
||||
|
||||
GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
|
||||
|
||||
for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
|
||||
{
|
||||
for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
|
||||
{
|
||||
int nXValid, nYValid;
|
||||
|
||||
poBand->ReadBlock( iXBlock, iYBlock, pabyData );
|
||||
|
||||
// Compute the portion of the block that is valid
|
||||
// for partial edge blocks.
|
||||
poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
|
||||
|
||||
// Collect the histogram counts.
|
||||
for( int iY = 0; iY < nYValid; iY++ )
|
||||
{
|
||||
for( int iX = 0; iX < nXValid; iX++ )
|
||||
{
|
||||
panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Source https://gdal.org/api/gdalrasterband_cpp.html
|
||||
*/
|
||||
|
||||
const size_t bufSize = xBlkSize * yBlkSize;
|
||||
std::unique_ptr<BufferType[]> bufferPtr(new BufferType[bufSize]);
|
||||
|
||||
int nXBlocks = (GDALGetRasterBandXSize(hBand) + xBlkSize - 1) / xBlkSize;
|
||||
int nYBlocks = (GDALGetRasterBandYSize(hBand) + yBlkSize - 1) / yBlkSize;
|
||||
|
||||
for (int iYBlock = 0; iYBlock < nYBlocks; ++iYBlock)
|
||||
{
|
||||
for (int iXBlock = 0; iXBlock < nXBlocks; ++iXBlock)
|
||||
{
|
||||
|
||||
CPLErr err = GDALReadBlock( hBand, iXBlock, iYBlock, bufferPtr.get() ); // Gdal liest spaltenweise !! x <-> y
|
||||
if (err != CE_None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int nXValid, nYValid;
|
||||
|
||||
// Unfortunately GDALGetActualBlockSize is not available at Suse 42.3 (gdal 2.1.3)
|
||||
// so check bounds using _totalColumns, _totalRows:
|
||||
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2, 2, 0)
|
||||
# define HAS_ACTUAL_BLOCKSIZE
|
||||
#endif
|
||||
|
||||
#ifdef HAS_ACTUAL_BLOCKSIZE
|
||||
GDALGetActualBlockSize(hBand, iXBlock, iYBlock, &nXValid, &nYValid);
|
||||
#else
|
||||
nXValid = xBlkSize;
|
||||
nYValid = yBlkSize;
|
||||
#endif // HAS_ACTUAL_BLOCKSIZE
|
||||
|
||||
|
||||
const int curYOffset = (iYBlock * yBlkSize);
|
||||
const int curXOffset = (iXBlock * xBlkSize);
|
||||
|
||||
for (int iY = 0; iY < nYValid; ++iY)
|
||||
{
|
||||
const int row = iY + curYOffset; // Line
|
||||
|
||||
#ifndef HAS_ACTUAL_BLOCKSIZE
|
||||
if (row >= _totalRows)
|
||||
continue;
|
||||
#endif // HAS_ACTUAL_BLOCKSIZE
|
||||
|
||||
for (int iX = 0; iX < nXValid; ++iX)
|
||||
{
|
||||
// identical to gdallocationinfo
|
||||
const int column = iX + curXOffset; // Pixel
|
||||
|
||||
#ifndef HAS_ACTUAL_BLOCKSIZE
|
||||
if (column >= _totalColumns)
|
||||
continue;
|
||||
#endif // HAS_ACTUAL_BLOCKSIZE
|
||||
|
||||
int bi = iX + (iY * xBlkSize);
|
||||
const int z = static_cast<int>( static_cast<double>(bufferPtr[bi]) / _toMeterFactor );
|
||||
|
||||
_elevationField[column + row * _totalColumns] = z;
|
||||
} // for
|
||||
} // for
|
||||
|
||||
} // for
|
||||
} // for
|
||||
|
||||
return true;
|
||||
|
||||
} // template<class BufferType> void copyBufferData(BufferType * bufferPtr, int xBlkSize, int yBlkSize)
|
||||
|
||||
}; // struct ElevationMap::Internal
|
||||
|
||||
|
||||
ElevationMap::ElevationMap(const QFileInfo &fileInfo)
|
||||
: m_internal(new Internal())
|
||||
, m_aproximation(true)
|
||||
, m_valid(false)
|
||||
, m_logger(getLogger("ElevationMap"))
|
||||
{
|
||||
GDALAllRegister();
|
||||
|
||||
m_fileName = fileInfo.absoluteFilePath();
|
||||
|
||||
INFO_LOG(m_logger) << " ctor ElevationMap: map of file '" << m_fileName << "'"
|
||||
<< ", this=" << this;
|
||||
|
||||
if (!fileInfo.exists())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " elevation data file \'" << m_fileName << "\' doesn't exists.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fileInfo.isReadable())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " elevation data file \'" << m_fileName << "\' isn't readable.";
|
||||
return;
|
||||
}
|
||||
|
||||
auto cb = [this]()
|
||||
{
|
||||
return readFromFile();
|
||||
};
|
||||
auto cbFinished = [this]()
|
||||
{
|
||||
NOTICE_LOG(m_logger) << " Finished reading elevation map of file '" << m_fileName << "'"
|
||||
<< ", this=" << this;
|
||||
};
|
||||
QObject::connect(&m_gdalReadWatcher, &QFutureWatcher<bool>::finished,
|
||||
&m_gdalReadWatcher, cbFinished);
|
||||
m_gdalReadWatcher.setFuture(QtConcurrent::run(cb));
|
||||
// sync init, takes ~800ms during sitmap loading 72MB file
|
||||
// QElapsedTimer t;
|
||||
// t.start();
|
||||
// m_gdalReadWatcher.waitForFinished();
|
||||
// NOTICE_LOG(m_logger) << "Time loading elevation map: " << t.elapsed();
|
||||
} // ElevationMap::ElevationMap( const QFile &file )
|
||||
|
||||
|
||||
ElevationMap::~ElevationMap()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
m_gdalReadWatcher.cancel();
|
||||
m_gdalReadWatcher.waitForFinished();
|
||||
|
||||
delete m_internal;
|
||||
m_internal = nullptr;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
} // ElevationMap::~ElevationMap
|
||||
|
||||
bool ElevationMap::waitForInitialization()
|
||||
{
|
||||
m_gdalReadWatcher.waitForFinished();
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
bool ElevationMap::isValid() const
|
||||
{
|
||||
// N. Thoden, 27.04.2020
|
||||
// isFinished seems to be unreliable:
|
||||
// if mainThread request ::isValid() diretly after ::waitForInitialization()
|
||||
// you get false (by 'if (!m_gdalReadWatcher.isFinished())'
|
||||
// but m_valid is true. So skip the additional check.
|
||||
// if (!m_gdalReadWatcher.isFinished())
|
||||
// return false;
|
||||
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
QString ElevationMap::filename() const
|
||||
{
|
||||
return m_fileName;
|
||||
}
|
||||
|
||||
bool ElevationMap::readFromFile()
|
||||
{
|
||||
m_valid = false;
|
||||
|
||||
GDALDatasetH hDataset = GDALOpen(m_fileName.toLocal8Bit().constData(), GA_ReadOnly);
|
||||
|
||||
if (nullptr == hDataset)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " GDALOpen failed, may be calling of GDALAllRegister is missing";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Detect basic parameters
|
||||
//
|
||||
GDALDriverH hDriver = GDALGetDatasetDriver(hDataset);
|
||||
int nRasterXSize = GDALGetRasterXSize(hDataset);
|
||||
int nRasterYSize = GDALGetRasterYSize(hDataset);
|
||||
double adfGeoTransform[6];
|
||||
CPLErr err = GDALGetGeoTransform(hDataset, adfGeoTransform); // XY Spatial Referenz WGS84 (4326) expected!!!
|
||||
|
||||
if (err != CE_None)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " GDAL failed to get geo raster transform.";
|
||||
GDALClose(hDataset);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (nullptr == hDriver) { GDALClose(hDataset); return false; }
|
||||
if (nRasterXSize <= 0) { GDALClose(hDataset); return false; }
|
||||
if (nRasterYSize <= 0) { GDALClose(hDataset); return false; }
|
||||
|
||||
double pixWidth = adfGeoTransform[1];
|
||||
double pixHeight = adfGeoTransform[5];
|
||||
|
||||
auto toRAD = [](double x) -> double { return x * MathConst::pi / 180.0; };
|
||||
|
||||
|
||||
m_internal->_location(toRAD(adfGeoTransform[0]) // adfGeoTransform is in degrees
|
||||
, toRAD(adfGeoTransform[3])
|
||||
, toRAD(adfGeoTransform[0] + double(nRasterXSize) * pixWidth + double(nRasterYSize) * adfGeoTransform[2])
|
||||
, toRAD(adfGeoTransform[3] + double(nRasterYSize) * pixHeight + double(nRasterXSize) * adfGeoTransform[4]));
|
||||
|
||||
m_internal->_elexelSize.setX(fabs(toRAD(pixWidth)));
|
||||
m_internal->_elexelSize.setY(fabs(toRAD(pixHeight)));
|
||||
|
||||
GDALRasterBandH hBand = GDALGetRasterBand(hDataset, 1);
|
||||
|
||||
if (nullptr == hBand)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " GDAL failed to read raster band.";
|
||||
GDALClose(hDataset);
|
||||
return false;
|
||||
}
|
||||
|
||||
int xBlkSize;
|
||||
int yBlkSize;
|
||||
GDALGetBlockSize(hBand, &xBlkSize, &yBlkSize);
|
||||
|
||||
if (xBlkSize <0 || yBlkSize < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no buffer, next operations will possible fail....";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_internal->_totalColumns = nRasterXSize;
|
||||
m_internal->_totalRows = nRasterYSize;
|
||||
m_internal->_elevationField.resize(nRasterXSize * nRasterYSize);
|
||||
|
||||
const GDALDataType type = GDALGetRasterDataType(hBand);
|
||||
switch (type)
|
||||
{
|
||||
case GDT_UInt16:
|
||||
m_internal->_toMeterFactor = 1.0;
|
||||
m_valid = m_internal->copyBufferData<unsigned short int> ( hBand, xBlkSize, yBlkSize );
|
||||
break;
|
||||
case GDT_Int16:
|
||||
m_internal->_toMeterFactor = 1.0;
|
||||
m_valid = m_internal->copyBufferData<short int> ( hBand, xBlkSize, yBlkSize );
|
||||
break;
|
||||
case GDT_Float32:
|
||||
m_internal->_toMeterFactor = 0.01;
|
||||
m_valid = m_internal->copyBufferData<float> ( hBand, xBlkSize, yBlkSize );
|
||||
break;
|
||||
case GDT_Float64:
|
||||
m_internal->_toMeterFactor = 0.01;
|
||||
m_valid = m_internal->copyBufferData<double> ( hBand, xBlkSize, yBlkSize );
|
||||
break;
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " data type isn't supported type or a floating point type"
|
||||
<< " (type=" << type << ")";
|
||||
GDALClose(hDataset);
|
||||
return false;
|
||||
}
|
||||
} // switch
|
||||
|
||||
if (!m_valid)
|
||||
{
|
||||
CPLErrorNum errNum = CPLGetLastErrorNo();
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " GDAL failed to read data block (error no " << int(errNum) << ")";
|
||||
}
|
||||
|
||||
GDALClose(hDataset);
|
||||
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " loaded, filename =" << m_fileName << "'"
|
||||
<< ", m_valid=" << m_valid;
|
||||
return m_valid;
|
||||
|
||||
} // bool ElevationMap::readFromFile(const QString & fileName)
|
||||
|
||||
|
||||
|
||||
|
||||
QRectF ElevationMap::extent() const
|
||||
{
|
||||
if (!isValid())
|
||||
return QRectF();
|
||||
|
||||
return m_internal->_location.toQRectF();
|
||||
}
|
||||
|
||||
QPair<double, double> ElevationMap::elexelSize() const
|
||||
{
|
||||
return {m_internal->_elexelSize._x, m_internal->_elexelSize._y};
|
||||
}
|
||||
|
||||
|
||||
int ElevationMap::getElevation(int column, int row) const
|
||||
{
|
||||
row = m_internal->_totalRows - row;
|
||||
const size_t index = column + row * m_internal->_totalColumns;
|
||||
|
||||
if (m_internal->_elevationField.empty() || m_internal->_elevationField.size() < index)
|
||||
return std::numeric_limits<int>::min();
|
||||
|
||||
return m_internal->_elevationField.at(index);
|
||||
} // int ElevationMap::getElevation( int column, int row)
|
||||
|
||||
|
||||
double ElevationMap::elevation(double lon, double lat) const
|
||||
{
|
||||
if (!isValid())
|
||||
return 0;
|
||||
|
||||
return getElevation(lon, lat) * m_internal->_toMeterFactor;
|
||||
} // double ElevationMap::elevation( double lon, double lat)
|
||||
|
||||
|
||||
double ElevationMap:: getElevation(double lon, double lat) const
|
||||
{
|
||||
if (!m_internal->_location.contains(QPointF(lon, lat)))
|
||||
{
|
||||
return std::numeric_limits<int>::min(); // ausserhalb der Höhenkarte !!
|
||||
}
|
||||
double x = (lon - m_internal->_location.left()) / m_internal->_elexelSize.x();
|
||||
int column = floor(x);
|
||||
|
||||
double y = (lat - m_internal->_location.bottom()) / m_internal->_elexelSize.y();
|
||||
int row = floor(y);
|
||||
|
||||
int elevation = getElevation(column, row);
|
||||
if (elevation == std::numeric_limits<int>::min())
|
||||
return elevation;
|
||||
|
||||
if (!m_aproximation)
|
||||
return elevation;
|
||||
|
||||
/*
|
||||
** Approximation: e0, e1, e2, e3 Hoehenwerte der 4 benachbarten Stützpunkte
|
||||
**
|
||||
** + e3 + e2
|
||||
** y
|
||||
** ^ + er er = e0 + x*(e1-e0) + y*(e3-e0) + x*y(e2-e3+e0-e1)
|
||||
** |
|
||||
** |
|
||||
** |
|
||||
** | + e0 + e1
|
||||
** -----> x
|
||||
**
|
||||
** Besonderheiten: die Stützpunkte liegen definitiongemaess jeweils in der Mitte des Rasters,
|
||||
** so dass je nach Groesse von x, y andere Nachbarpunkte zu berücksichtigen sind, und x, sowie y entsprechend
|
||||
** angepasst werden muesen.
|
||||
** Bei Randrasterpunkten kann keine Interpolation erfolgen, so dass hier entsprechend extrapoliert wird.
|
||||
*/
|
||||
|
||||
x = (x - (double)column); // Residuum normiert auf Stützpunktabstand
|
||||
y = (y - (double)row); // Residuum normiert auf Stützpunktabstand
|
||||
|
||||
x -= 0.5; // Mitte berücksichtigen
|
||||
y -= 0.5; // Mitte berücksichtigen
|
||||
|
||||
if (x < 0.0) { column--; x += 1.0;} // linke Spalte zur Interpolation nutzen
|
||||
|
||||
if (y < 0.0) { row--; y += 1.0;} // untere Reihe zur Interpolation nutzen
|
||||
|
||||
// Randrasterpunkte berücksichtigen: extrapolieren statt interpolieren
|
||||
if (column <= -1) { x = -x; column = 0;}
|
||||
else if (column >= (m_internal->_totalColumns - 1)) { x += 1.0; column = m_internal->_totalColumns - 2;}
|
||||
|
||||
if (row == -1) { y = -y; row = 0;}
|
||||
else if (row >= (m_internal->_totalRows - 1)) { y += 1.0; row = m_internal->_totalRows - 2;}
|
||||
|
||||
// Die Approximation:
|
||||
double substitute = elevation;
|
||||
double e0 = getOrSubstituteElevation(column, row, substitute);
|
||||
double e1 = getOrSubstituteElevation(column + 1, row, substitute);
|
||||
double e2 = getOrSubstituteElevation(column + 1, row + 1, substitute);
|
||||
double e3 = getOrSubstituteElevation(column, row + 1, substitute);
|
||||
|
||||
double er = e0 + x * (e1 - e0) + y * (e3 - e0) + x * y * (e2 - e3 + e0 - e1);
|
||||
|
||||
return er; // floor(er+0.5);; runden herausgenommen 19.8.2008 JT
|
||||
} // double ElevationMap:: getElevation( double lon, double lat)
|
||||
|
||||
|
||||
double ElevationMap::getOrSubstituteElevation(int column, int row, double substitute) const
|
||||
{
|
||||
int elevation = getElevation(column, row);
|
||||
|
||||
if (elevation != std::numeric_limits<int>::min())
|
||||
return elevation;
|
||||
|
||||
int substCount = 0;
|
||||
double calcSubstitute = 0.0;
|
||||
|
||||
elevation = getElevation(column + 1, row);
|
||||
if (elevation != std::numeric_limits<int>::min()) {substCount++; calcSubstitute += elevation; }
|
||||
|
||||
elevation = getElevation(column - 1, row);
|
||||
if (elevation != std::numeric_limits<int>::min()) {substCount++; calcSubstitute += elevation; }
|
||||
|
||||
elevation = getElevation(column, row + 1);
|
||||
if (elevation != std::numeric_limits<int>::min()) {substCount++; calcSubstitute += elevation; }
|
||||
|
||||
elevation = getElevation(column, row - 1);
|
||||
if (elevation != std::numeric_limits<int>::min()) {substCount++; calcSubstitute += elevation; }
|
||||
|
||||
if (substCount)
|
||||
substitute = calcSubstitute / substCount;
|
||||
|
||||
return substitute;
|
||||
} // double ElevationMap::getOrSubstituteElevation( int column, int row, double substitute)
|
||||
|
||||
double ElevationMap::distance(const QPointF &start, const QPointF &end) const
|
||||
{
|
||||
if (!isValid())
|
||||
return 0;
|
||||
|
||||
if (!m_internal->_location.contains(start) || !m_internal->_location.contains(end))
|
||||
{
|
||||
return -1.0; // ausserhalb{ der Höhenkarte !!
|
||||
}
|
||||
|
||||
double start_z = getElevation(start.x(), start.y());
|
||||
if (start_z <= std::numeric_limits<int>::min()) return -1.0;
|
||||
|
||||
double end_z = getElevation(end.x(), end.y());
|
||||
if (end_z <= std::numeric_limits<int>::min()) return -1.0;
|
||||
|
||||
const QPointF &dist = distance_in_meter_WGS84(start, end);
|
||||
|
||||
double dz = end_z - start_z;
|
||||
double d = sqrt(dist.x() * dist.x() + dist.y() * dist.y() + dz * dz) ;
|
||||
|
||||
return d;
|
||||
} // double ElevationMap::distance( const QPointF &start, const QPointF &end )
|
||||
|
||||
|
||||
double ElevationMap::profileDistance(const QPointF &start, const QPointF &end) const
|
||||
{
|
||||
if (!isValid())
|
||||
return 0;
|
||||
|
||||
if (!m_internal->_location.contains(start) || !m_internal->_location.contains(end))
|
||||
{
|
||||
return -1.0; // ausserhalb der Höhenkarte !!
|
||||
}
|
||||
|
||||
Vec3dVector elevProfile;
|
||||
getSamplePoints(start, end, elevProfile);
|
||||
|
||||
for (Vec3dVector::iterator itr = elevProfile.begin(); itr != elevProfile.end(); ++itr)
|
||||
itr->setZ(getElevation(itr->x(), itr->y()));
|
||||
|
||||
// Einzellaengen aufsummieren, Stützstellen mit undefinierten Hoehen werden ausgelassen!
|
||||
Point3D curPos(*elevProfile.begin());
|
||||
double sumLng = 0.0;
|
||||
for (Vec3dVector::iterator itr = elevProfile.begin() + 1; itr != elevProfile.end(); ++itr)
|
||||
{
|
||||
if ((*itr).z() > std::numeric_limits<int>::min())
|
||||
{
|
||||
if (curPos.z() > std::numeric_limits<int>::min())
|
||||
{
|
||||
const QPointF &dist = distance_in_meter_WGS84(QPointF(curPos.x(), curPos.y()), QPointF(itr->x(), itr->y()));
|
||||
double dz = itr->z() - curPos.z();
|
||||
sumLng += sqrt(dist.x() * dist.x() + dist.y() * dist.y() + dz * dz) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
double dx = itr->x() - curPos.x();
|
||||
double dy = itr->y() - curPos.y();
|
||||
sumLng += sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
curPos = *itr;
|
||||
}
|
||||
}
|
||||
return sumLng;
|
||||
} // double ElevationMap::profileDistance( const QPointF &start, const QPointF &end)
|
||||
|
||||
|
||||
unsigned int ElevationMap::elevationProfile(const QPointF &start, const QPointF &end, Vec3dVector &elevProfile) const
|
||||
{
|
||||
unsigned int startSize = elevProfile.size();
|
||||
|
||||
getSamplePoints(start, end, elevProfile);
|
||||
for (Vec3dVector::iterator itr = elevProfile.begin() + startSize; itr != elevProfile.end(); ++itr)
|
||||
itr->setZ(getElevation(itr->x(), itr->y()));
|
||||
|
||||
return (elevProfile.size() - startSize);
|
||||
} // unsigned int ElevationMap::elevationProfile( const QPointF &start, const QPointF &end, Vec3dVector &elevProfile)
|
||||
|
||||
bool ElevationMap::contains(const QPointF &point) const
|
||||
{
|
||||
return m_internal->_location.contains(point);
|
||||
}
|
||||
|
||||
bool ElevationMap::intersects(const QPolygonF &polygon) const
|
||||
{
|
||||
const BoundingRect &bbox = m_internal->_location;
|
||||
|
||||
// maybe QPointF uses float, but we can accept double to be reduced to float:
|
||||
const QPolygonF &ourBorder = QPolygonF({QPointF(bbox.left() , bbox.bottom()),
|
||||
QPointF(bbox.left() , bbox.top()),
|
||||
QPointF(bbox.right(), bbox.top()),
|
||||
QPointF(bbox.right(), bbox.bottom())});
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,10,0)
|
||||
return ourBorder.intersected(polygon).size() > 0;
|
||||
#else
|
||||
return ourBorder.intersects(polygon);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ElevationMap::getSamplePoints(const QPointF &start, const QPointF &end, Vec3dVector &sPnts) const
|
||||
{
|
||||
sPnts.clear();
|
||||
sPnts.push_back(Point3D::fromQPointF(start));
|
||||
|
||||
bool endIsClipped = false;
|
||||
QPointF cStart(start);
|
||||
QPointF cEnd(end);
|
||||
|
||||
if (!m_internal->_location.contains(start) || !m_internal->_location.contains(end))
|
||||
{
|
||||
int res = clipp2Map(start, end, cStart, cEnd);
|
||||
|
||||
if (res == 0) // no intersection
|
||||
{
|
||||
sPnts.push_back(Point3D::fromQPointF(end));
|
||||
return;
|
||||
}
|
||||
if (res & 1) // start clipped
|
||||
sPnts.push_back(Point3D::fromQPointF(cStart));
|
||||
if (res & 2) // end clipped
|
||||
endIsClipped = true;
|
||||
}
|
||||
|
||||
QPointF delta(cEnd - cStart);
|
||||
|
||||
// Berechne alle Schnittpunkte des Vektors( cStart, cEnd) mit den x-Grenzen der Hoehenstuetzrechtecke.
|
||||
// Die Stützpunkte liegen definitiongemaess jeweils in der Mitte des Raster-Rechtecks
|
||||
int startCol = floor((cStart.x() - m_internal->_location.left()) / m_internal->_elexelSize.x());
|
||||
if (startCol < 0) startCol = 0;
|
||||
else if (startCol >= m_internal->_totalColumns) startCol = m_internal->_totalColumns - 1;
|
||||
|
||||
int endCol = floor((cEnd.x() - m_internal->_location.left()) / m_internal->_elexelSize.x());
|
||||
if (endCol < 0) endCol = 0;
|
||||
else if (endCol >= m_internal->_totalColumns) endCol = m_internal->_totalColumns - 1;
|
||||
|
||||
int incCol = 0;
|
||||
if (endCol > startCol) incCol = 1;
|
||||
else if (endCol < startCol) incCol = -1;
|
||||
|
||||
double m = delta.y() / delta.x();
|
||||
Vec2dVector xCuts;
|
||||
xCuts.reserve(std::abs(endCol - startCol));
|
||||
for (int col = startCol; col != endCol; col += incCol)
|
||||
{
|
||||
double x = m_internal->_location.left() + ((col + 0.5) + (incCol * 0.5)) * m_internal->_elexelSize.x();
|
||||
double y = cStart.y() + (x - cStart.x()) * m;
|
||||
xCuts.push_back(QPointF(x, y));
|
||||
}
|
||||
|
||||
// Berechne alle Schnittpunkte des Vektors( cStart, cEnd) mit den y-Grenzen der Hoehenstuetzrechtecke.
|
||||
// Die Stützpunkte liegen definitiongemaess jeweils in der Mitte des Raster-Rechtecks
|
||||
int startRow = floor((cStart.y() - m_internal->_location.bottom()) / m_internal->_elexelSize.y());
|
||||
if (startRow < 0) startRow = 0;
|
||||
else if (startRow >= m_internal->_totalRows) startRow = m_internal->_totalRows - 1;
|
||||
|
||||
int endRow = floor((end.y() - m_internal->_location.bottom()) / m_internal->_elexelSize.y());
|
||||
if (endRow < 0) endRow = 0;
|
||||
else if (endRow >= m_internal->_totalRows) endRow = m_internal->_totalRows - 1;
|
||||
|
||||
int incRow = 0;
|
||||
if (endRow > startRow) incRow = 1;
|
||||
else if (endRow < startRow) incRow = -1;
|
||||
|
||||
m = delta.x() / delta.y();
|
||||
Vec2dVector yCuts;
|
||||
yCuts.reserve(std::abs(endRow - startRow));
|
||||
for (int row = startRow; row != endRow; row += incRow)
|
||||
{
|
||||
double y = m_internal->_location.bottom() + ((row + 0.5) + (incRow * 0.5)) * m_internal->_elexelSize.y();
|
||||
double x = cStart.x() + (y - cStart.y()) * m;
|
||||
yCuts.push_back(QPointF(x, y));
|
||||
}
|
||||
|
||||
// xCuts und yCuts zusammenführen, unter Berücksichtigung der Reihenfolge
|
||||
Vec2dVector mergeCuts;
|
||||
Vec2dVector::iterator xCutItr = xCuts.begin();
|
||||
Vec2dVector::iterator yCutItr = yCuts.begin();
|
||||
|
||||
while ((xCutItr != xCuts.end()) && (yCutItr != yCuts.end()))
|
||||
{
|
||||
if (incCol > 0)
|
||||
{
|
||||
if ((*xCutItr).x() < (*yCutItr).x()) { mergeCuts.push_back(*xCutItr); ++xCutItr; }
|
||||
else { mergeCuts.push_back(*yCutItr); ++yCutItr; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((*xCutItr).x() > (*yCutItr).x()) { mergeCuts.push_back(*xCutItr); ++xCutItr; }
|
||||
else { mergeCuts.push_back(*yCutItr); ++yCutItr; }
|
||||
}
|
||||
}
|
||||
while ((xCutItr != xCuts.end())) { mergeCuts.push_back(*xCutItr); ++xCutItr; }
|
||||
while ((yCutItr != yCuts.end())) { mergeCuts.push_back(*yCutItr); ++yCutItr; }
|
||||
|
||||
// mergeCuts enthält sequenziell alle Schnittpunkte des Vektors mit den Hoehengridkanten
|
||||
// Die 2 Schnittpunkte pro Hoehenwert werden gemittelt zu einem zusammengefasst
|
||||
if (mergeCuts.size() > 1)
|
||||
{
|
||||
for (Vec2dVector::iterator itr = mergeCuts.begin() + 1; itr != mergeCuts.end(); ++itr)
|
||||
sPnts.push_back(Point3D::fromQPointF((*(itr - 1) + *itr) * 0.5));
|
||||
}
|
||||
sPnts.push_back(Point3D::fromQPointF(cEnd));
|
||||
|
||||
// DEBUG_LOG(m_logger) << " xCuts.si " << xCuts.size()
|
||||
// << ", yCuts.si " << yCuts.size()
|
||||
// << ", mergeCuts.si " << mergeCuts.size();
|
||||
|
||||
|
||||
if (endIsClipped) sPnts.push_back(Point3D::fromQPointF(end));
|
||||
} // void ElevationMap::getSamplePoints( const QPointF &start, const QPointF &end, Vec3dVector & sPnts)
|
||||
|
||||
|
||||
// start und/oder end liegt ausserhalb !! in Lat/Lon !!
|
||||
int ElevationMap::clipp2Map(const QPointF &start, const QPointF &end, QPointF &cStart, QPointF &cEnd) const
|
||||
{
|
||||
Vec2dVector clippVec;
|
||||
|
||||
if (end.x() != start.x())
|
||||
{
|
||||
double x = m_internal->_location.right();
|
||||
double m = (end.y() - start.y()) / (end.x() - start.x());
|
||||
if (isInIntervall(x, start.x(), end.x()))
|
||||
{
|
||||
double yc = start.y() + (x - start.x()) * m;
|
||||
if ((yc <= m_internal->_location.top()) && (yc >= m_internal->_location.bottom()))
|
||||
clippVec.push_back(QPointF(x, yc));
|
||||
}
|
||||
x = m_internal->_location.left();
|
||||
if (isInIntervall(x, start.x(), end.x()))
|
||||
{
|
||||
double yc = start.y() + (x - start.x()) * (end.y() - start.y()) / (end.x() - start.x());
|
||||
if ((yc <= m_internal->_location.top()) && (yc >= m_internal->_location.bottom()))
|
||||
clippVec.push_back(QPointF(x, yc));
|
||||
}
|
||||
}
|
||||
|
||||
if (end.y() != start.y())
|
||||
{
|
||||
double y = m_internal->_location.top();
|
||||
double m = (end.x() - start.x()) / (end.y() - start.y());
|
||||
if (isInIntervall(y, start.y(), end.y()))
|
||||
{
|
||||
double xc = start.x() + (y - start.y()) * m;
|
||||
if ((xc < m_internal->_location.right()) && (xc > m_internal->_location.left()))
|
||||
clippVec.push_back(QPointF(xc, y));
|
||||
}
|
||||
y = m_internal->_location.bottom();
|
||||
if (isInIntervall(y, start.y(), end.y()))
|
||||
{
|
||||
double xc = start.x() + (y - start.y()) * m;
|
||||
if ((xc < m_internal->_location.right()) && (xc > m_internal->_location.left()))
|
||||
clippVec.push_back(QPointF(xc, y));
|
||||
}
|
||||
}
|
||||
int size = (int)clippVec.size();
|
||||
if (size == 0)
|
||||
{
|
||||
return 0; // komlett ausserhalb ( oder komplett innerhalb)
|
||||
}
|
||||
|
||||
if (size == 1)
|
||||
{
|
||||
if (m_internal->_location.contains(start))
|
||||
{
|
||||
cEnd = clippVec[0]; return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
cStart = clippVec[0]; return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (size == 2)
|
||||
{
|
||||
if (squareLength(clippVec[0] - start) < squareLength(clippVec[1] - start))
|
||||
{
|
||||
cStart = clippVec[0];
|
||||
cEnd = clippVec[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
cStart = clippVec[1];
|
||||
cEnd = clippVec[0];
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Internal Clipp Error!";
|
||||
|
||||
return 0;
|
||||
} // int ElevationMap::clipp2Map( const QPointF &start, const QPointF &end, QPointF &cStart, QPointF &cEnd)
|
||||
|
||||
|
||||
// Line of Sight Profile: berücksichtigt Erdkrümmung und WGS84 Erdellipsoid
|
||||
void ElevationMap::LOSProfile(const QPointF &start, const QPointF &end, LOSVector &losProfile)
|
||||
{
|
||||
m_gdalReadWatcher.waitForFinished();
|
||||
|
||||
if (!m_internal->_location.contains(start)) return ; // ausserhalb der Höhenkarte !!
|
||||
|
||||
bool clipped = false;
|
||||
double totalLng;
|
||||
QPointF startG = start;
|
||||
QPointF endG = end;
|
||||
|
||||
if (!m_internal->_location.contains(end)) // Clippen
|
||||
{
|
||||
clipped = true;
|
||||
totalLng = length(endG - startG);
|
||||
if (endG.x() < m_internal->_location.left())
|
||||
{
|
||||
double m = (endG.y() - startG.y()) / (endG.x() - startG.x());
|
||||
double x = m_internal->_location.left();
|
||||
endG.setX(x);
|
||||
endG.setY(startG.y() + m * (x - startG.x()));
|
||||
}
|
||||
else if (endG.x() > m_internal->_location.right())
|
||||
{
|
||||
double m = (endG.y() - startG.y()) / (endG.x() - startG.x());
|
||||
double x = m_internal->_location.right();
|
||||
endG.setX(x);
|
||||
endG.setY(startG.y() + m * (x - startG.x()));
|
||||
}
|
||||
if (endG.y() < m_internal->_location.bottom())
|
||||
{
|
||||
double m = (endG.x() - startG.x()) / (endG.y() - startG.y());
|
||||
double y = m_internal->_location.bottom();
|
||||
endG.setY(y);
|
||||
endG.setX(startG.x() + m * (y - startG.y()));
|
||||
}
|
||||
else if (endG.y() > m_internal->_location.top())
|
||||
{
|
||||
double m = (endG.x() - startG.x()) / (endG.y() - startG.y());
|
||||
double y = m_internal->_location.top();
|
||||
endG.setY(y);
|
||||
endG.setX(startG.x() + m * (y - startG.y()));
|
||||
}
|
||||
}
|
||||
|
||||
// Korrektursteigung aufgrund WGS84 Erdellipsoid, Lineare Approximation, Fehler bis 200 km: < 1.0m
|
||||
double startRadius = radiusWGS84(startG.y());
|
||||
double corrM = (radiusWGS84(endG.y()) - startRadius) / length(endG - startG);
|
||||
|
||||
Vec3dVector elevProfile;
|
||||
getSamplePoints(start, end, elevProfile);
|
||||
for (Vec3dVector::iterator itr = elevProfile.begin(); itr != elevProfile.end(); ++itr)
|
||||
{
|
||||
double dist = length(distance_in_meter_WGS84(start, itr->toPointF()));
|
||||
double height = elevation(itr->x(), itr->y());
|
||||
height += corrM * dist; // WGS84 Erdellipsoid Korrektur
|
||||
height -= (startRadius * (1 - cos(atan(dist / startRadius)))); // Einbeziehen der Erdkruemmung
|
||||
// alternativ als Naeherung: height -= ( dist * dist) / (startRadius * 2.0);
|
||||
losProfile.push_back(LOSentry(dist, height));
|
||||
}
|
||||
|
||||
if (clipped)
|
||||
losProfile.push_back(LOSentry(totalLng, -NAN));
|
||||
|
||||
qCritical() << " losProfile.isze() = " << losProfile.size();
|
||||
|
||||
} // void ElevationMap::LOSProfile( const QPointF &start, const QPointF &end, LOSVector &losProfile)
|
||||
|
||||
|
||||
|
||||
} // SituationMap
|
||||
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------------------------
|
||||
** CVS-Id/Release ...: $Header$
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Historie:
|
||||
**
|
||||
** $Log: not supported by cvs2svn $
|
||||
** Revision 1.17.1.1 2008/06/16 06:05:37 joerg
|
||||
** Transparenz und Bias einheitlich für alle Objekte implementiert
|
||||
**
|
||||
** Revision 1.17 2006/03/24 09:05:01 klaus
|
||||
** Elevationprofile: Begrenzung auf Kartengröße aufgehoben ( Clipping)
|
||||
**
|
||||
** Revision 1.16 2005/11/09 13:44:36 klaus
|
||||
** Umsetzung auf Linux;
|
||||
**
|
||||
** Revision 1.15 2005/04/15 13:05:45 joerg
|
||||
** Resource Control
|
||||
**
|
||||
** Revision 1.14 2005/03/04 14:29:26 klaus
|
||||
** Elevationmap mit CachedTileList versehen und automatischem Entladen von Tiles
|
||||
**
|
||||
** Revision 1.13 2005/03/03 12:37:53 klaus
|
||||
** dynamischen Laden und Entladen der ElevationTiles für Reliefmap
|
||||
**
|
||||
** Revision 1.12 2005/03/01 12:36:59 klaus
|
||||
** Reliefmap eingeführt, aus Elevationmap entfernt
|
||||
**
|
||||
** Revision 1.11 2005/02/25 15:32:56 klaus
|
||||
** Ergänzung um Reliefkarte
|
||||
**
|
||||
** Revision 1.10 2005/02/10 14:15:19 klaus
|
||||
** Bias in Basisklasse MapObject überführt
|
||||
**
|
||||
** Revision 1.9 2005/02/10 13:50:33 klaus
|
||||
** Bias für SightFans eingeführt
|
||||
**
|
||||
** Revision 1.8 2005/02/09 16:45:26 klaus
|
||||
** 1. Version der SightFans
|
||||
**
|
||||
** Revision 1.7 2005/01/26 12:26:23 klaus
|
||||
** todos bearbeitet, Fehlerrückmeldnugen
|
||||
**
|
||||
** Revision 1.6 2004/12/14 10:29:48 klaus
|
||||
** 7. Erweiterung für Höhenkarten
|
||||
**
|
||||
** Revision 1.5 2004/12/07 11:08:28 klaus
|
||||
** 5. Erweiterung für Höhenkarten
|
||||
**
|
||||
** Revision 1.4 2004/12/03 16:25:14 klaus
|
||||
** 4. Erweiterung für Höhenkarten
|
||||
**
|
||||
** Revision 1.3 2004/11/30 13:18:13 klaus
|
||||
** 3. Erweiterung für Höhenkarten
|
||||
**
|
||||
** Revision 1.2 2004/11/23 14:36:40 klaus
|
||||
** 2. Erweiterung für Höhenkarten
|
||||
**
|
||||
**
|
||||
** ----------------------------------------------------------------------------------------------- */
|
||||
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* adapting GeISiR source to SituationMap
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "elevation_map_helper.h"
|
||||
#include <ElevationMap/situationmapelevationmap_export.h>
|
||||
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
#include <QFutureWatcher>
|
||||
#include <QPointF>
|
||||
#include <QRectF>
|
||||
#include <QVector>
|
||||
|
||||
class QFileInfo;
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
// ElevationMap
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class SITUATIONMAPELEVATIONMAP_EXPORT ElevationMap final
|
||||
{
|
||||
|
||||
friend class ElevationMapManager;
|
||||
|
||||
public:
|
||||
ElevationMap() = delete;
|
||||
ElevationMap(const ElevationMap &) = delete;
|
||||
ElevationMap &operator = (const ElevationMap &) = delete;
|
||||
|
||||
explicit ElevationMap(const QFileInfo &fileInfo);
|
||||
|
||||
~ElevationMap();
|
||||
|
||||
bool waitForInitialization();
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
QString filename() const;
|
||||
|
||||
QRectF extent() const;
|
||||
|
||||
QPair<double, double> elexelSize() const;
|
||||
|
||||
double elevation(double lon, double lat) const; // rad
|
||||
|
||||
double distance(const QPointF &start, const QPointF &end) const;
|
||||
|
||||
double profileDistance(const QPointF &start, const QPointF &end) const;
|
||||
|
||||
unsigned int elevationProfile(const QPointF &start, const QPointF &end, Vec3dVector &elevProfile) const;
|
||||
|
||||
void interpolation(bool on) { m_aproximation = on; }
|
||||
bool interpolation() const { return m_aproximation; }
|
||||
|
||||
bool contains(const QPointF &point) const;
|
||||
bool intersects(const QPolygonF &polygon) const;
|
||||
|
||||
// Line of Sight Profile: berücksichtigt Erdkrümmung und WGS84 Erdellipsoid
|
||||
void LOSProfile(const QPointF &start, const QPointF &end, LOSVector &losProfile);
|
||||
|
||||
protected:
|
||||
|
||||
int getElevation(int column, int row) const;
|
||||
double getElevation(double lon, double lat) const;
|
||||
|
||||
double getOrSubstituteElevation(int column, int row, double substitute) const;
|
||||
|
||||
// getSamplePoints rastert den Vector( start, end) in Lat/Lon entsprechend dem Höhenraster
|
||||
void getSamplePoints(const QPointF &start, const QPointF &end, Vec3dVector &sPnts) const;
|
||||
|
||||
int clipp2Map(const QPointF &start, const QPointF &end, QPointF &cStart, QPointF &cEnd) const;
|
||||
|
||||
bool readFromFile();
|
||||
|
||||
struct Internal;
|
||||
|
||||
Internal *m_internal;
|
||||
QString m_fileName;
|
||||
bool m_aproximation;
|
||||
bool m_valid;
|
||||
QFutureWatcher<bool> m_gdalReadWatcher;
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
}; // ElevationMap
|
||||
|
||||
|
||||
} // SituationMap
|
||||
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------------------------
|
||||
** CVS-Id/Release ...: $Header$
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Historie:
|
||||
**
|
||||
** $Log: not supported by cvs2svn $
|
||||
** Revision 1.20 2006/09/26 07:51:12 Jörg
|
||||
** Syntax Fehler unter Suse Linux 10.1 behoben.
|
||||
**
|
||||
** Revision 1.19 2006/03/24 09:05:24 klaus
|
||||
** Elevationprofile: Begrenzung auf Kartengröße aufgehoben ( Clipping)
|
||||
**
|
||||
** Revision 1.18 2005/11/09 11:12:27 klaus
|
||||
** Anpassung an Linux: Kommentar hinter #endif mit "//" versehen
|
||||
**
|
||||
** Revision 1.17 2005/08/22 14:15:02 joerg
|
||||
** typeId()
|
||||
**
|
||||
** Revision 1.16 2005/08/12 09:37:44 joerg
|
||||
** Koordinaten-Umprojezieren bei Wechsel der Projektion
|
||||
**
|
||||
** Revision 1.15 2005/04/15 13:04:35 joerg
|
||||
** Resource Control
|
||||
**
|
||||
** Revision 1.14 2005/03/04 14:29:13 klaus
|
||||
** Elevationmap mit CachedTileList versehen und automatischem Entladen von Tiles
|
||||
**
|
||||
** Revision 1.13 2005/03/03 12:37:14 klaus
|
||||
** dynamischen Laden und Entladen der ElevationTiles für Reliefmap
|
||||
**
|
||||
** Revision 1.12 2005/03/01 12:33:12 klaus
|
||||
** Reliefmap eingeführt, aus Elevationmap entfernt
|
||||
**
|
||||
** Revision 1.11 2005/02/25 15:26:41 klaus
|
||||
** Ergänzung um Reliefkarte
|
||||
**
|
||||
** Revision 1.10 2005/02/10 14:13:21 klaus
|
||||
** Bias in Basisklasse MapObject überführt
|
||||
**
|
||||
** Revision 1.9 2005/02/10 13:51:01 klaus
|
||||
** Bias für SightFans eingeführt
|
||||
**
|
||||
** Revision 1.8 2005/02/09 16:53:06 klaus
|
||||
** 1. Version der SightFans
|
||||
**
|
||||
** Revision 1.7 2005/01/26 12:25:41 klaus
|
||||
** todos bearbeitet, Fehlerrückmeldnugen
|
||||
**
|
||||
** Revision 1.6 2004/12/14 09:43:25 klaus
|
||||
** 7. Erweiterung für Höhenkarten
|
||||
**
|
||||
** Revision 1.5 2004/12/07 11:07:20 klaus
|
||||
** 5. Erweiterung für Höhenkarten
|
||||
**
|
||||
** Revision 1.4 2004/12/03 16:24:12 klaus
|
||||
** 4. Erweiterung für Höhenkarten
|
||||
**
|
||||
** Revision 1.3 2004/11/30 13:15:28 klaus
|
||||
** 3. Erweiterung für Höhenkarten
|
||||
**
|
||||
** Revision 1.2 2004/11/23 14:36:14 klaus
|
||||
** 2. Erweiterung für Höhenkarten
|
||||
**
|
||||
**
|
||||
** ----------------------------------------------------------------------------------------------- */
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Some functions and struct for ElevationMap/LineOfSight (LOS)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <MathUtils/math_const.h>
|
||||
|
||||
|
||||
#include <QPointF>
|
||||
#include <QVector>
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
inline bool isInIntervall(double x, double x1, double x2)
|
||||
{
|
||||
return (((x > x1) && (x < x2)) || (((x > x2) && (x < x1))));
|
||||
} // inline bool isInIntervall(double x, double x1, double x2)
|
||||
|
||||
|
||||
inline double radiusWGS84(double lat)
|
||||
{
|
||||
double sinLAT = sin(lat);
|
||||
return (MathConst::WGS84_Major_a * sqrt(1.0 - MathConst::WGS84_SQR_EXC * sinLAT * sinLAT));
|
||||
} // inline double radiusWGS84(double lat)
|
||||
|
||||
|
||||
inline QPointF distance_in_meter_WGS84(const QPointF &start, const QPointF &end) // start, end in LonLat
|
||||
{
|
||||
// todo: prüfen ob Distanz zu groß, dann verbesserte Berechnung !!
|
||||
double lat = (end.y() + start.y()) / 2.0;
|
||||
double faktorLon = MathConst::WGS84_Major_a * cos(lat); // radiusWGS84(lat) * 2.0 * PI;
|
||||
double faktorLat = MathConst::WGS84_Minor_b;
|
||||
|
||||
return QPointF(faktorLon * (end.x() - start.x()), faktorLat * (end.y() - start.y()));
|
||||
|
||||
} // QPointF distance_in_meter_WGS84(const QPointF &start, const QPointF &end)
|
||||
|
||||
|
||||
inline double squareLength(const QPointF &v)
|
||||
{
|
||||
return v.x() * v.x() + v.y() * v.y();
|
||||
} // inline double squareLength(const QPoint & v)
|
||||
|
||||
|
||||
inline double length(const QPointF &v)
|
||||
{
|
||||
return sqrt(squareLength(v));
|
||||
} // inline double length(const QPoint & v)
|
||||
|
||||
|
||||
struct LOSentry // Defines 1 Entry for Line of Sight
|
||||
{
|
||||
LOSentry() = default;
|
||||
LOSentry(double dist, double height) : _dist(dist), _height(height) { ; }
|
||||
|
||||
double &dist() { return _dist; }
|
||||
double &height() { return _height; }
|
||||
|
||||
double dist() const { return _dist; }
|
||||
double height() const { return _height; }
|
||||
|
||||
bool isUndefined() const { return std::isnan(_height); }
|
||||
|
||||
private:
|
||||
|
||||
double _dist = 0; // Distance from Start
|
||||
double _height = -NAN;
|
||||
|
||||
}; /* LOSentry */
|
||||
|
||||
|
||||
using Point3D = LtsUtils::QPoint3D; ///< x = lon ; y = lat , z = elevation/altitude in meters
|
||||
using LOSVector = QVector<LOSentry>;
|
||||
using Vec2dVector = QVector<QPointF>;
|
||||
using Vec3dVector = QVector<Point3D>;
|
||||
|
||||
|
||||
} // SituationMap
|
||||
|
||||
@@ -0,0 +1,531 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Manage and combine several ElevationMap
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
|
||||
#include "elevation_map_manager.h"
|
||||
#include "elevation_map.h"
|
||||
|
||||
// Qt
|
||||
#include <QPointer>
|
||||
#include <QFileInfo>
|
||||
#include <QRectF>
|
||||
#include <QPolygonF>
|
||||
|
||||
// system
|
||||
#include <vector>
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
static long s_counter{0};
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
// ElevationMapManager::Private
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class ElevationMapManager::Private
|
||||
{
|
||||
public:
|
||||
// fine to rough
|
||||
std::vector<ElevationMap *> m_elevationMapCont;
|
||||
QRectF m_simpleExtent;
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
// ElevationMapManager
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
ElevationMapManager::ElevationMapManager()
|
||||
: BaseClass()
|
||||
, d(new Private())
|
||||
, m_logger(getLogger("ElevationMapManager"))
|
||||
{
|
||||
++s_counter;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, s_counter=" << s_counter << " this=" << this;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, s_counter=" << s_counter << " this=" << this;
|
||||
}
|
||||
|
||||
ElevationMapManager::~ElevationMapManager()
|
||||
{
|
||||
--s_counter;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, s_counter=" << s_counter << " this=" << this;
|
||||
cleanupCurrentContent();
|
||||
delete d;
|
||||
d = nullptr;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, s_counter=" << s_counter << " this=" << this;
|
||||
}
|
||||
int ElevationMapManager::init(const QStringList &filePaths_rough_to_fine)
|
||||
{
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " START" << " filePaths_rough_to_fine=" << filePaths_rough_to_fine.join(QStringLiteral(" ; "));
|
||||
|
||||
cleanupCurrentContent();
|
||||
|
||||
d->m_elevationMapCont.reserve(filePaths_rough_to_fine.size());
|
||||
int cnt = 0;
|
||||
for (const QString &filePath : filePaths_rough_to_fine)
|
||||
{
|
||||
QFileInfo fileInfo(filePath);
|
||||
|
||||
const QString &fileName = fileInfo.absoluteFilePath();
|
||||
|
||||
if (!fileInfo.exists())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " elevation data file \'" << fileName << "\' doesn't exists.";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!fileInfo.isReadable())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " elevation data file \'" << fileName << "\' isn't readable.";
|
||||
continue;
|
||||
}
|
||||
|
||||
// ctor will spawn thread via QtConcurrent and read file async:
|
||||
d->m_elevationMapCont.insert(d->m_elevationMapCont.begin(), new ElevationMap(fileInfo));
|
||||
++cnt;
|
||||
} // for
|
||||
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " END" << " filePaths_rough_to_fine=" << filePaths_rough_to_fine.join(QStringLiteral(" ; "))
|
||||
<< ", following number of files are going to be loaded: " << cnt;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void ElevationMapManager::cleanupCurrentContent()
|
||||
{
|
||||
qDeleteAll(d->m_elevationMapCont);
|
||||
d->m_elevationMapCont.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
bool ElevationMapManager::waitForInitialization()
|
||||
{
|
||||
for (ElevationMap *elevationMap : d->m_elevationMapCont)
|
||||
elevationMap->waitForInitialization();
|
||||
return isValid();
|
||||
}
|
||||
|
||||
bool ElevationMapManager::isValid() const
|
||||
{
|
||||
bool allAreValid = true;
|
||||
for (const ElevationMap *elevationMap : d->m_elevationMapCont)
|
||||
allAreValid = allAreValid && elevationMap->isValid();
|
||||
|
||||
// FATAL_LOG(m_logger) << LOGFUNCTION << " allAreValid = " << allAreValid;
|
||||
return allAreValid;
|
||||
}
|
||||
|
||||
double ElevationMapManager::elevation(double lon_rad, double lat_rad, bool *bIsCovered) const
|
||||
{
|
||||
// assume, that all children are ready
|
||||
for (const ElevationMap *elevationMap : d->m_elevationMapCont)
|
||||
{
|
||||
// qCritical() << " EMM::elevation: "
|
||||
// << " lon_rad=" << lon_rad
|
||||
// << " lat_rad=" << lat_rad
|
||||
// << " (try: " << elevationMap->filename() << ")...";
|
||||
|
||||
double singleResult = elevationMap->elevation(lon_rad, lat_rad);
|
||||
|
||||
if (singleResult > -300) // -300 -> ausserhalb der Höhenkarte !!
|
||||
{
|
||||
// qCritical() << " EMM::elevation: elevation= " << singleResult << " (taken from: " << elevationMap->filename() << ")";
|
||||
if (bIsCovered)
|
||||
*bIsCovered = true;
|
||||
return singleResult;
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG_LOG(m_logger) << LOGFUNCTION << " invalid= "
|
||||
// << " lon_rad=" << lon_rad
|
||||
// << " lat_rad=" << lat_rad;
|
||||
if (bIsCovered)
|
||||
*bIsCovered = false;
|
||||
return std::numeric_limits<double>::min();
|
||||
}
|
||||
|
||||
double ElevationMapManager::elevation(double lon_rad, double lat_rad, double defaultValue, bool *bIsCovered) const
|
||||
{
|
||||
bool bIsCoveredLocal = false;
|
||||
const double elevationValue = elevation(lon_rad, lat_rad, &bIsCoveredLocal);
|
||||
|
||||
// in any case: if provided, transfer isCovered back to caller
|
||||
if (bIsCovered)
|
||||
*bIsCovered = bIsCoveredLocal;
|
||||
|
||||
// which value to be returned?
|
||||
if (!bIsCoveredLocal)
|
||||
return defaultValue;
|
||||
|
||||
return elevationValue;
|
||||
}
|
||||
|
||||
|
||||
QRectF ElevationMapManager::simpleUnitedExtent() const
|
||||
{
|
||||
if (d->m_simpleExtent.isNull())
|
||||
{
|
||||
bool bFirst = true;
|
||||
for (const ElevationMap *elevationMap : d->m_elevationMapCont)
|
||||
{
|
||||
const QRectF &singleExtent = elevationMap->extent();
|
||||
if (bFirst)
|
||||
{
|
||||
bFirst = false;
|
||||
d->m_simpleExtent = singleExtent;
|
||||
// qCritical() << " bFirst.left " << singleExtent.left() << " bFirst.right " << singleExtent.right();
|
||||
// qCritical() << " bFirst.top " << singleExtent.top() << " bFirst.bottom " << singleExtent.bottom();
|
||||
|
||||
} else {
|
||||
// prefer following instead QRectF::united (top vs. bottom):
|
||||
// qCritical() << " next.left " << singleExtent.left() << " secnextright " << singleExtent.right();
|
||||
// qCritical() << " next.top " << singleExtent.top() << " next.bottom " << singleExtent.bottom();
|
||||
d->m_simpleExtent.setLeft (std::min(d->m_simpleExtent.left(), singleExtent.left()));
|
||||
d->m_simpleExtent.setTop (std::max(d->m_simpleExtent.top(), singleExtent.top())); // top - >use max !!!
|
||||
d->m_simpleExtent.setBottom(std::min(d->m_simpleExtent.bottom(), singleExtent.bottom())); // bottom -> use min
|
||||
d->m_simpleExtent.setRight (std::max(d->m_simpleExtent.right(), singleExtent.right()));
|
||||
}
|
||||
} // for
|
||||
}
|
||||
|
||||
return d->m_simpleExtent;
|
||||
}
|
||||
|
||||
bool ElevationMapManager::contains(const QPointF &point) const
|
||||
{
|
||||
for (const ElevationMap *elevationMap : d->m_elevationMapCont)
|
||||
{
|
||||
if (elevationMap->contains(point))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ElevationMapManager::LOSProfile(const QPointF &start, const QPointF &end, LOSVector &losProfile)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
if (d->m_elevationMapCont.empty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no elevationMap";
|
||||
return;
|
||||
}
|
||||
|
||||
waitForInitialization();
|
||||
|
||||
QRectF simpleExtentLocal = simpleUnitedExtent();
|
||||
|
||||
// qCritical() << " simpleExtent.left " << simpleExtentLocal.left() << " simpleExtent.right " << simpleExtentLocal.right();
|
||||
// qCritical() << " simpleExtent.top " << simpleExtentLocal.top() << " simpleExtent.bottom " << simpleExtentLocal.bottom();
|
||||
|
||||
if (!simpleExtentLocal.contains(start))
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " start coordinate not within area"
|
||||
<< ", start: x=" << start.x() << " ; y=" << start.y()
|
||||
<< ", area: "
|
||||
<< " left " << simpleExtentLocal.left() << ", right " << simpleExtentLocal.right()
|
||||
<< " top " << simpleExtentLocal.top() << ", bottom " << simpleExtentLocal.bottom()
|
||||
;
|
||||
return; // ausserhalb der Höhenkarte !!
|
||||
}
|
||||
|
||||
bool clipped = false;
|
||||
double totalLng;
|
||||
QPointF startG = start;
|
||||
QPointF endG = end;
|
||||
|
||||
if (!simpleExtentLocal.contains(end)) // Clippen
|
||||
{
|
||||
clipped = true;
|
||||
totalLng = length(endG - startG);
|
||||
if (endG.x() < simpleExtentLocal.left())
|
||||
{
|
||||
double m = (endG.y() - startG.y()) / (endG.x() - startG.x());
|
||||
double x = simpleExtentLocal.left();
|
||||
endG.setX(x);
|
||||
endG.setY(startG.y() + m * (x - startG.x()));
|
||||
}
|
||||
else if (endG.x() > simpleExtentLocal.right())
|
||||
{
|
||||
double m = (endG.y() - startG.y()) / (endG.x() - startG.x());
|
||||
double x = simpleExtentLocal.right();
|
||||
endG.setX(x);
|
||||
endG.setY(startG.y() + m * (x - startG.x()));
|
||||
}
|
||||
if (endG.y() < simpleExtentLocal.bottom())
|
||||
{
|
||||
double m = (endG.x() - startG.x()) / (endG.y() - startG.y());
|
||||
double y = simpleExtentLocal.bottom();
|
||||
endG.setY(y);
|
||||
endG.setX(startG.x() + m * (y - startG.y()));
|
||||
}
|
||||
else if (endG.y() > simpleExtentLocal.top())
|
||||
{
|
||||
double m = (endG.x() - startG.x()) / (endG.y() - startG.y());
|
||||
double y = simpleExtentLocal.top();
|
||||
endG.setY(y);
|
||||
endG.setX(startG.x() + m * (y - startG.y()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Korrektursteigung aufgrund WGS84 Erdellipsoid, Lineare Approximation, Fehler bis 200 km: < 1.0m
|
||||
double startRadius = radiusWGS84(startG.y());
|
||||
double corrM = (radiusWGS84(endG.y()) - startRadius) / length(endG - startG);
|
||||
|
||||
//
|
||||
// getSamplePoints(start, end, elevProfile);
|
||||
// find best elevationMap for equested path {startG, endG}
|
||||
//
|
||||
|
||||
// 1st find maps covering the desired pathG:
|
||||
const QPolygonF pathG( QVector<QPointF>{startG, endG} );
|
||||
|
||||
std::vector<ElevationMap *> coveredElevationMaps;
|
||||
coveredElevationMaps.reserve(d->m_elevationMapCont.size());
|
||||
for (auto curItem : qAsConst(d->m_elevationMapCont))
|
||||
{
|
||||
if (curItem && curItem->intersects(pathG))
|
||||
coveredElevationMaps.push_back(curItem);
|
||||
} // for
|
||||
|
||||
if (m_logger.isDebugEnabled())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " coveredElevationMap.size() = " << coveredElevationMaps.size();
|
||||
for (auto curItem : qAsConst(coveredElevationMaps))
|
||||
DEBUG_LOG(m_logger) << " coveredElevationMap = " << curItem->filename();
|
||||
}
|
||||
|
||||
// if no maps covers the desired path, stay on old approach: use most bottom elevation map:
|
||||
if (coveredElevationMaps.empty())
|
||||
coveredElevationMaps = d->m_elevationMapCont;
|
||||
|
||||
// 2nd: find elevation map with highest resolution to achieve best results:
|
||||
using ELE_VEC_IT = std::vector<ElevationMap*>::iterator;
|
||||
ELE_VEC_IT eleIt = coveredElevationMaps.begin();
|
||||
for (ELE_VEC_IT curItem = coveredElevationMaps.begin()+1; curItem != coveredElevationMaps.end(); ++curItem)
|
||||
{
|
||||
ElevationMap *elePtr = *curItem;
|
||||
if (!elePtr)
|
||||
continue;
|
||||
|
||||
if (elePtr->elexelSize().first < (*eleIt)->elexelSize().first)
|
||||
eleIt = curItem;
|
||||
} // for
|
||||
|
||||
Q_ASSERT_X((*eleIt), "ElevationMapManager::LOSProfile", "eleIt failed");
|
||||
|
||||
Vec3dVector elevProfile;
|
||||
(*eleIt)->getSamplePoints(start, end, elevProfile);
|
||||
|
||||
INFO_LOG(m_logger) << "Using ElevationMap '" << (*eleIt)->filename() << "'"
|
||||
<< " (of size = " << d->m_elevationMapCont.size() << ")"
|
||||
<< " with_elexelSize " << (*eleIt)->elexelSize().first
|
||||
<< " -> # SamplePoints = " << elevProfile.size();
|
||||
|
||||
for (Vec3dVector::iterator itr = elevProfile.begin(); itr != elevProfile.end(); ++itr)
|
||||
{
|
||||
double dist = length(distance_in_meter_WGS84(start, itr->toPointF()));
|
||||
double height = elevation(itr->x(), itr->y()); // use elevation over all seperate elevationMaps
|
||||
height += corrM * dist; // WGS84 Erdellipsoid Korrektur
|
||||
height -= (startRadius * (1 - cos(atan(dist / startRadius)))); // Einbeziehen der Erdkruemmung
|
||||
// alternativ als Naeherung: height -= ( dist * dist) / (startRadius * 2.0);
|
||||
losProfile.push_back(LOSentry(dist, height));
|
||||
}
|
||||
|
||||
if (clipped)
|
||||
losProfile.push_back(LOSentry(totalLng, -NAN));
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
ElevationMapManager::LineOfSight ElevationMapManager::lineOfSightCalculation(const LOSVector &losProfile,
|
||||
double centerHat,
|
||||
double objHat) const
|
||||
{
|
||||
// Analog zu SightFanImpl::calculateSightBeam
|
||||
|
||||
|
||||
if (losProfile.size() < 2) // Startpunkt undefiniert oder ausserhalb der Karte
|
||||
{
|
||||
return LineOfSight::LOS_ERROR;
|
||||
}
|
||||
|
||||
LOSVector::const_iterator itr = losProfile.begin();
|
||||
const double centerHeight = itr->height() + centerHat;
|
||||
|
||||
double d1 = 0.0;
|
||||
double height1 = itr->height();
|
||||
|
||||
// // überspringen bis _innerRadius erreicht ist !
|
||||
// while( ++itr != losProfile.end())
|
||||
// {
|
||||
// double d2 = itr->dist(); // *EarthRadius;
|
||||
// double height2 = itr->height();
|
||||
// if( d2 >= m_internal->m_innerRadius)
|
||||
// {
|
||||
// height1 = height1 + (m_internal->m_innerRadius - d1) * ( height2 - height1)/(d2 - d1);
|
||||
// d1 = m_internal->m_innerRadius;
|
||||
// --itr;
|
||||
// break;
|
||||
// }
|
||||
// d1 = d2;
|
||||
// height1 = height2;
|
||||
// }
|
||||
|
||||
// bool visible = true;
|
||||
// SightMode mode = START;
|
||||
|
||||
d1 = itr->dist();
|
||||
double curM = (height1 - centerHeight ) / d1; // bestimmende Steigung
|
||||
|
||||
// sBeam.add( SightEntry( d1, START) );
|
||||
|
||||
while (++itr != losProfile.end())
|
||||
{
|
||||
double d2 = itr->dist(); // *EarthRadius;
|
||||
double height2 = itr->height();
|
||||
|
||||
if (std::isnan(height2)) // Undefined
|
||||
{
|
||||
return LineOfSight::LOS_UNDEFINED;
|
||||
}
|
||||
|
||||
double hObj = (height2 + objHat - centerHeight );
|
||||
double objM = hObj / d2; // Steigung bezogen auf Objekte( Objekte verdecken nicht !)
|
||||
|
||||
LineOfSight newMode = ((objM >= curM)) ? LineOfSight::LOS_VISIBLE : LineOfSight::LOS_INVISIBLE;
|
||||
|
||||
if (newMode == LineOfSight::LOS_INVISIBLE)
|
||||
return LineOfSight::LOS_INVISIBLE;
|
||||
|
||||
|
||||
// if (newMode != mode)
|
||||
// {
|
||||
// if ( (mode != LineOfSight::LOS_UNDEFINED) && (d2 != d1) )
|
||||
// {
|
||||
// // Korrekturwert für Distanz berechnen, unter Berücksichtigung der Objekthoehe !!
|
||||
// double localM = (height2 - height1) /(d2 - d1);
|
||||
// // localM == curM kann nicht auftreten, da newMode != mode
|
||||
// double dCorr = (hObj - (curM * d2)) / (localM - curM);
|
||||
|
||||
// if (dCorr < 0.0)
|
||||
// dCorr = 0.0;
|
||||
// dCorr = d2 - dCorr;
|
||||
// if (dCorr < d1)
|
||||
// dCorr = d1;
|
||||
|
||||
// sBeam.add( SightEntry( dCorr, mode) );
|
||||
// }
|
||||
// mode = newMode;
|
||||
// }
|
||||
|
||||
double terrM = (height2 - centerHeight) / d2; // Steigung bezogen auf Gelaende
|
||||
if (terrM >= curM)
|
||||
{
|
||||
curM = terrM; // neue bestimmende Steigung
|
||||
}
|
||||
|
||||
// height1 = height2;
|
||||
// d1 = d2;
|
||||
} // while
|
||||
|
||||
return LineOfSight::LOS_VISIBLE;
|
||||
}
|
||||
|
||||
ElevationMapManager::LineOfSight ElevationMapManager::lineOfSightCalculation(const LtsUtils::QPoint3D &startPointGeo_absZ,
|
||||
const LtsUtils::QPoint3D &endPointGeo_absZ)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << ", startPointGeo_absZ = " << startPointGeo_absZ << ", endPointGeo_absZ = " << endPointGeo_absZ;
|
||||
|
||||
if (!isValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, LtsElevationManager not valid";
|
||||
return LineOfSight::LOS_ERROR;
|
||||
}
|
||||
|
||||
// 1st: a) centerHat / startHat:
|
||||
const double startHat = startPointGeo_absZ.z() - this->elevation(startPointGeo_absZ.x(), startPointGeo_absZ.y(), -10000);
|
||||
if (startHat < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, startHat is negativ";
|
||||
return LineOfSight::LOS_ERROR;
|
||||
}
|
||||
// 1st: b) endHat / objHat:
|
||||
const double endHat = endPointGeo_absZ.z() - this->elevation(endPointGeo_absZ.x(), endPointGeo_absZ.y(), -10000);
|
||||
if (endHat < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, objHat is negativ"
|
||||
<< ", startPointGeo_absZ=" << startPointGeo_absZ
|
||||
<< ", endPointGeo_absZ=" << endPointGeo_absZ;
|
||||
return LineOfSight::LOS_ERROR;
|
||||
}
|
||||
|
||||
SituationMap::ElevationMapManager::LineOfSight eleMapMgrResult = lineOfSightCalculation(startPointGeo_absZ.toPointF(), startHat,
|
||||
endPointGeo_absZ.toPointF(), endHat);
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << ", startPointGeo = " << startPointGeo_absZ << ", endPointGeo = " << endPointGeo_absZ
|
||||
<< " -> LineOfSight " << static_cast<int>(eleMapMgrResult);
|
||||
return eleMapMgrResult;
|
||||
}
|
||||
|
||||
ElevationMapManager::LineOfSight ElevationMapManager::lineOfSightCalculation(const QPointF &startPointGeo, double startHat,
|
||||
const QPointF &endPointGeo, double endHat)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||||
<< ", startPointGeo = " << startPointGeo << ", startHat = " << startHat
|
||||
<< ", endPointGeo = " << endPointGeo << ", endHat = " << endHat ;
|
||||
if (!isValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, LtsElevationManager not valid";
|
||||
return LineOfSight::LOS_ERROR;
|
||||
}
|
||||
|
||||
if (startHat < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, startHat is negativ";
|
||||
return LineOfSight::LOS_ERROR;
|
||||
}
|
||||
if (endHat < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, endHat is negativ";
|
||||
return LineOfSight::LOS_ERROR;
|
||||
}
|
||||
|
||||
// 1st: create LOSVector:
|
||||
SituationMap::LOSVector losProfile;
|
||||
LOSProfile(startPointGeo, endPointGeo, losProfile);
|
||||
if (losProfile.size() < 2)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, losProfile not valid"
|
||||
<< ", losProfile.size = " << losProfile.size();
|
||||
return LineOfSight::LOS_ERROR;
|
||||
}
|
||||
|
||||
// 2nd: lineOfSightCalculation
|
||||
SituationMap::ElevationMapManager::LineOfSight eleMapMgrResult = this->lineOfSightCalculation(losProfile, startHat, endHat);
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||||
<< ", startPointGeo = " << startPointGeo << ", startHat = " << startHat
|
||||
<< ", endPointGeo = " << endPointGeo << ", endPointHat = " << endHat
|
||||
<< " -> LineOfSight " << static_cast<int>(eleMapMgrResult);
|
||||
return eleMapMgrResult;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // SituationMap
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Manage and combine several ElevationMap
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "elevation_map_helper.h"
|
||||
#include <ElevationMap/situationmapelevationmap_export.h>
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
// forward:
|
||||
class ElevationMap;
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
// ElevationMapManager
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
class SITUATIONMAPELEVATIONMAP_EXPORT ElevationMapManager final : public QObject
|
||||
{
|
||||
using BaseClass = QObject;
|
||||
|
||||
public:
|
||||
ElevationMapManager();
|
||||
ElevationMapManager(const ElevationMapManager &) = delete;
|
||||
ElevationMapManager &operator = (const ElevationMapManager &) = delete;
|
||||
~ElevationMapManager();
|
||||
|
||||
int init(const QStringList &filePaths_rough_to_fine);
|
||||
void cleanupCurrentContent();
|
||||
|
||||
bool waitForInitialization();
|
||||
bool isValid() const;
|
||||
|
||||
|
||||
double elevation(double lon_rad, double lat_rad, bool *bIsCovered = nullptr) const;
|
||||
double elevation(double lon_rad, double lat_rad, double defaultValue, bool *bIsCovered = nullptr) const;
|
||||
|
||||
// united extent of seperate files:
|
||||
QRectF simpleUnitedExtent() const;
|
||||
|
||||
bool contains(const QPointF &point) const;
|
||||
|
||||
// Line of Sight Profile: berücksichtigt Erdkrümmung und WGS84 Erdellipsoid
|
||||
void LOSProfile(const QPointF &start, const QPointF &end, LOSVector &losProfile);
|
||||
|
||||
/*! \name Line of Sight */
|
||||
//@{
|
||||
enum class LineOfSight { LOS_UNDEFINED,
|
||||
LOS_ERROR,
|
||||
LOS_VISIBLE,
|
||||
LOS_INVISIBLE };
|
||||
|
||||
LineOfSight lineOfSightCalculation(const LOSVector &losProfile,
|
||||
double centerHat,
|
||||
double objHat) const;
|
||||
|
||||
LineOfSight lineOfSightCalculation(const LtsUtils::QPoint3D &startPointGeo_absZ,
|
||||
const LtsUtils::QPoint3D &endPointGeo_absZ);
|
||||
|
||||
LineOfSight lineOfSightCalculation(const QPointF &startPointGeo, double startHat,
|
||||
const QPointF &endPointGeo, double endHat);
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
|
||||
class Private;
|
||||
|
||||
Private *d;
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
}; // ElevationMapManager
|
||||
|
||||
|
||||
} // SituationMap
|
||||
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* LineOfSightCalculation (L400)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by N. Thoden, NLE, 06.04.2020
|
||||
*/
|
||||
|
||||
#include "line_of_sight_calculation.h"
|
||||
#include "elevation_map.h"
|
||||
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
|
||||
//
|
||||
// ESRI / ARCGIS
|
||||
// if you link libEsriCommonQt, you propably have to add ArcGISQt5Hack AND: # make sure it's loaded *before* libEsriCommonQt.so
|
||||
// this may effect all executables linking situationMapElevationMap. CHECK!
|
||||
//
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QTimer>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
|
||||
// some helper functions
|
||||
inline Q_CONSTEXPR double pi() { return M_PI; }
|
||||
inline Q_CONSTEXPR double deg2rad() { return pi() / 180.; }
|
||||
inline Q_CONSTEXPR double rad2deg() { return 1. / deg2rad(); }
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
LineOfSightCalculation::LineOfSightCalculation(ElevationMap *elevationMap)
|
||||
: m_logger(getLogger("LineOfSightCalculation"))
|
||||
, m_elevationMap(elevationMap)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
LineOfSightCalculation::~LineOfSightCalculation()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
bool LineOfSightCalculation::calculate(ObserverTargetData &observerTarget, unsigned int sampleIntervallMeter)
|
||||
{
|
||||
// same checks:
|
||||
if (!m_elevationMap || !m_elevationMap->isValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no elevationMap configured or not valid";
|
||||
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Undefined);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!observerTarget.isObserverAndTargetValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " observer and/or target not valid";
|
||||
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Undefined);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (observerTarget.observer().toPointF() == observerTarget.target().toPointF())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " observer and target are identical regarding x and y";
|
||||
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Undefined);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
|
||||
QElapsedTimer timer;
|
||||
if (m_logger.isInfoEnabled())
|
||||
timer.start();
|
||||
|
||||
//
|
||||
//
|
||||
// consider using ElevationMap::LOSProfile
|
||||
//
|
||||
//
|
||||
|
||||
// determine how many iterations we need:
|
||||
double distanceInMeter = distanceMeter(observerTarget.observer(),
|
||||
observerTarget.target());
|
||||
//ERROR_LOG(m_logger) << LOGFUNCTION << " distanceMeter = " << distanceInMeter;
|
||||
|
||||
int maxNumberOfIterations = distanceInMeter / sampleIntervallMeter; // check visibility every ~5m
|
||||
// maxNumberOfIterations = 1000000;
|
||||
|
||||
if (maxNumberOfIterations<=0)
|
||||
maxNumberOfIterations = 5;
|
||||
|
||||
|
||||
double distanceFromObserverToTargetAsFraction = 0;
|
||||
int i = 0;
|
||||
while (i<maxNumberOfIterations)
|
||||
{
|
||||
++i;
|
||||
|
||||
/*
|
||||
|
||||
z-axis (Elevation) pCandidate
|
||||
|---------- /
|
||||
| ----------
|
||||
| ----------
|
||||
| ----------
|
||||
| ----------
|
||||
|------------------------------------------------------------ xy-axis
|
||||
^ ^ ^ ^ ^ ^ ^ ^ samples (every ~5meters)
|
||||
^ ^
|
||||
ObserverPosition TargetPosition
|
||||
|
||||
On every sample position, check if directLineElevation (maximum) is
|
||||
obstructed by elevationMapElevation (real value)
|
||||
if (elevationMapElevation>directLineElevation) -> obstructed/break
|
||||
*/
|
||||
|
||||
distanceFromObserverToTargetAsFraction = (double)i/maxNumberOfIterations;
|
||||
|
||||
|
||||
const Point3D &pCandidate = movePoint(observerTarget.observer(),
|
||||
observerTarget.target(),
|
||||
distanceFromObserverToTargetAsFraction);
|
||||
|
||||
// {
|
||||
// static Point3D oldCandidate;
|
||||
// double distanceInMeter = distanceMeter(pCandidate, oldCandidate);
|
||||
// ERROR_LOG(m_logger) << LOGFUNCTION << " distanceMeter = " << distanceInMeter;
|
||||
// oldCandidate = pCandidate;
|
||||
// }
|
||||
|
||||
|
||||
// z is the elevation of a *direct* line:
|
||||
const double directLineElevation = pCandidate.z();
|
||||
const double elevationMapElevation = m_elevationMap->elevation(pCandidate.x(), pCandidate.y());
|
||||
|
||||
// Coord covered by elevationMap?
|
||||
if (elevationMapElevation <= std::numeric_limits<int>::min())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, coordinate not covered be elevationData. Finish this LineOfSightCalculation."
|
||||
<< " i=" << i
|
||||
<< ", pCandidate = " << pCandidate;
|
||||
|
||||
// write back data
|
||||
observerTarget.setObstacle(pCandidate);
|
||||
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Undefined);
|
||||
|
||||
// finish the loop:
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// analyze / check visibility:
|
||||
if (elevationMapElevation>directLineElevation)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " i=" << i
|
||||
<< " break - pCandidate = " << pCandidate
|
||||
<< " -> directLineElevation = " << directLineElevation
|
||||
<< " -> elevationMapElevation = " << elevationMapElevation;
|
||||
|
||||
// write result
|
||||
observerTarget.setObstacle(pCandidate);
|
||||
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Obstructed);
|
||||
|
||||
// finish the loop:
|
||||
break;
|
||||
} else {
|
||||
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Visible);
|
||||
}
|
||||
|
||||
} // while
|
||||
|
||||
|
||||
if (m_logger.isInfoEnabled())
|
||||
{
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " END"
|
||||
<< ", success = " << success
|
||||
<< ", " << i << " of "<< maxNumberOfIterations << " iterations"
|
||||
<< ", distanceFromObserverToTargetAsFraction = " << distanceFromObserverToTargetAsFraction
|
||||
<< ", pCandidate=" << observerTarget.obstacle()
|
||||
<< ", lineOfSightVisibility=" << static_cast<int>(observerTarget.lineOfSightVisibility())
|
||||
<< ", took [ms] " << timer.elapsed();
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << ", success = " << success;
|
||||
return success;
|
||||
}
|
||||
|
||||
Point3D LineOfSightCalculation::movePoint(const Point3D &oberserver, const Point3D &target, double distanceFromObserverToTargetAsFraction) // 0.0 ... 1.0
|
||||
{
|
||||
// positions are lon/lat @ rad.
|
||||
// for evaluation we do that very simple:
|
||||
|
||||
// strange, but: using Point3D seems to be faster then using QPointF
|
||||
const Point3D &dist = target - oberserver;
|
||||
const Point3D &point = oberserver + (dist * distanceFromObserverToTargetAsFraction);
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
double LineOfSightCalculation::distanceMeter(const Point3D &oberserver, const Point3D &target)
|
||||
{
|
||||
// Try to avoid the dependency to ESRI (keep ArcGISQt5Hack in mind)
|
||||
// And good accuracy is not required here
|
||||
// use LtsCoordTrans::distance
|
||||
|
||||
// Esri::ArcGISRuntime::Point geom1(oberserver.x()*rad2deg(), oberserver.y()*rad2deg(), oberserver.z(), Esri::ArcGISRuntime::SpatialReference::wgs84());
|
||||
// Esri::ArcGISRuntime::Point geom2(target.x() *rad2deg(), target.y() *rad2deg(), target.z() , Esri::ArcGISRuntime::SpatialReference::wgs84());
|
||||
|
||||
// Esri::ArcGISRuntime::GeometryEngine *gEngine = Esri::ArcGISRuntime::GeometryEngine::instance();
|
||||
// Esri::ArcGISRuntime::GeodeticDistanceResult geodeticDistanceResult = gEngine->distanceGeodetic(geom1, geom2,
|
||||
// Esri::ArcGISRuntime::LinearUnitId::Meters,
|
||||
// Esri::ArcGISRuntime::AngularUnitId::Degrees,
|
||||
// Esri::ArcGISRuntime::GeodeticCurveType::Geodesic);
|
||||
// double distance = geodeticDistanceResult.distance();
|
||||
|
||||
|
||||
double distance = LtsCoordTrans::distance(oberserver.toPointF(), target.toPointF());
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* LineOfSightCalculation (L400)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by N. Thoden, NLE, 06.04.2020
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ElevationMap/situationmapelevationmap_export.h>
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
using Point3D = LtsUtils::QPoint3D; ///< x = lon ; y = lat , z = elevation/altitude in meters
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
// forward
|
||||
class ElevationMap;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/*!
|
||||
\brief Define visibility.
|
||||
*/
|
||||
enum class LineOfSightVisibility
|
||||
{
|
||||
Undefined, /*!< no data at that location? */
|
||||
Visible,
|
||||
Obstructed
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class SITUATIONMAPELEVATIONMAP_EXPORT ObserverTargetData
|
||||
{
|
||||
public:
|
||||
explicit ObserverTargetData(const Point3D &oberserver = Point3D(), // z-value: incl. observerHeight
|
||||
const Point3D &target = Point3D()) // z-value: incl. targetHeight
|
||||
: m_oberserver(oberserver)
|
||||
, m_target(target)
|
||||
{}
|
||||
|
||||
const Point3D &observer() const { return m_oberserver; }
|
||||
const Point3D &target() const { return m_target; }
|
||||
|
||||
const Point3D &obstacle() const { return m_obstacle; }
|
||||
void setObstacle(const Point3D &obstacle) { m_obstacle = obstacle; }
|
||||
|
||||
LineOfSightVisibility lineOfSightVisibility() const { return m_visible; }
|
||||
void setLineOfSightVisibility(const LineOfSightVisibility &visible) { m_visible = visible; }
|
||||
|
||||
bool isObserverAndTargetValid() const { return (!m_oberserver.isNull()) && (!m_target.isNull()); }
|
||||
|
||||
private:
|
||||
Point3D m_oberserver;
|
||||
Point3D m_target;
|
||||
|
||||
Point3D m_obstacle;
|
||||
LineOfSightVisibility m_visible = LineOfSightVisibility::Undefined;
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class SITUATIONMAPELEVATIONMAP_EXPORT LineOfSightCalculation
|
||||
{
|
||||
public:
|
||||
explicit LineOfSightCalculation(ElevationMap *elevationMap);
|
||||
~LineOfSightCalculation();
|
||||
|
||||
bool calculate(ObserverTargetData &observerTarget, unsigned int sampleIntervallMeter = 5);
|
||||
|
||||
protected:
|
||||
static Point3D movePoint(const Point3D &oberserver,
|
||||
const Point3D &target,
|
||||
double distanceFromObserverToTargetAsFraction);
|
||||
|
||||
static double distanceMeter(const Point3D &oberserver,
|
||||
const Point3D &target);
|
||||
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
ElevationMap *m_elevationMap = nullptr;
|
||||
|
||||
ObserverTargetData m_observerTarget;
|
||||
};
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
# ADD_SUBDIRECTORY(Viewshed3D)
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
# Evaluation application for 3D viewshed
|
||||
|
||||
FIND_PACKAGE(ArcGIS REQUIRED)
|
||||
|
||||
INCLUDE_DIRECTORIES(${ARCGIS_INCLUDE_DIR}/arcgis)
|
||||
|
||||
SET(EXE_SRCS
|
||||
main.cpp
|
||||
ViewshedLocation.cpp
|
||||
)
|
||||
|
||||
SET(EXE_HDRS
|
||||
ViewshedLocation.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(EvalViewshed3DApp FILES ${EXE_SRCS} ${EXE_HDRS})
|
||||
|
||||
NGL_ADD_EXECUTABLE(WS NO_TRANSLATION EvalViewshed3DApp ${EXE_SRCS} ${EXE_HDRS})
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(
|
||||
EvalViewshed3DApp
|
||||
ArcGIS::ArcGIS
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Widgets
|
||||
Qt5::Network
|
||||
)
|
||||
|
||||
|
||||
IF(MSVC)
|
||||
# Configure the template file
|
||||
SET(VS_USER_FILE EvalViewshed3DApp.vcxproj.user)
|
||||
configure_file( ../../SituationMap.vcxproj.user.in ${CMAKE_CURRENT_BINARY_DIR}/${VS_USER_FILE} @ONLY)
|
||||
ENDIF(MSVC)
|
||||
|
||||
NGL_INSTALL_TARGET(EvalViewshed3DApp)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#-------------------------------------------------
|
||||
# Copyright 2015 Esri.
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at:
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#-------------------------------------------------
|
||||
|
||||
mac {
|
||||
cache()
|
||||
}
|
||||
|
||||
CONFIG += c++11 esri_runtime_qt100_0_0 debug
|
||||
|
||||
QT += core gui opengl xml network positioning sensors
|
||||
|
||||
win32:CONFIG += \
|
||||
embed_manifest_exe
|
||||
|
||||
TARGET = LocationViewshed
|
||||
TEMPLATE = app
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
ViewshedLocation.cpp
|
||||
|
||||
HEADERS += \
|
||||
ViewshedLocation.h
|
||||
|
||||
|
||||
win32 {
|
||||
INCLUDEPATH += "C:/Program Files (x86)/ArcGIS SDKs/Qt100.0/sdk/include"
|
||||
debug:LIBPATH += "C:/Program Files (x86)/ArcGIS SDKs/Qt100.0/sdk/windows/x64/lib/Debug"
|
||||
release:LIBPATH += "C:/Program Files (x86)/ArcGIS SDKs/Qt100.0/sdk/windows/x64/lib/Release"
|
||||
debug:LIBS += -lEsriCommonQtd
|
||||
release:LIBS += -lEsriCommonQt
|
||||
debug:LIBS += -lEsriRuntimeQtd
|
||||
release:LIBS += -lEsriRuntimeQt
|
||||
}
|
||||
|
||||
linux {
|
||||
INCLUDEPATH += /usr/include/arcgis
|
||||
LIBS += -lEsriCommonQt
|
||||
LIBS += -lEsriRuntimeQt
|
||||
LIBS += -lc++
|
||||
}
|
||||
|
||||
|
||||
macx {
|
||||
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.11
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Declaration/Definition
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
// [WriteFile Name=ViewshedLocation, Category=Analysis]
|
||||
// [Legal]
|
||||
// Copyright 2017 Esri.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// [Legal]
|
||||
|
||||
#include "ViewshedLocation.h"
|
||||
|
||||
#include "ArcGISTiledElevationSource.h"
|
||||
#include "Scene.h"
|
||||
#include "SceneGraphicsView.h"
|
||||
#include "LocationViewshed.h"
|
||||
#include "Camera.h"
|
||||
#include "Point.h"
|
||||
#include "AnalysisOverlay.h"
|
||||
|
||||
#include "QColor"
|
||||
|
||||
|
||||
using namespace Esri::ArcGISRuntime;
|
||||
|
||||
ViewshedLocation::ViewshedLocation(QObject* parent /* = nullptr */):
|
||||
QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void ViewshedLocation::init(Esri::ArcGISRuntime::SceneGraphicsView* sceneView)
|
||||
{
|
||||
m_sceneView = sceneView;
|
||||
|
||||
// Register classes for QML
|
||||
// qmlRegisterType<SceneQuickView>("Esri.Samples", 1, 0, "SceneView");
|
||||
// qmlRegisterType<ViewshedLocation>("Esri.Samples", 1, 0, "ViewshedLocationSample");
|
||||
|
||||
|
||||
Surface* surface = new Surface(this);
|
||||
surface->elevationSources()->append(
|
||||
new ArcGISTiledElevationSource(
|
||||
QUrl(QStringLiteral("http://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer")),
|
||||
this));
|
||||
m_sceneView->arcGISScene()->setBaseSurface(surface);
|
||||
|
||||
// set initial viewpoint
|
||||
setInitialViewpoint();
|
||||
|
||||
// connect signals
|
||||
connectSignals();
|
||||
}
|
||||
|
||||
|
||||
void ViewshedLocation::setInitialViewpoint()
|
||||
{
|
||||
// Set a viewpoint
|
||||
double x = 6.86088;
|
||||
double y = 45.3604;
|
||||
double z = 3582.55;
|
||||
Point point(x, y, z, SpatialReference(4326));
|
||||
double heading = 345;
|
||||
double pitch = 70;
|
||||
double roll = 0;
|
||||
Camera camera(point, heading, pitch, roll);
|
||||
m_sceneView->setViewpointCamera(camera);
|
||||
}
|
||||
|
||||
void ViewshedLocation::connectSignals()
|
||||
{
|
||||
// on mouse click perform the location viewshed
|
||||
connect(m_sceneView, &SceneGraphicsView::mouseClicked, this, [this](QMouseEvent& event)
|
||||
{
|
||||
if (!m_locationViewshed[0])
|
||||
createViewshed(event.x(), event.y());
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
const Point pt = m_sceneView->screenToBaseSurface(event.x(), event.y());
|
||||
m_locationViewshed[i]->setLocation(pt);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_sceneView, &SceneGraphicsView::mousePressedAndHeld, this, [this](QMouseEvent& event)
|
||||
{
|
||||
if (!m_locationViewshed[0])
|
||||
createViewshed(event.x(), event.y());
|
||||
|
||||
m_calculating = true;
|
||||
});
|
||||
|
||||
connect(m_sceneView, &SceneGraphicsView::mouseMoved, this, [this](QMouseEvent& event)
|
||||
{
|
||||
if (m_calculating)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
const Point pt = m_sceneView->screenToBaseSurface(event.x(), event.y());
|
||||
m_locationViewshed[i]->setLocation(pt);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_sceneView, &SceneGraphicsView::mouseReleased, this, [this](QMouseEvent)
|
||||
{
|
||||
m_calculating = false;
|
||||
});
|
||||
}
|
||||
|
||||
void ViewshedLocation::createViewshed(double x, double y)
|
||||
{
|
||||
|
||||
m_analysisOverlay = new AnalysisOverlay(this);
|
||||
m_sceneView->analysisOverlays()->append(m_analysisOverlay);
|
||||
|
||||
|
||||
const Point pt = m_sceneView->screenToBaseSurface(x, y);
|
||||
|
||||
qCritical() << " pt=";
|
||||
qCritical() << " pt=" << pt.x();
|
||||
qCritical() << " pt=" << pt.y();
|
||||
qCritical() << " pt=" << pt.z();
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
double heading = i * 120.0;
|
||||
m_locationViewshed[i] = new LocationViewshed(pt
|
||||
, heading
|
||||
, 90.0 // pitch
|
||||
, 120.0 // horizontalAngle
|
||||
, 90.0 // verticalAngle
|
||||
, 10.0 // minDistance
|
||||
, 20000
|
||||
, this);
|
||||
|
||||
|
||||
m_locationViewshed[i]->setVisible(m_viewshedVisible);
|
||||
|
||||
// Add the Viewshed to the Analysis Overlay
|
||||
m_analysisOverlay->analyses()->append(m_locationViewshed[i]);
|
||||
|
||||
m_locationViewshed[i]->setFrustumOutlineVisible(true);
|
||||
|
||||
// QColor frustumColor(0, 0, 0, 255);
|
||||
// m_locationViewshed->setFrustumOutlineColor(frustumColor);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Getters/Setters for each Q_PROPERTY
|
||||
bool ViewshedLocation::isViewshedVisible() const
|
||||
{
|
||||
return m_viewshedVisible;
|
||||
}
|
||||
|
||||
void ViewshedLocation::setViewshedVisible(bool viewshedVisible)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (m_locationViewshed[i])
|
||||
{
|
||||
if (m_locationViewshed[i]->isVisible() == viewshedVisible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
m_locationViewshed[i]->setVisible(viewshedVisible);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_viewshedVisible != viewshedVisible)
|
||||
{
|
||||
m_viewshedVisible = viewshedVisible;
|
||||
|
||||
emit viewshedVisibleChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewshedLocation::isFrustumOutlineVisible() const
|
||||
{
|
||||
return m_locationViewshed[0] ? m_locationViewshed[0]->isFrustumOutlineVisible() : m_frustumVisible;
|
||||
}
|
||||
|
||||
void ViewshedLocation::setFrustumOutlineVisible(bool frustumVisible)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (m_locationViewshed[i])
|
||||
{
|
||||
if (m_locationViewshed[i]->isFrustumOutlineVisible() == frustumVisible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
m_frustumVisible = frustumVisible;
|
||||
m_locationViewshed[i]->setFrustumOutlineVisible(frustumVisible);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_frustumVisible != frustumVisible)
|
||||
{
|
||||
m_frustumVisible = frustumVisible;
|
||||
emit frustumVisibleChanged();
|
||||
}
|
||||
}
|
||||
|
||||
double ViewshedLocation::minDistance() const
|
||||
{
|
||||
return m_locationViewshed[0] ? m_locationViewshed[0]->minDistance() : m_minDistance;
|
||||
}
|
||||
|
||||
void ViewshedLocation::setMinDistance(double minDistance)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (m_locationViewshed[i])
|
||||
{
|
||||
if (m_locationViewshed[i]->minDistance() == minDistance)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
m_locationViewshed[i]->setMinDistance(minDistance);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_minDistance != minDistance)
|
||||
{
|
||||
m_minDistance = minDistance;
|
||||
emit minDistanceChanged();
|
||||
}
|
||||
}
|
||||
|
||||
double ViewshedLocation::maxDistance() const
|
||||
{
|
||||
return m_locationViewshed[0] ? m_locationViewshed[0]->maxDistance() : m_maxDistance;
|
||||
}
|
||||
|
||||
void ViewshedLocation::setMaxDistance(double maxDistance)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (m_locationViewshed[i])
|
||||
{
|
||||
if (m_locationViewshed[i]->maxDistance() == maxDistance)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
m_locationViewshed[i]->setMaxDistance(maxDistance);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_maxDistance != maxDistance)
|
||||
{
|
||||
m_maxDistance = maxDistance;
|
||||
emit maxDistanceChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Declaration/Definition
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
// [WriteFile Name=ViewshedLocation, Category=Analysis]
|
||||
// [Legal]
|
||||
// Copyright 2017 Esri.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// [Legal]
|
||||
|
||||
#ifndef VIEWSHEDLOCATION_H
|
||||
#define VIEWSHEDLOCATION_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QColor>
|
||||
|
||||
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class SceneGraphicsView;
|
||||
class LocationViewshed;
|
||||
class AnalysisOverlay;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ViewshedLocation : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ViewshedLocation(QObject* parent = nullptr);
|
||||
~ViewshedLocation() = default;
|
||||
|
||||
// void componentComplete() Q_DECL_OVERRIDE;
|
||||
void init(Esri::ArcGISRuntime::SceneGraphicsView* sceneView);
|
||||
|
||||
Q_PROPERTY(bool viewshedVisible READ isViewshedVisible WRITE setViewshedVisible NOTIFY viewshedVisibleChanged)
|
||||
Q_PROPERTY(bool frustumVisible READ isFrustumOutlineVisible WRITE setFrustumOutlineVisible NOTIFY frustumVisibleChanged)
|
||||
Q_PROPERTY(double minDistance READ minDistance WRITE setMinDistance NOTIFY minDistanceChanged)
|
||||
Q_PROPERTY(double maxDistance READ maxDistance WRITE setMaxDistance NOTIFY maxDistanceChanged)
|
||||
|
||||
|
||||
bool isViewshedVisible() const;
|
||||
void setViewshedVisible(bool viewshedVisible);
|
||||
|
||||
bool isFrustumOutlineVisible() const;
|
||||
void setFrustumOutlineVisible(bool frustumVisible);
|
||||
|
||||
double minDistance() const;
|
||||
void setMinDistance(double minDistance);
|
||||
|
||||
double maxDistance() const;
|
||||
void setMaxDistance(double maxDistance);
|
||||
|
||||
|
||||
signals:
|
||||
void viewshedVisibleChanged();
|
||||
void frustumVisibleChanged();
|
||||
void minDistanceChanged();
|
||||
void maxDistanceChanged();
|
||||
|
||||
|
||||
private:
|
||||
void connectSignals();
|
||||
void setInitialViewpoint();
|
||||
void createViewshed(double x, double y);
|
||||
|
||||
Esri::ArcGISRuntime::SceneGraphicsView *m_sceneView = nullptr;
|
||||
Esri::ArcGISRuntime::LocationViewshed *m_locationViewshed[3] = { nullptr, nullptr, nullptr };
|
||||
Esri::ArcGISRuntime::AnalysisOverlay *m_analysisOverlay = nullptr;
|
||||
|
||||
bool m_viewshedVisible = true;
|
||||
bool m_frustumVisible = false;
|
||||
double m_minDistance = 50;
|
||||
double m_maxDistance = 1000;
|
||||
double m_horizontalAngle = 45;
|
||||
double m_veriticalAngle = 90;
|
||||
double m_heading = 0;
|
||||
double m_pitch = 90;
|
||||
bool m_calculating = false;
|
||||
};
|
||||
|
||||
#endif // VIEWSHEDLOCATION_H
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Showing artefacts when drawing 3D map.
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Windows 7, Linux, Qt 5.9. ArcGISRuntimeQt 100.1
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** 08.11.2017, JT : Initial
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include <QtGui/QSurface>
|
||||
|
||||
#include <QtNetwork/QNetworkProxy>
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QDesktopWidget>
|
||||
#include <QtWidgets/QComboBox>
|
||||
#include <QtWidgets/QHBoxLayout>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QPushButton>
|
||||
|
||||
#include <QtWidgets/QGraphicsScene>
|
||||
#include <QtWidgets/QGraphicsProxyWidget>
|
||||
|
||||
|
||||
#include <QtWidgets/QMainWindow>
|
||||
|
||||
#include <Map.h>
|
||||
#include <Scene.h>
|
||||
#include <SceneGraphicsView.h>
|
||||
#include <GraphicsOverlay.h>
|
||||
#include <GeoView.h>
|
||||
#include <Basemap.h>
|
||||
#include <ArcGISTiledLayer.h>
|
||||
#include <Layer.h>
|
||||
#include <GraphicsOverlay.h>
|
||||
|
||||
#include "ViewshedLocation.h"
|
||||
|
||||
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
class MapWindow : public QWidget
|
||||
{
|
||||
|
||||
Esri::ArcGISRuntime::Basemap * m_basemap;
|
||||
Esri::ArcGISRuntime::Scene * m_scene;
|
||||
Esri::ArcGISRuntime::SceneGraphicsView * m_sceneGraphicsView;
|
||||
Esri::ArcGISRuntime::GeoView * m_mapView;
|
||||
Esri::ArcGISRuntime::GraphicsOverlay * m_graphicsOverlay;
|
||||
|
||||
Qt::MouseButton m_pressedMouseButton;
|
||||
QPoint m_mouseMoveRefPos;
|
||||
Esri::ArcGISRuntime::TaskWatcher m_pickingTask;
|
||||
bool m_pendingRequest;
|
||||
|
||||
public:
|
||||
|
||||
MapWindow() : QWidget(), m_graphicsOverlay(nullptr), m_pickingTask(), m_pendingRequest(false)
|
||||
{
|
||||
m_pressedMouseButton = Qt::MouseButton::NoButton;
|
||||
m_mouseMoveRefPos = QPoint();
|
||||
|
||||
m_basemap = new Esri::ArcGISRuntime::Basemap(this);
|
||||
m_scene = new Esri::ArcGISRuntime::Scene(m_basemap,this);
|
||||
|
||||
connect( m_basemap, &Esri::ArcGISRuntime::Map::errorOccurred , this, &MapWindow::onErrorBasemap );
|
||||
connect( m_scene , &Esri::ArcGISRuntime::Scene::errorOccurred, this, &MapWindow::onErrorScene );
|
||||
connect( m_scene , &Esri::ArcGISRuntime::Scene::doneLoading , this, &MapWindow::onDoneLoading );
|
||||
|
||||
m_sceneGraphicsView = nullptr;
|
||||
try
|
||||
{
|
||||
m_sceneGraphicsView = new Esri::ArcGISRuntime::SceneGraphicsView(); // no parent,
|
||||
m_sceneGraphicsView->setObjectName(QLatin1String("EsriSceneView"));
|
||||
m_sceneGraphicsView->setFrameShape(QFrame::NoFrame); // frameless
|
||||
}
|
||||
catch (std::exception &stdEx)
|
||||
{
|
||||
const char *what = stdEx.what();
|
||||
if (what)
|
||||
qCritical()<< "MapWindow init SceneGraphicsView: std Exception " << " what: '" << what << "'";
|
||||
else
|
||||
qCritical() << "MapWindow init SceneGraphicsView: std Exception";
|
||||
|
||||
throw; // re-throw
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
qCritical() << "MapWindow init SceneGraphicsView: unknown Exception";
|
||||
throw; // re-throw
|
||||
}
|
||||
|
||||
if (!m_sceneGraphicsView)
|
||||
return;
|
||||
|
||||
m_sceneGraphicsView->setArcGISScene(m_scene);
|
||||
|
||||
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||
layout->addWidget(m_sceneGraphicsView);
|
||||
|
||||
initMapLayer(QLatin1String("http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"));
|
||||
initMapLayer(QLatin1String("http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"));
|
||||
|
||||
Esri::ArcGISRuntime::Camera camera(28.4, 83.9, 10010.0, 10.0, 80.0, 300.0);
|
||||
m_sceneGraphicsView->setViewpointCameraAndWait(camera);// set the viewpoint
|
||||
|
||||
/*
|
||||
QPushButton * aButton = new QPushButton(tr("Click me")); // toplevel widget
|
||||
QGraphicsProxyWidget *proxy = m_sceneGraphicsView->QGraphicsView::scene()->addWidget(aButton);
|
||||
proxy->setOpacity(0.99);
|
||||
|
||||
connect( aButton, &QPushButton::clicked, this, []() {qCritical() << "A Button has been clicked!";} );
|
||||
*/
|
||||
|
||||
QTimer *timer = new QTimer(this);
|
||||
timer->setSingleShot(true);
|
||||
timer->setInterval(5000);
|
||||
connect(timer, &QTimer::timeout, this, [this]() {
|
||||
|
||||
qCritical() << "Create viewshed ...";
|
||||
ViewshedLocation * vLoc = new ViewshedLocation(this);
|
||||
vLoc->init(m_sceneGraphicsView);
|
||||
});
|
||||
timer->start();
|
||||
|
||||
|
||||
} // MapWindow()
|
||||
|
||||
|
||||
~MapWindow() = default;
|
||||
|
||||
|
||||
void initMapLayer( const QString &mapServiceUrl )
|
||||
{
|
||||
Esri::ArcGISRuntime::ArcGISTiledLayer *tiledLayer = new Esri::ArcGISRuntime::ArcGISTiledLayer(QUrl(mapServiceUrl), this);
|
||||
tiledLayer->setName(mapServiceUrl);
|
||||
tiledLayer->setObjectName(tiledLayer->name());
|
||||
|
||||
m_basemap->baseLayers()->append(tiledLayer);
|
||||
|
||||
} // void initMapLayer()
|
||||
|
||||
private:
|
||||
|
||||
void onDoneLoading(const Esri::ArcGISRuntime::Error &loadError)
|
||||
{
|
||||
|
||||
} // void onDoneLoading(const Esri::ArcGISRuntime::Error &loadError)
|
||||
|
||||
|
||||
void onErrorBasemap(const Esri::ArcGISRuntime::Error &error)
|
||||
{
|
||||
qCritical() << " ---EsriError,Basemap --- occured: "
|
||||
<< " code=" << error.code()
|
||||
<< " domain=" << (int)error.domain()
|
||||
<< " extendedErrorType=" << (int)error.extendedErrorType()
|
||||
<< ", message='" << error.message() << "'";
|
||||
} // void onErrorBasemap(const Esri::ArcGISRuntime::Error &error)
|
||||
|
||||
|
||||
void onErrorScene(const Esri::ArcGISRuntime::Error &error)
|
||||
{
|
||||
qCritical() << " ---EsriError, Scene --- occured: "
|
||||
<< " code=" << error.code()
|
||||
<< " domain=" << (int)error.domain()
|
||||
<< " extendedErrorType=" << (int)error.extendedErrorType()
|
||||
<< ", message='" << error.message() << "'";
|
||||
} // void onErrorScene(const Esri::ArcGISRuntime::Error &error)
|
||||
|
||||
|
||||
}; // MapWindow
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication app(argc,argv);
|
||||
|
||||
// ESRI :
|
||||
#ifdef Q_OS_WIN
|
||||
// Force usage of OpenGL ES through ANGLE on Windows
|
||||
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
|
||||
#endif
|
||||
// : ESRI
|
||||
|
||||
#define PROXY
|
||||
#ifdef PROXY
|
||||
QNetworkProxy proxy;
|
||||
proxy.setType(QNetworkProxy::HttpProxy);
|
||||
proxy.setHostName(QStringLiteral("proxy-rde"));
|
||||
proxy.setPort(8080);
|
||||
proxy.setUser(QStringLiteral("norbert.thoden@rheinmetall.com"));
|
||||
proxy.setPassword(QStringLiteral("RDEWWW11"));
|
||||
QNetworkProxy::setApplicationProxy(proxy);
|
||||
#endif
|
||||
|
||||
MapWindow * mapWin = new MapWindow();
|
||||
|
||||
QDesktopWidget wid;
|
||||
|
||||
int width = mapWin->frameGeometry().width();
|
||||
int height = mapWin->frameGeometry().height();
|
||||
|
||||
int screenWidth = wid.screen()->width();
|
||||
int screenHeight = wid.screen()->height();
|
||||
|
||||
mapWin->setGeometry((screenWidth / 2) - (width / 2), (screenHeight / 2) - (height / 2), width, height);
|
||||
|
||||
mapWin->show();
|
||||
|
||||
app.setQuitOnLastWindowClosed(true);
|
||||
|
||||
int retval = app.exec();
|
||||
|
||||
delete mapWin;
|
||||
|
||||
return retval;
|
||||
|
||||
} // main
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
FIND_PACKAGE(ArcGIS REQUIRED)
|
||||
|
||||
|
||||
# LIBRARY
|
||||
SET(FunctionDialog_SRCS
|
||||
function_dialog.cpp
|
||||
simple_esri_layer.cpp
|
||||
)
|
||||
|
||||
SET(FunctionDialog_HDRS
|
||||
function_dialog_export.h
|
||||
function_dialog.h
|
||||
simple_esri_layer.h
|
||||
)
|
||||
|
||||
SET(FunctionDialog_ICONS
|
||||
state_icon_b.xpm
|
||||
state_icon_a.xpm
|
||||
state_icon_c.xpm
|
||||
)
|
||||
|
||||
SOURCE_GROUP(FunctionDialog FILES ${FunctionDialog_SRCS} ${FunctionDialog_HDRS})
|
||||
NGL_ADD_LIBRARY(WS situationMapFunctionDialog SHARED ${FunctionDialog_SRCS} ${FunctionDialog_HDRS})
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(situationMapFunctionDialog
|
||||
PRIVATE
|
||||
NGLLogger
|
||||
LtsCoordTrans
|
||||
LtsWidgets
|
||||
advancedSymbologyGui
|
||||
PUBLIC
|
||||
ArcGIS::ArcGIS
|
||||
situationMap
|
||||
situationMapObjects
|
||||
situationMapPortal
|
||||
Qt5::Core
|
||||
Qt5::Widgets
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(situationMapFunctionDialog)
|
||||
|
||||
+8905
File diff suppressed because it is too large.
Load diff
+289
@@ -0,0 +1,289 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* FunctionDialog
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "function_dialog_export.h"
|
||||
#include <Map/map.h>
|
||||
#include <QWidget>
|
||||
#include <Symbology/symbol_dictionary.h>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/Map.h>
|
||||
#include <arcgis/MapGraphicsView.h>
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
|
||||
// #define USE_LOCAL_SERVER
|
||||
|
||||
|
||||
class QStandardItemModel;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
namespace RB
|
||||
{
|
||||
class RubberbandBase;
|
||||
}
|
||||
|
||||
class Map;
|
||||
|
||||
// TODO: nur fuer Tests exportiert
|
||||
class FUNCTIONDIALOG_EXPORT FunctionDialog : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FunctionDialog(Esri::ArcGISRuntime::Map *esriMap,
|
||||
Esri::ArcGISRuntime::MapGraphicsView *esriView,
|
||||
QWidget *parent);
|
||||
explicit FunctionDialog(SituationMap::Map *map);
|
||||
virtual ~FunctionDialog();
|
||||
|
||||
static void addButtonToMap(SituationMap::Map *map, bool isVisible = true);
|
||||
|
||||
|
||||
void init();
|
||||
|
||||
void setGraphicsLayer(Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer);
|
||||
|
||||
void setMapPositionString(const QString &mapPosition);
|
||||
void setPixelSizeString(const QString &text);
|
||||
void addMapPositionString(const QString &mapPosition);
|
||||
|
||||
FunctionDialog(const FunctionDialog &other) = delete; // No copy
|
||||
FunctionDialog &operator=(const FunctionDialog &other) = delete; // No copy
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
void addSimpleLayerTab();
|
||||
void addLogicalLayerTab();
|
||||
void addLayerPerformanceTab();
|
||||
void addGraphicsTab();
|
||||
void addGraphics3DTab();
|
||||
void addMessageTab();
|
||||
void addMapObjectTab();
|
||||
void addRubberbandTab();
|
||||
void addRubberband3DTab();
|
||||
void addToolsTab();
|
||||
void addViewshedTab();
|
||||
void addOverlayPlanTab();
|
||||
void addIconRenderTab();
|
||||
void addPortalTab();
|
||||
void addMovePointLuxemburgTab();
|
||||
|
||||
|
||||
void getRotationAndAngle(const QPointF §Start, const QPointF §End, double &rotationDegOut, double &openAngleDegOut);
|
||||
// void addYourTab();
|
||||
|
||||
|
||||
Esri::ArcGISRuntime::Graphic *createCube(const SituationMap::PositionCont &mapPosCont,
|
||||
int baseHeight,
|
||||
double objHeight,
|
||||
const QString &partyNameValue = QString());
|
||||
|
||||
|
||||
public Q_SLOTS:
|
||||
void onDestroyed();
|
||||
|
||||
void onLayerPerfCreateLayer();
|
||||
|
||||
|
||||
void onGenerateGraphics();
|
||||
void onGenerateCube();
|
||||
void onGenerateCubeArray();
|
||||
void onGenerateStackedCubes();
|
||||
void onGenerateGraphicsKristenStrandford();
|
||||
void onGenerateUniqueVaueRendererMountingPoints();
|
||||
|
||||
void onGenerate3DGraphicSphereRENDERER();
|
||||
void onSphereOpacityChangedRENDERER(int opacityValue);
|
||||
|
||||
void onGenerate3DGraphicSphere();
|
||||
void onSphereOpacityChanged(int opacityValue);
|
||||
void onSphereZValueChanged(int ZValue);
|
||||
|
||||
void onGenerate3DGraphicCone();
|
||||
void onConeOpacityChanged(int opacityValue);
|
||||
void onConeZValueChanged(int ZValue);
|
||||
void onConeHeadingChanged(float angle);
|
||||
void onConeRollChanged(float angle);
|
||||
void onConePitchChanged(float angle);
|
||||
|
||||
void on3dModel();
|
||||
void on3dModelZValueChanged(int ZValue);
|
||||
|
||||
void onGenerate3DGraphicConeUniqueValueRenderer();
|
||||
|
||||
|
||||
|
||||
void onAddCivilSymbols();
|
||||
void onMessage();
|
||||
void onMessageSelect();
|
||||
void onAddSymbol();
|
||||
void onSomeParticipants();
|
||||
|
||||
void onRubberbandApply(RB::RubberbandBase *);
|
||||
void onRubberbandAbort(RB::RubberbandBase *);
|
||||
void onRubberband3DApply(RB::RubberbandBase *);
|
||||
void onRubberband3DAbort(RB::RubberbandBase *);
|
||||
void onRubberbandDefineArrow();
|
||||
void onRubberbandDefineEllipse();
|
||||
void onRubberbandBoobyTrapSector();
|
||||
void onRubberbandCheckCoordinates();
|
||||
void onRubberbandStateSelect();
|
||||
void onRubberbandTwoInOne();
|
||||
void onRectCheckCoordinates();
|
||||
|
||||
void onPolygonCreate();
|
||||
void onPolylineCreate();
|
||||
void onPolylineUpdate();
|
||||
void onTextCreate();
|
||||
void onTextUpdate();
|
||||
void onMapObjectIndicatorCreate();
|
||||
|
||||
|
||||
void onParticipantGetPosition();
|
||||
void onParticipantGetPositionApplied(RB::RubberbandBase *rubberband = nullptr);
|
||||
bool createParticipant(const Point3D &origin,
|
||||
const QString &debugInfo);
|
||||
void onParticipantCreate();
|
||||
void onParticipantUpdate();
|
||||
|
||||
void onAreaFireCreate();
|
||||
void onAreaFireUpdate();
|
||||
|
||||
void onBuildingCreate();
|
||||
void onBuildingUpdate();
|
||||
|
||||
void onBiologicalAgentCreate();
|
||||
void onBiologicalAgentUpdate();
|
||||
|
||||
void onChemicalAgentCreate();
|
||||
|
||||
void onCubeCreate();
|
||||
|
||||
void onDangerAreaCreate();
|
||||
void onDangerAreaUpdate();
|
||||
|
||||
void onFunctionalAreaCreate();
|
||||
void onFunctionalAreaUpdate();
|
||||
|
||||
void onGeoImageCreate();
|
||||
void onMapObjectClicked(const SituationMap::Map::RefPointerMapObjectList &mapObjList,
|
||||
const QPointF &viewportPosition);
|
||||
|
||||
void onSoundAreaCreate();
|
||||
void onSoundAreaUpdate();
|
||||
|
||||
void onHitLineCreate();
|
||||
void onHitLineUpdate();
|
||||
|
||||
void onLineOfSightLineCreate();
|
||||
|
||||
|
||||
void onMineCreate();
|
||||
void onMineUpdate();
|
||||
|
||||
void onMineFieldCreate();
|
||||
void onMineFieldUpdate();
|
||||
|
||||
void onNuclearCreate();
|
||||
void onNuclearUpdate();
|
||||
|
||||
void onChargeEffectCreate();
|
||||
void onChargeEffectUpdate();
|
||||
|
||||
void onBoobyTrapCreate();
|
||||
void onBoobyTrapUpdate();
|
||||
|
||||
void onSingleFireCreate();
|
||||
void onSingleFireUpdate();
|
||||
|
||||
void onShowBasePoint();
|
||||
|
||||
void onShowPolizei();
|
||||
|
||||
void onObjectIndicator();
|
||||
|
||||
void onMeasureLength();
|
||||
|
||||
void onStartLocationDisplay();
|
||||
void onStopLocationDisplay();
|
||||
|
||||
void onLoadFile();
|
||||
|
||||
void onPortal();
|
||||
|
||||
void onMovePoint();
|
||||
|
||||
#ifdef USE_LOCAL_SERVER
|
||||
void onStartLocalService();
|
||||
void onStopLocalService();
|
||||
void onStartViewshedSvc();
|
||||
void onStopViewshedSvc();
|
||||
|
||||
void onViewshedInteractive();
|
||||
void onViewshed();
|
||||
#endif // USE_LOCAL_SERVER
|
||||
|
||||
void onSightFan();
|
||||
void onViewshedSightFan();
|
||||
|
||||
void onLoadPlan();
|
||||
void onOverlayVisiChanged(bool checked);
|
||||
void onRemovePlan();
|
||||
void onRemoveAllPlans();
|
||||
|
||||
void onToPdf();
|
||||
|
||||
void onDump();
|
||||
|
||||
void onOverviewMap();
|
||||
|
||||
void onBackupOms();
|
||||
void onRestoreOms();
|
||||
|
||||
void onRemove();
|
||||
void onRemoveAll();
|
||||
void onToggleGrid();
|
||||
void onToggleVisibility();
|
||||
void onToggleVisibilityTechn();
|
||||
void onToggleVisibilityTact();
|
||||
void onToggleSelection();
|
||||
void onTogglePicking();
|
||||
void onToggleBoundingBox();
|
||||
void onToggleBB2();
|
||||
void onMapRotationChanged();
|
||||
void onSymbolSizeChanged();
|
||||
void onSymbolOpacityChanged();
|
||||
void onDrawOrderChanged();
|
||||
|
||||
|
||||
//void onBuildingPERFORMANCE();
|
||||
|
||||
void onMouseWindowPositionChanged(int x, int y);
|
||||
void onMouseMapPositionChanged(const Point3D &mapPos, bool isValid);
|
||||
void onMouseGeoPositionChanged(const Point3D &geoPos, bool isValid);
|
||||
|
||||
void onExtendChanged();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
/**
|
||||
* The private d-pointer to not break BC when changing internals of this class
|
||||
*/
|
||||
Private *d = nullptr;
|
||||
};
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Export definitions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <qglobal.h>
|
||||
|
||||
#ifndef FUNCTIONDIALOG_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define FUNCTIONDIALOG_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SITUATIONMAPFUNCTIONDIALOG_LIB)
|
||||
# define FUNCTIONDIALOG_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define FUNCTIONDIALOG_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
@@ -0,0 +1,378 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* FunctionDialog
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "simple_esri_layer.h"
|
||||
|
||||
#include <arcgis/Map.h>
|
||||
|
||||
#include <MapImpl/map_impl.h>
|
||||
#include <arcgis/Map.h>
|
||||
#include <arcgis/MapGraphicsView.h>
|
||||
#include <arcgis/LayerListModel.h>
|
||||
#include <arcgis/ArcGISTiledLayer.h>
|
||||
|
||||
|
||||
// for overview
|
||||
#include <QDebug>
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QCheckBox>
|
||||
#include <QPushButton>
|
||||
#include <QSlider>
|
||||
#include <QGridLayout>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
Esri::ArcGISRuntime::Layer *getEsriBasemap_Layer(Esri::ArcGISRuntime::Map *map,
|
||||
const QString &layername)
|
||||
{
|
||||
if (!(map &&
|
||||
map->basemap() &&
|
||||
map->basemap()->baseLayers())
|
||||
)
|
||||
return nullptr;
|
||||
|
||||
Esri::ArcGISRuntime::Layer *layerFound = nullptr;
|
||||
|
||||
const Esri::ArcGISRuntime::LayerListModel *model = map->basemap()->baseLayers();
|
||||
for (int i = 0; i < model->size(); ++i)
|
||||
{
|
||||
const Esri::ArcGISRuntime::Layer *curLayer = model->at(i);
|
||||
const QString &curName = curLayer->name();
|
||||
if (QString::compare(layername, curName) == 0)
|
||||
{
|
||||
layerFound = model->at(i);
|
||||
break;
|
||||
}
|
||||
} // for
|
||||
return layerFound;
|
||||
}
|
||||
|
||||
|
||||
Esri::ArcGISRuntime::ArcGISTiledLayer *getEsriBasemap_ArcGISTiledLayer(Esri::ArcGISRuntime::Map *map,
|
||||
const QString &layername)
|
||||
{
|
||||
Esri::ArcGISRuntime::Layer *layerFound = getEsriBasemap_Layer(map, layername);
|
||||
if (! layerFound)
|
||||
return nullptr;
|
||||
|
||||
if (layerFound->layerType() == Esri::ArcGISRuntime::LayerType::ArcGISTiledLayer)
|
||||
{
|
||||
Esri::ArcGISRuntime::ArcGISTiledLayer *layer2 =
|
||||
static_cast<Esri::ArcGISRuntime::ArcGISTiledLayer *>(layerFound);
|
||||
return layer2;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class SimpleEsriLayer::Private
|
||||
{
|
||||
|
||||
public:
|
||||
Private()
|
||||
{
|
||||
}
|
||||
|
||||
~Private()
|
||||
{
|
||||
}
|
||||
|
||||
// ESRI data:
|
||||
Esri::ArcGISRuntime::Map *m_map = nullptr;
|
||||
Esri::ArcGISRuntime::MapGraphicsView *m_mapView = nullptr;
|
||||
|
||||
// OWN data:
|
||||
QGridLayout *m_layout = nullptr;
|
||||
|
||||
|
||||
}; // class SimpleEsriLayer::Private
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
SimpleEsriLayer::SimpleEsriLayer(QWidget *parent, Esri::ArcGISRuntime::MapGraphicsView *mapView)
|
||||
: QWidget(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
d->m_mapView = mapView;
|
||||
if (d->m_mapView)
|
||||
d->m_map = d->m_mapView->map();
|
||||
|
||||
d->m_layout = new QGridLayout(this);
|
||||
|
||||
updatePanel();
|
||||
}
|
||||
|
||||
SimpleEsriLayer::~SimpleEsriLayer()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool SimpleEsriLayer::updatePanel()
|
||||
{
|
||||
|
||||
for (int row = 0; row < d->m_layout->rowCount(); ++row)
|
||||
{
|
||||
for (int col = 0; col < d->m_layout->columnCount(); ++col)
|
||||
{
|
||||
QLayoutItem *item = d->m_layout->itemAtPosition(row, col);
|
||||
if (item)
|
||||
{
|
||||
QWidget *w = item->widget();
|
||||
delete w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete d->m_layout;
|
||||
d->m_layout = new QGridLayout(this);
|
||||
|
||||
|
||||
if (d->m_map)
|
||||
{
|
||||
// Header
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
for (const char *name : { "OnOff", "Opac", "Brightness", "Contrast", "Gamma" })
|
||||
d->m_layout->addWidget(new QLabel(QString::fromLatin1(name)), row, col++);
|
||||
|
||||
|
||||
row = d->m_layout->rowCount();
|
||||
|
||||
// GraphicalOverlay
|
||||
Esri::ArcGISRuntime::GraphicsOverlayListModel *graphicsOverlayListModel = d->m_mapView->graphicsOverlays();
|
||||
if (graphicsOverlayListModel)
|
||||
{
|
||||
int graphicsOverlaySize = graphicsOverlayListModel->size();
|
||||
// qDebug() << LOGFUNCTION << " graphicsOverlayListModel -> size=" << graphicsOverlaySize;
|
||||
|
||||
row += graphicsOverlaySize;
|
||||
|
||||
for (int i = 0; i < graphicsOverlaySize; ++i)
|
||||
{
|
||||
--row;
|
||||
col = 0;
|
||||
// qDebug() << LOGFUNCTION << " graphicsOverlayListModel handle layer i='" << i;
|
||||
|
||||
Esri::ArcGISRuntime::GraphicsOverlay *gOverlay = graphicsOverlayListModel->at(i);
|
||||
if (! gOverlay)
|
||||
{
|
||||
qWarning() << LOGFUNCTION << " gOverlay is nil";
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString &layername = gOverlay->objectName();
|
||||
|
||||
QCheckBox *cbOnOff = new QCheckBox(layername);
|
||||
cbOnOff->setChecked(gOverlay->isVisible());
|
||||
|
||||
connect(cbOnOff, &QCheckBox::stateChanged, this, &SimpleEsriLayer::layerOnOff);
|
||||
d->m_layout->addWidget(cbOnOff, row, col++);
|
||||
|
||||
SimpleEsriLayerSlider *sl_opac = new SimpleEsriLayerSlider(layername, 0, 100);
|
||||
sl_opac->setValue(gOverlay->opacity() * 100);
|
||||
connect(sl_opac, &SimpleEsriLayerSlider::valueChanged, this, &SimpleEsriLayer::opacity);
|
||||
d->m_layout->addWidget(sl_opac, row, col++);
|
||||
|
||||
} // for
|
||||
} // if (graphicsOverlayListModel)
|
||||
|
||||
|
||||
|
||||
// BasemapLayer
|
||||
row = d->m_layout->rowCount();
|
||||
|
||||
Esri::ArcGISRuntime::LayerListModel *baseLayerModel = d->m_map->basemap()->baseLayers();
|
||||
if (baseLayerModel)
|
||||
{
|
||||
int baseLayerModelSize = baseLayerModel->size();
|
||||
qWarning() << LOGFUNCTION << " baseLayerModel -> size=" << baseLayerModelSize;
|
||||
|
||||
row += baseLayerModelSize;
|
||||
|
||||
for (int i = 0; i < baseLayerModelSize; ++i)
|
||||
{
|
||||
col = 0;
|
||||
--row;
|
||||
qWarning() << LOGFUNCTION << " baseLayerModel handle layer i=" << i;
|
||||
Esri::ArcGISRuntime::Layer *layer = baseLayerModel->at(i);
|
||||
if (! layer)
|
||||
{
|
||||
qWarning() << LOGFUNCTION << " layer is nil";
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString &layername = layer->name();
|
||||
|
||||
QCheckBox *cbOnOff = new QCheckBox(layername);
|
||||
cbOnOff->setChecked(layer->isVisible());
|
||||
|
||||
// QString tooltip = layer->url();
|
||||
// if (!l->serviceDescription().isEmpty())
|
||||
// tooltip += QLatin1String(" ; ") % l->serviceDescription();
|
||||
// if (!tooltip.isEmpty())
|
||||
// cbOnOff->setToolTip(tooltip);
|
||||
|
||||
connect(cbOnOff, &QCheckBox::stateChanged, this, &SimpleEsriLayer::layerOnOff);
|
||||
d->m_layout->addWidget(cbOnOff, row, col++);
|
||||
|
||||
SimpleEsriLayerSlider *sl_opac = new SimpleEsriLayerSlider(layername, 0, 100);
|
||||
sl_opac->setValue(layer->opacity() * 100);
|
||||
connect(sl_opac, &SimpleEsriLayerSlider::valueChanged, this, &SimpleEsriLayer::opacity);
|
||||
d->m_layout->addWidget(sl_opac, row, col++);
|
||||
|
||||
|
||||
if (layer->layerType() == Esri::ArcGISRuntime::LayerType::ArcGISTiledLayer
|
||||
// || layer->type() == EsriRuntimeQt::LayerType::ArcGISTiledMapService
|
||||
)
|
||||
{
|
||||
|
||||
Esri::ArcGISRuntime::ArcGISTiledLayer *realLayer =
|
||||
dynamic_cast<Esri::ArcGISRuntime::ArcGISTiledLayer *>(layer);
|
||||
if (realLayer)
|
||||
{
|
||||
float brightness = realLayer->brightness();
|
||||
float contrast = realLayer->contrast();
|
||||
float gamma = realLayer->gamma();
|
||||
|
||||
qWarning() << " brightness=" << brightness; // QuartzBeta1 -> not supported
|
||||
qWarning() << " contrast=" << contrast; // QuartzBeta1 -> not supported
|
||||
qWarning() << " gamma=" << gamma; // QuartzBeta1 -> not supported
|
||||
|
||||
SimpleEsriLayerSlider *sl_brightness = new SimpleEsriLayerSlider(layername, -100, 100);
|
||||
sl_brightness->setValue(brightness * 100);
|
||||
connect(sl_brightness, &SimpleEsriLayerSlider::valueChanged, this, &SimpleEsriLayer::brightness);
|
||||
d->m_layout->addWidget(sl_brightness, row, col++);
|
||||
|
||||
SimpleEsriLayerSlider *sl_contrast = new SimpleEsriLayerSlider(layername, -100, 100);
|
||||
sl_contrast->setValue(contrast * 100);
|
||||
connect(sl_contrast, &SimpleEsriLayerSlider::valueChanged, this, &SimpleEsriLayer::contrast);
|
||||
d->m_layout->addWidget(sl_contrast, row, col++);
|
||||
|
||||
SimpleEsriLayerSlider *sl_gamma = new SimpleEsriLayerSlider(layername, -100, 100);
|
||||
sl_gamma->setValue(gamma * 100);
|
||||
connect(sl_gamma, &SimpleEsriLayerSlider::valueChanged, this, &SimpleEsriLayer::gamma);
|
||||
d->m_layout->addWidget(sl_gamma, row, col++);
|
||||
} // ir (realLayer)
|
||||
|
||||
} // if (layer->type() == Es
|
||||
} // for
|
||||
} // if (baseLayerModel)
|
||||
|
||||
|
||||
QPushButton *pbMaximizeExtent = new QPushButton(QLatin1String("maximize scale of 1st basemap"));
|
||||
d->m_layout->addWidget(pbMaximizeExtent, 9999, 0);
|
||||
connect(pbMaximizeExtent, &QPushButton::clicked, this, [this]()
|
||||
{
|
||||
if (d->m_map)
|
||||
{
|
||||
d->m_map->setMinScale(500000000); // 5e+08
|
||||
d->m_map->setMaxScale(100);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
else
|
||||
qWarning() << LOGFUNCTION << " no map !!! ";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SimpleEsriLayer::layerOnOff()
|
||||
{
|
||||
QCheckBox *cb = qobject_cast<QCheckBox *>(sender());
|
||||
if (!cb)
|
||||
return;
|
||||
|
||||
QString layername = cb->text();
|
||||
qDebug() << LOGFUNCTION << " layername=" << layername;
|
||||
|
||||
Esri::ArcGISRuntime::Layer *l = getEsriBasemap_Layer(d->m_map, layername);
|
||||
if (l)
|
||||
l->setVisible(cb->isChecked());
|
||||
else
|
||||
qDebug() << LOGFUNCTION << " no layer!!!, layername=" << layername;
|
||||
}
|
||||
|
||||
void SimpleEsriLayer::opacity(int)
|
||||
{
|
||||
SimpleEsriLayerSlider *sl = qobject_cast<SimpleEsriLayerSlider *>(sender());
|
||||
if (!sl)
|
||||
return;
|
||||
|
||||
QString layername = sl->m_layername;
|
||||
double value = sl->value() / 100.0;
|
||||
|
||||
Esri::ArcGISRuntime::Layer *l = getEsriBasemap_Layer(d->m_map, layername);
|
||||
if (l)
|
||||
{
|
||||
qDebug() << LOGFUNCTION << " layername=" << layername << " set to val=" << value;
|
||||
l->setOpacity(value);
|
||||
}
|
||||
else
|
||||
qWarning() << LOGFUNCTION << " no layer!!!, layername=" << layername;
|
||||
}
|
||||
|
||||
void SimpleEsriLayer::brightness(int)
|
||||
{
|
||||
SimpleEsriLayerSlider *sl = qobject_cast<SimpleEsriLayerSlider *>(sender());
|
||||
if (!sl)
|
||||
return;
|
||||
|
||||
QString layername = sl->m_layername;
|
||||
Esri::ArcGISRuntime::ArcGISTiledLayer *l = getEsriBasemap_ArcGISTiledLayer(d->m_map, layername);
|
||||
|
||||
double value = sl->value() / 100.0;
|
||||
// double value = sl->value();
|
||||
|
||||
qDebug() << LOGFUNCTION << " layername=" << layername << " set to val=" << value;
|
||||
|
||||
l->setBrightness(value);
|
||||
}
|
||||
|
||||
void SimpleEsriLayer::contrast(int)
|
||||
{
|
||||
SimpleEsriLayerSlider *sl = qobject_cast<SimpleEsriLayerSlider *>(sender());
|
||||
if (!sl)
|
||||
return;
|
||||
|
||||
QString layername = sl->m_layername;
|
||||
Esri::ArcGISRuntime::ArcGISTiledLayer *l = getEsriBasemap_ArcGISTiledLayer(d->m_map, layername);
|
||||
|
||||
double value = sl->value() / 100.0;
|
||||
// double value = sl->value();
|
||||
|
||||
qDebug() << LOGFUNCTION << " layername=" << layername << " set to val=" << value;
|
||||
|
||||
l->setContrast(value);
|
||||
}
|
||||
|
||||
void SimpleEsriLayer::gamma(int)
|
||||
{
|
||||
SimpleEsriLayerSlider *sl = qobject_cast<SimpleEsriLayerSlider *>(sender());
|
||||
if (!sl)
|
||||
return;
|
||||
|
||||
QString layername = sl->m_layername;
|
||||
Esri::ArcGISRuntime::ArcGISTiledLayer *l = getEsriBasemap_ArcGISTiledLayer(d->m_map, layername);
|
||||
|
||||
double value = sl->value() / 100.0;
|
||||
// double value = sl->value();
|
||||
|
||||
qDebug() << LOGFUNCTION << " layername=" << layername << " set to val=" << value;
|
||||
|
||||
l->setGamma(value);
|
||||
}
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* FunctionDialog
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QSlider>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/Map.h>
|
||||
#include <arcgis/MapGraphicsView.h>
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
class SimpleEsriLayerSlider : public QSlider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SimpleEsriLayerSlider(const QString &layername, int min, int max)
|
||||
: QSlider(), m_layername(layername)
|
||||
{
|
||||
this->setOrientation(Qt::Horizontal);
|
||||
setMinimum(min);
|
||||
setMaximum(max);
|
||||
}
|
||||
|
||||
public:
|
||||
QString m_layername;
|
||||
};
|
||||
|
||||
|
||||
class SimpleEsriLayer : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
SimpleEsriLayer(QWidget *parent, Esri::ArcGISRuntime::MapGraphicsView *mapView);
|
||||
virtual ~SimpleEsriLayer();
|
||||
|
||||
SimpleEsriLayer(const SimpleEsriLayer &other) = delete; // No copy
|
||||
SimpleEsriLayer &operator=(const SimpleEsriLayer &other) = delete; // No copy
|
||||
|
||||
bool updatePanel();
|
||||
private slots:
|
||||
void layerOnOff();
|
||||
void opacity(int);
|
||||
void brightness(int);
|
||||
void contrast(int);
|
||||
void gamma(int);
|
||||
|
||||
private :
|
||||
|
||||
class Private;
|
||||
/**
|
||||
* The private d-pointer to not break BC when changing internals of this class
|
||||
*/
|
||||
Private *d = nullptr;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Q_DECLARE_METATYPE(SituationMap::GeometryType);
|
||||
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/* XPM */
|
||||
static const char * stateIconA_xpm[] = {
|
||||
"24 24 129 2",
|
||||
" c None",
|
||||
". c #4CE146",
|
||||
"+ c #9E8E3A",
|
||||
"@ c #4CE045",
|
||||
"# c #BDAB46",
|
||||
"$ c #A3912F",
|
||||
"% c #4BDF44",
|
||||
"& c #32942E",
|
||||
"* c #B8C14A",
|
||||
"= c #CABF35",
|
||||
"- c #4ADE43",
|
||||
"; c #F2DA55",
|
||||
"> c #A7973C",
|
||||
", c #CDC74E",
|
||||
"' c #E1D132",
|
||||
") c #347D25",
|
||||
"! c #48DD42",
|
||||
"~ c #E7CF4C",
|
||||
"{ c #F7D519",
|
||||
"] c #F8DB3E",
|
||||
"^ c #9D8E38",
|
||||
"/ c #E3CC50",
|
||||
"( c #F6D629",
|
||||
"_ c #56821F",
|
||||
": c #37AA32",
|
||||
"< c #47DB41",
|
||||
"[ c #DAC54B",
|
||||
"} c #F6D51F",
|
||||
"| c #F5D210",
|
||||
"1 c #F5D211",
|
||||
"2 c #F5DA3F",
|
||||
"3 c #819D38",
|
||||
"4 c #E8D14F",
|
||||
"5 c #F6D522",
|
||||
"6 c #A48D0C",
|
||||
"7 c #46DA40",
|
||||
"8 c #C3B445",
|
||||
"9 c #F4D425",
|
||||
"0 c #F3D00E",
|
||||
"a c #C9BF13",
|
||||
"b c #F3D00F",
|
||||
"c c #F2D840",
|
||||
"d c #8FAA3D",
|
||||
"e c #E7D54D",
|
||||
"f c #F4D31B",
|
||||
"g c #D4B50C",
|
||||
"h c #45D93E",
|
||||
"i c #AC9B3C",
|
||||
"j c #F3D52C",
|
||||
"k c #EBCC0D",
|
||||
"l c #7D9516",
|
||||
"m c #CCAE0A",
|
||||
"n c #F1CE0C",
|
||||
"o c #F1CE0E",
|
||||
"p c #F4D738",
|
||||
"q c #F1D015",
|
||||
"r c #DFC70E",
|
||||
"s c #43D73D",
|
||||
"t c #8E7F31",
|
||||
"u c #F0D434",
|
||||
"v c #DBC50D",
|
||||
"w c #588019",
|
||||
"x c #D6B709",
|
||||
"y c #EFCC0A",
|
||||
"z c #EDCB0A",
|
||||
"A c #5B8F1F",
|
||||
"B c #42D63B",
|
||||
"C c #ECD23C",
|
||||
"D c #C9BA0D",
|
||||
"E c #3A7F1F",
|
||||
"F c #DEBD07",
|
||||
"G c #EDCA08",
|
||||
"H c #A39309",
|
||||
"I c #2E972A",
|
||||
"J c #40D43A",
|
||||
"K c #E7CF41",
|
||||
"L c #C2A60A",
|
||||
"M c #27701E",
|
||||
"N c #33A92E",
|
||||
"O c #C1A405",
|
||||
"P c #38BB32",
|
||||
"Q c #DCC543",
|
||||
"R c #9D8709",
|
||||
"S c #37B931",
|
||||
"T c #3FD338",
|
||||
"U c #24711E",
|
||||
"V c #C2B33F",
|
||||
"W c #3DD137",
|
||||
"X c #C8B54A",
|
||||
"Y c #83A134",
|
||||
"Z c #3D6517",
|
||||
"` c #3CD036",
|
||||
" . c #E4CA37",
|
||||
".. c #EDD035",
|
||||
"+. c #29731E",
|
||||
"@. c #F6D726",
|
||||
"#. c #F9D821",
|
||||
"$. c #3ACF34",
|
||||
"%. c #39CD33",
|
||||
"&. c #8F8132",
|
||||
"*. c #F6D414",
|
||||
"=. c #F6D311",
|
||||
"-. c #AD9B39",
|
||||
";. c #38CC32",
|
||||
">. c #C9B337",
|
||||
",. c #D9BF33",
|
||||
"'. c #37CB30",
|
||||
"). c #E9CB29",
|
||||
"!. c #F1CD0C",
|
||||
"~. c #EFD022",
|
||||
"{. c #36CA2F",
|
||||
"]. c #EFCD12",
|
||||
"^. c #EECB09",
|
||||
"/. c #EECC0C",
|
||||
"(. c #8C7E2F",
|
||||
"_. c #35C92E",
|
||||
":. c #B29F34",
|
||||
"<. c #EBC806",
|
||||
"[. c #C4AD31",
|
||||
"}. c #D7BD29",
|
||||
"|. c #E8C503",
|
||||
"1. c #E4C722",
|
||||
"2. c #E8C714",
|
||||
"3. c #E7C402",
|
||||
"4. c #E8C508",
|
||||
"5. c #97872E",
|
||||
"6. c #E5C201",
|
||||
"7. c #E5C200",
|
||||
"8. c #B8A330",
|
||||
" ",
|
||||
" . . . . . . . . + ",
|
||||
" @ @ @ @ # $ ",
|
||||
" % & * = ",
|
||||
" - ; > , ' ) ",
|
||||
" ! ~ { ] ^ / ( _ : ",
|
||||
" < [ } | 1 2 3 4 5 6 < ",
|
||||
" 7 8 9 0 a 0 b c d e f g 7 ",
|
||||
" h i j k l m n o p q r h ",
|
||||
" s t u v w x y y z A s ",
|
||||
" B C D E F G H I B ",
|
||||
" J K L M N O J ",
|
||||
" P Q R S T ",
|
||||
" U V W # X W W ",
|
||||
" Y Z ` ... ` ` ",
|
||||
" +. @.#. $. $. ",
|
||||
" %. &.*.=.-. %. ",
|
||||
" ;. >.0 0 ,. ;. ",
|
||||
" '. ).!.!.~. '. ",
|
||||
" {. ].^.^./.(. {. ",
|
||||
" _. :.<.<.<.<.[. _. ",
|
||||
" }.|.|.|.|.1. ",
|
||||
" 2.3.3.3.3.4. ",
|
||||
" 5.6.7.7.7.7.7.8. "};
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
/* XPM */
|
||||
static const char * stateIconB_xpm[] = {
|
||||
"24 24 189 2",
|
||||
" c None",
|
||||
". c #4A8448",
|
||||
"+ c #69BC66",
|
||||
"@ c #75D272",
|
||||
"# c #7ADA76",
|
||||
"$ c #77D673",
|
||||
"% c #6CC269",
|
||||
"& c #508E4D",
|
||||
"* c #61AE5E",
|
||||
"= c #7EE57A",
|
||||
"- c #73E76E",
|
||||
"; c #64E55F",
|
||||
"> c #5BE355",
|
||||
", c #57E351",
|
||||
"' c #59E353",
|
||||
") c #62E55D",
|
||||
"! c #71E76C",
|
||||
"~ c #7EE779",
|
||||
"{ c #68BB65",
|
||||
"] c #7BE076",
|
||||
"^ c #69E563",
|
||||
"/ c #50E149",
|
||||
"( c #46CE40",
|
||||
"_ c #34982E",
|
||||
": c #44C93E",
|
||||
"< c #4EE047",
|
||||
"[ c #65E45F",
|
||||
"} c #7CE377",
|
||||
"| c #4A8447",
|
||||
"1 c #51934E",
|
||||
"2 c #75E56F",
|
||||
"3 c #51E04B",
|
||||
"4 c #48D541",
|
||||
"5 c #46D140",
|
||||
"6 c #4FE048",
|
||||
"7 c #71E56B",
|
||||
"8 c #59A056",
|
||||
"9 c #6EE368",
|
||||
"0 c #4BDE44",
|
||||
"a c #42C73C",
|
||||
"b c #40BF3A",
|
||||
"c c #6AE364",
|
||||
"d c #4C894A",
|
||||
"e c #6EDF69",
|
||||
"f c #49DD43",
|
||||
"g c #40C63B",
|
||||
"h c #3FC13A",
|
||||
"i c #6CE068",
|
||||
"j c #66BD62",
|
||||
"k c #4BDC45",
|
||||
"l c #44D03E",
|
||||
"m c #5EAB5B",
|
||||
"n c #75D571",
|
||||
"o c #42CD3D",
|
||||
"p c #65C062",
|
||||
"q c #5CDE57",
|
||||
"r c #46DA40",
|
||||
"s c #74D670",
|
||||
"t c #64E05F",
|
||||
"u c #52DC4C",
|
||||
"v c #44CF3E",
|
||||
"w c #5BDD56",
|
||||
"x c #5AA956",
|
||||
"y c #46D93F",
|
||||
"z c #3EC438",
|
||||
"A c #6DD168",
|
||||
"B c #4FDB49",
|
||||
"C c #3CBC36",
|
||||
"D c #6DD268",
|
||||
"E c #58A954",
|
||||
"F c #57C352",
|
||||
"G c #43D73D",
|
||||
"H c #389234",
|
||||
"I c #569F53",
|
||||
"J c #50DA4A",
|
||||
"K c #3ABA35",
|
||||
"L c #3ABB35",
|
||||
"M c #4FDA49",
|
||||
"N c #5BA758",
|
||||
"O c #58C553",
|
||||
"P c #50D04B",
|
||||
"Q c #42D63B",
|
||||
"R c #5CCA57",
|
||||
"S c #5BCE56",
|
||||
"T c #50D049",
|
||||
"U c #46D240",
|
||||
"V c #40D43A",
|
||||
"W c #4CD146",
|
||||
"X c #3ECE38",
|
||||
"Y c #3DCB38",
|
||||
"Z c #4AD545",
|
||||
"` c #41CF3A",
|
||||
" . c #3FD338",
|
||||
".. c #42CF3B",
|
||||
"+. c #43D03C",
|
||||
"@. c #45CF3E",
|
||||
"#. c #40D139",
|
||||
"$. c #41CE3A",
|
||||
"%. c #3EC738",
|
||||
"&. c #3DD137",
|
||||
"*. c #3ABC35",
|
||||
"=. c #41D23B",
|
||||
"-. c #BDAB46",
|
||||
";. c #C8B54A",
|
||||
">. c #42D23C",
|
||||
",. c #3ABF35",
|
||||
"'. c #3BB136",
|
||||
"). c #3CD036",
|
||||
"!. c #53A74F",
|
||||
"~. c #2F812B",
|
||||
"{. c #64CF60",
|
||||
"]. c #E4CA37",
|
||||
"^. c #EDD035",
|
||||
"/. c #66CF62",
|
||||
"(. c #30852C",
|
||||
"_. c #51A44D",
|
||||
":. c #3DB637",
|
||||
"<. c #338530",
|
||||
"[. c #3ACF34",
|
||||
"}. c #55CF51",
|
||||
"|. c #33B72E",
|
||||
"1. c #42CF3D",
|
||||
"2. c #F6D726",
|
||||
"3. c #F9D821",
|
||||
"4. c #3A6E37",
|
||||
"5. c #44D13E",
|
||||
"6. c #35BD2F",
|
||||
"7. c #55CC51",
|
||||
"8. c #348930",
|
||||
"9. c #38CA32",
|
||||
"0. c #3FCF39",
|
||||
"a. c #57A654",
|
||||
"b. c #278723",
|
||||
"c. c #8F8132",
|
||||
"d. c #F6D414",
|
||||
"e. c #F6D311",
|
||||
"f. c #AD9B39",
|
||||
"g. c #2EA72A",
|
||||
"h. c #519A4E",
|
||||
"i. c #42CF3C",
|
||||
"j. c #2C9928",
|
||||
"k. c #38CC32",
|
||||
"l. c #56D351",
|
||||
"m. c #C9B337",
|
||||
"n. c #F3D00E",
|
||||
"o. c #D9BF33",
|
||||
"p. c #5AD256",
|
||||
"q. c #2E9F2A",
|
||||
"r. c #34C02D",
|
||||
"s. c #38CB31",
|
||||
"t. c #62D25D",
|
||||
"u. c #E9CB29",
|
||||
"v. c #F1CD0C",
|
||||
"w. c #EFD022",
|
||||
"x. c #64CD5F",
|
||||
"y. c #3ACC33",
|
||||
"z. c #34BF2D",
|
||||
"A. c #35C62E",
|
||||
"B. c #3BCB34",
|
||||
"C. c #67D261",
|
||||
"D. c #EFCD12",
|
||||
"E. c #EECB09",
|
||||
"F. c #EECC0C",
|
||||
"G. c #8C7E2F",
|
||||
"H. c #6ACF65",
|
||||
"I. c #3FCC39",
|
||||
"J. c #34C42D",
|
||||
"K. c #39CA32",
|
||||
"L. c #5BC656",
|
||||
"M. c #B29F34",
|
||||
"N. c #EBC806",
|
||||
"O. c #C4AD31",
|
||||
"P. c #63CD5E",
|
||||
"Q. c #3ECB37",
|
||||
"R. c #34C52D",
|
||||
"S. c #30B82A",
|
||||
"T. c #2B8327",
|
||||
"U. c #D7BD29",
|
||||
"V. c #E8C503",
|
||||
"W. c #E4C722",
|
||||
"X. c #2D9428",
|
||||
"Y. c #2FB72A",
|
||||
"Z. c #E8C714",
|
||||
"`. c #E7C402",
|
||||
" + c #E8C508",
|
||||
".+ c #97872E",
|
||||
"++ c #E5C201",
|
||||
"@+ c #E5C200",
|
||||
"#+ c #B8A330",
|
||||
" . + @ # # $ % & ",
|
||||
" * = - ; > , , ' ) ! ~ { ",
|
||||
" ] ^ / ( _ : < [ } | ",
|
||||
" 1 2 3 4 5 6 7 8 ",
|
||||
" 9 0 a b 0 c d ",
|
||||
" e f g h f i ",
|
||||
" j k l m n = = n m o k p ",
|
||||
" q r s t u v v u t s r w ",
|
||||
"x y z A B C C B D z y E ",
|
||||
"F G H I J K L M N H G O ",
|
||||
"P Q R Q Q S Q T ",
|
||||
"U V W X Y Z V U ",
|
||||
"` . ..+. @.#. .$.",
|
||||
"%.&. *.=. -.;. >.,. &.%.",
|
||||
"'.).!. ~.).{. ].^. /.).(. _.).:.",
|
||||
"<.[.}. |.1. 2.3. 4.5.6. 7.[.8.",
|
||||
" 9.0.a. b. c.d.e.f. g. h.i.9. ",
|
||||
" j.k.l. m.n.n.o. p.k.q. ",
|
||||
" r.s.t. u.v.v.w. x.y.z. ",
|
||||
" A.B.C. D.E.E.F.G. H.I.A. ",
|
||||
" J.K.L. M.N.N.N.N.O. P.Q.R. ",
|
||||
" S.T. U.V.V.V.V.W. X.Y. ",
|
||||
" Z.`.`.`.`. + ",
|
||||
" .+++@+@+@+@+@+#+ "};
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/* XPM */
|
||||
static const char * stateIconC_xpm[] = {
|
||||
"24 24 83 1",
|
||||
" c None",
|
||||
". c #7FBD7C",
|
||||
"+ c #8BCF88",
|
||||
"@ c #84C582",
|
||||
"# c #588456",
|
||||
"$ c #63BE5F",
|
||||
"% c #57B953",
|
||||
"& c #73BF70",
|
||||
"* c #56B752",
|
||||
"= c #499B45",
|
||||
"- c #699F66",
|
||||
"; c #59B755",
|
||||
"> c #54B550",
|
||||
", c #52B14E",
|
||||
"' c #6ABC67",
|
||||
") c #52B34E",
|
||||
"! c #377334",
|
||||
"~ c #6FAF6C",
|
||||
"{ c #50B24C",
|
||||
"] c #4FB14B",
|
||||
"^ c #48A144",
|
||||
"/ c #4C734A",
|
||||
"( c #5DB559",
|
||||
"_ c #4DAE49",
|
||||
": c #4CAD48",
|
||||
"< c #6BB569",
|
||||
"[ c #4AAC46",
|
||||
"} c #377F35",
|
||||
"| c #5E915C",
|
||||
"1 c #50AD4C",
|
||||
"2 c #48A944",
|
||||
"3 c #44A040",
|
||||
"4 c #61B05E",
|
||||
"5 c #45A641",
|
||||
"6 c #527F50",
|
||||
"7 c #7BBF78",
|
||||
"8 c #78BA75",
|
||||
"9 c #639C60",
|
||||
"0 c #46A542",
|
||||
"a c #42A33E",
|
||||
"b c #368633",
|
||||
"c c #389035",
|
||||
"d c #3FA13B",
|
||||
"e c #43A33F",
|
||||
"f c #619B5E",
|
||||
"g c #56AC53",
|
||||
"h c #3D9D39",
|
||||
"i c #3B9C37",
|
||||
"j c #3C9E38",
|
||||
"k c #54A951",
|
||||
"l c #64A761",
|
||||
"m c #3D9E39",
|
||||
"n c #2A6B26",
|
||||
"o c #3A9B35",
|
||||
"p c #3B9B36",
|
||||
"q c #62A55F",
|
||||
"r c #4B7749",
|
||||
"s c #48A243",
|
||||
"t c #33892F",
|
||||
"u c #328B2F",
|
||||
"v c #379833",
|
||||
"w c #459F41",
|
||||
"x c #4F7E4D",
|
||||
"y c #5CA659",
|
||||
"z c #369632",
|
||||
"A c #349530",
|
||||
"B c #349630",
|
||||
"C c #59A955",
|
||||
"D c #3A9936",
|
||||
"E c #276C25",
|
||||
"F c #256C22",
|
||||
"G c #32932E",
|
||||
"H c #2F892B",
|
||||
"I c #2C8728",
|
||||
"J c #2F912B",
|
||||
"K c #2F902B",
|
||||
"L c #2D8E29",
|
||||
"M c #2D8F29",
|
||||
"N c #257322",
|
||||
"O c #226E1F",
|
||||
"P c #2B8D27",
|
||||
"Q c #298826",
|
||||
"R c #288424",
|
||||
" ",
|
||||
" ",
|
||||
" .+++@ ",
|
||||
" #$%%% ",
|
||||
" &***= ",
|
||||
" -;>>, ",
|
||||
" ')))! ",
|
||||
" ~{]]^ ",
|
||||
" /(__: ",
|
||||
" <[[[} ",
|
||||
" |1223 ",
|
||||
" 4555 ",
|
||||
" 67778 90aab ",
|
||||
" cddef gddh ",
|
||||
" ijjk lmjj ",
|
||||
" noopq rsoot ",
|
||||
" uvvwxyvvz ",
|
||||
" ABBCDBBE ",
|
||||
" FGGGGGH ",
|
||||
" IJJJK ",
|
||||
" LMMN ",
|
||||
" OPQ ",
|
||||
" R ",
|
||||
" "};
|
||||
+445
@@ -0,0 +1,445 @@
|
||||
"id";"name";"sym_klassifiz_id";"name";"symbol_id_code";"id";"name";"def_symbol_id"
|
||||
"611";"ADMINISTRATIVE FINANCE";"331";"FINANCE";"S*G*USAF--*****";"(null)";"(null)";"(null)"
|
||||
"609";"ADMINISTRATIVE JUDGE ADVOCATE GENERAL (JAG)";"325";"JUDGEADVOCATEGENERAL(JAG)";"S*G*USAJ--*****";"(null)";"(null)";"(null)"
|
||||
"606";"ADMINISTRATIVE LABOUR";"355";"LABOUR";"S*G*USAL--*****";"(null)";"(null)";"(null)"
|
||||
"607";"ADMINISTRATIVE MORAL, WELFARE, RECREATION (MWR)";"358";"MORAL,WELFARE,RECREATION(MWR)";"S*G*USAW--*****";"(null)";"(null)";"(null)"
|
||||
"613";"ADMINISTRATIVE MORTUARY/GRAVE REGISTRY";"337";"MORTUARY/GRAVESREGISTRY";"S*G*USAM--*****";"(null)";"(null)";"(null)"
|
||||
"612";"ADMINISTRATIVE PERSONNEL SERVICES";"334";"PERSONNELSERVICES";"S*G*USAS--*****";"(null)";"(null)";"(null)"
|
||||
"610";"ADMINISTRATIVE POSTAL";"328";"POSTAL";"S*G*USAO--*****";"(null)";"(null)";"(null)"
|
||||
"615";"ADMINISTRATIVE PUPLIC AFFAIRS";"343";"PUBLICAFFAIRS";"S*G*USAP--*****";"(null)";"(null)";"(null)"
|
||||
"608";"ADMINISTRATIVE QUARTERMASTER (";"361";"QUARTERMASTER(SUPPLY)";"S*G*USAQ--*****";"(null)";"(null)";"(null)"
|
||||
"614";"ADMINISTRATIVE RELIGIOUS/CHAPLAIN";"340";"RELIGIOUS/CHAPLAIN";"S*G*USAR--*****";"(null)";"(null)";"(null)"
|
||||
"605";"ADMINISTRATIVE REPLACEMENT HOLDING UNIT (RHV)";"352";"REPLACEMENTHOLDINGUNIT(RHU)";"S*G*USAX--*****";"(null)";"(null)";"(null)"
|
||||
"364";"AIR DEFENCE";"79";"AIRDEFENCE";"S*G*UCD---*****";"(null)";"(null)";"(null)"
|
||||
"664";"AIR DEFENCE (AD) MISSILE LAUNC";"471";"AIRDEFENCE(AD)MISSILELAUNCH";"S*G*EWMA--*****";"(null)";"(null)";"(null)"
|
||||
"379";"AIR DEFENCE COMPOSITE";"90";"COMPOSITE";"S*G*UCDC--*****";"(null)";"(null)";"(null)"
|
||||
"367";"Air Defence COY";"79";"AIRDEFENCE";"S*G*UCD---*****";"(null)";"(null)";"(null)"
|
||||
"683";"AIR DEFENCE GUN";"527";"AIRDEFENCEGUN";"S*G*EWA---*****";"(null)";"(null)";"(null)"
|
||||
"686";"AIR DEFENCE GUN HEAVY";"530";"AIRDEFENCEGUNHEAVY";"S*G*EWAH--*****";"(null)";"(null)";"(null)"
|
||||
"684";"AIR DEFENCE GUN LIGHT";"528";"AIRDEFENCEGUNLIGHT";"S*G*EWAL--*****";"(null)";"(null)";"(null)"
|
||||
"685";"AIR DEFENCE GUN MEDIUM";"529";"AIRDEFENCEGUNMEDIUM";"S*G*EWAM--*****";"44";"Soldier Air Defence";"685"
|
||||
"378";"AIR DEFENCE GUN UNIT";"89";"GUNUNIT";"S*G*UCDG--*****";"(null)";"(null)";"(null)"
|
||||
"377";"AIR DEFENCE H/MAD";"88";"H/MAD";"S*G*UCDH--*****";"(null)";"(null)";"(null)"
|
||||
"372";"AIR DEFENCE MISSILE";"83";"AIRDEFENCEMISSILE";"S*G*UCDM--*****";"(null)";"(null)";"(null)"
|
||||
"376";"AIR DEFENCE MISSILE HEAVY";"87";"AIRDEFENCEMISSILEHEAVY";"S*G*UCDMH-*****";"(null)";"(null)";"(null)"
|
||||
"373";"AIR DEFENCE MISSILE LIGHT";"84";"AIRDEFENCEMISSILELIGHT";"S*G*UCDML-*****";"229";"Legatus Wiesel";"373"
|
||||
"375";"AIR DEFENCE MISSILE MEDIUM";"86";"AIRDEFENCEMISSILEMEDIUM";"S*G*UCDMM-*****";"(null)";"(null)";"(null)"
|
||||
"374";"AIR DEFENCE MISSILE MOTORIZED";"85";"AIRDEFENCEMISSILEMOTORIZED";"S*G*UCDMLA*****";"(null)";"(null)";"(null)"
|
||||
"369";"AIR DEFENCE SHORT RANGE";"80";"SHORTRANGE";"S*G*UCDS--*****";"(null)";"(null)";"(null)"
|
||||
"371";"AIR DEFENCE SHORT RANGE GUN";"82";"GUN";"S*G*UCDS--*****";"(null)";"(null)";"(null)"
|
||||
"370";"AIR DEFENCE SHORT RANGE MISSILE";"81";"MISSILE";"S*G*UCDS--*****";"(null)";"(null)";"(null)"
|
||||
"380";"AIR DEFENCE TARGETING UNIT";"91";"TARGETINGUNIT";"S*G*UCDT--*****";"(null)";"(null)";"(null)"
|
||||
"381";"AIR DEFENCE THEATRE MISSILE DEFENCE UNIT";"92";"THEATREMISSILEDEFENCEUNIT";"S*G*UCDO--*****";"(null)";"(null)";"(null)"
|
||||
"781";"AIRPORT/AIRBASE";"605";"AIRPORT/AIRBASE";"S*G*IBA---H****";"(null)";"(null)";"(null)"
|
||||
"342";"AIR TRACK";"6";"AIRTRACK";"S*A*------*****";"(null)";"(null)";"(null)"
|
||||
"777";"AMMUNITION AND EXPLOSIVES PRODUCTION";"595";"AMMUNITIONANDEXPLOSIVESPRODUCTION";"S*G*IME---H****";"(null)";"(null)";"(null)"
|
||||
"788";"AMPHIBIOUS WARFARE SHIP";"620";"AMPHIBIOUSWARFARESHIP";"S*S*CA----*****";"(null)";"(null)";"(null)"
|
||||
"414";"ANTI ARMOUR";"110";"ANTIARMOUR";"S*G*UCAA--*****";"(null)";"(null)";"(null)"
|
||||
"422";"ANTI ARMOUR AIR ASSAULT";"114";"ANTIARMOURAIRASSAULT";"S*G*UCAAS-*****";"(null)";"(null)";"(null)"
|
||||
"421";"ANTI ARMOUR AIRBORNE";"113";"ANTIARMOURAIRBORNE";"S*G*UCAAM-*****";"(null)";"(null)";"(null)"
|
||||
"424";"ANTI ARMOUR ARMOURED";"117";"ANTIARMOURARMOURED";"S*G*UCAAA-*****";"(null)";"(null)";"(null)"
|
||||
"427";"ANTI ARMOUR ARMOURED AIR ASSAU";"120";"ANTIARMOURARMOUREDAIRASSAULT";"S*G*UCAAAS*****";"(null)";"(null)";"(null)"
|
||||
"425";"ANTI ARMOUR ARMOURED TRACKED";"118";"ANTIARMOURARMOUREDTRACKED";"S*G*UCAAAT*****";"(null)";"(null)";"(null)"
|
||||
"426";"ANTI ARMOUR ARMOURED WHEELED";"119";"ANTIARMOURARMOUREDWHEELED";"S*G*UCAAAW*****";"(null)";"(null)";"(null)"
|
||||
"419";"ANTI ARMOUR DISMOUNTED";"111";"ANTIARMOURDISMOUNTED";"S*G*UCAAD-*****";"(null)";"(null)";"(null)"
|
||||
"420";"ANTI ARMOUR LIGHT";"112";"ANTIARMOURLIGHT";"S*G*UCAAL-*****";"(null)";"(null)";"(null)"
|
||||
"428";"ANTI ARMOUR MOTORIZED";"121";"ANTIARMOURMOTORIZED";"S*G*UCAAO-*****";"(null)";"(null)";"(null)"
|
||||
"429";"ANTI ARMOUR MOTORIZED AIR ASSA";"122";"ANTIARMOURMOTORIZEDAIRASSAULT";"S*G*UCAAOS*****";"(null)";"(null)";"(null)"
|
||||
"423";"ANTI ARMOUR MOUNTAIN";"115";"ANTIARMOURMOUNTAIN";"S*G*UCAAU-*****";"(null)";"(null)";"(null)"
|
||||
"718";"ANTITANK GUN";"515";"ANTITANKGUN";"S*G*EWG---*****";"130";"Soldier AT (RPG7)";"718"
|
||||
"722";"ANTITANK GUN HEAVY";"519";"ANTITANKGUNHEAVY";"S*G*EWGH--*****";"(null)";"(null)";"(null)"
|
||||
"720";"ANTITANK GUN LIGHT";"517";"ANTITANKGUNLIGHT";"S*G*EWGL--*****";"(null)";"(null)";"(null)"
|
||||
"721";"ANTITANK GUN MEDIUM";"518";"ANTITANKGUNMEDIUM";"S*G*EWGM--*****";"(null)";"(null)";"(null)"
|
||||
"719";"ANTITANK GUN RECOILLESS";"516";"ANTITANKGUNRECOILLESS";"S*G*EWGR--*****";"(null)";"(null)";"(null)"
|
||||
"695";"ANTITANK ROCKET LAUNCHER";"492";"ANTITANKROCKETLAUNCHER";"S*G*EWT---*****";"(null)";"(null)";"(null)"
|
||||
"698";"ANTITANK ROCKET LAUNCHER HEAVY";"495";"ANTITANKROCKETLAUNCHERHEAVY";"S*G*EWTH--*****";"(null)";"(null)";"(null)"
|
||||
"696";"ANTITANK ROCKET LAUNCHER LIGHT";"493";"ANTITANKROCKETLAUNCHERLIGHT";"S*G*EWTL--*****";"(null)";"(null)";"(null)"
|
||||
"697";"ANTITANK ROCKET LAUNCHER MEDIU";"494";"ANTITANKROCKETLAUNCHERMEDIUM";"S*G*EWTM--*****";"(null)";"(null)";"(null)"
|
||||
"392";"ARMOUR";"93";"ARMOUR";"S*G*UCA---*****";"(null)";"(null)";"(null)"
|
||||
"752";"ARMOURED CARRIER WITH SCATTERA";"561";"ARMOUREDCARRIERWITHSCATTERABLEMINES";"S*G*EVEMSM*****";"(null)";"(null)";"(null)"
|
||||
"734";"ARMOURED INFANTRY";"542";"ARMOUREDINFANTRY";"S*G*EVAI--*****";"(null)";"(null)";"(null)"
|
||||
"732";"ARMOURED PERSONNEL CARRIER";"540";"ARMOUREDPERSONNELCARRIER";"S*G*EVAA--*****";"(null)";"(null)";"(null)"
|
||||
"733";"ARMOURED PERSONNEL CARRIER REC";"541";"ARMOUREDPERSONNELCARRIERRECOVERY";"S*G*EVAAR-*****";"(null)";"(null)";"(null)"
|
||||
"724";"ARMOURED VEHICLE";"532";"ARMOUREDVEHICLE";"S*G*EVA---*****";"231";"Marder";"724"
|
||||
"750";"ARMOURED VEHICLE MOUNTED";"558";"ARMOUREDVEHICLEMOUNTED";"S*G*EVEMA-*****";"(null)";"(null)";"(null)"
|
||||
"397";"ARMOUR TRACK";"94";"ARMOURTRACK";"S*G*UCAT--*****";"(null)";"(null)";"(null)"
|
||||
"398";"ARMOUR TRACK AIRBORNE";"95";"ARMOURTRACKAIRBORNE";"S*G*UCATA-*****";"(null)";"(null)";"(null)"
|
||||
"399";"ARMOUR TRACK AMPHIBIOUS";"96";"ARMOURTRACKAMPHIBIOUS";"S*G*UCATW-*****";"(null)";"(null)";"(null)"
|
||||
"400";"ARMOUR TRACK AMPHIBIOUS RECOVE";"97";"ARMOURTRACKAMPHIBIOUSRECOVERY";"S*G*UCATWR*****";"(null)";"(null)";"(null)"
|
||||
"403";"ARMOUR TRACK HEAVY";"100";"ARMOURTRACK,HEAVY";"S*G*UCATH-*****";"(null)";"(null)";"(null)"
|
||||
"401";"ARMOUR TRACK LIGHT";"98";"ARMOURTRACK,LIGHT";"S*G*UCATL-*****";"(null)";"(null)";"(null)"
|
||||
"402";"ARMOUR TRACK MEDIUM";"99";"ARMOURTRACK,MEDIUM";"S*G*UCATM-*****";"(null)";"(null)";"(null)"
|
||||
"404";"ARMOUR TRACK RECOVERY";"101";"ARMOURTRACK,RECOVERY";"S*G*UCATR-*****";"(null)";"(null)";"(null)"
|
||||
"405";"ARMOUR WHEELED";"102";"ARMOUR,WHEELED";"S*G*UCAW--*****";"(null)";"(null)";"(null)"
|
||||
"406";"ARMOUR WHEELED AIR ASSAULT";"103";"ARMOUR,WHEELEDAIRASSAULT";"S*G*UCAWS-*****";"(null)";"(null)";"(null)"
|
||||
"407";"ARMOUR WHEELED AIRBORNE";"104";"ARMOUR,WHEELEDAIRBORNE";"S*G*UCAWA-*****";"227";"BMP3 IFV";"407"
|
||||
"408";"ARMOUR WHEELED AMPHIBIOUS";"105";"ARMOUR,WHEELEDAMPHIBIOUS";"S*G*UCAWA-*****";"(null)";"(null)";"(null)"
|
||||
"409";"ARMOUR WHEELED AMPHIBIOUS RECO";"1325";"ARMOURWHEELEDAMPHIBIOUSRECOVERY";"S*G*UCAWWR*****";"(null)";"(null)";"(null)"
|
||||
"412";"ARMOUR WHEELED HEAVY";"108";"ARMOUR,WHEELEDHEAVY";"S*G*UCAWH-*****";"(null)";"(null)";"(null)"
|
||||
"410";"ARMOUR WHEELED LIGHT";"106";"ARMOUR,WHEELEDLIGHT";"S*G*UCAWL-*****";"(null)";"(null)";"(null)"
|
||||
"411";"ARMOUR WHEELED MEDIUM";"107";"ARMOUR,WHEELEDMEDIUM";"S*G*UCAWM-*****";"(null)";"(null)";"(null)"
|
||||
"413";"ARMOUR WHEELED RECOVERY";"109";"ARMOUR,WHEELEDRECOVERY";"S*G*UCAWR-*****";"10";"Armored Recovery Vehicle";"413"
|
||||
"789";"ASSAULT VESSEL";"621";"ASSAULTVESSEL";"S*S*CALA--*****";"(null)";"(null)";"(null)"
|
||||
"776";"ATOMIC ENERGY PRODUCTION";"593";"ATOMICENERGYPRODUCTION";"S*G*IMF---H****";"(null)";"(null)";"(null)"
|
||||
"430";"AVIATION";"123";"AVIATION";"S*G*UCV---*****";"(null)";"(null)";"(null)"
|
||||
"431";"AVIATION FIXED WING";"124";"FIXEDWING";"S*G*UCVF--*****";"(null)";"(null)";"(null)"
|
||||
"433";"AVIATION FIXED WING ATTACK";"126";"ATTACKFIXEDWING";"S*G*UCVFA-*****";"(null)";"(null)";"(null)"
|
||||
"436";"AVIATION FIXED WING RECON";"129";"RECONFIXEDWING";"S*G*UCVFR-*****";"(null)";"(null)";"(null)"
|
||||
"432";"AVIATION FIXED WING UTILITY";"125";"UTILITYFIXEDWING";"S*G*UCVFU-*****";"(null)";"(null)";"(null)"
|
||||
"435";"AVIATION FORWARD AIR CONTROLLER (FAC)";"128";"FORWARDAIRCONTROLLER(FAC)";"S*G*UCVUFC*****";"(null)";"(null)";"(null)"
|
||||
"437";"AVIATION ROTARY WING";"130";"ROTARYWING";"S*G*UCVR--*****";"(null)";"(null)";"(null)"
|
||||
"440";"AVIATION ROTARY WING C2";"138";"C2ROTARYWING";"S*G*UCVRUC*****";"(null)";"(null)";"(null)"
|
||||
"441";"AVIATION ROTARY WING MEDEVAC";"139";"MEDEVACROTARYWING";"S*G*UCVRUE*****";"(null)";"(null)";"(null)"
|
||||
"439";"AVIATION ROTARY WING UTILITY";"134";"UTILITYROTARYWING";"S*G*UCVRU-*****";"(null)";"(null)";"(null)"
|
||||
"434";"AVIATION TACTICAL AIR CONTROL";"127";"TACTICALAIRCONTROLPARTY(TACP)";"S*G*UCVUTP*****";"(null)";"(null)";"(null)"
|
||||
"445";"AVIATION UAV CONTROL";"1326";"AVIATIONUAVCONTROL";"S*G*UCVU--*****";"(null)";"(null)";"(null)"
|
||||
"446";"AVIATION UAV LAUNCHER";"1327";"AVIATIONUAVLAUNCHER";"S*G*UCVU--*****";"(null)";"(null)";"(null)"
|
||||
"447";"AVIATION UAV RECOVERY";"1337";"AVIATIONUAVRECOVERY";"S*G*UCVU--*****";"(null)";"(null)";"(null)"
|
||||
"444";"AVIATION UNMANNED AERIAL VEHIC";"145";"UNMANNEDAERIALVEHICLEFIXEDWING";"S*G*UCVUF-*****";"(null)";"(null)";"(null)"
|
||||
"448";"AVIATION UNMANNED AERIAL VEHICLE ROTARY WING";"146";"UNMANNEDAERIALVEHICLEROTARYWING";"S*G*UCVUR-*****";"(null)";"(null)";"(null)"
|
||||
"443";"AVIATION UNMANNED AVIATION VEH";"144";"UNMANNEDAERIALVEHICLE";"S*G*UCVU--*****";"(null)";"(null)";"(null)"
|
||||
"442";"AVIATION VERTICAL/SHORT TAKEOF";"143";"VERTICAL/SHORTTAKEOFFANDLANDING(V/STOL)";"S*G*UCVV--*****";"(null)";"(null)";"(null)"
|
||||
"769";"BIOLOGICAL";"581";"BIOLOGICAL";"S*G*IRNB--H****";"(null)";"(null)";"(null)"
|
||||
"745";"BRIDGE";"553";"BRIDGE";"S*G*EVEB--*****";"(null)";"(null)";"(null)"
|
||||
"778";"BRIDGE";"599";"BRIDGE";"S*G*IMNB--H****";"(null)";"(null)";"(null)"
|
||||
"739";"BUS";"547";"BUS";"S*G*EVUB--*****";"(null)";"(null)";"(null)"
|
||||
"735";"C2V/ACV";"543";"C2V/ACV";"S*G*EVAC--*****";"(null)";"(null)";"(null)"
|
||||
"548";"CBRN";"256";"COMBATSUPPORTCBRN";"S*G*UUA---*****";"(null)";"(null)";"(null)"
|
||||
"768";"CBRN";"580";"CBRN";"S*G*IRN---H****";"(null)";"(null)";"(null)"
|
||||
"560";"CBRN BIOLOGICAL";"268";"BIOLOGICAL";"S*G*UUAB--*****";"(null)";"(null)";"(null)"
|
||||
"561";"CBRN BIOLOGICAL RECON EQUIPPED";"269";"RECONEQUIPPED";"S*G*UUABR-*****";"(null)";"(null)";"(null)"
|
||||
"549";"CBRN CHEMICAL";"257";"CHEMICAL";"S*G*UUAC--*****";"(null)";"(null)";"(null)"
|
||||
"556";"CBRN CHEMICAL RECON";"264";"CHEMICALRECON";"S*G*UUACR-*****";"(null)";"(null)";"(null)"
|
||||
"553";"CBRN CHEMICAL SMOKE";"261";"SMOKE";"S*G*UUACS-*****";"(null)";"(null)";"(null)"
|
||||
"555";"CBRN CHEMICAL SMOKE ARMOUR";"263";"ARMOURSMOKE";"S*G*UUACSA*****";"(null)";"(null)";"(null)"
|
||||
"550";"CBRN CHEMICAL SMOKE/DECON";"258";"SMOKE/DECON";"S*G*UUACC-*****";"(null)";"(null)";"(null)"
|
||||
"551";"CBRN CHEMICAL SMOKE/DECON MECHANIZED";"259";"MECHANIZEDSMOKE/DECON";"S*G*UUACCK*****";"(null)";"(null)";"(null)"
|
||||
"552";"CBRN CHEMICAL SMOKE/DECON MOTO";"260";"MOTORIZEDSMOKE/DECON";"S*G*UUACCM*****";"(null)";"(null)";"(null)"
|
||||
"554";"CBRN CHEMICAL SMOKE MOTORIZED";"262";"MOTORIZEDSMOKE";"S*G*UUACSM*****";"(null)";"(null)";"(null)"
|
||||
"557";"CBRN CHEMICAL WHEELED ARMOURED VEHICLE";"265";"CHEMICALWHEELEDARMOUREDVEHICLE";"S*G*UUACRW*****";"(null)";"(null)";"(null)"
|
||||
"558";"CBRN CHEMICAL WHEELED ARMOURED VEHICLE RECONNAISAN";"266";"CHEMICALWHEELEDARMOUREDVEHICLERECONNAISSANCESURVEI";"S*G*UUACRS*****";"(null)";"(null)";"(null)"
|
||||
"562";"CBRN DECON";"270";"DECONTAMINATION";"S*G*UUAD--*****";"(null)";"(null)";"(null)"
|
||||
"564";"CBRN DECON EQUIPMENT";"1330";"CBRNDECONEQUIPMENT";"S*G*UUADE-*****";"(null)";"(null)";"(null)"
|
||||
"565";"CBRN DECON EQUIPMENT/TROOP";"1331";"CBRNDECONEQUIPMENT/TROOP";"S*G*UUADET*****";"(null)";"(null)";"(null)"
|
||||
"563";"CBRN DECON TROOP";"1329";"CBRNDECONTROOP";"S*G*UUADT-*****";"(null)";"(null)";"(null)"
|
||||
"760";"CBRN EQUIPMENT";"571";"CBRNEQUIPMENT";"S*G*EXN---*****";"(null)";"(null)";"(null)"
|
||||
"566";"CBRN LABORATORY";"1332";"CBRNLABORATORY";"S*G*UUAL--*****";"(null)";"(null)";"(null)"
|
||||
"559";"CBRN NUCLEAR";"267";"NUCLEAR";"S*G*UUAN--*****";"(null)";"(null)";"(null)"
|
||||
"770";"CHEMICAL";"582";"CHEMICAL";"S*G*IRNC--H****";"(null)";"(null)";"(null)"
|
||||
"356";"CIVIL FIXED WING";"73";"FIXEDWING";"S*A*CF----*****";"(null)";"(null)";"(null)"
|
||||
"755";"CIVILIAN VEHICLE";"565";"CIVILIANVEHICLE";"S*G*EVC---*****";"(null)";"(null)";"(null)"
|
||||
"357";"CIVIL ROTARY WING";"74";"ROTARYWING";"S*A*CH----*****";"(null)";"(null)";"(null)"
|
||||
"604";"COMBAT SERVICE SUPPORT";"321";"COMBATSERVICESUPPORT";"S*G*US----*****";"(null)";"(null)";"(null)"
|
||||
"736";"COMBAT SERVICE SUPPORT VEHICLE";"544";"COMBATSERVICESUPPORTVEHICLE";"S*G*EVAS--*****";"(null)";"(null)";"(null)"
|
||||
"547";"COMBAT SUPPORT";"255";"COMBATSUPPORT";"S*G*UU----*****";"(null)";"(null)";"(null)"
|
||||
"748";"CONSTRUCTION VEHICLE";"556";"CONSTRUCTIONVEHICLE";"S*G*EVEC--*****";"(null)";"(null)";"(null)"
|
||||
"742";"CROSS-COUNTRY TRUCK";"550";"CROSS-COUNTRYTRUCK";"S*G*EVUX--*****";"212";"TATRA Tanker Fuel";"742"
|
||||
"742";"CROSS-COUNTRY TRUCK";"550";"CROSS-COUNTRYTRUCK";"S*G*EVUX--*****";"50";"Truck 2t off-road";"742"
|
||||
"772";"DECON";"585";"DECON";"S*G*IPD---H****";"(null)";"(null)";"(null)"
|
||||
"676";"DIRECT FIRE GUN";"520";"DIRECTFIREGUN";"S*G*EWD---*****";"(null)";"(null)";"(null)"
|
||||
"681";"DIRECT FIRE GUN HEAVY";"525";"DIRECTFIREGUNHEAVY";"S*G*EWDH--*****";"(null)";"(null)";"(null)"
|
||||
"682";"DIRECT FIRE GUN HEAVY SELF-PRO";"526";"DIRECTFIREGUNHEAVYSELF-PROPELLED";"S*G*EWDHS-*****";"(null)";"(null)";"(null)"
|
||||
"677";"DIRECT FIRE GUN LIGHT";"521";"DIRECTFIREGUNLIGHT";"S*G*EWDL--*****";"(null)";"(null)";"(null)"
|
||||
"678";"DIRECT FIRE GUN LIGHT SELF PRO";"522";"DIRECTFIREGUNLIGHTSELF-PROPELLED";"S*G*EWDLS-*****";"(null)";"(null)";"(null)"
|
||||
"679";"DIRECT FIRE GUN MEDIUM";"523";"DIRECTFIREGUNMEDIUM";"S*G*EWDM--*****";"(null)";"(null)";"(null)"
|
||||
"680";"DIRECT FIRE GUN MEDIUM SELF-PR";"524";"DIRECTFIREGUNMEDIUMSELF-PROPELLED";"S*G*EWDMS-*****";"(null)";"(null)";"(null)"
|
||||
"753";"DOZER";"562";"DOZER";"S*G*EVED--*****";"215";"CAT Excavator";"753"
|
||||
"746";"EARTHMOVER";"554";"EARTHMOVER";"S*G*EVEE--*****";"(null)";"(null)";"(null)"
|
||||
"774";"ELCECTRIC POWER FACILITY";"590";"ELECTRICPOWERFACILITY";"S*G*IUE---H****";"(null)";"(null)";"(null)"
|
||||
"758";"EMPLACED SENSOR";"568";"EMPLACEDSENSOR";"S*G*ESE---*****";"(null)";"(null)";"(null)"
|
||||
"467";"ENGINEER";"159";"ENGINEER";"S*G*UCE---*****";"(null)";"(null)";"(null)"
|
||||
"472";"ENGINEER COMBAT";"160";"ENGINEERCOMBAT";"S*G*UCEC--*****";"(null)";"(null)";"(null)"
|
||||
"473";"ENGINEER COMBAT AIR ASSAULT";"161";"ENGINEERCOMBATAIRASSAULT";"S*G*UCECS-*****";"(null)";"(null)";"(null)"
|
||||
"478";"ENGINEER COMBAT AIRBORNE";"162";"ENGINEERCOMBATAIRBORNE";"S*G*UCECA-*****";"(null)";"(null)";"(null)"
|
||||
"475";"ENGINEER COMBAT BRIDGING";"171";"ENGINEERCOMBATBRIDGING";"S*G*UCEC--*****";"(null)";"(null)";"(null)"
|
||||
"481";"ENGINEER COMBAT HEAVY";"166";"ENGINEERCOMBATHEAVY";"S*G*UCECH-*****";"(null)";"(null)";"(null)"
|
||||
"479";"ENGINEER COMBAT LIGHT";"164";"ENGINEERCOMBATLIGHT";"S*G*UCECL-*****";"(null)";"(null)";"(null)"
|
||||
"482";"ENGINEER COMBAT MECH (TRACK)";"167";"ENGINEERCOMBATMECHANIZED(TRACK)";"S*G*UCECT-*****";"(null)";"(null)";"(null)"
|
||||
"480";"ENGINEER COMBAT MEDIUM";"165";"ENGINEERCOMBATMEDIUM";"S*G*UCECM-*****";"(null)";"(null)";"(null)"
|
||||
"476";"ENGINEER COMBAT MINE CLEARING";"172";"ENGINEERCOMBATMINECLEARING";"S*G*UCEC--*****";"(null)";"(null)";"(null)"
|
||||
"477";"ENGINEER COMBAT MINE LAYING";"173";"ENGINEERCOMBATMINELAYING";"S*G*UCEC--*****";"(null)";"(null)";"(null)"
|
||||
"483";"ENGINEER COMBAT MOTORIZED";"168";"ENGINEERCOMBATMOTORIZED";"S*G*UCECW-*****";"(null)";"(null)";"(null)"
|
||||
"484";"ENGINEER COMBAT MOUNTAIN";"169";"ENGINEERCOMBATMOUNTAIN";"S*G*UCECO-*****";"(null)";"(null)";"(null)"
|
||||
"474";"ENGINEER COMBAT RECON";"170";"ENGINEERCOMBATRECON";"S*G*UCECR-*****";"(null)";"(null)";"(null)"
|
||||
"485";"ENGINEER CONSTRUCTION";"175";"ENGINEERCONSTRUCTION";"S*G*UCEN--*****";"(null)";"(null)";"(null)"
|
||||
"744";"ENGINEER VEHICLE";"552";"ENGINEERVEHICLE";"S*G*EVE---*****";"(null)";"(null)";"(null)"
|
||||
"657";"ENVIRONMENTAL PROTECTION";"463";"ENVIRONMENTALPROTECTION";"S*G*USXEP-*****";"(null)";"(null)";"(null)"
|
||||
"576";"EW CORPS";"280";"CORPS";"S*G*UUMSEC*****";"(null)";"(null)";"(null)"
|
||||
"575";"EW THEATRE";"279";"THEATRE";"S*G*UUMSET*****";"(null)";"(null)";"(null)"
|
||||
"602";"EXPLOSIVE ORDNANCE DISPOSAL";"317";"EXPLOSIVEORDINANCEDISPOSAL";"S*G*UUE---*****";"(null)";"(null)";"(null)"
|
||||
"490";"FIELD ARTELLERY HOWITZER/GUN AIRBORNE";"181";"AIRBORNE";"S*G*UCFHA-*****";"(null)";"(null)";"(null)"
|
||||
"495";"FIELD ARTELLERY HOWITZER/GUN AMPHIBIOUS";"187";"AMPHIBIOUS";"S*G*UCFHX-*****";"(null)";"(null)";"(null)"
|
||||
"494";"FIELD ARTELLERY HOWITZER/GUN HEAVY";"186";"HEAVY";"S*G*UCFHH-*****";"(null)";"(null)";"(null)"
|
||||
"492";"FIELD ARTELLERY HOWITZER/GUN LIGHT";"184";"LIGHT";"S*G*UCFHL-*****";"(null)";"(null)";"(null)"
|
||||
"493";"FIELD ARTELLERY HOWITZER/GUN MEDIUM";"185";"MEDIUM";"S*G*UCFHM-*****";"(null)";"(null)";"(null)"
|
||||
"491";"FIELD ARTELLERY HOWITZER/GUN MOUNTAIN";"183";"MOUNTAIN";"S*G*UCFHO-*****";"(null)";"(null)";"(null)"
|
||||
"496";"FIELD ARTELLERY ROCKET";"188";"ROCKET";"S*G*UCFR--*****";"(null)";"(null)";"(null)"
|
||||
"498";"FIELD ARTILEERY ROCKET SINGLE";"190";"SINGLEROCKETSELFPROPELLED";"S*G*UCFRSS*****";"(null)";"(null)";"(null)"
|
||||
"486";"FIELD ARTILLERY";"177";"FIELDARTILLERY";"S*G*UCF---*****";"(null)";"(null)";"(null)"
|
||||
"521";"FIELD ARTILLERY ARTILLERY SURV";"214";"ARTILLERYSURVEY";"S*G*UCFS--*****";"(null)";"(null)";"(null)"
|
||||
"523";"FIELD ARTILLERY FIRE DIRECTION CENTRE";"224";"FIREDIRECTIONCENTRE";"S*G*UCF---*****";"(null)";"(null)";"(null)"
|
||||
"487";"FIELD ARTILLERY HOWITZER/GUN";"178";"HOWITZER/GUN";"S*G*UCFH--*****";"(null)";"(null)";"(null)"
|
||||
"489";"FIELD ARTILLERY HOWITZER/GUN AIR ASSAULT";"180";"AIRASSAULT";"S*G*UCFHS-*****";"(null)";"(null)";"(null)"
|
||||
"488";"FIELD ARTILLERY HOWITZER/GUN SELF-PROPELLED";"179";"SELFPROPELLED";"S*G*UCFHE-*****";"(null)";"(null)";"(null)"
|
||||
"522";"FIELD ARTILLERY METEOROLOGICAL";"219";"METEOROLOGICAL";"S*G*UCFO--*****";"(null)";"(null)";"(null)"
|
||||
"513";"FIELD ARTILLERY MORTAR";"205";"MORTAR";"S*G*UCFM--*****";"(null)";"(null)";"(null)"
|
||||
"514";"FIELD ARTILLERY MORTAR SP TRAC";"206";"SELFPROPELLED(SP)TRACKEDMORTAR";"S*G*UCFMS-*****";"(null)";"(null)";"(null)"
|
||||
"515";"FIELD ARTILLERY MORTAR SP WHEE";"207";"SPWHEELEDMORTAR";"S*G*UCFMSW*****";"(null)";"(null)";"(null)"
|
||||
"516";"FIELD ARTILLERY MORTAR TOWED";"208";"TOWEDMORTAR";"S*G*UCFMT-*****";"(null)";"(null)";"(null)"
|
||||
"518";"FIELD ARTILLERY MORTAR TOWED A";"210";"TOWEDAIRASSAULTMORTAR";"S*G*UCFMTS*****";"(null)";"(null)";"(null)"
|
||||
"517";"FIELD ARTILLERY MORTAR TOWED A";"209";"TOWEDAIRBORNEMORTAR";"S*G*UCFMTA*****";"(null)";"(null)";"(null)"
|
||||
"519";"FIELD ARTILLERY MORTAR TOWED M";"212";"TOWEDMOUNTAINMORTAR";"S*G*UCFMTO*****";"(null)";"(null)";"(null)"
|
||||
"524";"FIELD ARTILLERY OBERSERVER";"225";"OBERSERVER";"S*G*UCF---*****";"(null)";"(null)";"(null)"
|
||||
"502";"FIELD ARTILLERY ROCKET MULTI R";"194";"MULTIROCKETSELFPROPELLED";"S*G*UCFRMS*****";"(null)";"(null)";"(null)"
|
||||
"504";"FIELD ARTILLERY ROCKET MULTI ROCKET LAUNCER MULTI";"196";"MULTIROCKETTOWED";"S*G*UCFRMT*****";"(null)";"(null)";"(null)"
|
||||
"503";"FIELD ARTILLERY ROCKET MULTI ROCKET LAUNCER MULTI";"195";"MULTIROCKETTRUCK";"S*G*UCFRMR*****";"(null)";"(null)";"(null)"
|
||||
"501";"FIELD ARTILLERY ROCKET MULTI ROCKET LAUNCHER";"193";"MULTIROCKETLAUNCHER";"S*G*UCFRM-*****";"(null)";"(null)";"(null)"
|
||||
"497";"FIELD ARTILLERY ROCKET SINGLE";"189";"SINGLEROCKETLAUNCHER";"S*G*UCFRS-*****";"(null)";"(null)";"(null)"
|
||||
"499";"FIELD ARTILLERY ROCKET SINGLE ROCKET LAUNCHER SING";"191";"SINGLEROCKETTRUCK";"S*G*UCFRSR*****";"(null)";"(null)";"(null)"
|
||||
"500";"FIELD ARTILLERY ROCKET SINGLE ROCKET LAUNCHER SING";"192";"SINGLEROCKETTOWED";"S*G*UCFRST*****";"(null)";"(null)";"(null)"
|
||||
"506";"FIELD ARTILLERY TARGET ACQUISI";"198";"RADAR";"S*G*UCFTR-*****";"(null)";"(null)";"(null)"
|
||||
"505";"FIELD ARTILLERY TARGET ACQUISITION";"197";"TARGETACQUISITION";"S*G*UCFT--*****";"(null)";"(null)";"(null)"
|
||||
"510";"FIELD ARTILLERY TARGET ACQUISITION DISMOUNTED";"202";"TARGETACQUISITIONDISMOUNTED";"S*G*UCFTCD*****";"(null)";"(null)";"(null)"
|
||||
"508";"FIELD ARTILLERY TARGET ACQUISITION FLASH (OPTICAL)";"200";"FLASH(OPTICAL)";"S*G*UCFTF-*****";"(null)";"(null)";"(null)"
|
||||
"509";"FIELD ARTILLERY TARGET ACQUISITION MOUNTED";"201";"TARGETACQUISITIONMOUNTED";"S*G*UCFTC-*****";"(null)";"(null)";"(null)"
|
||||
"512";"FIELD ARTILLERY TARGET ACQUISITION NAVAL GUNFIRE";"204";"TARGETACQUISITIONNAVALGUNFIRE";"S*G*UCFTA-*****";"(null)";"(null)";"(null)"
|
||||
"507";"FIELD ARTILLERY TARGET ACQUISITION SOUND";"199";"SOUND";"S*G*UCFTS-*****";"(null)";"(null)";"(null)"
|
||||
"511";"FIELD ARTILLERY TARGET ACQUISITION TRACKED";"203";"TARGETACQUISITIONTRACKED";"S*G*UCFTCM*****";"(null)";"(null)";"(null)"
|
||||
"345";"FIXED WING DRONE (RPV/UAE)";"36";"DRONE(RPV/UAV)";"S*A*MFQ---*****";"(null)";"(null)";"(null)"
|
||||
"761";"FLAME THROWER";"572";"FLAMETHROWER";"S*G*EXF---*****";"(null)";"(null)";"(null)"
|
||||
"660";"GENERAL HEADQUATERS AND SERVICE";"466";"GENERALHEADQUARTERSANDSERVICE";"S*G*UH----*****";"(null)";"(null)";"(null)"
|
||||
"779";"GOVERNMENT LEADERSHIP";"603";"GOVERNMENTLEADERSHIP";"S*G*IG----H****";"(null)";"(null)";"(null)"
|
||||
"703";"GRENADE LAUNCHER";"500";"GRENADELAUNCHER";"S*G*EWZ---*****";"(null)";"(null)";"(null)"
|
||||
"706";"GRENADE LAUNCHER HEAVY";"503";"GRENADELAUNCHERHEAVY";"S*G*EWZH--*****";"(null)";"(null)";"(null)"
|
||||
"704";"GRENADE LAUNCHER LIGHT";"501";"GRENADELAUNCHERLIGHT";"S*G*EWZL--*****";"(null)";"(null)";"(null)"
|
||||
"705";"GRENADE LAUNCHER MEDIUM";"502";"GRENADELAUNCHERMEDIUM";"S*G*EWZM--*****";"(null)";"(null)";"(null)"
|
||||
"662";"GROUND TRACK EQUIPMENT";"468";"GROUNDTRACKEQUIPMENT";"S*G*E-----*****";"(null)";"(null)";"(null)"
|
||||
"358";"GROUND TRACK UNIT";"77";"UNIT";"S*G*U-----*****";"217";"Soldier (Role Player)";"358"
|
||||
"358";"GROUND TRACK UNIT";"77";"UNIT";"S*G*U-----*****";"106";"Soldier";"358"
|
||||
"363";"GROUND TRACK UNIT COMBAT";"78";"COMBAT";"S*G*UC----*****";"(null)";"(null)";"(null)"
|
||||
"520";"GROUND TRACK UNIT COMBAT FIELD ARTILLERY MORTAR AM";"213";"AMPHIBIOUSMORTAR";"S*G*UCFML-*****";"(null)";"(null)";"(null)"
|
||||
"659";"GROUND TRACK UNIT GENERAL HEADQUATERS";"465";"UNITGENERALHEADQUARTERS";"S*G*UH----*****";"(null)";"(null)";"(null)"
|
||||
"723";"GROUND VEHICLE";"531";"GROUNDVEHICLE";"S*G*EV----*****";"(null)";"(null)";"(null)"
|
||||
"702";"HEAVY MACHINE GUN";"499";"HEAVYMACHINEGUN";"S*G*EWRH--*****";"129";"Soldier HMG";"702"
|
||||
"785";"HOSPITAL";"609";"HOSPITAL";"S*G*IXH---H****";"(null)";"(null)";"(null)"
|
||||
"711";"HOWITZER";"508";"HOWITZER";"S*G*EWH---*****";"(null)";"(null)";"(null)"
|
||||
"716";"HOWITZER HEAVY";"513";"HOWITZERHEAVY";"S*G*EWHH--*****";"(null)";"(null)";"(null)"
|
||||
"717";"HOWITZER HEAVY SELF-PROPELLED";"514";"HOWITZERHEAVYSELF-PROPELLED";"S*G*EWHHS-*****";"(null)";"(null)";"(null)"
|
||||
"712";"HOWITZER LIGHT";"509";"HOWITZERLIGHT";"S*G*EWHL--*****";"(null)";"(null)";"(null)"
|
||||
"713";"HOWITZER LIGHT SELF-PROPELLED";"510";"HOWITZERLIGHTSELF-PROPELLED";"S*G*EWHLS-*****";"(null)";"(null)";"(null)"
|
||||
"714";"HOWITZER MEDIUM";"511";"HOWITZERMEDIUM";"S*G*EWHM--*****";"(null)";"(null)";"(null)"
|
||||
"715";"HOWITZER MEDIUM SELF-PROPELLED";"512";"HOWITZERMEDIUMSELF-PROPELLED";"S*G*EWHMS-*****";"(null)";"(null)";"(null)"
|
||||
"449";"INFANTRY";"149";"INFANTRY";"S*G*UCI---*****";"161";"TM";"449"
|
||||
"449";"INFANTRY";"149";"INFANTRY";"S*G*UCI---*****";"226";"TEST PLAYER";"449"
|
||||
"449";"INFANTRY";"149";"INFANTRY";"S*G*UCI---*****";"232";"0Soldier";"449"
|
||||
"449";"INFANTRY";"149";"INFANTRY";"S*G*UCI---*****";"128";"TM Leader";"449"
|
||||
"463";"INFANTRY AIR ASSAULT";"154";"INFANTRYAIRASSAULT";"S*G*UCIS--*****";"(null)";"(null)";"(null)"
|
||||
"462";"INFANTRY AIRBORNE";"153";"INFANTRYAIRBORNE";"S*G*UCIA--*****";"(null)";"(null)";"(null)"
|
||||
"466";"INFANTRY FIGHTING VEHICLE";"157";"INFANTRYFIGHTINGVEHICLE";"S*G*UCII--*****";"(null)";"(null)";"(null)"
|
||||
"454";"INFANTRY LIGHT";"150";"INFANTRYLIGHT";"S*G*UCIL--*****";"(null)";"(null)";"(null)"
|
||||
"464";"INFANTRY MECHANIZED";"155";"INFANTRYMECHANIZED";"S*G*UCIZ--*****";"(null)";"(null)";"(null)"
|
||||
"456";"INFANTRY MOTORIZED";"151";"INFANTRYMOTORIZED";"S*G*UCIM--*****";"(null)";"(null)";"(null)"
|
||||
"461";"INFANTRY MOUNTAIN";"152";"INFANTRYMOUNTAIN";"S*G*UCIO--*****";"(null)";"(null)";"(null)"
|
||||
"465";"INFANTRY NAVAL";"156";"INFANTRYNAVAL";"S*G*UCIN--*****";"(null)";"(null)";"(null)"
|
||||
"600";"INFORMATION OPERATIONS";"315";"INFORMATIONWARFAREUNIT";"S*G*UUI---*****";"(null)";"(null)";"(null)"
|
||||
"765";"INSTALLATION";"576";"INSTALLATION";"S*G*I-----H****";"225";"MEU";"765"
|
||||
"765";"INSTALLATION";"576";"INSTALLATION";"S*G*I-----H****";"224";"Building";"765"
|
||||
"666";"INTERMEDIATE RANGE AD MISSILE";"473";"INTERMEDIATERANGEADMISSILELAUNCH";"S*G*EWMAI-*****";"(null)";"(null)";"(null)"
|
||||
"670";"INTERMEDIATE RANGE SS MISSILE";"478";"INTERMEDIATERANGESSMISSILELAUNCH";"S*G*EWMSI-*****";"(null)";"(null)";"(null)"
|
||||
"382";"INTERNAL SECURITY FORCES";"246";"INTERNALSECURITYFORCES";"S*G*UCS---*****";"(null)";"(null)";"(null)"
|
||||
"390";"INTERNAL SECURITY FORCES AVIAT";"254";"AVIATION";"S*G*UCSA--*****";"(null)";"(null)";"(null)"
|
||||
"387";"INTERNAL SECURITY FORCES GROUN";"251";"MECHANIZEDGROUND";"S*G*UCSGA-*****";"(null)";"(null)";"(null)"
|
||||
"384";"INTERNAL SECURITY FORCES GROUND";"248";"GROUND";"S*G*UCSG--*****";"(null)";"(null)";"(null)"
|
||||
"385";"INTERNAL SECURITY FORCES GROUND DISMOUNTED";"249";"DISMOUNTEDGROUND";"S*G*UCSGD-*****";"(null)";"(null)";"(null)"
|
||||
"386";"INTERNAL SECURITY FORCES GROUND MOTORIZED";"250";"MOTORIZEDGROUND";"S*G*UCSGM-*****";"(null)";"(null)";"(null)"
|
||||
"389";"INTERNAL SECURITY FORCES RAILROAD";"253";"RAILROAD";"S*G*UCSR--*****";"(null)";"(null)";"(null)"
|
||||
"383";"INTERNAL SECURITY FORCES RIVERINE";"247";"RIVERINE";"S*G*UCSW--*****";"(null)";"(null)";"(null)"
|
||||
"388";"INTERNAL SECURITY FORCES WHEEL";"252";"WHEELEDMECHANIZED";"S*G*UCSM--*****";"(null)";"(null)";"(null)"
|
||||
"791";"LANDING CRAFT";"623";"LANDINGCRAFT";"S*S*CALC--*****";"(null)";"(null)";"(null)"
|
||||
"790";"LANDING SHIP";"622";"LANDINGSHIP";"S*S*CALS--*****";"(null)";"(null)";"(null)"
|
||||
"601";"LANDING SUPPORT";"316";"LANDINGSUPPORT";"S*G*UUX---*****";"(null)";"(null)";"(null)"
|
||||
"762";"LAND MINES";"573";"LANDMINES";"S*G*EXM---*****";"(null)";"(null)";"(null)"
|
||||
"763";"LAND MINES, LETHAL";"574";"LANDMINES,LETHAL";"S*G*EXMC--*****";"(null)";"(null)";"(null)"
|
||||
"759";"LASER";"570";"LASER";"S*G*EXL---*****";"(null)";"(null)";"(null)"
|
||||
"584";"LAW ENFORCEMENT UNIT";"292";"LAWENFORCEMENTUNIT";"S*G*UUL---*****";"(null)";"(null)";"(null)"
|
||||
"587";"LAW ENFORCEMENT UNIT CIVILIAN LAW ENFORCEMENT";"295";"CIVILIANLAWENFORCEMENT";"S*G*UULC--*****";"(null)";"(null)";"(null)"
|
||||
"588";"LAW ENFORCEMENT UNIT CRIMINAL INVESTIGATION DIVISI";"297";"CENTRALINTELLIGENCEDIVISION(CID)";"S*G*UULD--*****";"(null)";"(null)";"(null)"
|
||||
"586";"LAW ENFORCEMENT UNIT MILITARY POLICE";"294";"MILITARYPOLICE";"S*G*UULM--*****";"(null)";"(null)";"(null)"
|
||||
"585";"LAW ENFORCEMENT UNIT SHORE PATROL";"293";"SHOREPATROL";"S*G*UULS--*****";"(null)";"(null)";"(null)"
|
||||
"794";"LEISURE CRAFT";"665";"LEISURECRAFT";"S*S*XR----*****";"(null)";"(null)";"(null)"
|
||||
"764";"LESS THAN LETHAL";"575";"LESSTHANLETHAL";"S*G*EXML--*****";"(null)";"(null)";"(null)"
|
||||
"737";"LIGHT ARMOURED VEHICLE";"545";"LIGHTARMOUREDVEHICLE";"S*G*EVAL--*****";"(null)";"(null)";"(null)"
|
||||
"701";"LIGHT MACHINE GUN";"498";"LIGHTMACHINEGUN";"S*G*EWRL--*****";"131";"Soldier LMG";"701"
|
||||
"741";"LIMITED CROSS-COUNTRY TRUCK";"549";"LIMITEDCROSS-COUNTRYTRUCK";"S*G*EVUL--*****";"(null)";"(null)";"(null)"
|
||||
"667";"LONG RANGE AD MISSILE LAUNCH";"474";"LONGRANGEADMISSILELAUNCH";"S*G*EWMAL-*****";"(null)";"(null)";"(null)"
|
||||
"671";"LONG RANGE SS MISSILE LAUNCH";"479";"LONGRANGESSMISSILELAUNCH";"S*G*EWMSL-*****";"(null)";"(null)";"(null)"
|
||||
"648";"MAINTENANCE";"442";"MAINTENANCE";"S*G*USX---*****";"(null)";"(null)";"(null)"
|
||||
"654";"MAINTENANCE BATTLE DAMAGE REPA";"460";"BATTLEDAMAGEREPAIR";"S*G*USXBDR*****";"(null)";"(null)";"(null)"
|
||||
"653";"MAINTENANCE ELECTRO-OPTICAL";"457";"ELECTRO-OPTICAL";"S*G*USXE--*****";"(null)";"(null)";"(null)"
|
||||
"649";"MAINTENANCE HEAVY";"445";"MAINTENANCEHEAVY";"S*G*USXH--*****";"(null)";"(null)";"(null)"
|
||||
"651";"MAINTENANCE ORDINANCE";"451";"ORDINANCE";"S*G*USXO--*****";"(null)";"(null)";"(null)"
|
||||
"652";"MAINTENANCE ORDINANCE MISSILE";"454";"ORDINANCEMISSILE";"S*G*USXOM-*****";"(null)";"(null)";"(null)"
|
||||
"655";"MAINTENANCE PREVENTIVE MAINTEN";"461";"PREVENTIVEMAINTANANCE";"S*G*USXPM-*****";"(null)";"(null)";"(null)"
|
||||
"650";"MAINTENANCE RECOVERY";"448";"MAINTENANCERECOVERY";"S*G*USXR--*****";"(null)";"(null)";"(null)"
|
||||
"623";"MEDICAL DENTAL";"373";"MEDICALDENTAL";"S*G*USMD--*****";"(null)";"(null)";"(null)"
|
||||
"784";"MEDICAL FACILITY";"608";"MEDICALFACILITY";"S*G*IX----H****";"(null)";"(null)";"(null)"
|
||||
"624";"MEDICAL PSYCHOLOGICAL";"376";"MEDICALPSYCHOLOGICAL";"S*G*USMP--*****";"(null)";"(null)";"(null)"
|
||||
"621";"MEDICAL TREATMENT FACILITY";"367";"MEDICALTREATMENTFACILITY";"S*G*USMM--*****";"(null)";"(null)";"(null)"
|
||||
"622";"MEDICAL VETERINARY";"370";"MEDICALVETERINARY";"S*G*USMV--*****";"(null)";"(null)";"(null)"
|
||||
"343";"MILITARY";"7";"MILITARY";"S*A*M-----*****";"(null)";"(null)";"(null)"
|
||||
"780";"MILITARY BASE/FACILITY";"604";"MILITARYBASE/FACILITY";"S*G*IB----H****";"(null)";"(null)";"(null)"
|
||||
"344";"MILITARY FIXED WING";"8";"FIXEDWING";"S*A*MF----*****";"(null)";"(null)";"(null)"
|
||||
"567";"MILITARY INTELLIGENCE";"271";"MILITARYINTELLIGENCE";"S*G*UUM---*****";"(null)";"(null)";"(null)"
|
||||
"568";"MILITARY INTELLIGENCE AERIAL EXPLOITATION";"272";"AERIALEXPLOITATION";"S*G*UUMA--*****";"(null)";"(null)";"(null)"
|
||||
"577";"MILITARY INTELLIGENCE COUNTER INTELLIGENCE";"281";"COUNTERINTELLIGENCE";"S*G*UUMC--*****";"(null)";"(null)";"(null)"
|
||||
"573";"MILITARY INTELLIGENCE ELECTRON";"277";"INTERCEPT";"S*G*UUMSEI*****";"(null)";"(null)";"(null)"
|
||||
"572";"MILITARY INTELLIGENCE ELECTRON";"276";"DIRECTIONFINDING";"S*G*UUMSED*****";"(null)";"(null)";"(null)"
|
||||
"571";"MILITARY INTELLIGENCE ELECTRON";"275";"ARMOUREDWHEELEDVEHICLE";"S*G*UUMSEA*****";"(null)";"(null)";"(null)"
|
||||
"570";"MILITARY INTELLIGENCE ELECTRONIC WARFARE";"274";"ELECTRONICWARFARE";"S*G*UUMSE-*****";"(null)";"(null)";"(null)"
|
||||
"574";"MILITARY INTELLIGENCE ELECTRONIC WARFARE JAMMING";"278";"JAMMING";"S*G*UUMSEJ*****";"(null)";"(null)";"(null)"
|
||||
"582";"MILITARY INTELLIGENCE INTERROGATION";"290";"INTERROGATION";"S*G*UUMQ--*****";"(null)";"(null)";"(null)"
|
||||
"583";"MILITARY INTELLIGENCE JOINT INTELLIGENCE CENTRE";"291";"JOINTINTELLIGENCECENTRE";"S*G*UUMJ--*****";"(null)";"(null)";"(null)"
|
||||
"581";"MILITARY INTELLIGENCE OPERATIONS";"288";"OPERATIONS";"S*G*UUMO--*****";"(null)";"(null)";"(null)"
|
||||
"569";"MILITARY INTELLIGENCE SIGNALS";"273";"SIGNALINTELLIGENCE(SIGINT)";"S*G*UUMS--*****";"(null)";"(null)";"(null)"
|
||||
"579";"MILITARY INTELLIGENCE SURVEILL";"283";"GROUNDSURVEILLANCERADAR";"S*G*UUMRG-*****";"(null)";"(null)";"(null)"
|
||||
"578";"MILITARY INTELLIGENCE SURVEILLANCE";"282";"SURVEILLANCE";"S*G*UUMR--*****";"(null)";"(null)";"(null)"
|
||||
"580";"MILITARY INTELLIGENCE SURVEILLANCE SENSOR";"284";"SENSOR";"S*G*UUMRS-*****";"(null)";"(null)";"(null)"
|
||||
"346";"MILITARY ROTARY WING";"39";"ROTARYWING";"S*A*MH----*****";"195";"Apache";"346"
|
||||
"766";"MINE";"578";"MINE";"S*G*IRM---H****";"(null)";"(null)";"(null)"
|
||||
"749";"MINE LAYING VEHICLE";"557";"MINELAYINGVEHICLE";"S*G*EVEM--*****";"4";"Trailer, Minelaying";"749"
|
||||
"675";"MISSILE LAUNCHER AT HEAVY";"483";"MISSILELAUNCHERATHEAVY";"S*G*EWMTH-*****";"(null)";"(null)";"(null)"
|
||||
"674";"MISSILE LAUNCHER AT MEDIUM";"482";"MISSILELAUNCHERATMEDIUM";"S*G*EWMTM-*****";"(null)";"(null)";"(null)"
|
||||
"663";"MISSILE LAUNCHERS";"470";"MISSILELAUNCHERS";"S*G*EWM---*****";"(null)";"(null)";"(null)"
|
||||
"672";"MISSILE LAUNCHERS ANTI TANK (A";"480";"MISSILELAUNCHERSANTITANK(AT)";"S*G*EWMT--*****";"(null)";"(null)";"(null)"
|
||||
"673";"MISSILE LAUNCHERS AT LIGHT";"481";"MISSILELAUNCHERSATLIGHT";"S*G*EWMTL-*****";"(null)";"(null)";"(null)"
|
||||
"544";"MISSILE (SURF-SURF)";"243";"MISSILE(SURFACE-SURFACE)";"S*G*UCM---*****";"(null)";"(null)";"(null)"
|
||||
"546";"MISSILE (SURF-SURF) STRATEGIC";"245";"MISSILE(SURFACE-SURFACE)STRATEGIC";"S*G*UCMS--*****";"(null)";"(null)";"(null)"
|
||||
"545";"MISSILE (SURF-SURF) TACTICAL";"244";"MISSILE(SURFACE-SURFACE)TACTICAL";"S*G*UCMT--*****";"(null)";"(null)";"(null)"
|
||||
"707";"MORTAR";"504";"MORTAR";"S*G*EWO---*****";"209";"Soldier Mortar";"707"
|
||||
"710";"MORTAR HEAVY";"507";"MORTARHEAVY";"S*G*EWOH--*****";"(null)";"(null)";"(null)"
|
||||
"708";"MORTAR LIGHT";"505";"MORTARLIGHT";"S*G*EWOL--*****";"(null)";"(null)";"(null)"
|
||||
"709";"MORTAR MEDIUM";"506";"MORTARMEDIUM";"S*G*EWOM--*****";"(null)";"(null)";"(null)"
|
||||
"747";"MULTIFUNCTIONAL EARTHMOVER/DIG";"555";"MULTIFUNCTIONALEARTHMOVER/DIGGER";"S*G*EVEE--*****";"(null)";"(null)";"(null)"
|
||||
"691";"MULTIPLE ROCKET LAUNCHER";"488";"MULTIPLEROCKETLAUNCHER";"S*G*EWX---*****";"(null)";"(null)";"(null)"
|
||||
"694";"MULTIPLE ROCKET LAUNCHER HEAVY";"491";"MULTIPLEROCKETLAUNCHERHEAVY";"S*G*EWXH--*****";"(null)";"(null)";"(null)"
|
||||
"692";"MULTIPLE ROCKET LAUNCHER LIGHT";"489";"MULTIPLEROCKETLAUNCHERLIGHT";"S*G*EWXL--*****";"(null)";"(null)";"(null)"
|
||||
"693";"MULTIPLE ROCKET LAUNCHER MEDIU";"490";"MULTIPLEROCKETLAUNCHERMEDIUM";"S*G*EWXM--*****";"(null)";"(null)";"(null)"
|
||||
"771";"NUCLEAR";"583";"NUCLEAR";"S*G*IRNN--H****";"(null)";"(null)";"(null)"
|
||||
"188";"O/C Force";"5";"SPACESTATION";"S*P*T-----*****";"113";"O/C Staff";"188"
|
||||
"188";"O/C Force";"5";"SPACESTATION";"S*P*T-----*****";"180";"O/C TM";"188"
|
||||
"188";"O/C Force";"5";"SPACESTATION";"S*P*T-----*****";"114";"O/C Force";"188"
|
||||
"807";"O/C Force CE";"5";"SPACESTATION";"S*P*T-----*****";"(null)";"(null)";"(null)"
|
||||
"793";"OILER/TANKER";"655";"OILER/TANKER";"S*S*XMO---*****";"(null)";"(null)";"(null)"
|
||||
"792";"PATROL";"630";"PATROL";"S*S*CP----*****";"(null)";"(null)";"(null)"
|
||||
"767";"PETROLEUM/GAS/OIL";"579";"PETROLEUM/GAS/OIL";"S*G*IRP---H****";"(null)";"(null)";"(null)"
|
||||
"656";"PIPELINE";"462";"PIPELINE";"S*G*USXP--*****";"(null)";"(null)";"(null)"
|
||||
"775";"PUBLIC WATER SERVICES";"591";"PUBLICWATERSERVICES";"S*G*IUP---H****";"(null)";"(null)";"(null)"
|
||||
"757";"RADAR";"567";"RADAR";"S*G*ESR---*****";"(null)";"(null)";"(null)"
|
||||
"525";"RECONNAISSANCE";"226";"RECONNAISSANCE";"S*G*UCR---*****";"(null)";"(null)";"(null)"
|
||||
"535";"RECONNAISSANCE AIR ASSAULT";"234";"RECONNAISSANCEAIRASSAULT";"S*G*UCRS--*****";"(null)";"(null)";"(null)"
|
||||
"536";"RECONNAISSANCE AIRBORNE";"235";"RECONNAISSANCEAIRBORNE";"S*G*UCRA--*****";"(null)";"(null)";"(null)"
|
||||
"539";"RECONNAISSANCE AMPHIBIOUS";"238";"RECONNAISSANCEMARINE";"S*G*UCRR--*****";"(null)";"(null)";"(null)"
|
||||
"540";"RECONNAISSANCE AMPHIBIOUS DIVI";"239";"RECONNAISSANCEMARINEDIVISION";"S*G*UCRRD-*****";"(null)";"(null)";"(null)"
|
||||
"541";"RECONNAISSANCE AMPHIBIOUS FORC";"240";"RECONNAISSANCEMARINEFORCE";"S*G*UCRRF-*****";"(null)";"(null)";"(null)"
|
||||
"530";"RECONNAISSANCE CAVALRY";"228";"RECONNAISSANCECAVALRY";"S*G*UCRV--*****";"(null)";"(null)";"(null)"
|
||||
"534";"RECONNAISSANCE CAVALRY AIR";"232";"RECONNAISSANCECAVALRYAIR";"S*G*UCRVO-*****";"(null)";"(null)";"(null)"
|
||||
"531";"RECONNAISSANCE CAVALRY ARMOURE";"229";"RECONNAISSANCECAVALRYARMOURED";"S*G*UCRVA-*****";"(null)";"(null)";"(null)"
|
||||
"533";"RECONNAISSANCE CAVALRY GROUND";"231";"RECONNAISSANCECAVALRYGROUND";"S*G*UCRVG-*****";"(null)";"(null)";"(null)"
|
||||
"532";"RECONNAISSANCE CAVALRY MOTORIZ";"230";"RECONNAISSANCECAVALRYMOTORIZED";"S*G*UCRVM-*****";"(null)";"(null)";"(null)"
|
||||
"538";"RECONNAISSANCE LIGHT";"237";"RECONNAISSANCELIGHT";"S*G*UCRLL--*****";"(null)";"(null)";"(null)"
|
||||
"542";"RECONNAISSANCE MARINE LIGHT AR";"241";"RECONNAISSANCEMARINELIGHTARMOUREDRECONNAISSANCE(LA";"S*G*UCRRL-*****";"(null)";"(null)";"(null)"
|
||||
"537";"RECONNAISSANCE MOUNTAIN";"236";"RECONNAISSANCEMOUNTAIN";"S*G*UCRO--*****";"(null)";"(null)";"(null)"
|
||||
"543";"RECONNAISSANCE SURVEILLANCE LO";"242";"RECONNAISSANCELONGRANGESURVEILLANCE(LRS)";"S*G*UCRX--*****";"(null)";"(null)";"(null)"
|
||||
"700";"RIFLE";"497";"RIFLE";"S*G*EWRR--*****";"210";"Soldier Assault Rifle";"700"
|
||||
"699";"RIFLE/AUTOMATIC WEAPON";"496";"RIFLE/AUTOMATICWEAPON";"S*G*EWR---*****";"205";"Soldier Tgt";"699"
|
||||
"699";"RIFLE/AUTOMATIC WEAPON";"496";"RIFLE/AUTOMATICWEAPON";"S*G*EWR---*****";"216";"Soldier M203";"699"
|
||||
"699";"RIFLE/AUTOMATIC WEAPON";"496";"RIFLE/AUTOMATICWEAPON";"S*G*EWR---*****";"153";"Soldier MP";"699"
|
||||
"438";"ROTARY WING ATTACK";"131";"ATTACKROTARYWING";"S*G*UCVRA-*****";"(null)";"(null)";"(null)"
|
||||
"347";"ROTARY WING ATTACK";"40";"ATTACK";"S*A*MHA---*****";"(null)";"(null)";"(null)"
|
||||
"352";"ROTARY WING DRONE (RPV/UAV)";"49";"DRONE(RPV/UAV)";"S*A*MHQ---*****";"(null)";"(null)";"(null)"
|
||||
"348";"ROTARY WING MEDEVAC";"55";"MEDEVAC";"S*A*MHO---*****";"(null)";"(null)";"(null)"
|
||||
"351";"ROTARY WING RECCE";"48";"RECONNAISSANCE";"S*A*MHR---*****";"(null)";"(null)";"(null)"
|
||||
"349";"ROTARY WING SOF";"56";"SPECIALOPERATIONSFORCE(SOF)";"S*A*MHM---*****";"(null)";"(null)";"(null)"
|
||||
"350";"ROTARY WING UTILITY";"42";"UTILITY";"S*A*MHU---*****";"(null)";"(null)";"(null)"
|
||||
"782";"SEAPORT/NAVAL BASE";"606";"SEAPORT/NAVALBASE";"S*G*IBN---H****";"(null)";"(null)";"(null)"
|
||||
"786";"SEA SURFACE INSTALLATION, OIL RIG / PLATFORM";"611";"SEASURFACEINSTALLATION,OILRIG/PLATFORM";"S*G*IRR---H****";"(null)";"(null)";"(null)"
|
||||
"787";"SEA SURFACE TRACK";"612";"SEASURFACETRACK";"S*S*------*****";"(null)";"(null)";"(null)"
|
||||
"740";"SEMI";"548";"SEMI";"S*G*EVUS--*****";"(null)";"(null)";"(null)"
|
||||
"756";"SENSOR";"566";"SENSOR";"S*G*ES----*****";"(null)";"(null)";"(null)"
|
||||
"616";"SERVICE SUPPORT MEDICAL";"364";"MEDICAL";"S*G*USM---*****";"(null)";"(null)";"(null)"
|
||||
"641";"SERVICE SUPPORT TRANSPORTATION";"424";"TRANSPORTATION";"S*G*UST---*****";"53";"TATRA Logistics Carrier";"641"
|
||||
"665";"SHORT RANGE AD MISSILE LAUNCHE";"472";"SHORTRANGEADMISSILELAUNCHERS";"S*G*EWMAS-*****";"(null)";"(null)";"(null)"
|
||||
"669";"SHORT RANGE SS MISSILE LAUNCH";"477";"SHORTRANGESSMISSILELAUNCH";"S*G*EWMSS-*****";"(null)";"(null)";"(null)"
|
||||
"593";"SIGNALS UNIT FORWARD COMMUNICATIONS";"303";"FORWARDCOMMUNICATIONS";"S*G*UUSF--*****";"(null)";"(null)";"(null)"
|
||||
"597";"SIGNALS UNIT SIGNAL SUPPORT";"312";"SIGNALSUPPORT";"S*G*UUSS--*****";"(null)";"(null)";"(null)"
|
||||
"589";"SIGNAL UNIT";"298";"SIGNALUNIT";"S*G*UUS---*****";"(null)";"(null)";"(null)"
|
||||
"590";"SIGNAL UNIT AREA";"299";"AREA";"S*G*UUSA--*****";"(null)";"(null)";"(null)"
|
||||
"592";"SIGNAL UNIT COMMAND OPERATIONS";"302";"COMMANDOPERATIONS";"S*G*UUSO--*****";"(null)";"(null)";"(null)"
|
||||
"591";"SIGNAL UNIT COMMUNICATION CONF";"300";"COMMUNICATIONCONFIGUREDPACKAGE";"S*G*UUSC--*****";"(null)";"(null)";"(null)"
|
||||
"599";"SIGNAL UNIT ELECTRONIC RANGING";"314";"ELECTRONICRANGING";"S*G*UUSX--*****";"(null)";"(null)";"(null)"
|
||||
"594";"SIGNAL UNIT RADIO UNIT";"308";"RADIOUNIT";"S*G*UUSR--*****";"(null)";"(null)";"(null)"
|
||||
"596";"SIGNAL UNIT RADIO UNIT RELAY";"311";"RELAY";"S*G*UUSRW-*****";"(null)";"(null)";"(null)"
|
||||
"595";"SIGNAL UNIT RADIO UNIT TACTICA";"309";"TACTICALSATELLITE";"S*G*UUSRS-*****";"(null)";"(null)";"(null)"
|
||||
"598";"SIGNAL UNIT TELEPHONE SWITCH";"313";"TELEPHONESWITCH";"S*G*UUSW--*****";"(null)";"(null)";"(null)"
|
||||
"687";"SINGLE ROCKET LAUNCHER";"484";"SINGLEROCKETLAUNCHER";"S*G*EWS---*****";"(null)";"(null)";"(null)"
|
||||
"690";"SINGLE ROCKET LAUNCHER HEAVY";"487";"SINGLEROCKETLAUNCHERHEAVY";"S*G*EWSH--*****";"(null)";"(null)";"(null)"
|
||||
"688";"SINGLE ROCKET LAUNCHER LIGHT";"485";"SINGLEROCKETLAUNCHERLIGHT";"S*G*EWSL--*****";"(null)";"(null)";"(null)"
|
||||
"689";"SINGLE ROCKET LAUNCHER MEDIUM";"486";"SINGLEROCKETLAUNCHERMEDIUM";"S*G*EWSM--*****";"(null)";"(null)";"(null)"
|
||||
"796";"SOF AVIATION FIXED WING";"707";"SOFUNITFIXEDWING";"S*F*AF----*****";"(null)";"(null)";"(null)"
|
||||
"797";"SOF AVIATION FIXED WING ATTACK";"708";"SOFUNITATTACK";"S*F*AFA---*****";"(null)";"(null)";"(null)"
|
||||
"798";"SOF AVIATION FIXED WING UTILIT";"710";"SOFUNITUTILITY";"S*F*AFU---*****";"(null)";"(null)";"(null)"
|
||||
"799";"SOF AVIATION FIXED WING UTILIT";"711";"SOFUNITUTILITY(LIGHT)";"S*F*AFUL--*****";"(null)";"(null)";"(null)"
|
||||
"800";"SOF AVIATION ROTARY WING";"715";"SOFUNITROTARYWING";"S*F*AH----*****";"(null)";"(null)";"(null)"
|
||||
"803";"SOF UNIT GROUND";"727";"SOFUNITGROUND";"S*F*G-----*****";"(null)";"(null)";"(null)"
|
||||
"805";"SOF UNIT GROUND RANGER";"729";"SOFUNITRANGER";"S*F*GSR---*****";"(null)";"(null)";"(null)"
|
||||
"804";"SOF UNIT GROUND SPECIAL FORCES";"728";"SOFUNITSPECIALFORCES";"S*F*GS----*****";"(null)";"(null)";"(null)"
|
||||
"801";"SOF UNIT NAVAL";"722";"SOFUNITSOFUNITNAVAL";"S*F*SN----*****";"(null)";"(null)";"(null)"
|
||||
"802";"SOF UNIT NAVAL SPECIAL BOAT";"725";"SOFUNITSPECIALBOAT";"S*F*SNB---*****";"(null)";"(null)";"(null)"
|
||||
"806";"SOF UNIT PSYCHOLOGICAL OPERATI";"730";"SOFUNITPSYCHOLOGICALOPERATIONS(PSYOPS)";"S*F*GSP---*****";"(null)";"(null)";"(null)"
|
||||
"658";"SPECIAL C2 HEADQUATERS COMPONE";"464";"SPECIALC2HEADQUARTERSCOMPONENT";"S*G*UH----*****";"(null)";"(null)";"(null)"
|
||||
"795";"SPECIAL OPERATIONS FORCE (SOF)";"705";"SPECIALOPERATIONSFORCE(SOF)UNIT";"S*F*------*****";"(null)";"(null)";"(null)"
|
||||
"625";"SUPPLY";"379";"SUPPLY";"S*G*USS---*****";"(null)";"(null)";"(null)"
|
||||
"633";"SUPPLY CLASS I";"382";"SUPPLYCLASSI";"S*G*USS1--*****";"(null)";"(null)";"(null)"
|
||||
"634";"SUPPLY CLASS II";"385";"SUPPLYCLASSII";"S*G*USS2--*****";"(null)";"(null)";"(null)"
|
||||
"635";"SUPPLY CLASS III";"388";"SUPPLYCLASSIII";"S*G*USS3--*****";"(null)";"(null)";"(null)"
|
||||
"636";"SUPPLY CLASS III AVIATION";"391";"SUPPLYCLASSIIIAVIATION";"S*G*USS3A-*****";"(null)";"(null)";"(null)"
|
||||
"637";"SUPPLY CLASS IV";"394";"SUPPLYCLASSIV";"S*G*USS4--*****";"(null)";"(null)";"(null)"
|
||||
"627";"SUPPLY CLASS IX";"409";"SUPPLYCLASSIX";"S*G*USS9--*****";"(null)";"(null)";"(null)"
|
||||
"638";"SUPPLY CLASS V";"397";"SUPPLYCLASSV";"S*G*USS5--*****";"(null)";"(null)";"(null)"
|
||||
"639";"SUPPLY CLASS VI";"400";"SUPPLYCLASSVI";"S*G*USS6--*****";"(null)";"(null)";"(null)"
|
||||
"640";"SUPPLY CLASS VII";"403";"SUPPLYCLASSVII";"S*G*USS7--*****";"(null)";"(null)";"(null)"
|
||||
"626";"SUPPLY CLASS VIII";"406";"SUPPLYCLASSVIII";"S*G*USS8--*****";"(null)";"(null)";"(null)"
|
||||
"628";"SUPPLY CLASS X";"412";"SUPPLYCLASSX";"S*G*USSX--*****";"(null)";"(null)";"(null)"
|
||||
"629";"SUPPLY LAUNDRY/BATH";"415";"SUPPLYLAUNDRY/BATH";"S*G*USSL--*****";"(null)";"(null)";"(null)"
|
||||
"632";"SUPPLY MATERIEL (STOCK)";"1335";"SUPPLYMATERIEL(STOCK)";"S*G*US**--*****";"(null)";"(null)";"(null)"
|
||||
"630";"SUPPLY WATER";"418";"SUPPLYWATER";"S*G*USSW--*****";"(null)";"(null)";"(null)"
|
||||
"631";"SUPPLY WATER PURIFICATION";"421";"SUPPLYWATERPURIFICATION";"S*G*USSWP-*****";"(null)";"(null)";"(null)"
|
||||
"668";"SURFACE- SURFACE (SS) MISSILE";"476";"SURFACE-SURFACE(SS)MISSILELAUNCHER";"S*G*EWMS--*****";"(null)";"(null)";"(null)"
|
||||
"355";"SURFACE TO AIR MISSILE";"65";"SURFACETOAIRMISSILE(SAM)";"S*A*WMSA--*****";"(null)";"(null)";"(null)"
|
||||
"354";"SURFACE TO SURFACE MISSILE";"64";"SURFACETOSURFACEMISSILE(SSM)";"S*A*WMSS--*****";"(null)";"(null)";"(null)"
|
||||
"391";"SURVEILLANCE";"1334";"SURVEILLANCE";"S*G*F-S---*****";"(null)";"(null)";"(null)"
|
||||
"725";"TANK";"533";"TANK";"S*G*EVAT--*****";"233";"0Vehicle";"725"
|
||||
"725";"TANK";"533";"TANK";"S*G*EVAT--*****";"43";"MBT";"725"
|
||||
"725";"TANK";"533";"TANK";"S*G*EVAT--*****";"230";"LEOPARD 2A5";"725"
|
||||
"730";"TANK HEAVY";"538";"TANKHEAVY";"S*G*EVATH-*****";"(null)";"(null)";"(null)"
|
||||
"731";"TANK HEAVY RECOVERY";"539";"TANKHEAVYRECOVERY";"S*G*EVATY-*****";"(null)";"(null)";"(null)"
|
||||
"726";"TANK LIGHT";"534";"TANKLIGHT";"S*G*EVATL-*****";"(null)";"(null)";"(null)"
|
||||
"727";"TANK LIGHT RECOVERY";"535";"TANKLIGHTRECOVERY";"S*G*EVATW-*****";"110";"BMP3 Recovery";"727"
|
||||
"728";"TANK MEDIUM";"536";"TANKMEDIUM";"S*G*EVATM-*****";"(null)";"(null)";"(null)"
|
||||
"729";"TANK MEDIUM RECOVERY";"537";"TANKMEDIUMRECOVERY";"S*G*EVATX-*****";"(null)";"(null)";"(null)"
|
||||
"773";"TELECOMMUNICATIONS FACILITY";"589";"TELECOMMUNICATIONSFACILITY";"S*G*IUT---H****";"(null)";"(null)";"(null)"
|
||||
"603";"TOPOGRAPHIC";"318";"TOPOGRAPHIC";"S*G*UUT---*****";"(null)";"(null)";"(null)"
|
||||
"751";"TRAILER MOUNTED";"559";"TRAILERMOUNTED";"S*G*EVEMT-*****";"(null)";"(null)";"(null)"
|
||||
"754";"TRAIN LOCOMOTIVE";"564";"TRAINLOCOMOTIVE";"S*G*EVST--*****";"(null)";"(null)";"(null)"
|
||||
"645";"TRANSPORTATION APOD/APOE";"436";"APOD/APOE";"S*G*USTA--*****";"(null)";"(null)";"(null)"
|
||||
"647";"TRANSPORTATION INTERMODAL";"1328";"TRANSPORTATIONINTERMODAL";"S*G*UST---*****";"(null)";"(null)";"(null)"
|
||||
"646";"TRANSPORTATION MISSILE";"439";"MISSILE";"S*G*USTI--*****";"(null)";"(null)";"(null)"
|
||||
"642";"TRANSPORTATION MOVEMENT CONTRO";"427";"MOVEMENTCONTROLCENTRE(MCC)";"S*G*USTM--*****";"(null)";"(null)";"(null)"
|
||||
"643";"TRANSPORTATION RAILHEAD";"430";"RAILHEAD";"S*G*USTR--*****";"(null)";"(null)";"(null)"
|
||||
"644";"TRANSPORTATION SPOD/SPOE";"433";"SPOD/SPOE";"S*G*USTS--*****";"(null)";"(null)";"(null)"
|
||||
"783";"TRANSPORT FACILITY";"607";"TRANSPORTFACILITY";"S*G*IT----H****";"(null)";"(null)";"(null)"
|
||||
"661";"UNITS GENERAL LIAISON";"467";"UNITGENERALLIAISON";"S*G*UHGL--*****";"(null)";"(null)";"(null)"
|
||||
"738";"UTILITY VEHICLE";"546";"UTILITYVEHICLE";"S*G*EVU---*****";"54";"HMMWV Utility";"738"
|
||||
"738";"UTILITY VEHICLE";"546";"UTILITYVEHICLE";"S*G*EVU---*****";"221";"Vehicle Tgt";"738"
|
||||
"743";"WATER CRAFT";"551";"WATERCRAFT";"S*G*EVUR--*****";"213";"TATRA Tanker Water";"743"
|
||||
"353";"WEAPON";"61";"WEAPON";"S*A*W-----*****";"(null)";"(null)";"(null)"
|
||||
|
+42
@@ -0,0 +1,42 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
# PlanModel
|
||||
SET(GeometryModel_SRCS
|
||||
geometry_model.dtd
|
||||
geometry_model.cpp
|
||||
geometry_model.h
|
||||
geometry_model_export.h
|
||||
geometry_model_factory.cpp
|
||||
geometry_model_factory.h
|
||||
geometry_model_q_dom.cpp
|
||||
geometry_model_q_dom.h
|
||||
geometry_node_visitor.cpp
|
||||
geometry_node_visitor.h
|
||||
geometry_pixelTextBox.cpp
|
||||
)
|
||||
|
||||
SOURCE_GROUP(GeometryModel FILES ${GeometryModel_SRCS})
|
||||
|
||||
NGL_ADD_LIBRARY(WS situationMapGeometryModel SHARED ${GeometryModel_SRCS})
|
||||
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES( situationMapGeometryModel
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(situationMapGeometryModel
|
||||
PRIVATE
|
||||
NGLLogger
|
||||
PUBLIC
|
||||
situationMapCommon
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Xml
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(situationMapGeometryModel)
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** GeometryModel to write and read PlanEditor plans.
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** 11.11.2015, JT : First edition for use with Qt5
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "geometry_model.h"
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
GeometryModel::GeometryModel(QObject *parent) : QObject(parent) {;}
|
||||
|
||||
GeometryModel::GeometryModel(const GeometryModel &) : QObject() {;}
|
||||
|
||||
} // namespace SituationMap
|
||||
+400
@@ -0,0 +1,400 @@
|
||||
<!--
|
||||
DTD fuer Plan-Formate
|
||||
(c)RDE 2009
|
||||
Stephan Kuhagen
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
The Top-Element of the Plan. Defines global variables in the Attributes.
|
||||
-->
|
||||
<!ELEMENT GeometryModelDocument (GeometryModel|MapSettings) >
|
||||
|
||||
<!ELEMENT GeometryModel (dictionarySymbol|ellipse|line|polyline|rectangle|spline|symbol|text|node)>
|
||||
|
||||
<!ELEMENT MapSettings EMPTY>
|
||||
|
||||
<!--
|
||||
utm_zone: UTM-zone and band (two digits, one char)
|
||||
utm_grid: UTM-grid-Square (two chars)
|
||||
utm_east: UTM-easting-value (int)
|
||||
utm_north: UTM-northing-value (int)
|
||||
pe_show_utm: bool to indicate, if the PE should display the UTM-grid
|
||||
pe_map_saturation: saturation in % of the map in the PE
|
||||
pe_map_brightness: brightness in % of the map in the PE
|
||||
pe_map_zoom: zoom-value of the map in the PE
|
||||
pe_map_rotation: The rotation of the map (double)
|
||||
pe_map_type: The type of the map (Raster, Vector, Contour, Elevation, RasterElevation)
|
||||
pe_map_centerx: center-x of the map in the PE
|
||||
pe_map_centery: center-y of the map in the PE
|
||||
-->
|
||||
<!ATTLIST MapSettings
|
||||
utm_zone CDATA #REQUIRED
|
||||
utm_grid CDATA #REQUIRED
|
||||
utm_east CDATA #REQUIRED
|
||||
utm_north CDATA #REQUIRED
|
||||
pe_show_utm CDATA #REQUIRED
|
||||
pe_map_saturation CDATA #REQUIRED
|
||||
pe_map_brightness CDATA #REQUIRED
|
||||
pe_map_zoom CDATA #REQUIRED
|
||||
pe_map_rotation CDATA #REQUIRED
|
||||
pe_map_type CDATA #REQUIRED
|
||||
pe_map_centerx CDATA #REQUIRED
|
||||
pe_map_centery CDATA #REQUIRED
|
||||
pe_symbol_transparency CDATA #IMPLIED
|
||||
pe_symbol_fill_type CDATA #IMPLIED
|
||||
pe_symbol_scale CDATA #IMPLIED>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
A node is a grouping element, which can hold any number of primitives or
|
||||
other nodes, thus creating a tree.
|
||||
-->
|
||||
<!ELEMENT node (dictionarySymbol|ellipse|line|polyline|rectangle|spline|symbol|text|node)*>
|
||||
|
||||
|
||||
<!--
|
||||
The symbology library provides a symbol dictionary. Each symbol is defined by a list of coordinates and one non-ambiguous SIDC code. The SIDC
|
||||
is a string with 15 character. See symbology library for further details.
|
||||
-->
|
||||
<!ELEMENT dictionarySymbol (point+)>
|
||||
<!ATTLIST dictionarySymbol
|
||||
GuiDisplayName CDATA #IMPLIED
|
||||
SIDC CDATA #REQUIRED
|
||||
SIDC_Norm CDATA #REQUIRED >
|
||||
<!--
|
||||
Defines ellipsis and circles. Can have start-angle and extent for sections of
|
||||
circles/ellipsis. The point defines the center of the primitive. The
|
||||
Attributes width and height define the metric dimensions, resulting in a
|
||||
centered bounding box. The primitive can be rotated with attribute
|
||||
rotate. Start-angle and extent are defined for the axis-parallel bounding-box
|
||||
and are rotated with the box. Rotation is done around the center-point.
|
||||
The optional text-tag is used for text directly assigned to this primitive.
|
||||
-->
|
||||
<!ELEMENT ellipse (point,text?)>
|
||||
|
||||
|
||||
<!--
|
||||
width: The metric width of the ellipse.
|
||||
height: The metric height of the ellipse.
|
||||
rotate: The bounding rectangle, that defines the ellipse is rotated according
|
||||
to the angle here (360° for full rotation). Double-Value.
|
||||
start: Sets the start-angle of an open ellipse before (!) rotation. Double-Value.
|
||||
extent: Sets the extent of the ellipse. For a full ellipse this must be
|
||||
360. Double-Value.
|
||||
color: Color in 32-Bit hex RGBA (#RRGGBBAA)
|
||||
linewidth: Line-width. Double-Value.
|
||||
linestyle: An enum defining the line-style
|
||||
fill: A bool, if true, the primitive should be filled with the given color and pattern.
|
||||
fill_color: Fill-Color in 32-Bit hex RGBA (#RRGGBBAA)
|
||||
fill_pattern: An enum defining the fill-pattern.
|
||||
fill_style: An enum defining the style for a filles ellipse:
|
||||
- "chord": A straight line between the start-point and end-point
|
||||
defines the inner region to be filled.
|
||||
- "pieslice": A line from the start-point to the center and from the
|
||||
center to the end-point define the inner region to be filled.
|
||||
-->
|
||||
<!ATTLIST ellipse
|
||||
GuiDisplayName CDATA #IMPLIED
|
||||
rotate CDATA #IMPLIED
|
||||
width CDATA #REQUIRED
|
||||
height CDATA #REQUIRED
|
||||
start CDATA #IMPLIED
|
||||
extent CDATA #IMPLIED
|
||||
color CDATA #REQUIRED
|
||||
linewidth CDATA #REQUIRED
|
||||
linestyle (solid|dashed|dotted|dashed_dotted) #IMPLIED
|
||||
fill CDATA #IMPLIED
|
||||
fill_color CDATA #IMPLIED
|
||||
fill_pattern (none|dots|hor1|hor2|ver1|ver2|diag1|diag2|solid) #IMPLIED
|
||||
fill_style (chord|pieslice) #IMPLIED>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
Defines a line with start- and endpoint.
|
||||
The optional text-tag is used for text directly assigned to this primitive.
|
||||
-->
|
||||
<!ELEMENT line (point,point,text?)>
|
||||
|
||||
|
||||
<!--
|
||||
color: Color in 32-Bit hex RGBA (#RRGGBBAA)
|
||||
arrows: Enum defining, if and where to add arrows to the line.
|
||||
arrow_height: The height of the arrow from the arrow-head to the outer points,
|
||||
parallel to the middle axis of the arrow.
|
||||
arrow_clamp_height: The height from the the arrow-neck to the outer points,
|
||||
parallel to the middle axis of the arrow.
|
||||
arrow_width: The distance between the outer points of the arrow.
|
||||
arrow_line_width: The line width of the line used to draw the arrow.
|
||||
linewidth: Line-width. Double-Value.
|
||||
linestyle: An enum defining the line-style
|
||||
-->
|
||||
<!ATTLIST line
|
||||
GuiDisplayName CDATA #IMPLIED
|
||||
color CDATA #REQUIRED
|
||||
arrows (none|start|end|both) #IMPLIED
|
||||
arrow_height CDATA #IMPLIED
|
||||
arrow_clamp_height CDATA #IMPLIED
|
||||
arrow_width CDATA #IMPLIED
|
||||
arrow_line_width CDATA #IMPLIED
|
||||
linewidth CDATA #REQUIRED
|
||||
linestyle (solid|dashed|dotted|dashed_dotted) #IMPLIED>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
Defines a polyline with at least three points.
|
||||
The optional text-tag is used for text directly assigned to this primitive.
|
||||
-->
|
||||
<!ELEMENT polyline (point,point,point+,text?)>
|
||||
|
||||
|
||||
<!--
|
||||
color: Color in 32-Bit hex RGBA (#RRGGBBAA)
|
||||
linewidth: Line-width. Double-Value.
|
||||
linestyle: An enum defining the line-style
|
||||
arrows: Enum defining, if and where to add arrows to the line. If the
|
||||
primitive is closed, no arrows should be drawn.
|
||||
arrow_height: The height of the arrow from the arrow-head to the outer points,
|
||||
parallel to the middle axis of the arrow.
|
||||
arrow_clamp_height: The height from the the arrow-neck to the outer points,
|
||||
parallel to the middle axis of the arrow.
|
||||
arrow_width: The distance between the outer points of the arrow.
|
||||
arrow_line_width: The line width of the line used to draw the arrow.
|
||||
close: A bool. If true, connect the start- and end-point.
|
||||
fill: A bool, if true, the primitive should be filled with the given color and pattern.
|
||||
fill_color: Fill-Color in 32-Bit hex RGBA (#RRGGBBAA)
|
||||
fill_pattern: An enum defining the fill-pattern.
|
||||
-->
|
||||
<!ATTLIST polyline
|
||||
GuiDisplayName CDATA #IMPLIED
|
||||
color CDATA #REQUIRED
|
||||
linewidth CDATA #REQUIRED
|
||||
linestyle (solid|dashed|dotted|dashed_dotted) #IMPLIED
|
||||
arrows (none|start|end|both) #IMPLIED
|
||||
arrow_height CDATA #IMPLIED
|
||||
arrow_clamp_height CDATA #IMPLIED
|
||||
arrow_width CDATA #IMPLIED
|
||||
arrow_line_width CDATA #IMPLIED
|
||||
close CDATA #REQUIRED
|
||||
fill CDATA #IMPLIED
|
||||
fill_color CDATA #IMPLIED
|
||||
fill_pattern (none|dots|hor1|hor2|ver1|ver2|diag1|diag2|solid) #IMPLIED>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
Defines a rectangle with a center-point and width/height.
|
||||
The optional text-tag is used for text directly assigned to this primitive.
|
||||
-->
|
||||
<!ELEMENT rectangle (point,text?)>
|
||||
|
||||
|
||||
<!--
|
||||
color: Color in 32-Bit hex RGBA (#RRGGBBAA)
|
||||
width: The metric width of the rectangle.
|
||||
height: The metric height of the rectangle.
|
||||
rotate: The rectangle is rotated according to the angle here (360° for full
|
||||
rotation). Double-Value.
|
||||
linewidth: Line-width. Double-Value.
|
||||
linestyle: An enum defining the line-style
|
||||
rounding: A percentage-value (double) for round edges
|
||||
fill: A bool, if true, the primitive should be filled with the given color and pattern.
|
||||
fill_color: Fill-Color in 32-Bit hex RGBA (#RRGGBBAA)
|
||||
fill_pattern: An enum defining the fill-pattern.
|
||||
-->
|
||||
<!ATTLIST rectangle
|
||||
GuiDisplayName CDATA #IMPLIED
|
||||
color CDATA #REQUIRED
|
||||
width CDATA #REQUIRED
|
||||
height CDATA #REQUIRED
|
||||
rotate CDATA #IMPLIED
|
||||
linewidth CDATA #REQUIRED
|
||||
linestyle (solid|dashed|dotted|dashed_dotted) #IMPLIED
|
||||
rounding CDATA #IMPLIED
|
||||
fill CDATA #IMPLIED
|
||||
fill_color CDATA #IMPLIED
|
||||
fill_pattern (none|dots|hor1|hor2|ver1|ver2|diag1|diag2|solid) #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Defines a spline with at least three points. The first and the last point
|
||||
define the endpoints, all other points define the curve between them.
|
||||
The optional text-tag is used for text directly assigned to this primitive.
|
||||
-->
|
||||
<!ELEMENT spline (point,point,point+,text?)>
|
||||
|
||||
|
||||
<!--
|
||||
color: Color in 32-Bit hex RGBA (#RRGGBBAA)
|
||||
linewidth: Line-width. Double-Value.
|
||||
linestyle: An enum defining the line-style
|
||||
arrows: Enum defining, if and where to add arrows to the line. If the
|
||||
primitive is closed, no arrows should be drawn.
|
||||
arrow_height: The height of the arrow from the arrow-head to the outer points,
|
||||
parallel to the middle axis of the arrow.
|
||||
arrow_clamp_height: The height from the the arrow-neck to the outer points,
|
||||
parallel to the middle axis of the arrow.
|
||||
arrow_width: The distance between the outer points of the arrow.
|
||||
arrow_line_width: The line width of the line used to draw the arrow.
|
||||
close: A bool. If true, connect the start- and end-point.
|
||||
fill: A bool. If true, the primitive should be filled with the given color and
|
||||
pattern. This also means, that the start-point is automatically
|
||||
connected to the end-point to get a closed shape to fill.
|
||||
fill_color: Fill-Color in 32-Bit hex RGBA (#RRGGBBAA)
|
||||
fill_pattern: An enum defining the fill-pattern.
|
||||
-->
|
||||
<!ATTLIST spline
|
||||
GuiDisplayName CDATA #IMPLIED
|
||||
color CDATA #REQUIRED
|
||||
linewidth CDATA #REQUIRED
|
||||
linestyle (solid|dashed|dotted|dashed_dotted) #IMPLIED
|
||||
arrows (none|start|end|both) #IMPLIED
|
||||
arrow_height CDATA #IMPLIED
|
||||
arrow_clamp_height CDATA #IMPLIED
|
||||
arrow_width CDATA #IMPLIED
|
||||
arrow_line_width CDATA #IMPLIED
|
||||
close CDATA #REQUIRED
|
||||
fill CDATA #IMPLIED
|
||||
fill_color CDATA #IMPLIED
|
||||
fill_pattern (none|dots|hor1|hor2|ver1|ver2|diag1|diag2|solid) #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
A symbol to display in the plan.
|
||||
position, offsetx (in Pixel), offsety (in Pixel), direction of movement
|
||||
-->
|
||||
<!ELEMENT symbol (point)>
|
||||
|
||||
|
||||
<!--
|
||||
text_w: Text for symbols text-field w.
|
||||
text_xy: Text for symbols text-field xy.
|
||||
text_v: Text for symbols text-field v.
|
||||
text_t: Text for symbols text-field t.
|
||||
text_z: Text for symbols text-field z.
|
||||
text_ef: Text for symbols text-field ef.
|
||||
text_g: Text for symbols text-field g.
|
||||
text_h: Text for symbols text-field h.
|
||||
text_m: Text for symbols text-field m.
|
||||
text_jklnp: Text for symbols text-field jklnp.
|
||||
symbol_id: ID of the symbol (int).
|
||||
force_id: Force-ID of the symbol (int).
|
||||
abc_protection: Flag for abc_protection (bool).
|
||||
affil: Enum for affiliation of the symbol.
|
||||
mobility: Enum for the mobility of the symbol.
|
||||
w_vbg_et: Enum for tactical state of the symbol. Corresponds to enum w_vbg_et
|
||||
in zskssmal_teilnehmer.h.
|
||||
rotate: The Symbol is rotated according
|
||||
to the angle here (360° for full rotation). Double-Value.
|
||||
-->
|
||||
<!ATTLIST symbol
|
||||
GuiDisplayName CDATA #IMPLIED
|
||||
text_w CDATA #IMPLIED
|
||||
text_xy CDATA #IMPLIED
|
||||
text_v CDATA #IMPLIED
|
||||
text_t CDATA #IMPLIED
|
||||
text_z CDATA #IMPLIED
|
||||
text_ef CDATA #IMPLIED
|
||||
text_g CDATA #IMPLIED
|
||||
text_h CDATA #IMPLIED
|
||||
text_m CDATA #IMPLIED
|
||||
text_jklnp CDATA #IMPLIED
|
||||
symbol_id CDATA #IMPLIED
|
||||
symbol_offsetX CDATA #IMPLIED
|
||||
symbol_offsetY CDATA #IMPLIED
|
||||
symbol_direction CDATA #IMPLIED
|
||||
force_id CDATA #IMPLIED
|
||||
symbol_state CDATA #IMPLIED
|
||||
symbol_uncertainty CDATA #IMPLIED
|
||||
damage_force_id CDATA #IMPLIED
|
||||
abc_protection CDATA #IMPLIED
|
||||
affil (unknown|friend|neutral|enemy) #REQUIRED
|
||||
mobility (wheel|wheel_all_terrain|chain|chain_all_terrain|trailer|train) #REQUIRED
|
||||
w_vbg_et (einsatzbereit|treffer_ohne_wirkung|annaehender_treffer|zeitlicher_ausfall|leichter_treffer|mittlerer_treffer|schwerer_treffer|bewegungsunfaehig|bewegungsunfaehig_sichtb|ausfall_waffenanlage|ausfall_waffenanlage_sichtb|totalausfall) #REQUIRED
|
||||
rotate CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
A one-line or multiline-text with optional background and frame.
|
||||
If used as a child to another primitive, the point position of the text is
|
||||
ignored. The alignment attributes define the text-position in relation to the
|
||||
primitive instead.
|
||||
-->
|
||||
<!ELEMENT text (point,text_data)>
|
||||
|
||||
|
||||
<!--
|
||||
anchor_horizontal: Horizontal position of the text on its point
|
||||
anchor_vertical: Vertical position of the text on its point
|
||||
margin_horizontal: Horizontal margin in Pixels between the texts bounding box and the surrounding frame
|
||||
margin_vertical: Vertical margin in Pixels between the texts bounding box and the surrounding frame
|
||||
color: Color in 32-Bit hex RGBA (#RRGGBBAA)
|
||||
font: Font-Type
|
||||
font_size: Font-Size. Int.
|
||||
font_italic: A bool. If true, the font should be italic.
|
||||
font_bold: A bool. If true, the font should be bold.
|
||||
box: A bool, if true, the primitive should be filled with the given color and pattern.
|
||||
linewidth: Line-width for the box. Double-Value.
|
||||
linestyle: An enum defining the line-style for the box.
|
||||
linecolor: Color in 32-Bit hex RGBA (#RRGGBBAA) for the outline of the box.
|
||||
fill: A bool, if true, the box should be filled with the given color and pattern.
|
||||
fill_color: Fill-Color for the box in 32-Bit hex RGBA (#RRGGBBAA)
|
||||
fill_pattern: An enum defining the fill-pattern for the box.
|
||||
rotate: The bounding rectangle, that defines the ellipse is rotated according
|
||||
to the angle here (360° for full rotation). Double-Value.
|
||||
-->
|
||||
<!ATTLIST text
|
||||
GuiDisplayName CDATA #IMPLIED
|
||||
anchor_horizontal (left|center|right) #REQUIRED
|
||||
anchor_vertical (top|center|bottom) #REQUIRED
|
||||
margin_horizontal CDATA #IMPLIED
|
||||
margin_vertical CDATA #IMPLIED
|
||||
color CDATA #REQUIRED
|
||||
font (SansSerif|Serif|Fixed|Decorative) #REQUIRED
|
||||
font_size CDATA #REQUIRED
|
||||
font_italic CDATA #IMPLIED
|
||||
font_bold CDATA #IMPLIED
|
||||
box CDATA #IMPLIED
|
||||
linewidth CDATA #IMPLIED
|
||||
linestyle (solid|dashed|dotted|dashed_dotted) #IMPLIED
|
||||
linecolor CDATA #IMPLIED
|
||||
fill CDATA #IMPLIED
|
||||
fill_color CDATA #IMPLIED
|
||||
fill_pattern (none|dots|hor1|hor2|ver1|ver2|diag1|diag2|solid) #IMPLIED
|
||||
rotate CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
A tag that contains the actual text-data of a text-tag.
|
||||
-->
|
||||
<!ELEMENT text_data (#PCDATA)>
|
||||
|
||||
|
||||
<!--
|
||||
alignment: If this text contains more than one line, this defines the
|
||||
alignment of the text in the bounding box of all lines.
|
||||
-->
|
||||
<!ATTLIST text_data
|
||||
alignment (left|center|right) #REQUIRED>
|
||||
|
||||
|
||||
<!--
|
||||
Defines a point with a double precision x and y-value.
|
||||
-->
|
||||
<!ELEMENT point EMPTY>
|
||||
|
||||
|
||||
<!--
|
||||
x: The x-coordinate of the point.
|
||||
y: The y-coordinate of the point.
|
||||
-->
|
||||
<!ATTLIST point
|
||||
x CDATA #REQUIRED
|
||||
y CDATA #REQUIRED>
|
||||
+1028
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Export definitions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <qglobal.h>
|
||||
|
||||
#ifndef GEOMETRYMODEL_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define GEOMETRYMODEL_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SITUATIONMAPGEOMETRYMODEL_LIB)
|
||||
# define GEOMETRYMODEL_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define GEOMETRYMODEL_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** GeometryModelFactory to create geometry model
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** 20.11.2015, JT : First edition for use with Qt5
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#include "geometry_model_factory.h"
|
||||
#include "geometry_model_q_dom.h"
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
GeometryModelFactory *GeometryModelFactory::singleton()
|
||||
{
|
||||
static GeometryModelFactory s_factory;
|
||||
return &s_factory;
|
||||
} /* GeometryModelFactory::singleton() */
|
||||
|
||||
|
||||
GeometryModel *GeometryModelFactory::create()
|
||||
{
|
||||
return new GeometryModelQDom();
|
||||
} // GeometryModelFactory::create()
|
||||
|
||||
|
||||
GeometryModel *GeometryModelFactory::clone(GeometryModel *geoModel)
|
||||
{
|
||||
GeometryModelQDom * qdomModel = dynamic_cast<GeometryModelQDom*>(geoModel);
|
||||
if (qdomModel)
|
||||
return new GeometryModelQDom(*qdomModel);
|
||||
|
||||
return nullptr;
|
||||
} // GeometryModelFactory::clone()
|
||||
|
||||
} /* namespace SituationMap */
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** GeometryModelFactory to create geometry model
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** 20.11.2015, JT : First edition for use with Qt5
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "geometry_model_q_dom.h"
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
/**
|
||||
@brief Factory class to create GeometryModels
|
||||
|
||||
@see GeometryModel GeometryModelQDom
|
||||
*/
|
||||
|
||||
class GEOMETRYMODEL_EXPORT GeometryModelFactory
|
||||
{
|
||||
public:
|
||||
|
||||
static GeometryModelFactory *singleton();
|
||||
|
||||
GeometryModelFactory() = default;
|
||||
~GeometryModelFactory() = default;
|
||||
GeometryModelFactory(const GeometryModelFactory &) = delete;
|
||||
GeometryModelFactory operator =(const GeometryModelFactory &) = delete;
|
||||
|
||||
GeometryModel *create();
|
||||
GeometryModel *clone( GeometryModel * );
|
||||
|
||||
}; /* GeometryModelFactory */
|
||||
|
||||
} /* namespace SituationMap */
|
||||
+2711
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,374 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** GeometryModel implementation to write and read PlanEditor plans from/to XML and manipulate DOM-tree.
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Stephan Kuhagen <kuhagen@rheinmetall-de.com>
|
||||
** Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** ??.??.200?, SK : First edition for use with Qt4
|
||||
** 11.11.2015, JT : Splitting interface and implementation
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// clazy:excludeall=const-signal-or-slot
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtGui/QColor>
|
||||
#include <QtXml/QDomDocument>
|
||||
#include <QtCore/QMultiMap>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QPair>
|
||||
#include <QtCore/QPointF>
|
||||
#include <QtCore/QRectF>
|
||||
#include <QtCore/QStack>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVariant>
|
||||
|
||||
#include "geometry_model.h"
|
||||
class QTransform;
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
// exported for unit test only
|
||||
class GEOMETRYMODEL_EXPORT GeometryModelQDom : public GeometryModel, public QDomDocument
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit GeometryModelQDom(QObject *parent = nullptr);
|
||||
|
||||
//! Copy-Constructor
|
||||
GeometryModelQDom(const GeometryModelQDom &other);
|
||||
|
||||
~GeometryModelQDom();
|
||||
|
||||
GeometryModelQDom & operator = (const GeometryModelQDom &other);
|
||||
|
||||
QByteArray toByteArray() const override;
|
||||
QByteArray toByteArrayDebug() const override;
|
||||
|
||||
bool fromByteArray(const QByteArray &content) override;
|
||||
bool fromDevice(QIODevice *device) override;
|
||||
bool fromByteArrayDebug(const QByteArray &content) override;
|
||||
|
||||
bool isEmpty() const override;
|
||||
|
||||
Node getRootNode() const override;
|
||||
|
||||
Node getMapDefaultSettingsNode() const override;
|
||||
|
||||
void setModelAttribute(GeometryModel::Attribute attribute, const QVariant &value) override;
|
||||
|
||||
void setModelEditorAttribute(GeometryModel::Attribute attribute, const QVariant &value) override;
|
||||
|
||||
void setPrimitiveAttribute(const GeometryModel::Node &node, GeometryModel::Attribute attribute, const QVariant &value) override;
|
||||
|
||||
void movePrimitiveIntoGroup(const GeometryModel::Node &primitive, const GeometryModel::Node &target) override;
|
||||
|
||||
void releaseGroup(const GeometryModel::Node &group) override;
|
||||
|
||||
void deleteGroup(const GeometryModel::Node &group) override;
|
||||
|
||||
void removePrimitive(const GeometryModel::Node &primitive) override;
|
||||
|
||||
void removePrimitivesByUserData(const QList<int> &userDataList) override;
|
||||
|
||||
void removeText(GeometryModel::Node &parent) override;
|
||||
|
||||
void setTextData(const GeometryModel::Node &textNode, const QString &data, GeometryModel::HorizontalAlign textAlign) override;
|
||||
|
||||
void clearModel() override;
|
||||
|
||||
void translateNode(const GeometryModel::Node &node, double x, double y) override;
|
||||
|
||||
void moveNode(const GeometryModel::Node &node, double x, double y) override;
|
||||
|
||||
void scaleNode(const GeometryModel::Node &node, double scaleX, double scaleY) override;
|
||||
|
||||
|
||||
void rotateNode(const GeometryModel::Node &node, double angle) override;
|
||||
|
||||
void reorderPrimitives(const QList<GeometryModel::Node> &nodes, GeometryModel::PrimitivOrder order) override;
|
||||
|
||||
void merge(const GeometryModel::Node &other, bool skipUndo = false, bool intoNewGroup = false) override;
|
||||
|
||||
void merge(GeometryModel *other, bool skipUndo = false, bool intoNewGroup = false) override;
|
||||
|
||||
unsigned int modificationCounter() const override;
|
||||
|
||||
void resetModificationCounter() override;
|
||||
|
||||
void undo(unsigned int steps = 1) override;
|
||||
|
||||
void redo(unsigned int steps = 1) override;
|
||||
|
||||
void enableUndo(bool enable) override;
|
||||
|
||||
void startUndoBlock() override;
|
||||
|
||||
void endUndoBlock(const QString &eventDescription = QString()) override;
|
||||
|
||||
void abortUndoBlock() override;
|
||||
|
||||
void setMaxUndoSteps(unsigned int max) override;
|
||||
|
||||
unsigned int maxUndoSteps() const override;
|
||||
|
||||
void cleanModel() override;
|
||||
|
||||
|
||||
GeometryModel::Node addPrimitive(GeometryModel::PrimitiveType type
|
||||
, const QList<QPointF> &points
|
||||
, const QList<QPair<GeometryModel::Attribute, QVariant> > &attributes
|
||||
, int userData = -1
|
||||
, const QString &textData = QString()
|
||||
, GeometryModel::HorizontalAlign textAlign = HorizontalAlign::Left) override;
|
||||
|
||||
|
||||
bool setPrimitivePoints(const GeometryModel::Node &node, const QList<QPointF> &points) override;
|
||||
|
||||
GeometryModel::Node addText(const GeometryModel::Node &parent
|
||||
, const QString &textData
|
||||
, GeometryModel::HorizontalAlign textAlign
|
||||
, const QList<QPair<GeometryModel::Attribute, QVariant> > &attributes
|
||||
, int userData) override;
|
||||
|
||||
GeometryModel::Node getText(const GeometryModel::Node &parent) const override;
|
||||
|
||||
QString getTextData(const GeometryModel::Node &textNode) const override;
|
||||
|
||||
QList<QPointF> getPrimitivePoints(const GeometryModel::Node &node) const override;
|
||||
|
||||
QRectF getBoundingBox(const GeometryModel::Node &node) const override;
|
||||
|
||||
void setNodeDisplayName(const Node &node, const QString &name) override;
|
||||
|
||||
QString getNodeDisplayName(const Node &node) const override;
|
||||
|
||||
QVariant getModelAttribute(Attribute attribute) const override;
|
||||
|
||||
QVariant getAttribute(const GeometryModel::Node &node, GeometryModel::Attribute attribute) const override;
|
||||
|
||||
template <class T> T getAttribute(const Node &node, Attribute attribute) const;
|
||||
|
||||
bool hasAttribute(const GeometryModel::Node &node, GeometryModel::Attribute attribute) const override;
|
||||
|
||||
QVariant::Type attributeType(const GeometryModel::Attribute &attribute) const override;
|
||||
|
||||
QList<GeometryModel::Attribute> supportedAttributes(GeometryModel::PrimitiveType type) const override;
|
||||
|
||||
GeometryModel::Node createGroup(const QList<GeometryModel::Node> &primitives) override;
|
||||
|
||||
GeometryModel::Node isInGroup(const GeometryModel::Node &primitive) const override;
|
||||
|
||||
GeometryModel::NodeList getGroupPrimitives(const GeometryModel::Node &node) override;
|
||||
|
||||
GeometryModel::Node findPrimitive(int userData) const override;
|
||||
|
||||
bool hasUserData(const Node &node) const override;
|
||||
|
||||
int getUserData(const GeometryModel::Node &node, bool *ok = nullptr) const override;
|
||||
|
||||
void setUserData(const GeometryModel::Node &node, int userData) override;
|
||||
|
||||
QMultiMap<int, GeometryModel::Node> userDataMap(const GeometryModel::Node &node = GeometryModel::Node()) override;
|
||||
|
||||
GeometryModel::Node copy(const GeometryModel::Node &node, int userData = 0) override;
|
||||
|
||||
GeometryModel::PrimitiveType getType(const GeometryModel::Node &node) const override;
|
||||
|
||||
unsigned int undoSteps() const override;
|
||||
|
||||
unsigned int redoSteps() const override;
|
||||
|
||||
QStringList undoHistory() const override { return _undoHistory.toList(); }
|
||||
|
||||
QStringList redoHistory() const override { return _redoHistory.toList(); }
|
||||
|
||||
void clearUndoStack() override
|
||||
{
|
||||
_undoStack.clear();
|
||||
_undoHistory.clear();
|
||||
} // clearUndoStack
|
||||
|
||||
void clearRedoStack() override
|
||||
{
|
||||
_redoStack.clear();
|
||||
_redoHistory.clear();
|
||||
} // clearRedoStack
|
||||
|
||||
QString attributeToString(const GeometryModel::Attribute &attribute) const override;
|
||||
|
||||
bool parseSymbolAttributeString(const QString &sidcAttributes, QMap<QString, QVariant> &attrMap) const override;
|
||||
|
||||
QString buildSymbolAttributeString(const QMap<QString, QVariant> &attrMap) const override;
|
||||
|
||||
static void cleanupStaticMember();
|
||||
|
||||
private:
|
||||
|
||||
static void valueFromVariant(const QVariant &v, QPointF &result);
|
||||
static void valueFromVariant(const QVariant &v, QColor &result);
|
||||
|
||||
/**
|
||||
convert to QString (with non locale-aware conversions)
|
||||
*/
|
||||
static QString variant2XmlString(const QVariant &v);
|
||||
|
||||
/**
|
||||
Create a QColor from an attribute-value with alpha-channel (QVariant
|
||||
ignores Alpha)
|
||||
\param attColor: The QString-QVariant from an attribute of Type QColor
|
||||
\return QColor with alpha-channel or invalid QColor, if the value could be parsed.
|
||||
*/
|
||||
static QColor colorFromString(const QString &attColor);
|
||||
|
||||
/**
|
||||
Create a QPoint from an attribute-value
|
||||
\param attPoint: The QString-QVariant from an attribute of Type QPointF
|
||||
\return QPointF
|
||||
*/
|
||||
static QPointF pointFromString(const QString &attPoint);
|
||||
|
||||
//! A mapping between all primitives and the attributes they support
|
||||
static QMultiMap<GeometryModel::PrimitiveType, GeometryModel::Attribute> _primitiveSupportedAttributes;
|
||||
//! Mappings between all primitive-types and their string/tag-name
|
||||
static QMap<QString, GeometryModel::PrimitiveType> _primitiveTagsTypes;
|
||||
static QMap<GeometryModel::PrimitiveType, QString> _primitiveTagsStrings;
|
||||
|
||||
//! Default-Values for all supported attributes
|
||||
static QMap<QPair<GeometryModel::PrimitiveType, GeometryModel::Attribute>, QString> _attributeDefaults;
|
||||
|
||||
//! Mapping between Attributes and their QVariant-Type.
|
||||
static QMap<GeometryModel::Attribute, QVariant::Type> _attributeTypes;
|
||||
|
||||
//! Bool to check, if static class variables have been initialized
|
||||
static bool _staticInitDone;
|
||||
|
||||
/**
|
||||
Init data of the object
|
||||
*/
|
||||
void init();
|
||||
|
||||
|
||||
/**
|
||||
Transform the points of a primitive.
|
||||
\sa {translateNode(), moveNode(), rotateNode(), scaleNode()}
|
||||
\param node: The primitive to transform.
|
||||
\param t: The transformation-matrix.
|
||||
*/
|
||||
void transformNode(const QDomNode &node, const QTransform &t);
|
||||
|
||||
|
||||
GeometryModel::PrimitiveType getType(const QDomNode &node) const;
|
||||
|
||||
bool hasUserData(const QDomNode &node) const;
|
||||
|
||||
int getUserData(const QDomNode &node, bool *okPtr) const;
|
||||
|
||||
QRectF getBoundingBox(const QDomNode &node) const;
|
||||
|
||||
QList<QPointF> getPrimitivePoints(const QDomNode &node) const;
|
||||
|
||||
bool hasAttribute(const QDomNode &node, GeometryModel::Attribute attribute) const;
|
||||
|
||||
QVariant getAttribute(const QDomNode &node, GeometryModel::Attribute attribute) const;
|
||||
|
||||
void removePrimitive(const QDomNode &primitive);
|
||||
|
||||
void translateNode(const QDomNode &node, double x, double y);
|
||||
|
||||
void moveNode(const QDomNode &node, double x, double y);
|
||||
|
||||
void scaleNode(const QDomNode &node, double scaleX, double scaleY);
|
||||
|
||||
void rotateNode(const QDomNode &node, double angle);
|
||||
|
||||
void merge(const QDomNode &other, bool skipUndo = false, bool intoNewGroup = false);
|
||||
|
||||
QDomNode createGroup(const QList<QDomNode> &primitives);
|
||||
|
||||
QMultiMap<int, QDomNode> userDataMap(const QDomNode &node) const;
|
||||
|
||||
|
||||
/**
|
||||
Wrapper for signal changed(), checks _skipChangedSignal
|
||||
|
||||
!!! ATTENTION: Do not use the signal changed directly.
|
||||
Use emitChangedSignal() instead !!!
|
||||
|
||||
\param what: Short description of the change for logging
|
||||
\param node: the changed node (if this is a Null-Node, the Root-Node of
|
||||
the plan has changed)
|
||||
\param att: The attribute, that changed. If att==MaxAttributes, then
|
||||
multiple attributes are changed
|
||||
\param coordsChanged: if true, the coordinated of the primitive are changed
|
||||
*/
|
||||
void emitChangedSignal(const Node &node, Attribute att, bool coordsChanged);
|
||||
|
||||
|
||||
//! Lock for temporarily blocking changed()-Signals
|
||||
bool _skipChangedSignal;
|
||||
|
||||
//! Undo-Stack
|
||||
bool _undoEnabled;
|
||||
unsigned int _maxUndoSteps;
|
||||
QStack<QDomNode> _undoStack;
|
||||
QStack<QString> _undoHistory;
|
||||
QStack<QDomNode> _redoStack;
|
||||
QStack<QString> _redoHistory;
|
||||
|
||||
//! Undo-blocks
|
||||
QDomNode _undoBlock;
|
||||
QString _undoHistoryBlock;
|
||||
bool _insideUndoBlock;
|
||||
unsigned int _modificationCounter;
|
||||
|
||||
//! Push/pop current state to undo-stack, if not locked
|
||||
void pushUndo(const QString &eventDescription = QString());
|
||||
GeometryModel::Node popUndo();
|
||||
}; // GeometryModelQDom
|
||||
|
||||
|
||||
template <class T> T GeometryModelQDom::getAttribute(const Node &node, Attribute attribute) const
|
||||
{
|
||||
const QVariant &v = getAttribute(node, attribute);
|
||||
|
||||
switch (qMetaTypeId<T>())
|
||||
{
|
||||
case QMetaType::QPointF:
|
||||
case QMetaType::QColor:
|
||||
{
|
||||
T result; valueFromVariant(v, result); return result;
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
return v.value<T>();
|
||||
} // template <class T> T GeometryModelQDom::getAttribute( const Node & node, Attribute attribute ) const
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Node visitor for GeometryModel.
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** 07.07.2016, JT : First edition for use with Qt5
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "geometry_node_visitor.h"
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
GeometryNodeVisitor::GeometryNodeVisitor(GeometryModel *geoModel) : m_geometryModel(geoModel) {;}
|
||||
|
||||
bool GeometryNodeVisitor::traverse()
|
||||
{
|
||||
if (!m_geometryModel)
|
||||
return true;
|
||||
return traverse(m_geometryModel->getRootNode());
|
||||
} // bool GeometryNodeVisitor::traverse()
|
||||
|
||||
|
||||
bool GeometryNodeVisitor::traverse(GeometryModel::Node node)
|
||||
{
|
||||
if (!m_geometryModel)
|
||||
return true;
|
||||
|
||||
if (node.isValid())
|
||||
{
|
||||
const GeometryModel::PrimitiveType primitiveType = m_geometryModel->getType(node);
|
||||
|
||||
if ((GeometryModel::PrimitiveType::RootNode == primitiveType) || (GeometryModel::PrimitiveType::Node == primitiveType))
|
||||
{
|
||||
if (node.hasChildNodes())
|
||||
{
|
||||
node = node.firstChildNode();
|
||||
while (node.isValid())
|
||||
{
|
||||
if (!traverse(node))
|
||||
return false;
|
||||
node = node.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!apply(m_geometryModel, node, primitiveType))
|
||||
return false;
|
||||
|
||||
} // if
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Node visitor for GeometryModel.
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** 07.07.2016, JT : First edition for use with Qt5
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "geometry_model.h"
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
/**
|
||||
GeometryNopdeVisitor implements visitor pattern to traverse geoemtry model tree. The apply function will be
|
||||
called for each node in geometry model.
|
||||
*/
|
||||
class GEOMETRYMODEL_EXPORT GeometryNodeVisitor
|
||||
{
|
||||
public:
|
||||
|
||||
explicit GeometryNodeVisitor(GeometryModel *geoModel);
|
||||
virtual ~GeometryNodeVisitor() = default;
|
||||
GeometryNodeVisitor(const GeometryNodeVisitor &) = delete;
|
||||
|
||||
/**
|
||||
Traversing the complete geometry model
|
||||
*/
|
||||
bool traverse();
|
||||
|
||||
/**
|
||||
Traversing the sub-tree of node. Coming in deepth first.
|
||||
*/
|
||||
bool traverse(GeometryModel::Node node);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
For each node the apply function will be called. If apply returns false the traversal is aborted. In
|
||||
other case if return value is true the traversel is continued.
|
||||
|
||||
@param geoModel Pointer to geometry model
|
||||
@param node Node of geometry model
|
||||
@param nodeType Type of node
|
||||
@return false to abort traversael otherwise true
|
||||
*/
|
||||
virtual bool apply(GeometryModel *geoModel, const GeometryModel::Node &node, GeometryModel::PrimitiveType nodeType) = 0;
|
||||
|
||||
GeometryModel *m_geometryModel;
|
||||
|
||||
}; // GeometryNodeVisitor
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* PixelTextBoxData as Addon to GeometryModel
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Norbert Thoden, SLSE, 2023-04-27
|
||||
*/
|
||||
|
||||
#include "geometry_pixelTextBox.h"
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QJsonArray>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
PixelTextBoxData::PixelTextBoxData(const QString &htmlText, const QColor &backgroundColor)
|
||||
: m_htmlText(htmlText), m_backgroundColor(backgroundColor)
|
||||
{
|
||||
}
|
||||
|
||||
void PixelTextBoxData::reset()
|
||||
{
|
||||
m_htmlText.clear();
|
||||
m_backgroundColor = QColor();
|
||||
m_position = QPoint();
|
||||
m_size = QSize();
|
||||
}
|
||||
|
||||
bool PixelTextBoxData::isEmpty() const
|
||||
{
|
||||
return m_htmlText.isEmpty();
|
||||
}
|
||||
|
||||
QString PixelTextBoxData::toDebugString() const
|
||||
{
|
||||
QJsonDocument jDoc(toJson());
|
||||
return QString::fromStdString(jDoc.toJson(QJsonDocument::JsonFormat::Compact).toStdString());
|
||||
}
|
||||
|
||||
bool PixelTextBoxData::operator==(const PixelTextBoxData &o) const
|
||||
{
|
||||
return m_htmlText == o.m_htmlText &&
|
||||
m_backgroundColor == o.m_backgroundColor &&
|
||||
m_position == o.m_position &&
|
||||
m_size == o.m_size;
|
||||
}
|
||||
|
||||
|
||||
QJsonObject PixelTextBoxData::toJson() const
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("text")] = m_htmlText;
|
||||
obj[QStringLiteral("backgroundColor")] = m_backgroundColor.name();
|
||||
|
||||
obj[QStringLiteral("position")] = QJsonObject({{QStringLiteral("x"), m_position.x()},
|
||||
{QStringLiteral("y"), m_position.y()},
|
||||
});
|
||||
|
||||
obj[QStringLiteral("size")] = QJsonObject({{QStringLiteral("width"), m_size.width()},
|
||||
{QStringLiteral("height"), m_size.height()},
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
bool get(const QJsonObject &obj, const QString &key, int &val)
|
||||
{
|
||||
const auto jVal = obj[key];
|
||||
if (!jVal.isDouble())
|
||||
{
|
||||
qCritical() << " isDouble failed";
|
||||
}
|
||||
val = jVal.toInt();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PixelTextBoxData PixelTextBoxData::fromJson(const QJsonValue &json)
|
||||
{
|
||||
if (json.isUndefined())
|
||||
return {};
|
||||
if (!json.isObject())
|
||||
return {};
|
||||
|
||||
PixelTextBoxData ret;
|
||||
|
||||
// text
|
||||
ret.m_htmlText = json[QStringLiteral("text")].toString();
|
||||
|
||||
// backgroundColor
|
||||
QString temp = json[QStringLiteral("backgroundColor")].toString();
|
||||
ret.m_backgroundColor.setNamedColor(temp);
|
||||
|
||||
// position:
|
||||
{
|
||||
const auto jVal = json[QStringLiteral("position")];
|
||||
get(jVal.toObject(), QStringLiteral("x"), ret.m_position.rx());
|
||||
get(jVal.toObject(), QStringLiteral("y"), ret.m_position.ry());
|
||||
}
|
||||
|
||||
// size:
|
||||
{
|
||||
const auto jVal = json[QStringLiteral("size")];
|
||||
get(jVal.toObject(), QStringLiteral("width"), ret.m_size.rwidth());
|
||||
get(jVal.toObject(), QStringLiteral("height"), ret.m_size.rheight());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString PixelTextBoxData::toJsonStr(QJsonDocument::JsonFormat format) const
|
||||
{
|
||||
QJsonObject obj = toJson();
|
||||
QJsonDocument jDoc(obj);
|
||||
return QString::fromStdString(jDoc.toJson(format).toStdString());
|
||||
}
|
||||
|
||||
PixelTextBoxData PixelTextBoxData::fromJsonStr(const QString &jsonStr)
|
||||
{
|
||||
if (jsonStr.isEmpty())
|
||||
return {};
|
||||
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument jDoc(QJsonDocument::fromJson(jsonStr.toStdString().c_str(), &parseError));
|
||||
|
||||
if (parseError.error != QJsonParseError::NoError)
|
||||
{
|
||||
qCritical() << " QJsonParseError->errorString: '" << parseError.errorString() << "'"
|
||||
<< ", offset: " << parseError.offset;
|
||||
return {};
|
||||
}
|
||||
|
||||
QJsonObject jObj = jDoc.object();
|
||||
if (jObj.isEmpty())
|
||||
return {};
|
||||
|
||||
return PixelTextBoxData::fromJson(jObj);
|
||||
}
|
||||
|
||||
//
|
||||
// Container
|
||||
//
|
||||
|
||||
QJsonObject PixelTextBoxData::pixelTextBoxContainerToJson(const QVector<PixelTextBoxData> &ptbdCont)
|
||||
{
|
||||
QJsonArray arr;
|
||||
for (const PixelTextBoxData &item : qAsConst(ptbdCont))
|
||||
arr.push_back(item.toJson());
|
||||
|
||||
QJsonObject jObj;
|
||||
jObj[QStringLiteral("PixelTextBoxData")] = arr;
|
||||
return jObj;
|
||||
}
|
||||
QVector<PixelTextBoxData> PixelTextBoxData::pixelTextBoxContainerFromJson(const QJsonValue &json)
|
||||
{
|
||||
QVector<PixelTextBoxData> ret;
|
||||
|
||||
if (!json.isObject())
|
||||
return ret;
|
||||
|
||||
const QJsonObject jObj = json.toObject();
|
||||
if (!jObj.contains(QStringLiteral("PixelTextBoxData")))
|
||||
return ret;
|
||||
|
||||
const QJsonArray &array = jObj[QStringLiteral("PixelTextBoxData")].toArray();
|
||||
ret.reserve(array.size());
|
||||
for(int i = 0; i < array.size(); ++i)
|
||||
ret.push_back(PixelTextBoxData::fromJson(array.at(i)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString PixelTextBoxData::pixelTextBoxContainerToJsonStr(const QVector<PixelTextBoxData> &ptbdCont, QJsonDocument::JsonFormat format)
|
||||
{
|
||||
QJsonObject obj = pixelTextBoxContainerToJson(ptbdCont);
|
||||
QJsonDocument jDoc(obj);
|
||||
return QString::fromStdString(jDoc.toJson(format).toStdString());
|
||||
}
|
||||
QVector<PixelTextBoxData> PixelTextBoxData::pixelTextBoxContainerFromJsonStr(const QString &jsonStr)
|
||||
{
|
||||
if (jsonStr.isEmpty())
|
||||
return {};
|
||||
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument jDoc(QJsonDocument::fromJson(jsonStr.toStdString().c_str(), &parseError));
|
||||
|
||||
if (parseError.error != QJsonParseError::NoError)
|
||||
{
|
||||
qCritical() << " QJsonParseError->errorString: '" << parseError.errorString() << "'"
|
||||
<< ", offset: " << parseError.offset;
|
||||
return {};
|
||||
}
|
||||
|
||||
QJsonObject jObj = jDoc.object();
|
||||
if (jObj.isEmpty())
|
||||
return {};
|
||||
|
||||
return PixelTextBoxData::pixelTextBoxContainerFromJson(jObj);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
GEOMETRYMODEL_EXPORT std::ostream &operator<<(std::ostream &stream, const PixelTextBoxData &value)
|
||||
{
|
||||
stream << value.toDebugString().toStdString().c_str();
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* PixelTextBoxData as Addon to GeometryModel
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Norbert Thoden, SLSE, 2023-04-27
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QColor>
|
||||
#include <QPoint>
|
||||
#include <QSize>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "geometry_model_export.h"
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
class GEOMETRYMODEL_EXPORT PixelTextBoxData
|
||||
{
|
||||
public:
|
||||
PixelTextBoxData() = default;
|
||||
explicit PixelTextBoxData(const QString &htmlText, const QColor &backgroundColor);
|
||||
|
||||
void reset();
|
||||
bool isEmpty() const;
|
||||
|
||||
QString toDebugString() const;
|
||||
|
||||
QString m_htmlText;
|
||||
QColor m_backgroundColor;
|
||||
QPoint m_position;
|
||||
QSize m_size;
|
||||
|
||||
// operator
|
||||
bool operator==(const PixelTextBoxData &o) const;
|
||||
|
||||
|
||||
// Json:
|
||||
QJsonObject toJson() const;
|
||||
static PixelTextBoxData fromJson(const QJsonValue &json);
|
||||
|
||||
QString toJsonStr(QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Indented) const;
|
||||
static PixelTextBoxData fromJsonStr(const QString &jsonStr);
|
||||
|
||||
static QJsonObject pixelTextBoxContainerToJson(const QVector<PixelTextBoxData> &ptbdCont);
|
||||
static QVector<PixelTextBoxData> pixelTextBoxContainerFromJson(const QJsonValue &json);
|
||||
|
||||
static QString pixelTextBoxContainerToJsonStr(const QVector<PixelTextBoxData> &ptbdCont, QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Indented);
|
||||
static QVector<PixelTextBoxData> pixelTextBoxContainerFromJsonStr(const QString &jsonStr);
|
||||
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
GEOMETRYMODEL_EXPORT std::ostream &operator<< (std::ostream &stream,
|
||||
const PixelTextBoxData &value);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,556 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AbstractGraphicalObject
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/GeoView.h>
|
||||
#include <arcgis/Graphic.h>
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/Multipart.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QDebug>
|
||||
#include <QSharedPointer>
|
||||
#include <QApplication>
|
||||
#include <QThread>
|
||||
#include <QObject>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
AbstractGraphicalObject::AbstractGraphicalObject(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: m_geoView(geoView)
|
||||
, m_graphicsLayer(graphicsLayer)
|
||||
, m_uniqueMapId(uniqueMapId)
|
||||
, m_debugInfo(debugInfo)
|
||||
, m_logger(getLogger("AbstractGraphicalObject"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
m_pickable = (m_uniqueMapId != INVALID_MAP_ID);
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
AbstractGraphicalObject::~AbstractGraphicalObject()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< ", m_graphicsLayer-overlayId=" << (m_graphicsLayer ? m_graphicsLayer->overlayId() : QString(QStringLiteral("unknown")));
|
||||
|
||||
#if ACRGIS_VERSION >= 0x640F00 // 100.15.0
|
||||
// removeOne ist helpful to let ModuleTest succeed: 'situationMapModuleTest checkOverlayHandler3 none'
|
||||
if (m_graphic && m_graphicsLayer && m_graphicsLayer->graphics())
|
||||
m_graphicsLayer->graphics()->removeOne(m_graphic);
|
||||
delete m_graphic;
|
||||
m_graphic = nullptr;
|
||||
#else
|
||||
|
||||
/*
|
||||
// cleanup
|
||||
// to make sure, the the graphic is removed from internal container BEFORE
|
||||
// graphic is deleted, follow the documentation: use Layer::removeGraphic
|
||||
// (instead 'delete m_graphic')
|
||||
if (m_graphic && m_graphicsLayer && m_graphicsLayer->graphics())
|
||||
m_graphicsLayer->graphics()->removeOne(m_graphic);
|
||||
|
||||
if (m_graphic)
|
||||
{
|
||||
delete m_graphic;
|
||||
m_graphic = nullptr;
|
||||
}
|
||||
*/
|
||||
|
||||
// Race condition between removeOne() and delete m_graphic :
|
||||
// BUG-000116867 is for the deadlock
|
||||
// BUG-000117464 is for the crash
|
||||
// Use following workaround until ESRI will release the fix (with 100.5!?)
|
||||
if (m_graphic && m_graphicsLayer && m_graphicsLayer->graphics())
|
||||
{
|
||||
const int idx = m_graphicsLayer->graphics()->indexOf(m_graphic);
|
||||
|
||||
if (idx < 0)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " indexOf failed, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
auto graphicCopy = m_graphic;
|
||||
|
||||
QObject::connect (m_graphicsLayer->graphics(), &Esri::ArcGISRuntime::GraphicListModel::graphicRemoved,
|
||||
m_graphic, [idx, graphicCopy](int index)
|
||||
{
|
||||
if (idx == index)
|
||||
delete graphicCopy;
|
||||
});
|
||||
m_graphicsLayer->graphics()->removeOne(m_graphic);
|
||||
}
|
||||
// : Race condition between removeOne() and delete m_graphic
|
||||
|
||||
// m_esriSimpleLineSymbol AND m_esriSimpleFillSymbol will be destroyed m_graphic
|
||||
|
||||
#endif // ACRGIS_VERSION >= 0x640F00
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
Esri::ArcGISRuntime::Graphic *AbstractGraphicalObject::graphic()
|
||||
{
|
||||
return m_graphic;
|
||||
}
|
||||
|
||||
Esri::ArcGISRuntime::GraphicsOverlay *AbstractGraphicalObject::graphicsLayer()
|
||||
{
|
||||
return m_graphicsLayer;
|
||||
}
|
||||
|
||||
Esri::ArcGISRuntime::Geometry AbstractGraphicalObject::getGraphicGeometry() const
|
||||
{
|
||||
if (! m_graphic)
|
||||
return Esri::ArcGISRuntime::Geometry();
|
||||
return m_graphic->geometry();
|
||||
}
|
||||
|
||||
bool AbstractGraphicalObject::updateView()
|
||||
{
|
||||
if (!changed())
|
||||
return true;
|
||||
|
||||
bool success = updateViewImpl();
|
||||
resetChanged();
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QString AbstractGraphicalObject::debugInfo() const
|
||||
{
|
||||
return m_debugInfo;
|
||||
}
|
||||
void AbstractGraphicalObject::setDebugInfo(const QString &debugInfo)
|
||||
{
|
||||
m_debugInfo = debugInfo;
|
||||
}
|
||||
|
||||
int AbstractGraphicalObject::drawOrder() const
|
||||
{
|
||||
return m_drawOrder.value();
|
||||
}
|
||||
void AbstractGraphicalObject::setDrawOrder(int drawOrder)
|
||||
{
|
||||
m_drawOrder = drawOrder;
|
||||
// if (m_graphic)
|
||||
// m_graphic->setDrawOrder(m_drawOrder.value());
|
||||
}
|
||||
|
||||
|
||||
QString AbstractGraphicalObject::toString() const
|
||||
{
|
||||
QString str;
|
||||
|
||||
if (!m_debugInfo.isEmpty())
|
||||
str.append(QStringLiteral("debugInfo=%1").arg(m_debugInfo));
|
||||
if (m_graphicsLayer)
|
||||
str.append(QStringLiteral(" layer='%1'").arg(m_graphicsLayer->objectName()));
|
||||
|
||||
str.append(QStringLiteral(" m_drawOrder='%1'").arg(m_drawOrder.value()));
|
||||
|
||||
if (m_graphic)
|
||||
str.append(QStringLiteral(" zIndex='%1'").arg(m_graphic->zIndex()));
|
||||
|
||||
str.append(QStringLiteral(" visibility='%1'").arg(m_visibility.value()));
|
||||
str.append(QStringLiteral(" selected='%1'").arg(m_selected.value()));
|
||||
|
||||
str.append(QStringLiteral(" scale='%1'").arg(m_scale.value()));
|
||||
str.append(QStringLiteral(" positions.count='%1'").arg(m_positions.value().count()));
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
UniqueMapId AbstractGraphicalObject::uniqueMapId() const
|
||||
{
|
||||
return m_uniqueMapId;
|
||||
}
|
||||
|
||||
void AbstractGraphicalObject::setUniqueMapId(UniqueMapId uniqueId)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId=" << uniqueId;
|
||||
|
||||
m_uniqueMapId = uniqueId;
|
||||
|
||||
// use attribute to store application obj id (SimWorld) at graphic
|
||||
if (m_graphic)
|
||||
{
|
||||
// use attributeModel to store application obj id (SimWorld) at graphic
|
||||
Esri::ArcGISRuntime::AttributeListModel *attListModel = m_graphic->attributes();
|
||||
if (attListModel)
|
||||
attListModel->insertAttribute(QLatin1String(SituationMap::UniqueMapIdAttribute), m_uniqueMapId);
|
||||
else
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no AttributeListModel, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId=" << m_uniqueMapId;
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId=" << uniqueId;
|
||||
}
|
||||
|
||||
Point3D AbstractGraphicalObject::origin() const
|
||||
{
|
||||
return m_positions.value().value(0); // value => if index is out of range -> default object
|
||||
}
|
||||
void AbstractGraphicalObject::setOrigin(const Point3D &origin)
|
||||
{
|
||||
// TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
// << " origin=" << origin;
|
||||
|
||||
if (m_positions.value().isEmpty())
|
||||
m_positions.refValue().append(origin);
|
||||
else
|
||||
{
|
||||
// https://stackoverflow.com/a/1573715/2352507
|
||||
// Any comparison(except with "!=") with NaN returns false.
|
||||
// NaN != NaN -> true!!!
|
||||
if (m_positions.value().value(0) != origin) // NaN != NaN -> true!!!
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " value(0) = " << m_positions.value().value(0) << " origin = " << origin;
|
||||
m_positions.refValue().clear();
|
||||
m_positions.refValue().append(origin);
|
||||
}
|
||||
}
|
||||
|
||||
// TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
// << " origin=" << origin
|
||||
// << " changed=" << m_positions.changed()
|
||||
// << " SIZE=" << m_positions.value().size();
|
||||
}
|
||||
|
||||
void AbstractGraphicalObject::setOrigin(const QPointF &origin)
|
||||
{
|
||||
setOrigin(Point3D(origin.x(), origin.y(), .0));
|
||||
}
|
||||
|
||||
PositionCont AbstractGraphicalObject::positions() const
|
||||
{
|
||||
return m_positions.value();
|
||||
}
|
||||
void AbstractGraphicalObject::setPositions(const PositionCont &posCont)
|
||||
{
|
||||
m_positions = posCont;
|
||||
|
||||
// TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
// << " changed=" << m_positions.changed();
|
||||
}
|
||||
|
||||
|
||||
bool AbstractGraphicalObject::isSinglePoint() const
|
||||
{
|
||||
return m_positions.value().count() == 1;
|
||||
}
|
||||
bool AbstractGraphicalObject::isMultiPoint() const
|
||||
{
|
||||
return m_positions.value().count() > 1;
|
||||
}
|
||||
bool AbstractGraphicalObject::isArea() const
|
||||
{
|
||||
return m_positions.value().count() > 2;
|
||||
}
|
||||
|
||||
LineStyle AbstractGraphicalObject::lineStyle() const
|
||||
{
|
||||
return m_lineStyle.value();
|
||||
}
|
||||
LineStyle &AbstractGraphicalObject::rLineStyle()
|
||||
{
|
||||
return m_lineStyle.refValue();
|
||||
}
|
||||
void AbstractGraphicalObject::setLineStyle(const LineStyle &lineStyle)
|
||||
{
|
||||
m_lineStyle = lineStyle;
|
||||
}
|
||||
|
||||
FillStyle AbstractGraphicalObject::fillStyle() const
|
||||
{
|
||||
return m_fillStyle.value();
|
||||
}
|
||||
FillStyle &AbstractGraphicalObject::rFillStyle()
|
||||
{
|
||||
return m_fillStyle.refValue();
|
||||
}
|
||||
void AbstractGraphicalObject::setFillStyle(const FillStyle &fillStyle)
|
||||
{
|
||||
m_fillStyle = fillStyle;
|
||||
}
|
||||
|
||||
|
||||
bool AbstractGraphicalObject::visibility() const
|
||||
{
|
||||
return m_visibility.value();
|
||||
}
|
||||
void AbstractGraphicalObject::setVisibility(bool visibility)
|
||||
{
|
||||
m_visibility = visibility;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " visibility=" << m_visibility;
|
||||
}
|
||||
|
||||
bool AbstractGraphicalObject::selected() const
|
||||
{
|
||||
return m_selected.value();
|
||||
}
|
||||
void AbstractGraphicalObject::setSelected(bool selected)
|
||||
{
|
||||
m_selected = selected;
|
||||
}
|
||||
|
||||
|
||||
bool AbstractGraphicalObject::pickable() const
|
||||
{
|
||||
return m_pickable.value();
|
||||
}
|
||||
void AbstractGraphicalObject::setPickable(bool pickable)
|
||||
{
|
||||
// allow pickable only if m_uniqueMapId is valid:
|
||||
m_pickable = pickable && (m_uniqueMapId != INVALID_MAP_ID);
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " pickable=" << m_pickable;
|
||||
}
|
||||
|
||||
|
||||
float AbstractGraphicalObject::scale() const
|
||||
{
|
||||
return m_scale.value();
|
||||
}
|
||||
void AbstractGraphicalObject::setScale(float scale)
|
||||
{
|
||||
m_scale = scale;
|
||||
}
|
||||
|
||||
|
||||
bool AbstractGraphicalObject::addUpdateGraphic()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " updateGraphic";
|
||||
|
||||
bool successGraphic = true;
|
||||
|
||||
if (! m_graphic)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " no m_graphic -> return true";
|
||||
return true;
|
||||
}
|
||||
|
||||
// append just once :-)
|
||||
if (! m_graphicsLayer->graphics()->contains(m_graphic))
|
||||
{
|
||||
m_graphicsLayer->graphics()->append(m_graphic);
|
||||
successGraphic = m_graphicsLayer->graphics()->contains(m_graphic);
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " successGraphic=" << successGraphic;
|
||||
return successGraphic;
|
||||
}
|
||||
|
||||
|
||||
bool AbstractGraphicalObject::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId =" << m_uniqueMapId
|
||||
<< " origin =" << this->origin()
|
||||
<< " visibility=" << m_visibility;
|
||||
bool success = true;
|
||||
|
||||
// some checks:
|
||||
if (!m_graphicsLayer)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " no graphicsLayer";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_graphic)
|
||||
{
|
||||
m_graphic = new Esri::ArcGISRuntime::Graphic();
|
||||
m_graphic->setObjectName(m_debugInfo);
|
||||
m_graphic->setZIndex(m_drawOrder.value());
|
||||
|
||||
// use attributeModel to store application obj id (SimWorld) at graphic
|
||||
Esri::ArcGISRuntime::AttributeListModel *attLisModel = m_graphic->attributes();
|
||||
if (attLisModel)
|
||||
attLisModel->insertAttribute(QLatin1String(SituationMap::UniqueMapIdAttribute), m_uniqueMapId);
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no AttributeListModel, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId=" << m_uniqueMapId;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success=" << success;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool AbstractGraphicalObject::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId=" << m_uniqueMapId
|
||||
<< " origin=" << this->origin()
|
||||
<< " visibility=" << m_visibility
|
||||
<< " selected=" << m_selected
|
||||
<< " drawOrder=" << m_drawOrder
|
||||
<< " pickable=" << m_pickable
|
||||
<< " pickableCHG=" << m_pickable.changed();
|
||||
|
||||
if (QApplication::instance()->thread()->currentThreadId() != QThread::currentThreadId())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " wrong Thread, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId=" << m_uniqueMapId;
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
if (m_graphic)
|
||||
{
|
||||
m_graphic->setZIndex(m_drawOrder.value());
|
||||
m_graphic->setVisible(m_visibility.value());
|
||||
m_graphic->setSelected(m_selected.value());
|
||||
|
||||
// Picking:
|
||||
if (m_pickable.changed())
|
||||
{
|
||||
// use attributeModel to store m_pickable at graphic
|
||||
Esri::ArcGISRuntime::AttributeListModel *attLisModel = m_graphic->attributes();
|
||||
if (attLisModel)
|
||||
attLisModel->insertAttribute(QLatin1String(SituationMap::IsPickableAttribute), m_pickable.value());
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no AttributeListModel, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId=" << m_uniqueMapId;
|
||||
}
|
||||
}
|
||||
m_pickable.reset();
|
||||
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId =" << m_uniqueMapId;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AbstractGraphicalObject::assignLineStyleToGraphic()
|
||||
{
|
||||
if (!m_graphic)
|
||||
return false;
|
||||
|
||||
const LineStyle &ls = m_lineStyle.value();
|
||||
|
||||
if (!m_esriSimpleLineSymbol)
|
||||
{
|
||||
m_esriSimpleLineSymbol =
|
||||
new Esri::ArcGISRuntime::SimpleLineSymbol(convert(ls.linePattern()), ls.lineColor(), ls.lineWidth() * m_scale.value(), m_graphic);
|
||||
} else {
|
||||
m_esriSimpleLineSymbol->setStyle(convert(ls.linePattern()));
|
||||
m_esriSimpleLineSymbol->setColor(ls.lineColor());
|
||||
m_esriSimpleLineSymbol->setWidth(ls.lineWidth() * m_scale.value());
|
||||
}
|
||||
m_graphic->setSymbol(m_esriSimpleLineSymbol.data());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AbstractGraphicalObject::assignFillStyleToGraphic()
|
||||
{
|
||||
if (!m_graphic)
|
||||
return false;
|
||||
|
||||
const LineStyle &ls = m_lineStyle.value();
|
||||
const FillStyle &fs = m_fillStyle.value();
|
||||
|
||||
// 1. the Line
|
||||
if (!m_esriSimpleLineSymbol)
|
||||
{
|
||||
m_esriSimpleLineSymbol =
|
||||
new Esri::ArcGISRuntime::SimpleLineSymbol(convert(ls.linePattern()), ls.lineColor(), ls.lineWidth() * m_scale.value(), m_graphic);
|
||||
} else {
|
||||
m_esriSimpleLineSymbol->setStyle(convert(ls.linePattern()));
|
||||
m_esriSimpleLineSymbol->setColor(ls.lineColor());
|
||||
m_esriSimpleLineSymbol->setWidth(ls.lineWidth() * m_scale.value());
|
||||
}
|
||||
|
||||
// 1. the Fill
|
||||
if (!m_esriSimpleFillSymbol)
|
||||
{
|
||||
m_esriSimpleFillSymbol =
|
||||
new Esri::ArcGISRuntime::SimpleFillSymbol(convert(fs.fillPattern()), fs.fillColor(), m_esriSimpleLineSymbol, m_graphic);
|
||||
} else {
|
||||
m_esriSimpleFillSymbol->setStyle(convert(fs.fillPattern()));
|
||||
m_esriSimpleFillSymbol->setColor(fs.fillColor());
|
||||
m_esriSimpleFillSymbol->setOutline(m_esriSimpleLineSymbol);
|
||||
}
|
||||
m_graphic->setSymbol(m_esriSimpleFillSymbol.data());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Esri::ArcGISRuntime::SimpleLineSymbolStyle AbstractGraphicalObject::convert(const LinePattern linePattern)
|
||||
{
|
||||
switch (linePattern)
|
||||
{
|
||||
case LinePattern::Dash: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Dash;
|
||||
case LinePattern::DashDot: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::DashDot;
|
||||
case LinePattern::DashDotDot: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::DashDotDot;
|
||||
case LinePattern::Dot: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Dot;
|
||||
case LinePattern::Null: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Null;
|
||||
case LinePattern::Solid: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Solid;
|
||||
} // switch
|
||||
|
||||
return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Solid;
|
||||
}
|
||||
|
||||
|
||||
Esri::ArcGISRuntime::SimpleFillSymbolStyle AbstractGraphicalObject::convert(const FillPattern fillPattern)
|
||||
{
|
||||
switch (fillPattern)
|
||||
{
|
||||
case FillPattern::BackwardDiagonal: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::BackwardDiagonal;
|
||||
case FillPattern::Cross: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Cross;
|
||||
case FillPattern::DiagonalCross: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::DiagonalCross;
|
||||
case FillPattern::ForwardDiagonal: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::ForwardDiagonal;
|
||||
case FillPattern::Horizontal: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Horizontal;
|
||||
case FillPattern::Null: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Null;
|
||||
case FillPattern::Solid: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Solid;
|
||||
case FillPattern::Vertical: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Vertical;
|
||||
} // switch
|
||||
|
||||
return Esri::ArcGISRuntime::SimpleFillSymbolStyle::BackwardDiagonal;
|
||||
}
|
||||
|
||||
int AbstractGraphicalObject::countOfPolygonFirstPart(const Esri::ArcGISRuntime::Multipart &polylinePolygon)
|
||||
{
|
||||
if (polylinePolygon.isEmpty() || polylinePolygon.parts().isEmpty())
|
||||
return -1;
|
||||
|
||||
return polylinePolygon.parts().part(0).pointCount();
|
||||
}
|
||||
|
||||
|
||||
const Esri::ArcGISRuntime::SpatialReference AbstractGraphicalObject::spatialReference() const
|
||||
{
|
||||
return m_geoView->spatialReference();
|
||||
}
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AbstractGraphicalObject
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include <Map/situation_map_types.h>
|
||||
#include <Map/line_style.h>
|
||||
#include <Map/fill_style.h>
|
||||
#include <Common/simple_value.h>
|
||||
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/SimpleLineSymbol.h>
|
||||
#include <arcgis/SimpleFillSymbol.h>
|
||||
|
||||
// Qt
|
||||
#include <QPointer>
|
||||
|
||||
|
||||
// forward:
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class GeoView;
|
||||
class Graphic;
|
||||
class GraphicsOverlay;
|
||||
class Geometry;
|
||||
class Multipart;
|
||||
class SpatialReference;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
//forward
|
||||
class GraphicalObjectText;
|
||||
|
||||
|
||||
class SITUATIONMAP_EXPORT AbstractGraphicalObject
|
||||
{
|
||||
|
||||
public:
|
||||
AbstractGraphicalObject(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
virtual ~AbstractGraphicalObject();
|
||||
|
||||
AbstractGraphicalObject(const AbstractGraphicalObject &other) = delete;
|
||||
AbstractGraphicalObject &operator=(AbstractGraphicalObject &other) = delete;
|
||||
|
||||
virtual Esri::ArcGISRuntime::Graphic *graphic();
|
||||
virtual Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer();
|
||||
|
||||
virtual QString toString() const;
|
||||
|
||||
virtual UniqueMapId uniqueMapId() const;
|
||||
virtual void setUniqueMapId(UniqueMapId uniqueId);
|
||||
|
||||
virtual QString debugInfo() const;
|
||||
virtual void setDebugInfo(const QString &debugInfo);
|
||||
|
||||
virtual int drawOrder() const;
|
||||
virtual void setDrawOrder(int drawOrder);
|
||||
|
||||
// Data access:
|
||||
|
||||
// for SinglePoint:
|
||||
virtual Point3D origin() const;
|
||||
virtual void setOrigin(const Point3D &origin);
|
||||
virtual void setOrigin(const QPointF &origin); // ToDO accept this??
|
||||
|
||||
// for MultiPoint:
|
||||
virtual PositionCont positions() const;
|
||||
virtual void setPositions(const PositionCont &posCont);
|
||||
|
||||
virtual bool isSinglePoint() const;
|
||||
virtual bool isMultiPoint() const;
|
||||
virtual bool isArea() const;
|
||||
|
||||
virtual LineStyle lineStyle() const;
|
||||
virtual LineStyle &rLineStyle();
|
||||
/**
|
||||
* @brief setLineStyle (Font-)size is limited to 500.
|
||||
* (High values can lead to coredump with 'SymbolDrawHelper::create_line_image FAILED, SkBitmap is NULL or empty')
|
||||
* @param lineStyle to set.
|
||||
*/
|
||||
virtual void setLineStyle(const LineStyle &lineStyle);
|
||||
|
||||
virtual FillStyle fillStyle() const;
|
||||
virtual FillStyle &rFillStyle();
|
||||
virtual void setFillStyle(const FillStyle &fillStyle);
|
||||
|
||||
// Scale :
|
||||
virtual float scale() const;
|
||||
virtual void setScale(float scale);
|
||||
// : Scale
|
||||
|
||||
|
||||
// Visibility :
|
||||
virtual bool visibility() const;
|
||||
virtual void setVisibility(bool visibility);
|
||||
// : Visibility
|
||||
|
||||
// Selection, Picking :
|
||||
bool selected() const;
|
||||
void setSelected(bool selected);
|
||||
|
||||
bool pickable() const;
|
||||
/**
|
||||
* @brief setPickable The method allows pickable=true only if uniqueMapIdis valid.
|
||||
* @param pickable new value.
|
||||
*/
|
||||
void setPickable(bool pickable);
|
||||
// : Selection, Picking
|
||||
|
||||
|
||||
virtual Esri::ArcGISRuntime::Geometry getGraphicGeometry() const;
|
||||
|
||||
bool updateView();
|
||||
|
||||
bool addUpdateGraphic();
|
||||
|
||||
static Esri::ArcGISRuntime::SimpleLineSymbolStyle convert(const LinePattern linePattern);
|
||||
static Esri::ArcGISRuntime::SimpleFillSymbolStyle convert(const FillPattern fillPattern);
|
||||
|
||||
bool assignLineStyleToGraphic();
|
||||
bool assignFillStyleToGraphic();
|
||||
|
||||
|
||||
static int countOfPolygonFirstPart(const Esri::ArcGISRuntime::Multipart &polylinePolygon);
|
||||
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
const Esri::ArcGISRuntime::SpatialReference spatialReference() const;
|
||||
|
||||
virtual bool changed()
|
||||
{
|
||||
return m_drawOrder.changed()
|
||||
|| m_positions.changed()
|
||||
|| m_visibility.changed()
|
||||
|| m_selected.changed()
|
||||
|| m_pickable.changed()
|
||||
|| m_scale.changed()
|
||||
|| m_lineStyle.changed()
|
||||
|| m_fillStyle.changed();
|
||||
}
|
||||
|
||||
virtual bool updateViewImpl() = 0;
|
||||
|
||||
virtual void resetChanged()
|
||||
{
|
||||
m_drawOrder.reset();
|
||||
m_positions.reset();
|
||||
m_visibility.reset();
|
||||
m_selected.reset();
|
||||
m_pickable.reset();
|
||||
m_scale.reset();
|
||||
m_lineStyle.reset();
|
||||
m_fillStyle.reset();
|
||||
}
|
||||
|
||||
|
||||
virtual bool create() = 0;
|
||||
|
||||
|
||||
const Esri::ArcGISRuntime::GeoView *m_geoView = nullptr;
|
||||
Esri::ArcGISRuntime::GraphicsOverlay *m_graphicsLayer = nullptr;
|
||||
Esri::ArcGISRuntime::Graphic *m_graphic = nullptr;
|
||||
SimpleValue<int> m_drawOrder = 0;
|
||||
|
||||
// Data
|
||||
UniqueMapId m_uniqueMapId;
|
||||
|
||||
|
||||
QString m_debugInfo; ///< for debugging
|
||||
|
||||
SimpleValue<PositionCont> m_positions;
|
||||
|
||||
SimpleValue<bool> m_visibility = true;
|
||||
|
||||
SimpleValue<bool> m_selected = false;
|
||||
SimpleValue<bool> m_pickable = true;
|
||||
|
||||
SimpleValue<float> m_scale = 1.0;
|
||||
|
||||
SimpleValue<LineStyle> m_lineStyle;
|
||||
SimpleValue<FillStyle> m_fillStyle;
|
||||
QPointer<Esri::ArcGISRuntime::SimpleLineSymbol> m_esriSimpleLineSymbol = nullptr;
|
||||
QPointer<Esri::ArcGISRuntime::SimpleFillSymbol> m_esriSimpleFillSymbol = nullptr;
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* EllipseParameters
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "ellipse_parameters.h"
|
||||
|
||||
|
||||
// ESRI
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QString>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
float EllipseParameters::lengthX() const
|
||||
{
|
||||
return m_lengthX;
|
||||
}
|
||||
|
||||
void EllipseParameters::setLengthX(float lengthX)
|
||||
{
|
||||
m_lengthX = lengthX;
|
||||
}
|
||||
float EllipseParameters::lengthY() const
|
||||
{
|
||||
return m_lengthY;
|
||||
}
|
||||
|
||||
void EllipseParameters::setLengthY(float lengthY)
|
||||
{
|
||||
m_lengthY = lengthY;
|
||||
}
|
||||
float EllipseParameters::directionDegree() const
|
||||
{
|
||||
return m_directionDegree;
|
||||
}
|
||||
|
||||
void EllipseParameters::setDirectionDegree(float directionDegree)
|
||||
{
|
||||
m_directionDegree = directionDegree;
|
||||
}
|
||||
int EllipseParameters::maxSegmentLength() const
|
||||
{
|
||||
return m_maxSegmentLength;
|
||||
}
|
||||
|
||||
void EllipseParameters::setMaxSegmentLength(int value)
|
||||
{
|
||||
m_maxSegmentLength = value;
|
||||
}
|
||||
|
||||
int EllipseParameters::maxPointCount() const
|
||||
{
|
||||
return m_maxPointCount;
|
||||
}
|
||||
|
||||
void EllipseParameters::setMaxPointCount(int maxPointCount)
|
||||
{
|
||||
m_maxPointCount = maxPointCount;
|
||||
}
|
||||
|
||||
|
||||
bool EllipseParameters::isValid() const
|
||||
{
|
||||
return ((m_lengthX > 0) && (m_lengthY > 0)) ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<< (std::ostream &stream,
|
||||
const EllipseParameters &value)
|
||||
{
|
||||
QString str;
|
||||
str.append(QStringLiteral(" lengthX=%1").arg(value.lengthX()));
|
||||
str.append(QStringLiteral(" lengthY=%1").arg(value.lengthY()));
|
||||
str.append(QStringLiteral(" directionDegree=%1").arg(value.directionDegree()));
|
||||
str.append(QStringLiteral(" maxSegmentLength=%1").arg(value.maxSegmentLength()));
|
||||
|
||||
stream << str.toStdString();
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* EllipseParameters
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include <situation_map_export.h>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class SITUATIONMAP_EXPORT EllipseParameters
|
||||
{
|
||||
public:
|
||||
|
||||
static constexpr unsigned int MAX_POINT_COUNT_DEFAULT = 30;
|
||||
|
||||
EllipseParameters() = default;
|
||||
|
||||
float lengthX() const;
|
||||
void setLengthX(float lengthX);
|
||||
|
||||
float lengthY() const;
|
||||
void setLengthY(float lengthY);
|
||||
|
||||
float directionDegree() const;
|
||||
void setDirectionDegree(float directionDegree);
|
||||
|
||||
int maxSegmentLength() const;
|
||||
void setMaxSegmentLength(int value);
|
||||
|
||||
int maxPointCount() const;
|
||||
void setMaxPointCount(int maxPointCount);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* @brief operator== Compare two objects
|
||||
* @param other to be compared with
|
||||
* @return true if identical, otherwise false.
|
||||
*/
|
||||
bool operator==(const EllipseParameters &other) const
|
||||
{
|
||||
return ((this->m_lengthX == other.m_lengthX) &&
|
||||
(this->m_lengthY == other.m_lengthY) &&
|
||||
(this->m_directionDegree == other.m_directionDegree) &&
|
||||
(this->m_maxSegmentLength == other.m_maxSegmentLength) &&
|
||||
(this->m_maxPointCount == other.m_maxPointCount)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief operator!= Compare two objects
|
||||
* @param other to be compared with
|
||||
* @return true if NOT identical, otherwise false.
|
||||
*/
|
||||
bool operator!=(const EllipseParameters &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
float m_lengthX = 0;
|
||||
float m_lengthY = 0;
|
||||
float m_directionDegree = 0;
|
||||
int m_maxSegmentLength = 10; // meter
|
||||
int m_maxPointCount = MAX_POINT_COUNT_DEFAULT;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
SITUATIONMAP_EXPORT std::ostream &operator<< (std::ostream &stream,
|
||||
const EllipseParameters &value);
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectAttributes
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_attributes.h"
|
||||
#include <MapImpl/map_impl.h>
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
#include <Common/simple_value.h>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/Map.h>
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
class GraphicalObjectAttributes::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
~Private() = default;
|
||||
|
||||
// ESRI data:
|
||||
MapImpl *m_mapImpl = nullptr;
|
||||
QString m_logicalLayerName;
|
||||
|
||||
// OWN data:
|
||||
SimpleValue<QVariantMap> m_attributes;
|
||||
|
||||
}; // class GraphicalObjectAttributes::Private
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
GraphicalObjectAttributes::GraphicalObjectAttributes(MapImpl *mapImpl,
|
||||
Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer,
|
||||
const QString &debugInfo,
|
||||
const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(mapImpl->getEsriGeoView(), graphicsLayer, debugInfo, uniqueMapId),
|
||||
m_logger(getLogger("GraphicalObjectAttributes")),
|
||||
d(new Private)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectAttributes::~GraphicalObjectAttributes()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
delete d;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
bool GraphicalObjectAttributes::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_visibility = " << m_visibility;
|
||||
|
||||
bool success = BaseClass::create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
bool successGraphic = addUpdateGraphic(); // CHECK
|
||||
if (!successGraphic)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " addUpdateGraphic failed, debugInfo='" << m_debugInfo << "'" << " uniqueMapId=" << m_uniqueMapId;
|
||||
return false;
|
||||
}
|
||||
|
||||
// real work:
|
||||
// empty
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
return success;
|
||||
}
|
||||
|
||||
QVariantMap GraphicalObjectAttributes::attributes() const
|
||||
{
|
||||
return d->m_attributes.value();
|
||||
}
|
||||
|
||||
void GraphicalObjectAttributes::setAttributes(const QVariantMap &attributes)
|
||||
{
|
||||
d->m_attributes = attributes;
|
||||
}
|
||||
|
||||
bool GraphicalObjectAttributes::changed()
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| d->m_attributes.changed();
|
||||
}
|
||||
void GraphicalObjectAttributes::resetChanged()
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
d->m_attributes.reset();
|
||||
}
|
||||
|
||||
Esri::ArcGISRuntime::Geometry GraphicalObjectAttributes::getGraphicGeometry() const
|
||||
{
|
||||
if (m_graphic) return m_graphic->geometry();
|
||||
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Geometry is undefined";
|
||||
|
||||
return Esri::ArcGISRuntime::Geometry();
|
||||
} // Esri::ArcGISRuntime::Geometry GraphicalObjectAttributes::getGraphicGeometry() const
|
||||
|
||||
|
||||
bool GraphicalObjectAttributes::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " visibility=" << m_visibility
|
||||
<< " selected=" << m_selected
|
||||
<< " origin=" << this->origin()
|
||||
<< " scale=" << m_scale.value();
|
||||
|
||||
bool success = create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!BaseClass::updateViewImpl())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// real work:
|
||||
if (m_positions.changed())
|
||||
{
|
||||
const PositionCont &posCont = m_positions.value();
|
||||
if (posCont.size() == 1)
|
||||
{
|
||||
const Point3D &origin = this->origin();
|
||||
Esri::ArcGISRuntime::Point originGeometry(origin.x(),
|
||||
origin.y(),
|
||||
origin.z(),
|
||||
spatialReference());
|
||||
m_graphic->setGeometry(originGeometry);
|
||||
}
|
||||
}
|
||||
|
||||
if (d->m_attributes.changed())
|
||||
{
|
||||
QVariantMap rawAttributes = d->m_attributes.value();
|
||||
|
||||
// add basics:
|
||||
rawAttributes[QLatin1String(SituationMap::UniqueMapIdAttribute)] = m_uniqueMapId;
|
||||
rawAttributes[QLatin1String(SituationMap::IsPickableAttribute)] = m_pickable.value();
|
||||
m_graphic->attributes()->setAttributesMap(rawAttributes);
|
||||
|
||||
if (m_logger.isDebugEnabled())
|
||||
qCritical() << " XXXXX set rawAttributes " << rawAttributes;
|
||||
}
|
||||
|
||||
if (m_graphic)
|
||||
{
|
||||
m_graphic->setZIndex(m_drawOrder.value());
|
||||
m_graphic->setVisible(m_visibility.value());
|
||||
m_graphic->setSelected(m_selected.value());
|
||||
}
|
||||
|
||||
if (!success)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " failure, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success = " << success
|
||||
<< " visibility=" << m_visibility;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectAttributes
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
// forward:
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
// forward:
|
||||
class MapImpl;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The GraphicalObjectAttributes class
|
||||
*/
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectAttributes : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief GraphicalObjectAttributes
|
||||
* @param mapImpl map to be used.
|
||||
* @param logicalLayerName logical layer name to be used.
|
||||
* @param debugInfo debugInfo to be used
|
||||
* @param uniqueMapId uniqueMapId to be used. (Optional to fulfill rubberband requirements)
|
||||
*/
|
||||
GraphicalObjectAttributes(MapImpl *mapImpl,
|
||||
Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer,
|
||||
const QString &debugInfo,
|
||||
const UniqueMapId &uniqueMapId = INVALID_MAP_ID);
|
||||
|
||||
GraphicalObjectAttributes(const GraphicalObjectAttributes &other) = delete;
|
||||
GraphicalObjectAttributes &operator=(GraphicalObjectAttributes &other) = delete;
|
||||
|
||||
virtual ~GraphicalObjectAttributes();
|
||||
|
||||
|
||||
QVariantMap attributes() const;
|
||||
void setAttributes(const QVariantMap &attributes);
|
||||
|
||||
Esri::ArcGISRuntime::Geometry getGraphicGeometry() const override;
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
virtual bool create() override;
|
||||
|
||||
bool changed() override;
|
||||
void resetChanged() override;
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
// logical
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
class Private;
|
||||
/**
|
||||
* The private d-pointer to not break BC when changing internals of this class
|
||||
*/
|
||||
Private *d = nullptr;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectCube
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_cube.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/PolygonBuilder.h>
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
GraphicalObjectCube::GraphicalObjectCube(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_logger(getLogger("GraphicalObjectCube"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectCube::~GraphicalObjectCube()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
bool GraphicalObjectCube::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool success = BaseClass::create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
}
|
||||
|
||||
// real work:
|
||||
// empty
|
||||
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
// << " drawOrder = " << m_graphic->drawOrder()
|
||||
<< " success = " << success;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectCube::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
// some checks:
|
||||
if (!this->isArea())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!create())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!BaseClass::updateViewImpl())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
// real work:
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
|
||||
// Attribute 'height':
|
||||
QVariantMap attMap = m_graphic->attributes()->attributesMap();
|
||||
|
||||
attMap[QStringLiteral("height")] = QVariant(m_height.value());
|
||||
//
|
||||
// Attribute 'PartyName' is replaced by Attribute 'Extrusion_Color' to be more flexible
|
||||
//
|
||||
|
||||
|
||||
// Attribute 'Extrusion_Color':
|
||||
if (m_extrusionColorName.value().isEmpty())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||||
<< " debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_extrusionColorName is empty";
|
||||
// -> time for the defaultSymbol of the Renderer
|
||||
attMap[QStringLiteral("Extrusion_Color")] = QStringLiteral("DOES_NOT_EXIST");
|
||||
}
|
||||
else
|
||||
attMap[QStringLiteral("Extrusion_Color")] = QVariant(m_extrusionColorName.value());
|
||||
|
||||
m_graphic->attributes()->setAttributesMap(attMap);
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " attributesMap[height] ='" << attMap[QStringLiteral("height")].toDouble() << "'";
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " attributesMap[Extrusion_Color] ='" << attMap[QStringLiteral("Extrusion_Color")].toString() << "'";
|
||||
|
||||
// geometry:
|
||||
Esri::ArcGISRuntime::PolygonBuilder builder(spatialReference());
|
||||
|
||||
const PositionCont &posCont = m_positions.value();
|
||||
for (const Point3D &pos : posCont)
|
||||
{
|
||||
builder.addPoint(pos.x(), pos.y());
|
||||
}
|
||||
|
||||
if (! builder.isSketchValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " builder -> sketch invalid";
|
||||
return false;
|
||||
}
|
||||
m_graphic->setGeometry(builder.toGeometry());
|
||||
|
||||
|
||||
// add
|
||||
bool successGraphic = addUpdateGraphic();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " drawOrder = " << m_graphic->zIndex();
|
||||
return successGraphic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<<(std::ostream &stream,
|
||||
const GraphicalObjectCube &value)
|
||||
{
|
||||
stream << value.toString();
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectCube
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
// forward:
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The GraphicalObjectCube class for 3D
|
||||
*
|
||||
*/
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectCube : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
explicit GraphicalObjectCube(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectCube();
|
||||
|
||||
double height() const
|
||||
{
|
||||
return m_height.value();
|
||||
}
|
||||
void setHeight(double height)
|
||||
{
|
||||
m_height = height;
|
||||
}
|
||||
|
||||
const QString &extrusionColorName() const
|
||||
{
|
||||
return m_extrusionColorName.value();
|
||||
}
|
||||
void setExtrusionColorName(const QString &extrusionColorName)
|
||||
{
|
||||
m_extrusionColorName = extrusionColorName;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_height.changed()
|
||||
|| m_extrusionColorName.changed();
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_height.reset();
|
||||
m_extrusionColorName.reset();
|
||||
}
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
|
||||
// Data
|
||||
SimpleValue<double> m_height;
|
||||
SimpleValue<QString> m_extrusionColorName;
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
SITUATIONMAP_EXPORT std::ostream &operator<< (std::ostream &stream,
|
||||
const GraphicalObjectCube &value);
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectEllipse
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_ellipse.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/Polygon.h>
|
||||
#include <arcgis/GeometryEngine.h>
|
||||
#include <arcgis/SimpleLineSymbol.h>
|
||||
#include <arcgis/SimpleFillSymbol.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QElapsedTimer>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
GraphicalObjectEllipse::GraphicalObjectEllipse(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_logger(getLogger("GraphicalObjectEllipse"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectEllipse::~GraphicalObjectEllipse()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
delete m_internalParameters;
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
bool GraphicalObjectEllipse::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool success = BaseClass::create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
// real work:
|
||||
// empty
|
||||
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
// << " drawOrder = " << m_graphic->drawOrder()
|
||||
<< " success = " << success;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectEllipse::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
// some checks:
|
||||
if (!this->isSinglePoint())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!create())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!BaseClass::updateViewImpl())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_ellipseParameters.value().isValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " ellipseParameters not valid";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// real work:
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " update geometry";
|
||||
|
||||
bool successEllipse = true;
|
||||
if (m_ellipseParameters.changed() || m_positions.changed())
|
||||
{
|
||||
// apply attributes:
|
||||
parameterToInternal();
|
||||
|
||||
Esri::ArcGISRuntime::Polygon ellipse;
|
||||
successEllipse = createEllipse(ellipse);
|
||||
if (successEllipse)
|
||||
m_graphic->setGeometry(ellipse);
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " createEllipse failed";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
assignFillStyleToGraphic();
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool successGraphic = addUpdateGraphic();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " drawOrder = " << m_graphic->zIndex()
|
||||
<< " successEllipse = " << successEllipse
|
||||
<< " successGraphic = " << successGraphic;
|
||||
return successEllipse && successGraphic;
|
||||
}
|
||||
|
||||
void GraphicalObjectEllipse::parameterToInternal()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
if (!m_internalParameters)
|
||||
{
|
||||
m_internalParameters = new Esri::ArcGISRuntime::GeodesicEllipseParameters();
|
||||
m_internalParameters->setGeometryType(Esri::ArcGISRuntime::GeometryType::Polygon);
|
||||
}
|
||||
|
||||
// TODO !!??: set xy correct, calc maxSegLength...
|
||||
|
||||
|
||||
const EllipseParameters &ellipseParameterRef = m_ellipseParameters.value();
|
||||
|
||||
// 1a, 1b
|
||||
m_internalParameters->setMaxSegmentLength(ellipseParameterRef.maxSegmentLength());
|
||||
m_internalParameters->setMaxPointCount(ellipseParameterRef.maxPointCount());
|
||||
|
||||
// 2
|
||||
const Point3D &origin = this->origin();
|
||||
Esri::ArcGISRuntime::Point mapPoint(origin.x(), origin.y(), origin.z(), spatialReference()); // center of ellipse
|
||||
|
||||
Esri::ArcGISRuntime::Point normalizedPt =
|
||||
Esri::ArcGISRuntime::GeometryEngine::normalizeCentralMeridian(mapPoint);
|
||||
m_internalParameters->setCenter(normalizedPt);
|
||||
// m_internalParameters->setCenter(mapPoint);
|
||||
|
||||
// 3, 4
|
||||
m_internalParameters->setSemiAxis1Length(ellipseParameterRef.lengthX());
|
||||
m_internalParameters->setSemiAxis2Length(ellipseParameterRef.lengthY());
|
||||
|
||||
// 5
|
||||
m_internalParameters->setAxisDirection(ellipseParameterRef.directionDegree());
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
bool GraphicalObjectEllipse::createEllipse(Esri::ArcGISRuntime::Polygon &ellipse)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool success = createEllipsePolygon(*m_internalParameters, ellipse);
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success = " << success
|
||||
// << " pointCount = " << ellipse.pointCount()
|
||||
<< " dimension = " << ellipse.dimension();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GraphicalObjectEllipse::createEllipsePolygon(const Esri::ArcGISRuntime::GeodesicEllipseParameters &ellipseParameters,
|
||||
Esri::ArcGISRuntime::Polygon &polygon)
|
||||
{
|
||||
LOGGER_T m_logger = getLogger("GraphicalObjectEllipse");
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
QElapsedTimer timer;
|
||||
|
||||
if (m_logger.isInfoEnabled())
|
||||
timer.start();
|
||||
|
||||
|
||||
bool success = false;
|
||||
|
||||
Esri::ArcGISRuntime::Geometry ellipseGeometry =
|
||||
Esri::ArcGISRuntime::GeometryEngine::ellipseGeodesic(ellipseParameters);
|
||||
if (ellipseGeometry.isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " There was an error computing the geodesic ellipse. Try a different segment length.";
|
||||
}
|
||||
else
|
||||
{
|
||||
polygon = Esri::ArcGISRuntime::Polygon(ellipseGeometry);
|
||||
success = true;
|
||||
}
|
||||
int count = AbstractGraphicalObject::countOfPolygonFirstPart(polygon);
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||||
<< " count=" << count
|
||||
<< " (semiAxis1Length=" << ellipseParameters.semiAxis1Length()
|
||||
<< " , semiAxis2Length=" << ellipseParameters.semiAxis2Length()
|
||||
<< " , maxPointCount=" << ellipseParameters.maxPointCount()
|
||||
<< " , maxSegmentLength=" << ellipseParameters.maxSegmentLength()
|
||||
<< " , dimension = " << polygon.dimension()
|
||||
<< ")";
|
||||
|
||||
|
||||
|
||||
if (m_logger.isDebugEnabled())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||||
<< " took " << timer.elapsed() << "ms"
|
||||
<< " (semiAxis1Length=" << ellipseParameters.semiAxis1Length()
|
||||
<< " , semiAxis2Length=" << ellipseParameters.semiAxis2Length()
|
||||
<< " , maxPointCount=" << ellipseParameters.maxPointCount()
|
||||
<< " , maxSegmentLength=" << ellipseParameters.maxSegmentLength()
|
||||
<< " , dimension = " << polygon.dimension()
|
||||
<< ")";
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||||
<< " success = " << success;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GraphicalObjectEllipse::createCirclePolygon(const Esri::ArcGISRuntime::Point &originMap,
|
||||
float radius,
|
||||
unsigned int maxPointCount,
|
||||
Esri::ArcGISRuntime::Polygon &polygon)
|
||||
{
|
||||
LOGGER_T m_logger = getLogger("GraphicalObjectEllipse");
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||||
<< " origin=" << originMap.x() << " ; " << originMap.y() << " ; " << originMap.z()
|
||||
<< " radius=" << radius;
|
||||
|
||||
Esri::ArcGISRuntime::GeodesicEllipseParameters ePara;
|
||||
ePara.setGeometryType(Esri::ArcGISRuntime::GeometryType::Polygon);
|
||||
|
||||
// 1
|
||||
ePara.setMaxSegmentLength(10);
|
||||
if (maxPointCount == 0)
|
||||
ePara.setMaxPointCount(EllipseParameters::MAX_POINT_COUNT_DEFAULT);
|
||||
else
|
||||
ePara.setMaxPointCount(maxPointCount);
|
||||
|
||||
// 2
|
||||
const Esri::ArcGISRuntime::Point &mapPoint = originMap; // center of ellipse
|
||||
|
||||
Esri::ArcGISRuntime::Point normalizedPt =
|
||||
Esri::ArcGISRuntime::GeometryEngine::normalizeCentralMeridian(mapPoint);
|
||||
ePara.setCenter(normalizedPt);
|
||||
|
||||
// 3, 4
|
||||
ePara.setSemiAxis1Length(radius);
|
||||
ePara.setSemiAxis2Length(radius);
|
||||
|
||||
// 5
|
||||
ePara.setAxisDirection(0);
|
||||
|
||||
return createEllipsePolygon(ePara, polygon);
|
||||
}
|
||||
|
||||
bool GraphicalObjectEllipse::createCirclePolygon(const Esri::ArcGISRuntime::Point &originMap,
|
||||
float radius,
|
||||
unsigned int maxPointCount,
|
||||
PositionCont &posCont)
|
||||
{
|
||||
Esri::ArcGISRuntime::Polygon circle;
|
||||
bool success = GraphicalObjectEllipse::createCirclePolygon(originMap,
|
||||
radius,
|
||||
maxPointCount,
|
||||
circle);
|
||||
|
||||
if (success && !circle.isEmpty())
|
||||
{
|
||||
posCont.clear();
|
||||
|
||||
const Esri::ArcGISRuntime::ImmutablePart &immutablePart = circle.parts().part(0);
|
||||
const int size = immutablePart.pointCount();
|
||||
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
const Esri::ArcGISRuntime::Point &p = immutablePart.point(i);
|
||||
posCont.append(Point3D(p.x(), p.y(), p.z()));
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
EllipseParameters GraphicalObjectEllipse::ellipseParameters() const
|
||||
{
|
||||
return m_ellipseParameters.value();
|
||||
}
|
||||
|
||||
EllipseParameters &GraphicalObjectEllipse::rEllipseParameters()
|
||||
{
|
||||
return m_ellipseParameters.refValue();
|
||||
}
|
||||
|
||||
void GraphicalObjectEllipse::setEllipseParameters(const EllipseParameters &ellipseParameters)
|
||||
{
|
||||
m_ellipseParameters = ellipseParameters;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<<(std::ostream &stream,
|
||||
const GraphicalObjectEllipse &value)
|
||||
{
|
||||
stream << value.toString();
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectEllipse
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
#include "ellipse_parameters.h"
|
||||
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
// forward:
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class Polygon;
|
||||
class Point;
|
||||
class GeodesicEllipseParameters;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectEllipse : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
GraphicalObjectEllipse(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectEllipse();
|
||||
|
||||
EllipseParameters ellipseParameters() const;
|
||||
EllipseParameters &rEllipseParameters();
|
||||
void setEllipseParameters(const EllipseParameters &ellipseParameters);
|
||||
|
||||
|
||||
static bool createEllipsePolygon(const Esri::ArcGISRuntime::GeodesicEllipseParameters &ellipseParameters,
|
||||
Esri::ArcGISRuntime::Polygon &polygon);
|
||||
|
||||
static bool createCirclePolygon(const Esri::ArcGISRuntime::Point &originMap,
|
||||
float radius,
|
||||
unsigned int maxPointCount,
|
||||
Esri::ArcGISRuntime::Polygon &polygon);
|
||||
|
||||
static bool createCirclePolygon(const Esri::ArcGISRuntime::Point &originMap,
|
||||
float radius,
|
||||
unsigned int maxPointCount,
|
||||
PositionCont &posCont);
|
||||
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_ellipseParameters.changed();
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_ellipseParameters.reset();
|
||||
}
|
||||
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
|
||||
// Data
|
||||
Esri::ArcGISRuntime::GeodesicEllipseParameters *m_internalParameters = nullptr;
|
||||
SimpleValue<EllipseParameters> m_ellipseParameters;
|
||||
|
||||
void parameterToInternal();
|
||||
virtual bool createEllipse(Esri::ArcGISRuntime::Polygon &ellipse);
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
// Forbid some overloaded methods without effects of this object;
|
||||
virtual PositionCont positions() const override
|
||||
{
|
||||
return PositionCont();
|
||||
}
|
||||
virtual void setPositions(const PositionCont &posCont) override
|
||||
{
|
||||
Q_UNUSED(posCont);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<< (std::ostream &stream,
|
||||
const GraphicalObjectEllipse &value);
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectModelSceneMarker
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_model_scene_marker.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
#include <MathUtils/simple_helper.h>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/ModelSceneSymbol.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QPainter>
|
||||
#include <QFile>
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
GraphicalObjectModelSceneMarker::GraphicalObjectModelSceneMarker(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_logger(getLogger("GraphicalObjectModelSceneMarker"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectModelSceneMarker::~GraphicalObjectModelSceneMarker()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
delete m_modelSceneSymbol;
|
||||
m_modelSceneSymbol = nullptr;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectModelSceneMarker::setUrl(const QUrl &url)
|
||||
{
|
||||
m_url = url;
|
||||
}
|
||||
|
||||
QUrl GraphicalObjectModelSceneMarker::url() const
|
||||
{
|
||||
return m_url.value();
|
||||
}
|
||||
|
||||
void GraphicalObjectModelSceneMarker::setHeading(float heading)
|
||||
{
|
||||
m_heading = heading;
|
||||
}
|
||||
|
||||
float GraphicalObjectModelSceneMarker::heading() const
|
||||
{
|
||||
return m_heading.value();
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectModelSceneMarker::create()
|
||||
{
|
||||
return BaseClass::create();
|
||||
}
|
||||
|
||||
bool GraphicalObjectModelSceneMarker::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " origin =" << this->origin() // .x() << " , " << this->origin().y()
|
||||
<< " visibility=" << m_visibility
|
||||
<< " pickable=" << m_pickable
|
||||
<< " pickable.changed=" << m_pickable.changed()
|
||||
<< " selected=" << m_selected
|
||||
<< " m_url = " << m_url.value().toString()
|
||||
<< " m_drawOrder = " << m_drawOrder
|
||||
<< " m_scale = " << m_scale.value()
|
||||
<< " m_heading = " << m_heading.value();
|
||||
|
||||
// some checks:
|
||||
if (!isSinglePoint())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " debugInfo='" << m_debugInfo << "'"
|
||||
<< " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile fi(m_url.value().path());
|
||||
if (!fi.exists())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_url does not exists: '" << fi.fileName() << "'";
|
||||
m_url.reset();
|
||||
}
|
||||
|
||||
if (m_url.value().isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " debugInfo='" << m_debugInfo << "'"
|
||||
<< " no url provided (or does not exist)";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
const Point3D &origin = this->origin();
|
||||
Esri::ArcGISRuntime::Point originGeometry(origin.x(),
|
||||
origin.y(),
|
||||
origin.z(),
|
||||
spatialReference());
|
||||
m_graphic->setGeometry(originGeometry);
|
||||
|
||||
// url changed?
|
||||
if ( (m_modelSceneSymbol && (m_modelSceneSymbol->url() != m_url.value())) ||
|
||||
m_scale.changed())
|
||||
{
|
||||
// force re-create ModelSceneSymbol:
|
||||
delete m_modelSceneSymbol;
|
||||
m_modelSceneSymbol = nullptr;
|
||||
}
|
||||
|
||||
if (!m_modelSceneSymbol)
|
||||
{
|
||||
m_modelSceneSymbol = new Esri::ArcGISRuntime::ModelSceneSymbol(m_url.value(), m_scale.value()); // url, scale
|
||||
}
|
||||
|
||||
m_modelSceneSymbol->setHeading(m_heading.value()); // degree, clockwise, 0 is north/12
|
||||
// m_modelSceneSymbol->setAnchorPosition(Esri::ArcGISRuntime::SceneSymbolAnchorPosition::Bottom);
|
||||
m_graphic->setSymbol(m_modelSceneSymbol);
|
||||
|
||||
|
||||
|
||||
success = BaseClass::updateViewImpl();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
success = addUpdateGraphic();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success=" << success
|
||||
<< " m_drawOrder = " << m_drawOrder
|
||||
<< " m_graphic->drawOrder = " << m_graphic->zIndex();
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace SituationMap
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectModelSceneMarker
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
#include <Map/text_style.h>
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
|
||||
// Esri
|
||||
#include <arcgis/SymbolTypes.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QImage>
|
||||
#include <QUrl>
|
||||
|
||||
|
||||
// forward:
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class Graphic;
|
||||
class GraphicsOverlay;
|
||||
class ModelSceneSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectModelSceneMarker : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
GraphicalObjectModelSceneMarker(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectModelSceneMarker();
|
||||
|
||||
// Data access:
|
||||
// to be cont.
|
||||
void setUrl(const QUrl &url);
|
||||
QUrl url() const;
|
||||
|
||||
// degree ; 0 is north/12
|
||||
void setHeading(float heading);
|
||||
float heading() const;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_url.changed()
|
||||
|| m_heading.changed()
|
||||
;
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_url.reset();
|
||||
m_heading.reset();
|
||||
}
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
// used ModelSceneSymbol:
|
||||
Esri::ArcGISRuntime::ModelSceneSymbol *m_modelSceneSymbol{nullptr};
|
||||
|
||||
SimpleValue<QUrl> m_url; // e.g. /shd/CTC/TOOLS/ArcGIS/Runtime/Data/3D/Bristol/Collada/Bristol.dae
|
||||
SimpleValue<float> m_heading{0.0}; // degree, clockwise, 0 is north/12
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
// Forbid some overloaded methods without effects of this object;
|
||||
PositionCont positions() const override
|
||||
{
|
||||
return PositionCont();
|
||||
}
|
||||
void setPositions(const PositionCont &posCont) override
|
||||
{
|
||||
Q_UNUSED(posCont);
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,323 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectPath
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_multi_path.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/PolygonBuilder.h>
|
||||
#include <arcgis/PolylineBuilder.h>
|
||||
#include <arcgis/SimpleLineSymbol.h>
|
||||
#include <arcgis/SimpleFillSymbol.h>
|
||||
#include <arcgis/GeoView.h>
|
||||
#include <arcgis/GeometryEngine.h>
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
GraphicalObjectMultiPath::GraphicalObjectMultiPath(const GraphicalObjectPathType type
|
||||
, const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, UniqueMapId uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_pathType(type)
|
||||
, m_logger(getLogger("GraphicalObjectMultiPath"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
}
|
||||
|
||||
GraphicalObjectMultiPath::~GraphicalObjectMultiPath()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
}
|
||||
|
||||
PositionCont GraphicalObjectMultiPath::path(int pathIndex) const
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " pathIndex=" << pathIndex;
|
||||
if (hasPosCont(pathIndex))
|
||||
return getPosCont(pathIndex).value();
|
||||
return {};
|
||||
}
|
||||
void GraphicalObjectMultiPath::setPath(int pathIndex, const PositionCont &positions)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " pathIndex=" << pathIndex
|
||||
<< " positions=" << positions;
|
||||
m_positionsCont[pathIndex] = positions;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectMultiPath::clearPath(int pathIndex)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " pathIndex=" << pathIndex;
|
||||
if (pathIndex == -1)
|
||||
{
|
||||
m_positions.refValue().clear();
|
||||
m_positionsCont.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasPosCont(pathIndex))
|
||||
{
|
||||
// Do not remove the whole entry to let changed() work
|
||||
m_positionsCont[pathIndex].refValue().clear();
|
||||
}
|
||||
}
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectMultiPath::clearAllPaths()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
m_positions.refValue().clear();
|
||||
m_positionsCont.clear();
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectMultiPath::reduceTo(const QList<int> &remainingPathIndexes)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " remainingPathIndexes=" << remainingPathIndexes;
|
||||
QList<int> keys = m_positionsCont.keys();
|
||||
for (int key : qAsConst(keys))
|
||||
{
|
||||
if (!remainingPathIndexes.contains(key))
|
||||
{
|
||||
// Do not remove the whole entry to let chanded() work
|
||||
m_positionsCont[key].refValue().clear();
|
||||
}
|
||||
}
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
QList<int> GraphicalObjectMultiPath::pathIndexInUse()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
QList<int> ret;
|
||||
///// ret << 0; // pathIndex=0 -> m_positions
|
||||
|
||||
QMapIterator<int, SimpleValue<PositionCont> > mapIt(m_positionsCont);
|
||||
while (mapIt.hasNext())
|
||||
{
|
||||
mapIt.next();
|
||||
const SimpleValue<PositionCont> &posData = mapIt.value();
|
||||
const PositionCont &posCont = posData.value();
|
||||
if (! posCont.isEmpty())
|
||||
ret += mapIt.key();
|
||||
} // while
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectMultiPath::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool success = BaseClass::create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectMultiPath::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool success = create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
success = BaseClass::updateViewImpl();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
success = updatePositions();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success = " << success
|
||||
<< " drawOrder = " << m_graphic->zIndex();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GraphicalObjectMultiPath::updatePositions()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool success = true;
|
||||
|
||||
int pathIdxToInsert = 0;
|
||||
const int minPoints = this->pathType() == GraphicalObjectPathType::Polyline ? 2 : 3;
|
||||
|
||||
QSharedPointer<Esri::ArcGISRuntime::MultipartBuilder> builder;
|
||||
|
||||
// some preparations: ( do no check isMultiPoint / isArea: m_positions should typically be empty!!!
|
||||
switch (m_pathType)
|
||||
{
|
||||
case GraphicalObjectPathType::Polyline:
|
||||
builder = QSharedPointer<Esri::ArcGISRuntime::PolylineBuilder>(new Esri::ArcGISRuntime::PolylineBuilder(spatialReference()));
|
||||
|
||||
break;
|
||||
case GraphicalObjectPathType::Polygon:
|
||||
builder = QSharedPointer<Esri::ArcGISRuntime::PolygonBuilder>(new Esri::ArcGISRuntime::PolygonBuilder(spatialReference()));
|
||||
break;
|
||||
} // switch
|
||||
|
||||
QSharedPointer<Esri::ArcGISRuntime::PartCollection> partCollection =
|
||||
QSharedPointer<Esri::ArcGISRuntime::PartCollection>(new Esri::ArcGISRuntime::PartCollection(builder->spatialReference()));
|
||||
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< ", m_positionsCont.size() /#rings=" << m_positionsCont.size();
|
||||
|
||||
QMutableMapIterator<int, SimpleValue<PositionCont> > mapIt(m_positionsCont);
|
||||
//
|
||||
// LOOP PER SINGLE POLY
|
||||
//
|
||||
while (mapIt.hasNext())
|
||||
{
|
||||
mapIt.next();
|
||||
const int key = mapIt.key();
|
||||
|
||||
const SimpleValue<PositionCont> &posData = mapIt.value();
|
||||
const PositionCont &posCont = posData.value();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< ", key / #ring=" << key
|
||||
<< ", rings.size()=" << posCont.size();
|
||||
|
||||
// maybe some pathIdx are cleared by clearPath() or similar:
|
||||
if (posCont.isEmpty())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||||
<< " posCont empty, cleared? -> remove/cleanup"
|
||||
<< " pathIdxToInsert = " << pathIdxToInsert
|
||||
<< " mapIt.key() = " << key;
|
||||
mapIt.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (posCont.count() < minPoints)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " incorrect number of positions"
|
||||
<< " (" << posCont.count() << ")"
|
||||
<< ", minPoints=" << minPoints
|
||||
<< ", pathIdxToInsert = " << pathIdxToInsert
|
||||
<< ", mapIt.key() = " << key
|
||||
<< ", m_debugInfo = " << m_debugInfo;
|
||||
|
||||
success = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Esri::ArcGISRuntime::Part part(builder->spatialReference());
|
||||
|
||||
//
|
||||
// LOOP PER POINT
|
||||
//
|
||||
for (auto pos : qAsConst(posCont))
|
||||
{
|
||||
part.addPoint(pos.x(), pos.y(), pos.z());
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< ", key / #ring=" << key
|
||||
<< ", addPoint=" << pos;
|
||||
|
||||
}
|
||||
|
||||
partCollection->addPart(&part);
|
||||
} // if (posCont.count() < minPoints)
|
||||
|
||||
} // while
|
||||
|
||||
builder->setParts(partCollection.get());
|
||||
|
||||
//
|
||||
// builder to geometry;
|
||||
//
|
||||
switch (m_pathType)
|
||||
{
|
||||
case GraphicalObjectPathType::Polyline:
|
||||
{
|
||||
const Esri::ArcGISRuntime::Polyline &multipartPolyline =
|
||||
static_cast<Esri::ArcGISRuntime::PolylineBuilder *>(builder.data())->toPolyline();
|
||||
m_graphic->setGeometry(multipartPolyline);
|
||||
assignLineStyleToGraphic();
|
||||
}
|
||||
break;
|
||||
case GraphicalObjectPathType::Polygon:
|
||||
{
|
||||
const Esri::ArcGISRuntime::Polygon &multipartPolygon =
|
||||
static_cast<Esri::ArcGISRuntime::PolygonBuilder *>(builder.data())->toPolygon();
|
||||
m_graphic->setGeometry(multipartPolygon);
|
||||
//assignLineStyleToGraphic();
|
||||
assignFillStyleToGraphic();
|
||||
}
|
||||
break;
|
||||
} // switch
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'";
|
||||
success = addUpdateGraphic();
|
||||
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success = " << success
|
||||
<< " drawOrder = " << m_graphic->zIndex();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GraphicalObjectMultiPath::hasPosCont(int idx) const
|
||||
{
|
||||
return m_positionsCont.contains(idx);
|
||||
}
|
||||
|
||||
SimpleValue<PositionCont> &GraphicalObjectMultiPath::getPosCont(int idx)
|
||||
{
|
||||
return m_positionsCont[idx];
|
||||
}
|
||||
|
||||
const SimpleValue<PositionCont> GraphicalObjectMultiPath::getPosCont(int idx) const
|
||||
{
|
||||
return m_positionsCont[idx];
|
||||
}
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectPath
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "graphical_object_path.h"
|
||||
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QMap>
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectMultiPath : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
|
||||
GraphicalObjectMultiPath(const GraphicalObjectPathType type
|
||||
, const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, UniqueMapId uniqueMapId);
|
||||
|
||||
~GraphicalObjectMultiPath();
|
||||
|
||||
GraphicalObjectPathType pathType() const
|
||||
{
|
||||
return m_pathType;
|
||||
}
|
||||
|
||||
virtual PositionCont path(int pathIndex) const;
|
||||
virtual void setPath(int pathIndex, const PositionCont &positions);
|
||||
|
||||
/*! \name Subsidiary polyline/polygons */
|
||||
//@{
|
||||
virtual void clearPath(int pathIndex);
|
||||
virtual void clearAllPaths();
|
||||
virtual QList<int> pathIndexInUse();
|
||||
virtual void reduceTo(const QList<int> &remainingPathIndexes);
|
||||
//@}
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
bool updatePositions();
|
||||
bool changed() override
|
||||
{
|
||||
bool baseClassChanged = BaseClass::changed();
|
||||
if (baseClassChanged)
|
||||
return true;
|
||||
|
||||
for (const SimpleValue<PositionCont> &posData : qAsConst(m_positionsCont))
|
||||
{
|
||||
if (posData.changed())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
|
||||
for (SimpleValue<PositionCont> &posData : m_positionsCont)
|
||||
posData.reset();
|
||||
}
|
||||
|
||||
bool create() override;
|
||||
bool updateViewImpl() override;
|
||||
|
||||
// logical
|
||||
const GraphicalObjectPathType m_pathType;
|
||||
//bool updatePositions();
|
||||
|
||||
private:
|
||||
// Attention: will contain 'positions' of idx == 1 and higher :
|
||||
bool hasPosCont(int idx) const;
|
||||
SimpleValue<PositionCont> &getPosCont(int idx);
|
||||
const SimpleValue<PositionCont> getPosCont(int idx) const;
|
||||
|
||||
QMap<int, SimpleValue<PositionCont> > m_positionsCont;
|
||||
// : Attention: will contain 'positions' of idx == 1 and higher
|
||||
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectPath
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_path.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/PolygonBuilder.h>
|
||||
#include <arcgis/PolylineBuilder.h>
|
||||
#include <arcgis/SimpleLineSymbol.h>
|
||||
#include <arcgis/SimpleFillSymbol.h>
|
||||
#include <arcgis/GeoView.h>
|
||||
#include <arcgis/GeometryEngine.h>
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
QLatin1String toString(const GraphicalObjectPathType subType)
|
||||
{
|
||||
switch (subType)
|
||||
{
|
||||
case GraphicalObjectPathType::Polyline:
|
||||
return QLatin1String("Polyline");
|
||||
break;
|
||||
case GraphicalObjectPathType::Polygon:
|
||||
return QLatin1String("Polygon");
|
||||
break;
|
||||
} // switch
|
||||
return QLatin1String("GraphicalObjectPathTypeERROR");
|
||||
}
|
||||
|
||||
|
||||
GraphicalObjectPath::GraphicalObjectPath(const GraphicalObjectPathType type
|
||||
, const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_pathType(type)
|
||||
, m_logger(getLogger("GraphicalObjectPath"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
}
|
||||
|
||||
GraphicalObjectPath::~GraphicalObjectPath()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
}
|
||||
|
||||
bool GraphicalObjectPath::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool success = BaseClass::create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success = " << success
|
||||
// << " drawOrder = " << m_graphic->drawOrder()
|
||||
;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectPath::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_positions= " << m_positions.value()
|
||||
<< ", m_maxSegmentLength=" << m_maxSegmentLength;
|
||||
|
||||
QSharedPointer<Esri::ArcGISRuntime::MultipartBuilder> builder;
|
||||
|
||||
// some checks:
|
||||
switch (m_pathType)
|
||||
{
|
||||
case GraphicalObjectPathType::Polyline:
|
||||
if (!this->isMultiPoint())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
builder = QSharedPointer<Esri::ArcGISRuntime::PolylineBuilder>(new Esri::ArcGISRuntime::PolylineBuilder(spatialReference()));
|
||||
|
||||
break;
|
||||
case GraphicalObjectPathType::Polygon:
|
||||
if (!this->isArea())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
builder = QSharedPointer<Esri::ArcGISRuntime::PolygonBuilder>(new Esri::ArcGISRuntime::PolygonBuilder(spatialReference()));
|
||||
break;
|
||||
} // switch
|
||||
|
||||
|
||||
if (! builder)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " no builder";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
success = BaseClass::updateViewImpl();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// real work:
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " update geometry";
|
||||
|
||||
|
||||
const PositionCont &posCont = m_positions.value();
|
||||
for (const Point3D &pos : posCont)
|
||||
builder->addPoint(pos.x(), pos.y(), pos.z());
|
||||
|
||||
if (! builder->isSketchValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " builder -> sketch invalid";
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// apply attributes:
|
||||
//
|
||||
|
||||
// N. Thoden, 13.02.2018
|
||||
// Case #02062713 [BOS] BasicSceneView_lineNotComplete
|
||||
// If a line has a line of ~10km (Borderline)
|
||||
// the line may 'move' on the ground (3D, RenderMode::Dynamic, SurfarcePlacement::Draped)
|
||||
// To avoid these kind of effect, the advice is to densify the geometry
|
||||
// [similar: Case #02054233 [BOS] LineArtefacts in 3D ->
|
||||
// BUG-000111565 : Lines created on the GraphicsOverlay with "Dynamic" Rendering mode on 3D doesn't render completely when zooming in]
|
||||
|
||||
//
|
||||
// N. Thoden, 29.03.2018
|
||||
// Consulting with Luke Smallwood / using the V100.2.1. debug libs:
|
||||
// densify leads to an assert, so avoid densify
|
||||
// (until now densify does not lead to an improvement..)
|
||||
|
||||
//
|
||||
// N. Thoden, 19.04.2021
|
||||
// [GUEZE-495]: 3D Lagedarstellung Trefferlinien
|
||||
// Linie fehlt teilweise
|
||||
// jetzt (typeweise) per m_maxSegmentLength aktivierbar
|
||||
|
||||
switch (m_pathType)
|
||||
{
|
||||
case GraphicalObjectPathType::Polyline:
|
||||
{
|
||||
const Esri::ArcGISRuntime::Polyline &polyline =
|
||||
static_cast<Esri::ArcGISRuntime::PolylineBuilder *>(builder.data())->toPolyline();
|
||||
if (m_maxSegmentLength > 0)
|
||||
{
|
||||
m_graphic->setGeometry(Esri::ArcGISRuntime::GeometryEngine::densifyGeodetic(polyline,
|
||||
m_maxSegmentLength,
|
||||
Esri::ArcGISRuntime::LinearUnit::meters(),
|
||||
Esri::ArcGISRuntime::GeodeticCurveType::Geodesic));
|
||||
} else {
|
||||
m_graphic->setGeometry(polyline);
|
||||
} // if (densify)
|
||||
assignLineStyleToGraphic();
|
||||
}
|
||||
break;
|
||||
case GraphicalObjectPathType::Polygon:
|
||||
{
|
||||
const Esri::ArcGISRuntime::Polygon &polygon =
|
||||
static_cast<Esri::ArcGISRuntime::PolygonBuilder *>(builder.data())->toPolygon();
|
||||
|
||||
if (m_maxSegmentLength > 0)
|
||||
{
|
||||
m_graphic->setGeometry(Esri::ArcGISRuntime::GeometryEngine::densifyGeodetic(polygon,
|
||||
m_maxSegmentLength,
|
||||
Esri::ArcGISRuntime::LinearUnit::meters(),
|
||||
Esri::ArcGISRuntime::GeodeticCurveType::Geodesic));
|
||||
} else {
|
||||
m_graphic->setGeometry(polygon);
|
||||
}
|
||||
assignFillStyleToGraphic();
|
||||
}
|
||||
break;
|
||||
} // switch
|
||||
|
||||
const int count = AbstractGraphicalObject::countOfPolygonFirstPart(m_graphic->geometry());
|
||||
if (count > 1000)
|
||||
WARNING_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< ", huge amount of vertices, countOfPolygonFirstPart = " << count;
|
||||
else
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< ", amount of vertices, countOfPolygonFirstPart = " << count;
|
||||
|
||||
success = addUpdateGraphic();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success = " << success
|
||||
<< " drawOrder = " << m_graphic->zIndex();
|
||||
return success;
|
||||
}
|
||||
|
||||
double GraphicalObjectPath::maxSegmentLength() const
|
||||
{
|
||||
return m_maxSegmentLength;
|
||||
}
|
||||
|
||||
void GraphicalObjectPath::setMaxSegmentLength(double maxSegmentLength)
|
||||
{
|
||||
m_maxSegmentLength = maxSegmentLength;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<<(std::ostream &stream,
|
||||
const GraphicalObjectPathType &value)
|
||||
{
|
||||
stream << toString(value).latin1();
|
||||
return stream;
|
||||
}
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectPath
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
// forward:
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
enum class GraphicalObjectPathType {Polyline, Polygon};
|
||||
QLatin1String toString(const GraphicalObjectPathType subType);
|
||||
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectPath : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
|
||||
explicit GraphicalObjectPath(const GraphicalObjectPathType type
|
||||
, const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectPath();
|
||||
|
||||
GraphicalObjectPathType pathType() const
|
||||
{
|
||||
return m_pathType;
|
||||
}
|
||||
|
||||
|
||||
double maxSegmentLength() const;
|
||||
void setMaxSegmentLength(double maxSegmentLength);
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
bool updateViewImpl() override;
|
||||
|
||||
// logical
|
||||
const GraphicalObjectPathType m_pathType;
|
||||
double m_maxSegmentLength{-1};
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
SITUATIONMAP_EXPORT std::ostream &operator<< (std::ostream &stream,
|
||||
const GraphicalObjectPathType &value);
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
+573
@@ -0,0 +1,573 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectPictureMarker
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_picture_marker.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
#include <SymbologyImpl/symbol_extension_renderer.h>
|
||||
#include <MathUtils/simple_helper.h>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/PictureMarkerSymbol.h>
|
||||
#include <arcgis/SimpleMarkerSymbol.h>
|
||||
#include <arcgis/MultipointBuilder.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QPainter>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
/**
|
||||
* @brief getSimpleMarkerSymbolStyle
|
||||
* @param markerSymbolType type to get
|
||||
* @param filePath filePath of requested marker; if empty -> use return value, if !empty -> use filePath and get file out of qrc
|
||||
* @param hotSpotPercent -0.5 to 0.5; e.g. x=center, y=bottom -> -0.5
|
||||
* @return corrosponding Esri::ArcGISRuntime::SimpleMarkerSymbolStyle, see filePath
|
||||
*/
|
||||
Esri::ArcGISRuntime::SimpleMarkerSymbolStyle getSimpleMarkerSymbolStyle(MarkerSymbolType markerSymbolType,
|
||||
QString &filePath,
|
||||
QPointF *hotSpotPercent = nullptr)
|
||||
{
|
||||
if (hotSpotPercent)
|
||||
*hotSpotPercent = QPointF();
|
||||
|
||||
filePath.clear();
|
||||
|
||||
Esri::ArcGISRuntime::SimpleMarkerSymbolStyle esriSMSS =
|
||||
Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Circle;
|
||||
|
||||
switch (markerSymbolType)
|
||||
{
|
||||
case SituationMap::MarkerSymbolType::Undefined:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Circle;
|
||||
break;
|
||||
|
||||
case SituationMap::MarkerSymbolType::Circle:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Circle;
|
||||
break;
|
||||
case SituationMap::MarkerSymbolType::Cross:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Cross;
|
||||
break;
|
||||
case SituationMap::MarkerSymbolType::Diamond:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Diamond;
|
||||
break;
|
||||
case SituationMap::MarkerSymbolType::Square:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Square;
|
||||
break;
|
||||
case SituationMap::MarkerSymbolType::X:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::X;
|
||||
break;
|
||||
case SituationMap::MarkerSymbolType::Triangle:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Triangle;
|
||||
break;
|
||||
|
||||
case SituationMap::MarkerSymbolType::PushPin2D:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Circle;
|
||||
filePath = QLatin1String(":/situationMap/pushPinRedClipArt.png");
|
||||
if (hotSpotPercent)
|
||||
*hotSpotPercent = QPointF(0, -0.5);
|
||||
|
||||
break;
|
||||
} //switch
|
||||
|
||||
return esriSMSS;
|
||||
}
|
||||
|
||||
GraphicalObjectPictureMarker::GraphicalObjectPictureMarker(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_logger(getLogger("GraphicalObjectPictureMarker"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectPictureMarker::~GraphicalObjectPictureMarker()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
resetPictureMarkerSymbol();
|
||||
resetImage();
|
||||
resetSimpleMarkerSymbol();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectPictureMarker::setImage(const QImage &image, const QSize &defaultSize)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " visibility=" << m_visibility
|
||||
<< " image.size()=" << image.size()
|
||||
<< " defaultSize=" << defaultSize
|
||||
<< " m_imageDefaultSize=" << m_imageDefaultSize
|
||||
<< " m_imageChanged=" << m_imageChanged
|
||||
<< " m_imageDefaultSize.changed()=" << m_imageDefaultSize.changed();
|
||||
resetSimpleMarkerSymbol();
|
||||
|
||||
if (m_image != image)
|
||||
{
|
||||
m_image = image;
|
||||
m_imageChanged = true;
|
||||
}
|
||||
|
||||
// store defautlSize (member shouldn´t be modified)
|
||||
m_imageDefaultSize = defaultSize;
|
||||
if (m_imageDefaultSize.changed())
|
||||
m_imageChanged = true;
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " visibility=" << m_visibility
|
||||
<< " image.size()=" << image.size()
|
||||
<< " defaultSize=" << defaultSize
|
||||
<< " m_imageDefaultSize=" << m_imageDefaultSize
|
||||
<< " m_imageChanged=" << m_imageChanged
|
||||
<< " m_imageDefaultSize.changed()=" << m_imageDefaultSize.changed();
|
||||
}
|
||||
|
||||
void GraphicalObjectPictureMarker::setPictureMarkerSymbol(Esri::ArcGISRuntime::PictureMarkerSymbol *pms, QSize defaultSize)
|
||||
{
|
||||
resetSimpleMarkerSymbol();
|
||||
resetImage();
|
||||
|
||||
if (m_isOwnPms)
|
||||
{
|
||||
delete m_pictureMarkerSymbol;
|
||||
m_pictureMarkerSymbol = nullptr;
|
||||
}
|
||||
|
||||
if (m_pictureMarkerSymbol == pms &&
|
||||
m_imageDefaultSize.value() == defaultSize)
|
||||
return;
|
||||
m_isOwnPms = false;
|
||||
m_pictureMarkerSymbol = pms;
|
||||
m_imageDefaultSize = defaultSize;
|
||||
m_imageChanged = true;
|
||||
}
|
||||
|
||||
void GraphicalObjectPictureMarker::resetImage()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
m_image = QImage();
|
||||
m_imageChanged = true;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectPictureMarker::resetPictureMarkerSymbol()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
if (m_isOwnPms)
|
||||
delete m_pictureMarkerSymbol;
|
||||
m_pictureMarkerSymbol = nullptr;
|
||||
if (m_workaorundTimer)
|
||||
m_workaorundTimer->stop();
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectPictureMarker::resetSimpleMarkerSymbol()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
delete m_simpleMarkerSymbol;
|
||||
m_simpleMarkerSymbol = nullptr;
|
||||
m_markerSymbolType = MarkerSymbolType::Undefined;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
|
||||
MarkerSymbolType GraphicalObjectPictureMarker::markerSymbolType()
|
||||
{
|
||||
return m_markerSymbolType.value();
|
||||
}
|
||||
|
||||
int GraphicalObjectPictureMarker::markerSymbolSize()
|
||||
{
|
||||
return m_markerSize.value();
|
||||
}
|
||||
|
||||
void GraphicalObjectPictureMarker::setMarkerSymbol(MarkerSymbolType markerSymbolType,
|
||||
int size, const QColor &color)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " color=" << color;
|
||||
|
||||
resetImage();
|
||||
|
||||
m_markerSymbolType = markerSymbolType;
|
||||
m_markerSize = size;
|
||||
m_markerColor = color;
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
QSize GraphicalObjectPictureMarker::currentSize() const
|
||||
{
|
||||
return m_currentSize;
|
||||
}
|
||||
|
||||
bool GraphicalObjectPictureMarker::create()
|
||||
{
|
||||
return BaseClass::create();
|
||||
}
|
||||
|
||||
int GraphicalObjectPictureMarker::xOffset() const
|
||||
{
|
||||
return m_externalOffset.value().x();
|
||||
}
|
||||
void GraphicalObjectPictureMarker::setXOffset(int xOffset)
|
||||
{
|
||||
m_externalOffset.refValue().rx() = xOffset;
|
||||
}
|
||||
int GraphicalObjectPictureMarker::yOffset() const
|
||||
{
|
||||
return m_externalOffset.value().y();
|
||||
}
|
||||
void GraphicalObjectPictureMarker::setYOffset(int yOffset)
|
||||
{
|
||||
m_externalOffset.refValue().ry() = yOffset;
|
||||
}
|
||||
|
||||
float GraphicalObjectPictureMarker::rotationAngle()
|
||||
{
|
||||
return m_angle.value();
|
||||
}
|
||||
void GraphicalObjectPictureMarker::setRotationAngle(float angle)
|
||||
{
|
||||
m_angle = angle;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectPictureMarker::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " origin =" << this->origin() // .x() << " , " << this->origin().y()
|
||||
<< " visibility=" << m_visibility
|
||||
<< " pickable=" << m_pickable
|
||||
<< " pickable.changed=" << m_pickable.changed()
|
||||
<< " selected=" << m_selected
|
||||
<< " m_angle = " << m_angle.value()
|
||||
<< " m_drawOrder = " << m_drawOrder
|
||||
<< " m_image.size() = " << m_image.size()
|
||||
<< " m_imageChanged = " << m_imageChanged
|
||||
<< " m_imageDefaultSize=" << m_imageDefaultSize
|
||||
<< " m_imageDefaultSize.changed()=" << m_imageDefaultSize.changed()
|
||||
<< " m_scale = " << m_scale.value();
|
||||
|
||||
// some checks:
|
||||
if (m_positions.value().size() < 1)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " debugInfo='" << m_debugInfo << "'"
|
||||
<< " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Image or Marker ???
|
||||
//
|
||||
QString filePath;
|
||||
QPointF hotSpotPercent;
|
||||
Esri::ArcGISRuntime::SimpleMarkerSymbolStyle esriSMSS =
|
||||
getSimpleMarkerSymbolStyle(m_markerSymbolType.value(),
|
||||
filePath,
|
||||
&hotSpotPercent);
|
||||
m_markerHotSpotPercent = hotSpotPercent;
|
||||
|
||||
if (m_markerSymbolType.value() != MarkerSymbolType::Undefined)
|
||||
{
|
||||
if (m_markerSize.changed() ||
|
||||
m_markerSymbolType.changed() ||
|
||||
m_markerColor.changed() ||
|
||||
m_markerSymbolType.changed() ||
|
||||
m_angle.changed() ||
|
||||
m_markerHotSpotPercent.changed())
|
||||
{
|
||||
if (!reCreateSymbol(filePath, esriSMSS))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_image.isNull() && (!m_isOwnPms && m_pictureMarkerSymbol == nullptr))
|
||||
{
|
||||
// in context of class 'TacticalAppearance' the PictureMarker exist always...
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " no image and m_markerSymbolType==Undefined -> nothing to do";
|
||||
// -> nothing to do:
|
||||
return true; // -> nothing to do:
|
||||
}
|
||||
|
||||
if (m_scale.changed() ||
|
||||
m_imageChanged ||
|
||||
m_markerSymbolType.changed() ||
|
||||
m_markerSize.changed() ||
|
||||
m_angle.changed() ||
|
||||
!m_pictureMarkerSymbol)
|
||||
{
|
||||
if (!reCreateSymbol(filePath, esriSMSS))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const PositionCont &posCont = m_positions.value();
|
||||
if (posCont.size() == 1)
|
||||
{
|
||||
const Point3D &origin = this->origin();
|
||||
Esri::ArcGISRuntime::Point originGeometry(origin.x(),
|
||||
origin.y(),
|
||||
origin.z(),
|
||||
spatialReference());
|
||||
m_graphic->setGeometry(originGeometry);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Eception: Layer with name "AES2" should NOT have no renderer 8 to enable multipoint graphics
|
||||
// [GUEZE-496] RPL Nr 770: 3D Lagedarstellung Einfrieren der SW Appl.
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " posCont.size() = " << posCont.size();
|
||||
Esri::ArcGISRuntime::MultipointBuilder builder(spatialReference());
|
||||
for (const Point3D &pos : posCont)
|
||||
builder.points()->addPoint(pos.x(), pos.y(), pos.z());
|
||||
|
||||
if (! builder.isSketchValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " builder -> sketch invalid";
|
||||
return false;
|
||||
}
|
||||
m_graphic->setGeometry(builder.toGeometry());
|
||||
}
|
||||
|
||||
bool success = BaseClass::updateViewImpl();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
success = addUpdateGraphic();
|
||||
|
||||
|
||||
QSize imgSize = m_image.size();
|
||||
QSizeF pmSize;
|
||||
if (m_pictureMarkerSymbol)
|
||||
pmSize = QSizeF(m_pictureMarkerSymbol->width(), m_pictureMarkerSymbol->height());
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
// << " success=" << success
|
||||
<< " m_drawOrder = " << m_drawOrder
|
||||
<< " m_graphic->drawOrder = " << m_graphic->zIndex()
|
||||
<< " m_image->size() = " << imgSize
|
||||
<< " pictureMarkerSymbol->size() = " << pmSize;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GraphicalObjectPictureMarker::reCreateSymbol(const QString &filePath,
|
||||
const Esri::ArcGISRuntime::SimpleMarkerSymbolStyle esriSMSS)
|
||||
{
|
||||
const bool imageRequired = !m_image.isNull() || !filePath.isEmpty();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " filePath = '" << filePath << "'"
|
||||
<< " m_image->size() = " << m_image.size()
|
||||
<< " m_imageChanged = " << m_imageChanged
|
||||
<< " m_angle = " << m_angle.value()
|
||||
<< " m_currentSize = " << m_currentSize
|
||||
<< " m_imageDefaultSize = " << m_imageDefaultSize.value()
|
||||
<< " m_imageDefaultSize.changed() = " << m_imageDefaultSize.changed();
|
||||
|
||||
//
|
||||
// Now we know what to use: Image or Marker
|
||||
//
|
||||
|
||||
if (!create())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
// what is used currently?
|
||||
// image or m_simpleMarkerSymbol(esri)?
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " imageRequired=" << imageRequired
|
||||
<< " m_pictureMarkerSymbol=" << m_pictureMarkerSymbol
|
||||
<< " m_simpleMarkerSymbol=" << m_simpleMarkerSymbol;
|
||||
|
||||
if (!filePath.isEmpty())
|
||||
{
|
||||
// e.g. case PushPin2D
|
||||
QImage img;
|
||||
if (img.load(filePath))
|
||||
{
|
||||
int iSize = qRound(m_markerSize.value() * m_scale.value());
|
||||
m_currentSize = QSize(iSize, iSize);
|
||||
img = img.scaledToHeight(iSize, Qt::SmoothTransformation);
|
||||
|
||||
QColor localColor = m_markerColor.value();
|
||||
|
||||
if (m_markerSymbolType.value() == MarkerSymbolType::PushPin2D && localColor.isValid())
|
||||
{
|
||||
QColor colorToBeReplaced(255, 0, 0);
|
||||
AdvancedSymbology::ExtensionRenderer::replaceColor(img, colorToBeReplaced.rgba(), localColor.rgba());
|
||||
}
|
||||
setImage(img);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " loading image failed, debugInfo='" << m_debugInfo << "'"
|
||||
<< " path='" << filePath << "'";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Transfer data to esriSymbols:
|
||||
//
|
||||
|
||||
// Image:
|
||||
if (!m_image.isNull() || (!m_isOwnPms && m_pictureMarkerSymbol))
|
||||
{
|
||||
resetSimpleMarkerSymbol();
|
||||
|
||||
QSize realImageSize;
|
||||
if (!m_isOwnPms && m_pictureMarkerSymbol)
|
||||
{
|
||||
if (m_imageDefaultSize.value().isEmpty())
|
||||
m_currentSize = m_image.size() * m_scale.value();
|
||||
else
|
||||
m_currentSize = m_imageDefaultSize.value() * m_scale.value();
|
||||
realImageSize = m_currentSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// scale localImage by m_scale
|
||||
QImage localImage;
|
||||
if (!filePath.isEmpty())
|
||||
{
|
||||
// case PushPin2D -> already scaled by m_scale. So don´t scale again:
|
||||
localImage = m_image;
|
||||
m_currentSize = localImage.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_imageDefaultSize.value().isEmpty())
|
||||
m_currentSize = m_image.size() * m_scale.value();
|
||||
else
|
||||
m_currentSize = m_imageDefaultSize.value() * m_scale.value();
|
||||
|
||||
// scaled required?
|
||||
if (m_image.size() != m_currentSize)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " SCALE FROM " << m_image.size() << " TO " << m_currentSize;
|
||||
localImage = m_image.scaled(m_currentSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
++m_scaleCounter4Moduletest;
|
||||
} else {
|
||||
localImage = m_image;
|
||||
m_currentSize = localImage.size();
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_scaleCounter4Moduletest = " << m_scaleCounter4Moduletest
|
||||
<< ", localImage.size() = " << localImage.size();
|
||||
|
||||
delete m_pictureMarkerSymbol;
|
||||
m_pictureMarkerSymbol = new Esri::ArcGISRuntime::PictureMarkerSymbol(localImage);
|
||||
realImageSize = localImage.size();
|
||||
|
||||
|
||||
// Workaround :
|
||||
// Norbert Thoden, 11.06.2020:
|
||||
// do some calls again to fix ESRI-Bug:
|
||||
// Bug: new Image('localImage#) / pictureMarkerSymbol, but sometimes it will not be shown :-(
|
||||
// Using try and error, we recognize that an additional call seems to fix that issue:
|
||||
if (!m_workaorundTimer)
|
||||
{
|
||||
m_workaorundTimer = new QTimer(m_graphic);
|
||||
m_workaorundTimer->setInterval(150);
|
||||
m_workaorundTimer->setSingleShot(true);
|
||||
QObject::connect(m_workaorundTimer, &QTimer::timeout, m_graphic, [this]() {
|
||||
if (!m_graphic)
|
||||
return;
|
||||
m_graphic->setZIndex(m_drawOrder.value());
|
||||
m_graphic->setVisible(m_visibility.value());
|
||||
m_graphic->setSelected(m_selected.value());
|
||||
});
|
||||
}
|
||||
m_workaorundTimer->start();
|
||||
// : Workaround
|
||||
|
||||
}
|
||||
m_imageChanged = false;
|
||||
|
||||
// set image to pms AND ALSO the Heigth and Width!!!
|
||||
|
||||
// // !!! Important !!!
|
||||
// // Case #01713501 - PictureMarker-offset
|
||||
// // Esri::PictureMarkerSymbol:: setHeight/setWidth -> typographic points.
|
||||
// // 36pt -> 48pixel -> factor 0.75
|
||||
// double pixelToPointFactor = 0.71;
|
||||
// m_pictureMarkerSymbol->setHeight(m_image->size().height() * pixelToPointFactor);
|
||||
// m_pictureMarkerSymbol->setWidth (m_image->size().width() * pixelToPointFactor);
|
||||
// // !!! Important !!!
|
||||
|
||||
QPointF markerHotSpot = QPointF(realImageSize.width() / 2.0 * m_markerHotSpotPercent.value().x(),
|
||||
realImageSize.height() / 2.0 * m_markerHotSpotPercent.value().y());
|
||||
|
||||
QPointF finalOffset = (markerHotSpot.toPoint() * -1) * 1.33 // 1.33; // try and error (48pixel / 36pt)
|
||||
+
|
||||
(m_externalOffset.value() * 0.75); // 0.75; // try and error (36pt / 48pixel)
|
||||
|
||||
m_pictureMarkerSymbol->setOffsetX(finalOffset.x());
|
||||
m_pictureMarkerSymbol->setOffsetY(finalOffset.y());
|
||||
|
||||
m_pictureMarkerSymbol->setAngle(m_angle.value());
|
||||
|
||||
m_graphic->setSymbol(m_pictureMarkerSymbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
resetPictureMarkerSymbol();
|
||||
resetImage();
|
||||
if (!m_simpleMarkerSymbol)
|
||||
m_simpleMarkerSymbol = new Esri::ArcGISRuntime::SimpleMarkerSymbol();
|
||||
|
||||
m_simpleMarkerSymbol->setSize(m_markerSize.value() * m_scale.value());
|
||||
m_simpleMarkerSymbol->setStyle(esriSMSS);
|
||||
m_simpleMarkerSymbol->setAngle(m_angle.value());
|
||||
|
||||
m_simpleMarkerSymbol->setOffsetX(m_externalOffset.value().x());
|
||||
m_simpleMarkerSymbol->setOffsetY(m_externalOffset.value().y());
|
||||
|
||||
m_simpleMarkerSymbol->setColor(m_markerColor.value());
|
||||
|
||||
m_graphic->setSymbol(m_simpleMarkerSymbol);
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " filePath = '" << filePath << "'"
|
||||
<< " m_image->size() = " << m_image.size()
|
||||
<< " m_imageChanged = " << m_imageChanged
|
||||
<< " m_currentSize = " << m_currentSize
|
||||
<< " m_imageDefaultSize = " << m_imageDefaultSize.value()
|
||||
<< " m_imageDefaultSize.changed() = " << m_imageDefaultSize.changed();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace SituationMap
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectPictureMarker
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
#include <Map/text_style.h>
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
|
||||
// Esri
|
||||
#include <arcgis/SymbolTypes.h>
|
||||
#include <arcgis/DistanceCompositeSceneSymbol.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QImage>
|
||||
|
||||
|
||||
// forward:
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class Graphic;
|
||||
class GraphicsOverlay;
|
||||
class PictureMarkerSymbol;
|
||||
class SimpleMarkerSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
class QTimer;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectPictureMarker : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
GraphicalObjectPictureMarker(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectPictureMarker();
|
||||
|
||||
// Data access:
|
||||
const QImage &image() const { return m_image; }
|
||||
QSize imageDefaultSize() const { return m_imageDefaultSize.value(); }
|
||||
void setImage(const QImage &image, const QSize &defaultSize = QSize());
|
||||
|
||||
void setPictureMarkerSymbol(Esri::ArcGISRuntime::PictureMarkerSymbol *pms, QSize defaultSize);
|
||||
|
||||
virtual MarkerSymbolType markerSymbolType();
|
||||
virtual int markerSymbolSize();
|
||||
virtual void setMarkerSymbol(MarkerSymbolType markerSymbolType,
|
||||
int size,
|
||||
const QColor &color = QColor());
|
||||
|
||||
virtual QSize currentSize() const;
|
||||
|
||||
// Offset (x: to right ; y: to north)
|
||||
virtual int xOffset() const;
|
||||
virtual void setXOffset(int xOffset);
|
||||
virtual int yOffset() const;
|
||||
virtual void setYOffset(int yOffset);
|
||||
|
||||
// rotation / angle
|
||||
virtual float rotationAngle();
|
||||
virtual void setRotationAngle(float angle);
|
||||
|
||||
protected:
|
||||
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_markerSymbolType.changed()
|
||||
|| m_markerSize.changed()
|
||||
|| m_markerColor.changed()
|
||||
|| m_angle.changed()
|
||||
|| m_markerHotSpotPercent.changed()
|
||||
|| m_externalOffset.changed()
|
||||
|| m_imageChanged
|
||||
;
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_markerSymbolType.reset();
|
||||
m_markerSize.reset();
|
||||
m_markerColor.reset();
|
||||
m_angle.reset();
|
||||
m_markerHotSpotPercent.reset();
|
||||
m_externalOffset.reset();
|
||||
m_imageChanged = false;
|
||||
|
||||
m_imageDefaultSize.reset();
|
||||
}
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
void resetImage();
|
||||
void resetPictureMarkerSymbol();
|
||||
void resetSimpleMarkerSymbol();
|
||||
bool reCreateSymbol(const QString &filePath,
|
||||
const Esri::ArcGISRuntime::SimpleMarkerSymbolStyle esriSMSS);
|
||||
|
||||
// used for image:
|
||||
QImage m_image;
|
||||
SimpleValue<QSize> m_imageDefaultSize;
|
||||
Esri::ArcGISRuntime::PictureMarkerSymbol *m_pictureMarkerSymbol = nullptr;
|
||||
bool m_imageChanged = true;
|
||||
bool m_isOwnPms = true;
|
||||
|
||||
// used marker:
|
||||
Esri::ArcGISRuntime::SimpleMarkerSymbol *m_simpleMarkerSymbol = nullptr;
|
||||
QTimer *m_workaorundTimer = nullptr; // for re-new of Esri::ArcGISRuntime::PictureMarkerSymbol
|
||||
|
||||
QSize m_currentSize;
|
||||
int m_scaleCounter4Moduletest = 0;
|
||||
|
||||
|
||||
SimpleValue<MarkerSymbolType> m_markerSymbolType = MarkerSymbolType::Undefined;
|
||||
SimpleValue<int> m_markerSize = 10;
|
||||
SimpleValue<QColor> m_markerColor = QColor(Qt::red);
|
||||
|
||||
SimpleValue<float> m_angle = 0; ///
|
||||
SimpleValue<QPointF> m_markerHotSpotPercent; ///< Store marker-specific offset.
|
||||
SimpleValue<QPoint> m_externalOffset; ///< Stores external offset.
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectRange
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_range.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/PolygonBuilder.h>
|
||||
#include <arcgis/MultipartBuilder.h>
|
||||
#include <arcgis/ImmutablePartCollection.h>
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
GraphicalObjectRange::GraphicalObjectRange(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_logger(getLogger("GraphicalObjectRange"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectRange::~GraphicalObjectRange()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
|
||||
int GraphicalObjectRange::range() const
|
||||
{
|
||||
return m_range.value();
|
||||
}
|
||||
|
||||
float GraphicalObjectRange::angle() const
|
||||
{
|
||||
return m_angleDegree.value();
|
||||
}
|
||||
|
||||
void GraphicalObjectRange::setRange(int range, float angleDegree)
|
||||
{
|
||||
m_angleDegree = angleDegree;
|
||||
m_range = range;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool GraphicalObjectRange::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
EllipseParameters ellipsePara;
|
||||
ellipsePara.setLengthX(m_range.value());
|
||||
ellipsePara.setLengthY(m_range.value());
|
||||
ellipsePara.setDirectionDegree(m_angleDegree.value()) ;
|
||||
ellipsePara.setDirectionDegree((m_angleDegree.value() * -1) + 90);
|
||||
ellipsePara.setMaxSegmentLength(10);
|
||||
ellipsePara.setMaxPointCount(30); // limit to 30 to reduce the number of vertices. If to high, keep performance impact to 3D in mind!!!
|
||||
|
||||
this->setEllipseParameters(ellipsePara);
|
||||
|
||||
bool success = BaseClass::updateViewImpl();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " drawOrder = " << m_graphic->zIndex()
|
||||
<< " success = " << success;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectRange::createEllipse(Esri::ArcGISRuntime::Polygon &ellipse)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " range=" << m_range
|
||||
<< " angle=" << m_angleDegree;
|
||||
|
||||
bool success = BaseClass::createEllipse(ellipse);
|
||||
|
||||
if (success &&
|
||||
!ellipse.isEmpty() &&
|
||||
!ellipse.parts().isEmpty() &&
|
||||
!ellipse.parts().part(0).isEmpty())
|
||||
{
|
||||
const Point3D ¢er = this->origin();
|
||||
|
||||
// 'modify' ellipe (by copying, adding and re-assigning):
|
||||
|
||||
// part 0 - ellipse
|
||||
// we have to copy the point since the ellipse does not contain the z value anymore :-(
|
||||
Esri::ArcGISRuntime::Part partCircle(ellipse.spatialReference());
|
||||
const Esri::ArcGISRuntime::ImmutablePart &im = ellipse.parts().part(0);
|
||||
|
||||
for (int i = 0; i < im.pointCount(); ++i)
|
||||
{
|
||||
const Esri::ArcGISRuntime::Point &p = im.point(i);
|
||||
partCircle.addPoint(Esri::ArcGISRuntime::Point(p.x(),
|
||||
p.y(),
|
||||
center.z() // p.z()
|
||||
));
|
||||
}
|
||||
|
||||
// part 1 - line to center
|
||||
Esri::ArcGISRuntime::Part partLine(ellipse.spatialReference());
|
||||
partLine.addPoint(im.startPoint().x(),
|
||||
im.startPoint().y(),
|
||||
center.z());
|
||||
partLine.addPoint(center.x(),
|
||||
center.y(),
|
||||
center.z());
|
||||
// a polyGON requiree to have at least 3 points:
|
||||
partLine.addPoint(center.x(),
|
||||
center.y(),
|
||||
center.z()+0.01);
|
||||
|
||||
// combine them to a PartCollection:
|
||||
Esri::ArcGISRuntime::PartCollection pc(ellipse.spatialReference());
|
||||
pc.addPart(&partCircle);
|
||||
pc.addPart(&partLine);
|
||||
|
||||
Esri::ArcGISRuntime::PolygonBuilder builder(ellipse.spatialReference());
|
||||
builder.setParts(&pc);
|
||||
|
||||
ellipse = builder.toPolygon();
|
||||
|
||||
success = true;
|
||||
|
||||
}
|
||||
else
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'";
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<<(std::ostream &stream,
|
||||
const GraphicalObjectRange &value)
|
||||
{
|
||||
stream << value.toString();
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectRange
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "graphical_object_ellipse.h"
|
||||
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectRange : public GraphicalObjectEllipse
|
||||
{
|
||||
|
||||
using BaseClass = GraphicalObjectEllipse;
|
||||
|
||||
public:
|
||||
GraphicalObjectRange(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectRange();
|
||||
|
||||
int range() const;
|
||||
float angle() const;
|
||||
|
||||
void setRange(int range, float angleDegree);
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
// bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_angleDegree.changed()
|
||||
|| m_range.changed();
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_angleDegree.reset();
|
||||
m_range.reset();
|
||||
}
|
||||
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
|
||||
bool createEllipse(Esri::ArcGISRuntime::Polygon &ellipse) override;
|
||||
|
||||
|
||||
private:
|
||||
SimpleValue<float> m_angleDegree = 0;
|
||||
SimpleValue<int> m_range = 0;
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<< (std::ostream &stream,
|
||||
const GraphicalObjectRange &value);
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectRendererAttributes
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_renderer_attributes.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
#include <MathUtils/simple_helper.h>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/ModelSceneSymbol.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QPainter>
|
||||
#include <QFile>
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
GraphicalObjectRendererAttributes::GraphicalObjectRendererAttributes(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_logger(getLogger("GraphicalObjectRendererAttributes"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectRendererAttributes::~GraphicalObjectRendererAttributes()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectRendererAttributes::setAttributeMap(const QVariantMap &attribMap)
|
||||
{
|
||||
m_attributeMap = attribMap;
|
||||
}
|
||||
|
||||
QVariantMap GraphicalObjectRendererAttributes::attributeMap() const
|
||||
{
|
||||
return m_attributeMap.value();
|
||||
}
|
||||
|
||||
bool GraphicalObjectRendererAttributes::create()
|
||||
{
|
||||
return BaseClass::create();
|
||||
}
|
||||
|
||||
bool GraphicalObjectRendererAttributes::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " origin =" << this->origin() // .x() << " , " << this->origin().y()
|
||||
<< " visibility=" << m_visibility
|
||||
<< " pickable=" << m_pickable
|
||||
<< " pickable.changed=" << m_pickable.changed()
|
||||
<< " selected=" << m_selected
|
||||
<< " m_attributeMap = " << m_attributeMap.value().size()
|
||||
<< " m_drawOrder = " << m_drawOrder;
|
||||
|
||||
// some checks:
|
||||
if (!isSinglePoint())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " debugInfo='" << m_debugInfo << "'"
|
||||
<< " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
const Point3D &origin = this->origin();
|
||||
m_graphic->setGeometry(Esri::ArcGISRuntime::Point(origin.x(),
|
||||
origin.y(),
|
||||
origin.z(),
|
||||
spatialReference()));
|
||||
|
||||
if (m_attributeMap.changed())
|
||||
{
|
||||
QVariantMap cur = m_graphic->attributes()->attributesMap();
|
||||
|
||||
if (m_logger.isDebugEnabled())
|
||||
qCritical() << " debugInfo='" << m_debugInfo << "'" << ", QVariantMap before unite " << cur;
|
||||
|
||||
cur.unite(m_attributeMap.value());
|
||||
|
||||
if (m_logger.isDebugEnabled())
|
||||
qCritical() << " debugInfo='" << m_debugInfo << "'" << ", QVariantMap after unite " << cur;
|
||||
|
||||
m_graphic->attributes()->setAttributesMap(cur);
|
||||
}
|
||||
|
||||
// keep anchor like Esri::ArcGISRuntime::SceneSymbolAnchorPosition::Bottom in mind.
|
||||
// assigned during setup the Renderer (LayerFactory, AdapterDds...)
|
||||
|
||||
success = BaseClass::updateViewImpl();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
success = addUpdateGraphic();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success=" << success
|
||||
<< " m_drawOrder = " << m_drawOrder
|
||||
<< " m_graphic->drawOrder = " << m_graphic->zIndex();
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace SituationMap
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectRendererAttributes
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
#include <Map/text_style.h>
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
|
||||
// Esri
|
||||
#include <arcgis/SymbolTypes.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QImage>
|
||||
#include <QVariantMap>
|
||||
|
||||
|
||||
// forward:
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class Graphic;
|
||||
class GraphicsOverlay;
|
||||
class ModelSceneSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectRendererAttributes : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
GraphicalObjectRendererAttributes(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectRendererAttributes();
|
||||
|
||||
// Data access:
|
||||
// to be cont.
|
||||
void setAttributeMap(const QVariantMap &attribMap);
|
||||
QVariantMap attributeMap() const;
|
||||
|
||||
protected:
|
||||
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_attributeMap.changed()
|
||||
;
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_attributeMap.reset();
|
||||
}
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
// no ModelSceneSymbol since Renderer-based
|
||||
|
||||
SimpleValue<QVariantMap> m_attributeMap;
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
// Forbid some overloaded methods without effects of this object;
|
||||
PositionCont positions() const override
|
||||
{
|
||||
return PositionCont();
|
||||
}
|
||||
void setPositions(const PositionCont &posCont) override
|
||||
{
|
||||
Q_UNUSED(posCont);
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectSceneMarker
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_scene_marker.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
#include <MathUtils/simple_helper.h>
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/SimpleMarkerSceneSymbol.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QPainter>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
GraphicalObjectSceneMarker::GraphicalObjectSceneMarker(SceneMarkerType type
|
||||
, const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_type(type)
|
||||
, m_logger(getLogger("GraphicalObjectSceneMarker"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectSceneMarker::~GraphicalObjectSceneMarker()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
delete m_simpleMarkerSceneSymbol;
|
||||
m_simpleMarkerSceneSymbol = nullptr;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectSceneMarker::setDiameter(double diameter)
|
||||
{
|
||||
m_diameter = diameter;
|
||||
}
|
||||
|
||||
double GraphicalObjectSceneMarker::diameter() const
|
||||
{
|
||||
return m_diameter.value();
|
||||
}
|
||||
|
||||
bool GraphicalObjectSceneMarker::create()
|
||||
{
|
||||
return BaseClass::create();
|
||||
}
|
||||
|
||||
bool GraphicalObjectSceneMarker::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " origin =" << this->origin() // .x() << " , " << this->origin().y()
|
||||
<< " visibility=" << m_visibility
|
||||
<< " pickable=" << m_pickable
|
||||
<< " pickable.changed=" << m_pickable.changed()
|
||||
<< " selected=" << m_selected
|
||||
<< " m_diameter = " << m_diameter.value()
|
||||
<< " m_heading = " << m_heading.value()
|
||||
<< " m_pitch = " << m_pitch.value()
|
||||
<< " m_roll = " << m_roll.value()
|
||||
<< " m_drawOrder = " << m_drawOrder
|
||||
<< " m_lineStyle = " << m_lineStyle.value()
|
||||
<< " m_fillStyle = " << m_fillStyle.value()
|
||||
<< " fillColor = " << m_fillStyle.value().fillColor()
|
||||
<< " m_scale = " << m_scale.value();
|
||||
|
||||
if (m_graphicsLayer->renderingMode() != Esri::ArcGISRuntime::GraphicsRenderingMode::Dynamic)
|
||||
for (int i=0; i<10; ++i)
|
||||
ERROR_LOG(m_logger) << " RenderingMode::Dynamic required!!! , debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
// some checks:
|
||||
if (!isSinglePoint())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " debugInfo='" << m_debugInfo << "'"
|
||||
<< " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
const double radiusHeight = m_diameter.value()/2.0;
|
||||
|
||||
Point3D origin = this->origin();
|
||||
|
||||
// Try to set AnchorPosition::Top, to let the cone rotate around top/tip.
|
||||
// Using a cone, the anchor point does not work as expected, we have to move
|
||||
if (m_type == SceneMarkerType::CONE)
|
||||
{
|
||||
//
|
||||
// It´s a SCENE Marker. So we are per definition in 3D and origin is in degree.
|
||||
//
|
||||
// heading is in degree:m_heading.value()
|
||||
// offset as vector:
|
||||
QPointF offsetMeter(0, radiusHeight/2.0);
|
||||
const int rotAngleDegree = (static_cast<int>(m_heading.value())-90)%360;
|
||||
DEBUG_LOG(m_logger) << " offsetMeter = " << offsetMeter << ", m_heading = " << m_heading.value() << ", rotAngleDegree = " << rotAngleDegree;
|
||||
MathUtils::rotatePoint(offsetMeter, QPointF(), rotAngleDegree);
|
||||
// new temporary origin...
|
||||
// -> rad
|
||||
origin *= LtsCoordTrans::deg2rad();
|
||||
LtsCoordTrans::UtmCoordinate newOrigin = LtsCoordTrans::UtmCoordinate::fromGeographic(origin.x(), origin.y());
|
||||
DEBUG_LOG(m_logger) << " newOrigin = " << newOrigin.mgrs();
|
||||
|
||||
// add rotated offset to temporary origin:
|
||||
const QPointF origin2D = newOrigin.geographic(offsetMeter) * LtsCoordTrans::rad2deg();
|
||||
// -> deg
|
||||
// write back; z-value stays untouched:
|
||||
origin.rx() = origin2D.x();
|
||||
origin.ry() = origin2D.y();
|
||||
}
|
||||
|
||||
const Esri::ArcGISRuntime::Point originGeometry(origin.x(),
|
||||
origin.y(),
|
||||
origin.z(),
|
||||
spatialReference());
|
||||
m_graphic->setGeometry(originGeometry);
|
||||
|
||||
if (!m_simpleMarkerSceneSymbol)
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case SceneMarkerType::CONE: // Kegel
|
||||
m_simpleMarkerSceneSymbol =
|
||||
Esri::ArcGISRuntime::SimpleMarkerSceneSymbol::cone(
|
||||
m_fillStyle.value().fillColor(),
|
||||
radiusHeight, radiusHeight, // V100.8: cone: 'diameter' is interpreted as radius
|
||||
Esri::ArcGISRuntime::SceneSymbolAnchorPosition::Center); // V100.8: cone: Top does not work as aspected - grrr
|
||||
break;
|
||||
case SceneMarkerType::SPHERE: // Kugel
|
||||
m_simpleMarkerSceneSymbol =
|
||||
Esri::ArcGISRuntime::SimpleMarkerSceneSymbol::sphere(
|
||||
m_fillStyle.value().fillColor(),
|
||||
radiusHeight*2.0,
|
||||
Esri::ArcGISRuntime::SceneSymbolAnchorPosition::Center);
|
||||
break;
|
||||
} // switch
|
||||
}
|
||||
m_simpleMarkerSceneSymbol->setColor(m_fillStyle.value().fillColor());
|
||||
|
||||
if (m_type == SceneMarkerType::CONE)
|
||||
{
|
||||
m_simpleMarkerSceneSymbol->setWidth(radiusHeight);
|
||||
m_simpleMarkerSceneSymbol->setHeight(radiusHeight);
|
||||
m_simpleMarkerSceneSymbol->setDepth(radiusHeight);
|
||||
} else {
|
||||
m_simpleMarkerSceneSymbol->setWidth(m_diameter.value());
|
||||
m_simpleMarkerSceneSymbol->setHeight(m_diameter.value());
|
||||
m_simpleMarkerSceneSymbol->setDepth(m_diameter.value());
|
||||
}
|
||||
|
||||
m_simpleMarkerSceneSymbol->setHeading(m_heading.value());
|
||||
m_simpleMarkerSceneSymbol->setPitch(m_pitch.value());
|
||||
m_simpleMarkerSceneSymbol->setRoll(m_roll.value());
|
||||
|
||||
m_graphic->setSymbol(m_simpleMarkerSceneSymbol);
|
||||
|
||||
success = BaseClass::updateViewImpl();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
success = addUpdateGraphic();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success=" << success
|
||||
<< " m_drawOrder = " << m_drawOrder
|
||||
<< " m_graphic->drawOrder = " << m_graphic->zIndex();
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectSceneMarker
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
#include <Map/text_style.h>
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
|
||||
// Esri
|
||||
#include <arcgis/SymbolTypes.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QImage>
|
||||
|
||||
|
||||
// forward:
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class Graphic;
|
||||
class GraphicsOverlay;
|
||||
class SimpleMarkerSceneSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
class QTimer;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
// !!! Layer with RenderingMode::Dynamic required !!!
|
||||
// !!! Layer with RenderingMode::Dynamic required !!!
|
||||
// !!! Layer with RenderingMode::Dynamic required !!!
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
enum class SceneMarkerType {CONE, SPHERE};
|
||||
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectSceneMarker : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
|
||||
public:
|
||||
GraphicalObjectSceneMarker(SceneMarkerType type
|
||||
, const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectSceneMarker();
|
||||
|
||||
// Data access:
|
||||
// to be cont. (type is sphere, to support cube, cylinder etc)
|
||||
void setDiameter(double diameter);
|
||||
double diameter() const;
|
||||
|
||||
double heading() const { return m_heading.value(); }
|
||||
void setHeading(double headingDegree) { m_heading = headingDegree; }
|
||||
double pitch() const { return m_pitch.value(); }
|
||||
void setPitch(double pitchDegree) { m_pitch = pitchDegree; }
|
||||
double roll() const { return m_roll.value(); }
|
||||
void setRoll(double rollDegree) { m_roll = rollDegree; }
|
||||
|
||||
protected:
|
||||
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_diameter.changed()
|
||||
|| m_heading.changed()
|
||||
|| m_pitch.changed()
|
||||
|| m_roll.changed()
|
||||
;
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_diameter.reset();
|
||||
m_heading.reset();
|
||||
m_pitch.reset();
|
||||
m_roll.reset();
|
||||
}
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
// used marker:
|
||||
Esri::ArcGISRuntime::SimpleMarkerSceneSymbol *m_simpleMarkerSceneSymbol{nullptr};
|
||||
|
||||
SceneMarkerType m_type{SceneMarkerType::SPHERE};
|
||||
SimpleValue<double> m_diameter{25};
|
||||
|
||||
SimpleValue<double> m_heading{0}; // degree
|
||||
SimpleValue<double> m_pitch{0}; // degree
|
||||
SimpleValue<double> m_roll{0}; // degree
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
// Forbid some overloaded methods without effects of this object;
|
||||
PositionCont positions() const override
|
||||
{
|
||||
return PositionCont();
|
||||
}
|
||||
void setPositions(const PositionCont &posCont) override
|
||||
{
|
||||
Q_UNUSED(posCont);
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,340 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectText
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_text.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/TextSymbol.h>
|
||||
#include <arcgis/PictureMarkerSymbol.h>
|
||||
|
||||
// Qt
|
||||
#include <QString>
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
GraphicalObjectText::GraphicalObjectText(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_textSymbol(nullptr)
|
||||
, m_logger(getLogger("GraphicalObjectText"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectText::~GraphicalObjectText()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " text='" << m_text << "'";
|
||||
|
||||
delete m_textSymbol;
|
||||
m_textSymbol = nullptr;
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " text='" << m_text << "'";
|
||||
}
|
||||
|
||||
QString GraphicalObjectText::toString() const
|
||||
{
|
||||
QString str;
|
||||
// str.append( BaseClass::toString() );
|
||||
|
||||
if (!m_debugInfo.isEmpty())
|
||||
str.append(QStringLiteral("debugInfo=%1").arg(m_debugInfo));
|
||||
|
||||
if (m_graphicsLayer)
|
||||
str.append(QStringLiteral(" layer='%1'").arg(m_graphicsLayer->objectName()));
|
||||
|
||||
if (m_graphic)
|
||||
str.append(QStringLiteral(" zIndex='%1'").arg(m_graphic->zIndex()));
|
||||
|
||||
std::ostringstream stream;
|
||||
stream << this->origin();
|
||||
str.append(QLatin1String(stream.str().c_str()));
|
||||
|
||||
if (!m_text.value().isEmpty())
|
||||
str.append(QStringLiteral("text=%1").arg(m_text.value()));
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
QString GraphicalObjectText::text() const
|
||||
{
|
||||
return m_text.value();
|
||||
}
|
||||
|
||||
void GraphicalObjectText::setText(const QString &text)
|
||||
{
|
||||
m_text = text;
|
||||
}
|
||||
|
||||
TextStyle GraphicalObjectText::textStyle() const
|
||||
{
|
||||
return m_textStyle.value();
|
||||
}
|
||||
TextStyle &GraphicalObjectText::rTextStyle()
|
||||
{
|
||||
return m_textStyle.refValue();
|
||||
}
|
||||
void GraphicalObjectText::setTextStyle(const TextStyle &textStyle)
|
||||
{
|
||||
m_textStyle = textStyle;
|
||||
}
|
||||
|
||||
float GraphicalObjectText::xOffset() const
|
||||
{
|
||||
return m_offset.value().x();
|
||||
}
|
||||
void GraphicalObjectText::setXOffset(float xOffset)
|
||||
{
|
||||
QPointF temp = m_offset.value();
|
||||
temp.rx() = xOffset;
|
||||
m_offset = temp;
|
||||
}
|
||||
float GraphicalObjectText::yOffset() const
|
||||
{
|
||||
return m_offset.value().y();
|
||||
}
|
||||
void GraphicalObjectText::setYOffset(float yOffset)
|
||||
{
|
||||
QPointF temp = m_offset.value();
|
||||
temp.ry() = yOffset;
|
||||
m_offset = temp;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectText::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " text='" << m_text << "'"
|
||||
<< " origin =" << this->origin() // .x() << " , " << this->origin().y()
|
||||
<< " visibility=" << m_visibility;
|
||||
bool success = true;
|
||||
|
||||
// some checks:
|
||||
if (!m_graphicsLayer)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " no graphicsLayer";
|
||||
return false;
|
||||
}
|
||||
|
||||
BaseClass::create();
|
||||
|
||||
if (!m_textSymbol)
|
||||
m_textSymbol = new Esri::ArcGISRuntime::TextSymbol();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " text='" << m_text << "'"
|
||||
<< " success=" << success
|
||||
<< " drawOrder = " << m_graphic->zIndex();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GraphicalObjectText::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " text='" << m_text << "'"
|
||||
<< " origin =" << this->origin() // .x() << " , " << this->origin().y()
|
||||
<< " visibility=" << m_visibility
|
||||
<< " m_textStyle=" << m_textStyle
|
||||
<< " offset=" << m_offset;
|
||||
|
||||
// some checks:
|
||||
if (!this->isSinglePoint())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
if (m_visibility.value())
|
||||
{
|
||||
success = create(); // create only if visible
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! BaseClass::updateViewImpl())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateViewImpl failed";
|
||||
}
|
||||
|
||||
// FATAL_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
// << " text='" << m_text << "'"
|
||||
// << " changed1=" << m_text.changed()
|
||||
// << " changed2="<< m_textStyle.changed();
|
||||
|
||||
bool assignTextSymbol = false;
|
||||
|
||||
// || m_visibility.changed()) -> szenario: create invisible object and make it visible
|
||||
if (m_text.changed() || m_visibility.changed())
|
||||
{
|
||||
m_textSymbol->setText(m_text.value());
|
||||
assignTextSymbol = true;
|
||||
}
|
||||
|
||||
// TextStyle to TextSymbol@ESRI :
|
||||
if (m_textStyle.changed()
|
||||
|| m_scale.changed()
|
||||
|| m_visibility.changed() // -> szenario: create invisible object and make it visible
|
||||
)
|
||||
{
|
||||
const TextStyle &textStyle = m_textStyle.value();
|
||||
m_textSymbol->setColor(textStyle.textColor());
|
||||
|
||||
// High values can lead to coredump with 'SymbolDrawHelper::create_line_image FAILED, SkBitmap is NULL or empty' -> limit
|
||||
m_textSymbol->setSize(std::min(500.0f, textStyle.size() * m_scale.value()));
|
||||
m_textSymbol->setAngle(textStyle.angle());
|
||||
|
||||
m_textSymbol->setFontFamily(textStyle.fontFamily());
|
||||
|
||||
m_textSymbol->setFontWeight(textStyle.bold() ? Esri::ArcGISRuntime::FontWeight::Bold : Esri::ArcGISRuntime::FontWeight::Normal);
|
||||
m_textSymbol->setFontStyle(textStyle.italic() ? Esri::ArcGISRuntime::FontStyle::Italic : Esri::ArcGISRuntime::FontStyle::Normal);
|
||||
|
||||
Esri::ArcGISRuntime::FontDecoration fd = Esri::ArcGISRuntime::FontDecoration::None;
|
||||
if (textStyle.underline())
|
||||
fd = Esri::ArcGISRuntime::FontDecoration::Underline;
|
||||
if (textStyle.strikeThrough())
|
||||
fd = Esri::ArcGISRuntime::FontDecoration::LineThrough;
|
||||
m_textSymbol->setFontDecoration(fd);
|
||||
|
||||
float outlineWidth = 0;
|
||||
if (textStyle.textOutlineWidth() > 0)
|
||||
outlineWidth = textStyle.textOutlineWidth() * m_scale.value();
|
||||
if (m_textSymbol->size() <= 15) // small size -> outline reduces readability :-(
|
||||
outlineWidth = 0.0;
|
||||
m_textSymbol->setHaloWidth(outlineWidth);
|
||||
|
||||
if (textStyle.textOutlineColor().isValid())
|
||||
m_textSymbol->setHaloColor(textStyle.textOutlineColor());
|
||||
|
||||
// qWarning() << " haloWidth = " << m_textSymbol->haloWidth();
|
||||
|
||||
// m_textSymbol->setHaloColor(Qt::white);
|
||||
// m_textSymbol->setHaloWidth(outlineWidth);
|
||||
|
||||
// qWarning() << " fontSize " << textStyle.size() * m_scale.value()
|
||||
// <<" (textStyle.size() " << textStyle.size()
|
||||
// << " m_scale.value() " << m_scale.value() << ")";
|
||||
|
||||
// qWarning() << " outlineWidth " << outlineWidth
|
||||
// <<" (textStyle.textOutlineWidth() " << textStyle.textOutlineWidth()
|
||||
// << " m_scale.value() " << m_scale.value() << ")";
|
||||
|
||||
// if (textStyle.backgroundColor().isValid())
|
||||
m_textSymbol->setBackgroundColor(textStyle.backgroundColor());
|
||||
|
||||
// m_textSymbol->setAntiAliased(textStyle.antiAliased());
|
||||
|
||||
m_textSymbol->setHorizontalAlignment(convert(textStyle.horizontalAlignment()));
|
||||
m_textSymbol->setVerticalAlignment(convert(textStyle.verticalAlignment()));
|
||||
|
||||
assignTextSymbol = true;
|
||||
// : TextStyle to TextSymbol@ESRI
|
||||
}
|
||||
|
||||
// || m_visibility.changed()) -> szenario: create invisible object and make it visible
|
||||
if (m_offset.changed() || m_visibility.changed())
|
||||
{
|
||||
m_textSymbol->setOffsetX(m_offset.value().x());
|
||||
m_textSymbol->setOffsetY(m_offset.value().y());
|
||||
assignTextSymbol = true;
|
||||
}
|
||||
|
||||
if (assignTextSymbol)
|
||||
m_graphic->setSymbol(m_textSymbol);
|
||||
|
||||
|
||||
// check ChangedFlags:
|
||||
// Object is created and text is invisble due to scale (meterPerPixel)
|
||||
// map is zoomed in -> text should arise, but on m_visibility is changed:
|
||||
if (m_visibility.changed() || m_positions.changed())
|
||||
{
|
||||
const Point3D &origin = this->origin();
|
||||
m_graphic->setGeometry(Esri::ArcGISRuntime::Point(origin.x(),
|
||||
origin.y(),
|
||||
origin.z(),
|
||||
spatialReference()));
|
||||
success = addUpdateGraphic();
|
||||
} // m_visibility.changed() || m_positions.changed()
|
||||
|
||||
}
|
||||
else // if visible
|
||||
{
|
||||
BaseClass::updateViewImpl();
|
||||
success = addUpdateGraphic();
|
||||
}
|
||||
|
||||
if (m_logger.isTraceEnabled())
|
||||
{
|
||||
int drawOrder = -1;
|
||||
if (m_graphic)
|
||||
drawOrder = m_graphic->zIndex();
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " text='" << m_text << "'"
|
||||
<< " success=" << success
|
||||
<< " drawOrder = " << drawOrder;
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
// << " fontFamily='" << m_textSymbol->fontFamily() << "'"
|
||||
;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Esri::ArcGISRuntime::HorizontalAlignment GraphicalObjectText::convert(const HorizontalAlignment horizontalAlignment)
|
||||
{
|
||||
Esri::ArcGISRuntime::HorizontalAlignment esriAlignmenmt =
|
||||
Esri::ArcGISRuntime::HorizontalAlignment::Left;
|
||||
switch (horizontalAlignment)
|
||||
{
|
||||
case HorizontalAlignment::Left: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Left; break;
|
||||
case HorizontalAlignment::Center: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Center; break;
|
||||
case HorizontalAlignment::Right: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Right; break;
|
||||
case HorizontalAlignment::Justify: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Justify; break;
|
||||
} // switch
|
||||
|
||||
return esriAlignmenmt;
|
||||
}
|
||||
|
||||
Esri::ArcGISRuntime::VerticalAlignment GraphicalObjectText::convert(const VerticalAlignment verticalAlignment)
|
||||
{
|
||||
Esri::ArcGISRuntime::VerticalAlignment esriAlignmenmt =
|
||||
Esri::ArcGISRuntime::VerticalAlignment::Bottom;
|
||||
switch (verticalAlignment)
|
||||
{
|
||||
case VerticalAlignment::Bottom: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Bottom; break;
|
||||
case VerticalAlignment::Middle: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Middle; break;
|
||||
case VerticalAlignment::Top: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Top; break;
|
||||
case VerticalAlignment::BaseLine: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Baseline; break;
|
||||
} // switch
|
||||
return esriAlignmenmt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectText
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
#include <Map/text_style.h>
|
||||
#include <Map/situation_map_utils.h>
|
||||
#include <Common/simple_value.h>
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
// forward:
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class Graphic;
|
||||
class GraphicsOverlay;
|
||||
class PictureMarkerSymbol;
|
||||
class TextSymbol;
|
||||
|
||||
enum class HorizontalAlignment;
|
||||
enum class VerticalAlignment;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectText : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
GraphicalObjectText(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId
|
||||
);
|
||||
|
||||
~GraphicalObjectText();
|
||||
|
||||
QString toString() const override; // specialized
|
||||
|
||||
// Data access:
|
||||
QString text() const;
|
||||
void setText(const QString &text);
|
||||
|
||||
TextStyle textStyle() const;
|
||||
TextStyle &rTextStyle();
|
||||
void setTextStyle(const TextStyle &textStyle);
|
||||
|
||||
// Offset
|
||||
virtual float xOffset() const;
|
||||
virtual void setXOffset(float xOffset);
|
||||
virtual float yOffset() const;
|
||||
virtual void setYOffset(float yOffset);
|
||||
|
||||
static Esri::ArcGISRuntime::HorizontalAlignment convert(const HorizontalAlignment horizontalAlignment);
|
||||
static Esri::ArcGISRuntime::VerticalAlignment convert(const VerticalAlignment verticalAlignment);
|
||||
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_text.changed()
|
||||
|| m_textStyle.changed()
|
||||
|| m_offset.changed();
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_text.reset();
|
||||
m_textStyle.reset();
|
||||
m_offset.reset();
|
||||
}
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
Esri::ArcGISRuntime::TextSymbol *m_textSymbol = nullptr;
|
||||
|
||||
SimpleValue<QString> m_text; ///< to be displayed on map
|
||||
SimpleValue<TextStyle> m_textStyle;
|
||||
SimpleValue<QPointF> m_offset; ///< Offset (pixel).
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
// Forbid some overloaded methods without effects of this object;
|
||||
virtual PositionCont positions() const override
|
||||
{
|
||||
return PositionCont();
|
||||
}
|
||||
virtual void setPositions(const PositionCont &posCont) override
|
||||
{
|
||||
Q_UNUSED(posCont);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* StubGraphicalObject
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
|
||||
#include <Map/situation_map_types.h>
|
||||
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@class StubGraphicalObject stub_graphical_object.h
|
||||
The class \c StubGraphicalObject is used as substitution for a graphical object. It does
|
||||
nothing and the purpose is only to satisfy the interface of AbstractGraphicalObject.
|
||||
@see AbstractGraphicalObject
|
||||
*/
|
||||
class StubGraphicalObject : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
explicit StubGraphicalObject()
|
||||
: AbstractGraphicalObject(nullptr, nullptr, QString(), UniqueMapId())
|
||||
{
|
||||
}
|
||||
|
||||
~StubGraphicalObject() = default;
|
||||
|
||||
StubGraphicalObject(const StubGraphicalObject &other) = delete;
|
||||
StubGraphicalObject &operator=(StubGraphicalObject &other) = delete;
|
||||
|
||||
protected:
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool updateViewImpl() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool create() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,622 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* TacticalAppearance
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "tactical_appearance.h"
|
||||
#include <MapImpl/map_impl.h>
|
||||
#include <Symbology/symbol_dictionary.h>
|
||||
#include <Symbology/sidc_builder_base.h>
|
||||
#include <Symbology/sidc_codec.h>
|
||||
#include <GraphicalObjects/graphical_object_picture_marker.h>
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
#include <Common/simple_value.h>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/Map.h>
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/PolygonBuilder.h>
|
||||
#include <arcgis/PolylineBuilder.h>
|
||||
#include <arcgis/MultipointBuilder.h>
|
||||
|
||||
// Qt
|
||||
#include <QElapsedTimer>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
class TacticalAppearance::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
~Private() = default;
|
||||
|
||||
// ESRI data:
|
||||
MapImpl *m_mapImpl = nullptr;
|
||||
QString m_logicalLayerName;
|
||||
|
||||
Esri::ArcGISRuntime::GraphicsOverlay *m_graphicOverlayTactical = nullptr;
|
||||
AdvancedSymbology::SymbolDictionary *m_dictionary = nullptr;
|
||||
AdvancedSymbology::SymbolResultWatcher m_symbolResultWatcher;
|
||||
|
||||
// OWN data:
|
||||
SimpleValue<QString> m_uniqueDesignation;
|
||||
SimpleValue<SymbolData> m_symbol;
|
||||
|
||||
|
||||
AdvancedSymbology::SymbolDataToRender m_symDataToRender;
|
||||
GraphicalObjectPictureMarker *m_pictureMarker = nullptr;
|
||||
|
||||
}; // class TacticalAppearance::Private
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
TacticalAppearance::TacticalAppearance(MapImpl *mapImpl,
|
||||
const QString &logicalLayerName,
|
||||
const QString &debugInfo,
|
||||
const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(mapImpl->getEsriGeoView(), nullptr, debugInfo, uniqueMapId),
|
||||
m_logger(getLogger("TacticalAppearance")),
|
||||
d(new Private)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< ", logicalLayerName='" << logicalLayerName << "'";
|
||||
|
||||
d->m_symDataToRender.sizeL = 100;
|
||||
d->m_mapImpl = mapImpl;
|
||||
d->m_logicalLayerName = logicalLayerName;
|
||||
|
||||
if (!m_graphicsLayer && d->m_mapImpl)
|
||||
m_graphicsLayer = d->m_mapImpl->getGraphicsLayer(d->m_logicalLayerName);
|
||||
|
||||
if (!m_graphicsLayer)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " getGraphicsLayer failed";
|
||||
}
|
||||
|
||||
if (d->m_mapImpl)
|
||||
d->m_dictionary = &(d->m_mapImpl->symbolDictionary());
|
||||
|
||||
|
||||
// lambda:
|
||||
// m_symbolResultWatcher is canceled on destruction.
|
||||
// So it`s safe that no signal will be fired afterwards.
|
||||
// To avoid CLang warnings use m_symbolResultWatcher as context (3rd para), although it´s not intended.
|
||||
// Better idea?
|
||||
QObject::connect(&d->m_symbolResultWatcher, &AdvancedSymbology::SymbolResultWatcher::resultReady, &d->m_symbolResultWatcher, [this]()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " resultReady...";
|
||||
|
||||
QSharedPointer<AdvancedSymbology::SymbolResult> symResult = d->m_symbolResultWatcher.symbolResult();
|
||||
if (! symResult)
|
||||
return; // should NEVER happen! (Which object should have triggered the signal???)
|
||||
|
||||
if (d->m_pictureMarker)
|
||||
{
|
||||
d->m_pictureMarker->setImage(symResult->symbolImage().image());
|
||||
d->m_pictureMarker->updateView();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
TacticalAppearance::~TacticalAppearance()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
// abort pending call to SymbolDictionary::findSymbol:
|
||||
d->m_symbolResultWatcher.cancel();
|
||||
|
||||
delete d->m_pictureMarker;
|
||||
d->m_pictureMarker = nullptr;
|
||||
|
||||
removeGraphicFromGraphicOverlayTactical();
|
||||
|
||||
delete d;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void TacticalAppearance::removeGraphicFromGraphicOverlayTactical()
|
||||
{
|
||||
if (m_logger.isTraceEnabled())
|
||||
{
|
||||
if (m_graphic)
|
||||
{
|
||||
Esri::ArcGISRuntime::GraphicsOverlay *gOverlay = m_graphic->graphicsOverlay();
|
||||
if (gOverlay)
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START debugInfo='" << m_debugInfo << "'" << " name = '" << gOverlay->overlayId() << "'";
|
||||
}
|
||||
}
|
||||
|
||||
if (m_graphic && d->m_graphicOverlayTactical && d->m_graphicOverlayTactical->graphics())
|
||||
d->m_graphicOverlayTactical->graphics()->removeOne(m_graphic);
|
||||
|
||||
delete m_graphic;
|
||||
m_graphic = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool TacticalAppearance::useDictionaryRenderMode(const AdvancedSymbology::GeometryType &geomType) const
|
||||
{
|
||||
bool usePictureMarker = isSinglePoint() && (AdvancedSymbology::GeometryType::Point == geomType || AdvancedSymbology::GeometryType::Undefined == geomType);
|
||||
return !usePictureMarker || symbol().useAlwaysDictionaryRenderer;
|
||||
} // bool TacticalAppearance::useDictionaryRenderMode() const
|
||||
|
||||
|
||||
bool TacticalAppearance::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_visibility = " << m_visibility;
|
||||
|
||||
bool success = true;
|
||||
|
||||
//
|
||||
// Prepare / create :
|
||||
//
|
||||
// a) singlePoint / exactly one coordinate -> use pictureMarker
|
||||
// or
|
||||
// b) multiPoint / more than one coordinate -> m_graphic / DictionaryRenderer
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* This assumption doesn't work any more because some polyline and polygon symbols will have only one
|
||||
* anchor point and the real geometry is defined by additional attributes like radius, with, length ...
|
||||
*
|
||||
* JT 2016/12/20
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
if (m_graphicsLayer && m_visibility.value())
|
||||
{
|
||||
const SymbolData &symbolData_ref = d->m_symbol.value();
|
||||
const QString &baseSymbolCode = AdvancedSymbology::SidcBuilderBase::concreteSidcToBaseSymbolCode(symbolData_ref.sidc);
|
||||
const AdvancedSymbology::SymbolProperties &symbolProperties = d->m_dictionary->symbolProperties(baseSymbolCode);
|
||||
AdvancedSymbology::GeometryType geomType = symbolProperties.geometryType();
|
||||
|
||||
if (useDictionaryRenderMode(geomType))
|
||||
{
|
||||
if (!d->m_graphicOverlayTactical)
|
||||
d->m_graphicOverlayTactical = d->m_mapImpl->getGraphicsLayerDict(d->m_logicalLayerName);
|
||||
|
||||
if (!d->m_graphicOverlayTactical)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " getGraphicsLayerDict failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_graphic)
|
||||
{
|
||||
m_graphic = new Esri::ArcGISRuntime::Graphic();
|
||||
m_graphic->setObjectName(m_debugInfo);
|
||||
m_graphic->setZIndex(m_drawOrder.value());
|
||||
|
||||
// use attributeModel to store application obj id (SimWorld) at graphic
|
||||
Esri::ArcGISRuntime::AttributeListModel *attLisModel = m_graphic->attributes();
|
||||
if (attLisModel)
|
||||
attLisModel->insertAttribute(QLatin1String(SituationMap::UniqueMapIdAttribute), m_uniqueMapId);
|
||||
else
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no AttributeListModel, debugInfo='" << m_debugInfo << "'" << " uniqueMapId=" << m_uniqueMapId;
|
||||
|
||||
// Adding an empty graphic leads to Segmentation fault.
|
||||
// (in Esri_runtimecore::Map_renderer::Dictionary_renderer::derive_geometry)
|
||||
|
||||
bool successGraphic = addUpdateGraphic(); // CHECK
|
||||
if (!successGraphic)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " addUpdateGraphic failed, debugInfo='" << m_debugInfo << "'" << " uniqueMapId=" << m_uniqueMapId;
|
||||
|
||||
} // if (!m_graphic)
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_graphic is needless now:
|
||||
removeGraphicFromGraphicOverlayTactical();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// : Prepare / create
|
||||
|
||||
bool positionsEmpty = m_positions.value().isEmpty();
|
||||
if (positionsEmpty)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " positions empty";
|
||||
|
||||
success = success && !positionsEmpty;
|
||||
|
||||
if (!success)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " create failed";
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
return success;
|
||||
}
|
||||
|
||||
void TacticalAppearance::createPictureMarker()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
if (!d->m_pictureMarker && d->m_mapImpl)
|
||||
{
|
||||
d->m_pictureMarker = new GraphicalObjectPictureMarker(d->m_mapImpl->getEsriGeoView()
|
||||
, m_graphicsLayer
|
||||
, m_debugInfo + QLatin1String("#PicMarkTacticalAppearance")
|
||||
, m_uniqueMapId);
|
||||
}
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void TacticalAppearance::removePictureMarker()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
delete d->m_pictureMarker;
|
||||
d->m_pictureMarker = nullptr;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
QString TacticalAppearance::uniqueDesignation() const
|
||||
{
|
||||
return d->m_uniqueDesignation.value();
|
||||
}
|
||||
void TacticalAppearance::setUniqueDesignation(const QString &uniqueDesignation)
|
||||
{
|
||||
d->m_uniqueDesignation = uniqueDesignation;
|
||||
}
|
||||
|
||||
SymbolImage TacticalAppearance::symbolImage() const
|
||||
{
|
||||
SymbolImage symImage;
|
||||
if (d->m_pictureMarker)
|
||||
{
|
||||
symImage.setImage(d->m_pictureMarker->image());
|
||||
symImage.setValid(!symImage.image().isNull());
|
||||
}
|
||||
return symImage;
|
||||
}
|
||||
|
||||
|
||||
SymbolData TacticalAppearance::symbol() const
|
||||
{
|
||||
return d->m_symbol.value();
|
||||
}
|
||||
|
||||
void TacticalAppearance::setSymbol(const SymbolData &symbol)
|
||||
{
|
||||
d->m_symbol = symbol;
|
||||
}
|
||||
|
||||
bool TacticalAppearance::changed()
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| d->m_uniqueDesignation.changed()
|
||||
|| d->m_symbol.changed();
|
||||
}
|
||||
void TacticalAppearance::resetChanged()
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
d->m_uniqueDesignation.reset();
|
||||
d->m_symbol.reset();
|
||||
}
|
||||
|
||||
Esri::ArcGISRuntime::Geometry TacticalAppearance::getGraphicGeometry() const
|
||||
{
|
||||
if (d->m_pictureMarker) return d->m_pictureMarker->getGraphicGeometry();
|
||||
if (m_graphic) return m_graphic->geometry();
|
||||
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Geometry is undefined";
|
||||
|
||||
return Esri::ArcGISRuntime::Geometry();
|
||||
} // Esri::ArcGISRuntime::Geometry TacticalAppearance::getGraphicGeometry() const
|
||||
|
||||
|
||||
bool TacticalAppearance::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " symbol='" << d->m_symbol.value().sidc << "'"
|
||||
<< " visibility=" << m_visibility
|
||||
<< " selected=" << m_selected
|
||||
<< " origin=" << this->origin()
|
||||
<< " scale=" << m_scale.value();
|
||||
|
||||
const SymbolData &symbolData_ref = d->m_symbol.value();
|
||||
const QString &baseSymbolCode = AdvancedSymbology::SidcBuilderBase::concreteSidcToBaseSymbolCode(symbolData_ref.sidc);
|
||||
const AdvancedSymbology::SymbolProperties &symbolProperties = d->m_dictionary->symbolProperties(baseSymbolCode);
|
||||
AdvancedSymbology::GeometryType geomType = symbolProperties.geometryType();
|
||||
|
||||
if (geomType == AdvancedSymbology::GeometryType::Undefined)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " GeometryType::Undefined, symbolProperties failed!?!";
|
||||
return false;
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< ", geomType=" << geomType
|
||||
<< ", useDictionaryRenderMode(geomType)=" << useDictionaryRenderMode(geomType);
|
||||
|
||||
bool success = create();
|
||||
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (useDictionaryRenderMode(geomType))
|
||||
{
|
||||
// real work:
|
||||
if (m_positions.changed() || d->m_symbol.changed() || m_visibility.changed())
|
||||
{
|
||||
auto buildPointClusterGeometry = [this]() -> Esri::ArcGISRuntime::Geometry
|
||||
{
|
||||
QSharedPointer<Esri::ArcGISRuntime::MultipointBuilder> builder(new Esri::ArcGISRuntime::MultipointBuilder(spatialReference()));
|
||||
Esri::ArcGISRuntime::PointCollection points(spatialReference());
|
||||
const auto posCont = positions();
|
||||
for (const auto &pos : posCont)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " addPoint:" << pos.x() << " - " << pos.y();
|
||||
points.addPoint(pos.x(), pos.y());
|
||||
}
|
||||
builder->setPoints(&points);
|
||||
return builder->toGeometry();
|
||||
}; // buildPointClusterGeometry
|
||||
|
||||
Esri::ArcGISRuntime::Geometry geom;
|
||||
|
||||
switch (geomType)
|
||||
{
|
||||
case AdvancedSymbology::GeometryType::Undefined : break;
|
||||
|
||||
case AdvancedSymbology::GeometryType::Point :
|
||||
case AdvancedSymbology::GeometryType::Polyline :
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " m_positions.count()=" << m_positions.value().count();
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* If a PolylineBuilder is used here to create symbol geometry the construction appropriate symbol standard (MIL2525C / MIL2525D / App6)
|
||||
* will not be done and the symbol is always a simple polyline. Using MultipointBuilder to build symbol geometry the result is based on
|
||||
* underlying symbol standard.
|
||||
* 2016/12/9 JT
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
geom = buildPointClusterGeometry();
|
||||
|
||||
} break;
|
||||
|
||||
case AdvancedSymbology::GeometryType::Polygon :
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " m_positions.count()=" << m_positions.value().count();
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* Some symbols have polygon geometry and could have only one or two positions. In case of less than 3 positions do the same as for
|
||||
* polylines and use MultipointBuilder to create the symbol geometry. In other case use PolygonBuilder.
|
||||
* 2016/12/13 JT
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
if (positions().size() > 2)
|
||||
{
|
||||
QSharedPointer<Esri::ArcGISRuntime::PolygonBuilder> builder(new Esri::ArcGISRuntime::PolygonBuilder(spatialReference()));
|
||||
const auto posCont = positions();
|
||||
for (const auto &pos : posCont)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " addPoint:" << pos.x() << " - " << pos.y();
|
||||
builder->addPoint(pos.x(), pos.y());
|
||||
}
|
||||
geom = builder->toGeometry();
|
||||
}
|
||||
else
|
||||
geom = buildPointClusterGeometry();
|
||||
|
||||
} break;
|
||||
|
||||
} // switch
|
||||
|
||||
if (geom.isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " Geometry NOT OK -> fallback symbol" << " (geometryType was " << geomType << ")";
|
||||
createPictureMarker();
|
||||
d->m_pictureMarker->setDebugInfo(m_debugInfo + QLatin1String("#fallback"));
|
||||
|
||||
int size = symbolData_ref.size;
|
||||
if (size < 10) size = 10;
|
||||
if (size > 100) size = 100;
|
||||
|
||||
d->m_pictureMarker->setMarkerSymbol(MarkerSymbolType::Diamond, size, symbolData_ref.color);
|
||||
d->m_pictureMarker->setOrigin(this->origin());
|
||||
d->m_pictureMarker->setDrawOrder(m_drawOrder.value());
|
||||
d->m_pictureMarker->updateView();
|
||||
success = false;
|
||||
}
|
||||
else // geom is not empty
|
||||
{
|
||||
removePictureMarker();
|
||||
|
||||
if (m_graphic)
|
||||
{
|
||||
success = true;
|
||||
|
||||
// move to graphic:
|
||||
m_graphic->setGeometry(geom);
|
||||
|
||||
// prepare rawAttributes for DictionaryRenderer:
|
||||
|
||||
QVariantMap rawAttributes = d->m_symbol.value().attributeMap;
|
||||
|
||||
// build from scratch to honor removed attributes:
|
||||
// (Otherwise the will remain wrongly)
|
||||
|
||||
rawAttributes[QLatin1String(SituationMap::UniqueMapIdAttribute)] = m_uniqueMapId;
|
||||
rawAttributes[QLatin1String(SituationMap::IsPickableAttribute)] = m_pickable.value(); // set pickable attribute JT 2016/12/21
|
||||
|
||||
rawAttributes[QLatin1String("_type")] = QLatin1String("position_report");
|
||||
rawAttributes[QLatin1String("_action")] = QLatin1String("update");
|
||||
rawAttributes[QLatin1String("sidc")] = AdvancedSymbology::SidcCodec::decodeRawSidc(d->m_symbol.value().sidc); // in case of MIL2525
|
||||
rawAttributes[QLatin1String("sic")] = AdvancedSymbology::SidcCodec::decodeRawSidc(d->m_symbol.value().sidc); // in case of APP6
|
||||
|
||||
Esri::ArcGISRuntime::AttributeListModel * attributeModel = m_graphic->attributes();
|
||||
if (attributeModel)
|
||||
attributeModel->setAttributesMap(rawAttributes);
|
||||
else
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " no AttributeListModel";
|
||||
|
||||
|
||||
|
||||
// // prepare rawAttributes for DictionaryRenderer:
|
||||
// QVariantMap rawAttributes = d->m_symbol.value().attributeMap;
|
||||
|
||||
// rawAttributes[QLatin1String(SituationMap::IsPickableAttribute)] = m_pickable.value(); // set pickable attribute JT 2016/12/21
|
||||
|
||||
// rawAttributes[QLatin1String("_type")] = QLatin1String("position_report");
|
||||
// rawAttributes[QLatin1String("_action")] = QLatin1String("update");
|
||||
// rawAttributes[QLatin1String("sidc")] = AdvancedSymbology::SidcCodec::decodeRawSidc(d->m_symbol.value().sidc); // in case of MIL2525
|
||||
// rawAttributes[QLatin1String("sic")] = AdvancedSymbology::SidcCodec::decodeRawSidc(d->m_symbol.value().sidc); // in case of APP6
|
||||
// // move to graphic:
|
||||
// m_graphic->setGeometry(geom);
|
||||
|
||||
// /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// * Replace:
|
||||
// * m_graphic->attributes()->setAttributesMap(rawAttributes);
|
||||
// *
|
||||
// * because it doesn't work anymore in ArcGISRuntime V100.2
|
||||
// * JT, 2018/01/24
|
||||
// * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
// Esri::ArcGISRuntime::AttributeListModel * attributeModel = m_graphic->attributes();
|
||||
// if (attributeModel)
|
||||
// {
|
||||
// if (!attributeModel->isEmpty())
|
||||
// {
|
||||
// for (auto it = rawAttributes.cbegin(); it != rawAttributes.cend(); ++it)
|
||||
// {
|
||||
// const QString &attrKey = it.key();
|
||||
// if (attributeModel->containsAttribute(attrKey))
|
||||
// {
|
||||
// attributeModel->replaceAttribute(attrKey, rawAttributes[attrKey]);
|
||||
// continue;
|
||||
// }
|
||||
// attributeModel->insertAttribute(attrKey, rawAttributes[attrKey]);
|
||||
// }
|
||||
// }
|
||||
// else attributeModel->setAttributesMap(rawAttributes);
|
||||
// }
|
||||
|
||||
// 2021-08, N. Thoden
|
||||
// While switching back to the behaviour that one logical layer has
|
||||
// 1st getGraphicsLayer and 2nd getGraphicsLayerDict [GUEZE-496],
|
||||
// the tactical appereance of DangerArea and similar disappears.
|
||||
// Reason: m_graphicsLayer and m_graphicOverlayTactical are different now!
|
||||
// It seems like that in former versions (< V100.8) the graphic could
|
||||
// be added to more than one Esri layer.
|
||||
// Now (V100.8) adding to a second layer fails.
|
||||
// But we can remove the m_graphic from the default m_graphicsLayer
|
||||
// before adding the the desired one: m_graphicOverlayTactical
|
||||
if (m_graphicsLayer->graphics()->contains(m_graphic))
|
||||
m_graphicsLayer->graphics()->removeOne(m_graphic);
|
||||
|
||||
// add to graphicOverlayTactical:
|
||||
if (! d->m_graphicOverlayTactical->graphics()->contains(m_graphic))
|
||||
d->m_graphicOverlayTactical->graphics()->append(m_graphic);
|
||||
|
||||
bool successGraphic = d->m_graphicOverlayTactical->graphics()->contains(m_graphic);
|
||||
if (!successGraphic)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_graphic not added to m_graphicOverlayTactical";
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " no m_graphic";
|
||||
// success = false;
|
||||
success = true; // if the DictionaryRenderer is used, m_graphic is null and that is ok.
|
||||
}
|
||||
|
||||
} // if (geom.isEmpty())
|
||||
}
|
||||
|
||||
}
|
||||
else // !useDictionaryRenderMode(geomType)
|
||||
{
|
||||
createPictureMarker();
|
||||
d->m_pictureMarker->setOrigin(this->origin());
|
||||
|
||||
// real work:
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " update geometry";
|
||||
|
||||
|
||||
if (d->m_symbol.changed() || m_scale.changed())
|
||||
{
|
||||
if (d->m_dictionary)
|
||||
{
|
||||
int widthPixel = SituationMap::SymbolSizeLdefault;
|
||||
widthPixel *= symbolData_ref.size * m_scale.value();
|
||||
|
||||
d->m_symDataToRender.sidc = symbolData_ref.sidc;
|
||||
d->m_symDataToRender.fillColor = symbolData_ref.color;
|
||||
d->m_symDataToRender.fillColorReplace = true;
|
||||
d->m_symDataToRender.sizeL = widthPixel;
|
||||
|
||||
if (d->m_pictureMarker->image().isNull())
|
||||
d->m_pictureMarker->setImage(d->m_dictionary->temporaryImage(d->m_symDataToRender.sizeL));
|
||||
d->m_symbolResultWatcher.setSymbolResult(d->m_dictionary->fetchSymbol(d->m_symDataToRender));
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " visibility=" << m_visibility
|
||||
<< " no dictionary";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (d->m_pictureMarker)
|
||||
{
|
||||
d->m_pictureMarker->setDrawOrder(m_drawOrder.value());
|
||||
d->m_pictureMarker->setVisibility(m_visibility.value());
|
||||
d->m_pictureMarker->setSelected(m_selected.value());
|
||||
d->m_pictureMarker->setPickable(m_pickable.value());
|
||||
|
||||
success = success && d->m_pictureMarker->updateView();
|
||||
}
|
||||
} // else !useDictionaryRenderMode(geomType)
|
||||
|
||||
|
||||
if (d->m_pictureMarker)
|
||||
{
|
||||
d->m_pictureMarker->setOrigin(this->origin()); // to avoid incorrect number of positions..
|
||||
d->m_pictureMarker->setVisibility(m_visibility.value());
|
||||
d->m_pictureMarker->setSelected(m_selected.value());
|
||||
success = d->m_pictureMarker->updateView() && success;
|
||||
}
|
||||
|
||||
// in case of no pictureMarker:
|
||||
if (m_graphic)
|
||||
{
|
||||
m_graphic->setZIndex(m_drawOrder.value());
|
||||
m_graphic->setVisible(m_visibility.value());
|
||||
m_graphic->setSelected(m_selected.value());
|
||||
}
|
||||
|
||||
// reset flags
|
||||
d->m_symbol.reset();
|
||||
|
||||
if (!success)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " failure, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success = " << success
|
||||
<< " visibility=" << m_visibility;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* TacticalAppearance
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
// forward:
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
// forward:
|
||||
class MapImpl;
|
||||
class GraphicalObjectPictureMarker;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The TacticalAppearance class displays sidcs.
|
||||
* To do so, the number of coordinate lead to use
|
||||
* - the GraphicalObjectPictureMarker (exactly one coordinate)
|
||||
* or
|
||||
* - the Message (more than one coordinate)
|
||||
*
|
||||
* Use cases:
|
||||
* - Participant: sidc with #coords == 1, TacticalAppearance should get exactly one coordinate.
|
||||
* (GraphicalObjectPictureMarker on ESRI::GraphicsLayer is used)
|
||||
* - Tactical display of a Building: sidc #coords >= 2, TacticalAppearance should get list of positions.
|
||||
* (Message on ESRI::MessageGroupLayer is used)
|
||||
* - (Tactical) PreviewIcon of a Building: sidc #coords == 1, TacticalAppearance should get exactly one coordinate.
|
||||
* (GraphicalObjectPictureMarker on ESRI::GraphicsLayer is used)
|
||||
* - Tactical symbols of plan editor
|
||||
*
|
||||
* In case of GraphicalObjectPictureMarker the image creation is done by AdvancedSymbology::SymbolDictionary::symbolImageBySidcExtended().
|
||||
*/
|
||||
class SITUATIONMAP_EXPORT TacticalAppearance : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief TacticalAppearance
|
||||
* @param mapImpl map to be used.
|
||||
* @param logicalLayerName logical layer name to be used.
|
||||
* @param debugInfo debugInfo to be used
|
||||
* @param uniqueMapId uniqueMapId to be used. (Optional to fulfill rubberband requirements)
|
||||
*/
|
||||
TacticalAppearance(MapImpl *mapImpl,
|
||||
const QString &logicalLayerName,
|
||||
const QString &debugInfo,
|
||||
const UniqueMapId &uniqueMapId = INVALID_MAP_ID);
|
||||
|
||||
TacticalAppearance(const TacticalAppearance &other) = delete;
|
||||
TacticalAppearance &operator=(TacticalAppearance &other) = delete;
|
||||
|
||||
virtual ~TacticalAppearance();
|
||||
|
||||
|
||||
SymbolData symbol() const;
|
||||
void setSymbol(const SymbolData &symbol);
|
||||
|
||||
QString uniqueDesignation() const;
|
||||
void setUniqueDesignation(const QString &uniqueDesignation);
|
||||
|
||||
|
||||
SymbolImage symbolImage() const;
|
||||
|
||||
Esri::ArcGISRuntime::Geometry getGraphicGeometry() const override;
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
virtual bool create() override;
|
||||
virtual void createPictureMarker();
|
||||
virtual void removePictureMarker();
|
||||
|
||||
void removeGraphicFromGraphicOverlayTactical();
|
||||
|
||||
bool changed() override;
|
||||
void resetChanged() override;
|
||||
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
bool useDictionaryRenderMode(const AdvancedSymbology::GeometryType &geomType) const;
|
||||
|
||||
// logical
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
class Private;
|
||||
/**
|
||||
* The private d-pointer to not break BC when changing internals of this class
|
||||
*/
|
||||
Private *d = nullptr;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,603 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Handles aggregation of participant layer
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** 16.08.2017, JT : first edition
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "layer_aggregation_widget.h"
|
||||
|
||||
#include <Map/map.h>
|
||||
|
||||
#include <Map/layer_parameter.h>
|
||||
|
||||
#include <LtsWidgets/lts_message_dialog.h>
|
||||
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QRegularExpression>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
#include <QtWidgets/QCheckBox>
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QPushButton>
|
||||
#include <QtWidgets/QGridLayout>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
using namespace SituationMap;
|
||||
|
||||
|
||||
struct AggregationData
|
||||
{
|
||||
QString layerName;
|
||||
QString displayName;
|
||||
double minScale = LayerParameter::UNDEFINED_SCALE; // 0
|
||||
double maxScale = LayerParameter::UNDEFINED_SCALE; // 0
|
||||
bool minScaleValid = false;
|
||||
bool maxScaleValid = false;
|
||||
|
||||
}; // AggregationData
|
||||
|
||||
|
||||
struct AggregationWidgets
|
||||
{
|
||||
QCheckBox *cbMinScaleValid = nullptr;
|
||||
QPushButton *pbMinScale = nullptr;
|
||||
QPushButton *pbMinScaleTo = nullptr;
|
||||
|
||||
QCheckBox *cbMaxScaleValid = nullptr;
|
||||
QPushButton *pbMaxScale = nullptr;
|
||||
QPushButton *pbMaxScaleTo = nullptr;
|
||||
|
||||
QPushButton *pbReset = nullptr;
|
||||
QPushButton *pbApply = nullptr;
|
||||
};
|
||||
|
||||
|
||||
class LayerAggregationWidget::InternalData
|
||||
{
|
||||
public:
|
||||
|
||||
Map *m_map = nullptr;
|
||||
bool m_valid = false;
|
||||
|
||||
LayerType m_layerType;
|
||||
|
||||
QVector<AggregationData> m_aggregationList;
|
||||
QMap<QString, AggregationData> m_aggregationReset;
|
||||
QMap<QString, AggregationWidgets> m_aggregationWidgets;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
|
||||
explicit InternalData(Map *map,LayerType layerType)
|
||||
: m_map(map)
|
||||
, m_layerType(layerType)
|
||||
, m_logger(getLogger("LayerAggregation"))
|
||||
{}
|
||||
|
||||
}; // LayerAggregationWidget::InternalData
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
QString LayerAggregationWidget::scaleText(double scale)
|
||||
{
|
||||
return (scale >= 1) ? QStringLiteral("1:%1").arg(int(scale)) : tr("undefined");
|
||||
} // QString LayerAggregationWidget::scaleText(double scale)
|
||||
|
||||
|
||||
void LayerAggregationWidget::setMinScaleLabel(QPushButton *btn, double scale)
|
||||
{
|
||||
btn->setText(tr("Min. Scale from Map\n%1").arg(scaleText(scale)));
|
||||
} // void LayerAggregationWidget::setMinScaleLabel(QPushButton * btn, double scale)
|
||||
|
||||
|
||||
void LayerAggregationWidget::setMaxScaleLabel(QPushButton *btn, double scale)
|
||||
{
|
||||
btn->setText(tr("Max. Scale from Map\n%1").arg(scaleText(scale)));
|
||||
} // void LayerAggregationWidget::setMaxScaleLabel(QPushButton * btn, double scale)
|
||||
|
||||
|
||||
LayerAggregationWidget::LayerAggregationWidget(Map *map, LayerType layerType, const QRegularExpression &nameCondition, QWidget *parent)
|
||||
: QWidget(parent), m_internal(new InternalData(map,layerType))
|
||||
{
|
||||
if (!nameCondition.isValid())
|
||||
{
|
||||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " Illegal regular expression in nameCondition.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (map == nullptr)
|
||||
{
|
||||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " Invalid situation map, cannot initialize dialog";
|
||||
return;
|
||||
}
|
||||
|
||||
QGridLayout *layout = new QGridLayout(this);
|
||||
|
||||
layout->setSpacing(10);
|
||||
|
||||
const LayerFactory &layerFactory = map->layerFactory();
|
||||
|
||||
QIcon scaleToIcon(QStringLiteral("icon:search.svg"));
|
||||
|
||||
const auto ln = layerFactory.layernames(layerType);
|
||||
for (const QString &layerName : ln)
|
||||
{
|
||||
if (nameCondition.match(layerName).hasMatch())
|
||||
{
|
||||
// get layer
|
||||
AggregationData data;
|
||||
AggregationWidgets &widgets = m_internal->m_aggregationWidgets[layerName];
|
||||
const LayerParameter &layerPara = layerFactory.layerParameter(layerName);
|
||||
|
||||
data.layerName = layerName;
|
||||
data.minScale = layerPara.minScale;
|
||||
data.maxScale = layerPara.maxScale;
|
||||
data.minScaleValid = layerPara.minScaleValid();
|
||||
data.maxScaleValid = layerPara.maxScaleValid();
|
||||
data.displayName = layerPara.displayName;
|
||||
|
||||
int row = m_internal->m_aggregationList.size();
|
||||
|
||||
QLabel *laName = new QLabel(layerPara.displayName.isEmpty() ? layerName : layerPara.displayName, this);
|
||||
widgets.pbReset = new QPushButton(this);
|
||||
widgets.pbApply = new QPushButton(this);
|
||||
|
||||
widgets.pbReset->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
widgets.pbApply->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
|
||||
QHBoxLayout *minLayout = new QHBoxLayout();
|
||||
|
||||
minLayout->addSpacing(20);
|
||||
minLayout->addWidget(widgets.cbMinScaleValid = new QCheckBox(QString(), this));
|
||||
minLayout->addWidget(widgets.pbMinScale = new QPushButton(QString(), this));
|
||||
minLayout->addWidget(widgets.pbMinScaleTo = new QPushButton(scaleToIcon, QString(), this));
|
||||
minLayout->addSpacing(20);
|
||||
setMinScaleLabel(widgets.pbMinScale, layerPara.minScale);
|
||||
|
||||
QHBoxLayout *maxLayout = new QHBoxLayout();
|
||||
|
||||
maxLayout->addWidget(widgets.cbMaxScaleValid = new QCheckBox(QString(), this));
|
||||
maxLayout->addWidget(widgets.pbMaxScale = new QPushButton(QString(), this));
|
||||
maxLayout->addWidget(widgets.pbMaxScaleTo = new QPushButton(scaleToIcon, QString(), this));
|
||||
|
||||
maxLayout->addSpacing(20);
|
||||
|
||||
setMaxScaleLabel(widgets.pbMaxScale, layerPara.maxScale);
|
||||
|
||||
widgets.pbMinScale->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
widgets.pbMaxScale->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
|
||||
layout->addWidget(laName, row, 0);
|
||||
layout->addLayout(minLayout, row, 1);
|
||||
layout->addLayout(maxLayout, row, 2);
|
||||
layout->addWidget(widgets.pbReset, row, 3);
|
||||
layout->addWidget(widgets.pbApply, row, 4);
|
||||
|
||||
m_internal->m_aggregationList << data;
|
||||
m_internal->m_aggregationReset[layerName] = data;
|
||||
|
||||
widgets.pbMinScale->setProperty("row", row);
|
||||
widgets.pbMaxScale->setProperty("row", row);
|
||||
widgets.cbMinScaleValid->setProperty("row", row);
|
||||
widgets.cbMaxScaleValid->setProperty("row", row);
|
||||
widgets.pbMinScaleTo->setProperty("row", row);
|
||||
widgets.pbMaxScaleTo->setProperty("row", row);
|
||||
|
||||
widgets.pbReset->setProperty("row", row);
|
||||
widgets.pbApply->setProperty("row", row);
|
||||
|
||||
connect(widgets.cbMinScaleValid, &QCheckBox::clicked, this, &LayerAggregationWidget::onSetValid);
|
||||
connect(widgets.cbMaxScaleValid, &QCheckBox::clicked, this, &LayerAggregationWidget::onSetValid);
|
||||
connect(widgets.pbMinScale, &QPushButton::clicked, this, &LayerAggregationWidget::onGetMinScale);
|
||||
connect(widgets.pbMaxScale, &QPushButton::clicked, this, &LayerAggregationWidget::onGetMaxScale);
|
||||
connect(widgets.pbMinScaleTo, &QPushButton::clicked, this, &LayerAggregationWidget::onZoomTo);
|
||||
connect(widgets.pbMaxScaleTo, &QPushButton::clicked, this, &LayerAggregationWidget::onZoomTo);
|
||||
connect(widgets.pbReset, &QPushButton::clicked, this, &LayerAggregationWidget::onReset);
|
||||
connect(widgets.pbApply, &QPushButton::clicked, this, &LayerAggregationWidget::onApply);
|
||||
|
||||
widgets.cbMinScaleValid->setChecked(data.minScaleValid);
|
||||
widgets.cbMinScaleValid->setEnabled(data.minScaleValid);
|
||||
widgets.cbMaxScaleValid->setChecked(data.maxScaleValid);
|
||||
widgets.cbMaxScaleValid->setEnabled(data.maxScaleValid);
|
||||
|
||||
widgets.pbMinScaleTo->setEnabled(data.minScaleValid);
|
||||
widgets.pbMaxScaleTo->setEnabled(data.maxScaleValid);
|
||||
|
||||
widgets.pbReset->setEnabled(false);
|
||||
widgets.pbApply->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
retranslate();
|
||||
|
||||
if (m_internal->m_aggregationList.isEmpty())
|
||||
{
|
||||
QLabel *lbEmpty = new QLabel(tr("Can't find any layer"), this);
|
||||
QPixmap icon(QStringLiteral("icon:overlays.svg"));
|
||||
|
||||
lbEmpty->setWindowIcon(icon);
|
||||
layout->addWidget(lbEmpty, 0, 0, Qt::AlignCenter);
|
||||
return;
|
||||
}
|
||||
} // LayerAggregation::LayerAggregation( Map * map, QObject * parent )
|
||||
|
||||
|
||||
void LayerAggregationWidget::retranslate()
|
||||
{
|
||||
if (m_internal->m_map == nullptr)
|
||||
return;
|
||||
|
||||
const LayerFactory &layerFactory = m_internal->m_map->layerFactory();
|
||||
const auto ln = layerFactory.layernames(m_internal->m_layerType);
|
||||
for (const QString &layerName : ln)
|
||||
{
|
||||
if (!m_internal->m_aggregationWidgets.contains(layerName)) continue;
|
||||
|
||||
AggregationWidgets &widgets = m_internal->m_aggregationWidgets[layerName];
|
||||
|
||||
widgets.pbReset->setText(tr("Reset"));
|
||||
widgets.pbApply->setText(tr("Apply to Map"));
|
||||
|
||||
widgets.pbReset->setToolTip(tr("Restore initial scales of this level"));
|
||||
widgets.pbApply->setToolTip(tr("Set scales to corresponding map layer temporarily"));
|
||||
|
||||
widgets.cbMinScaleValid->setToolTip(tr("Activate or deactivate this scale value"));
|
||||
widgets.pbMinScale ->setToolTip(tr("Get current map scale of map view"));
|
||||
widgets.pbMinScaleTo ->setToolTip(tr("Set this scale value to map view as current scale"));
|
||||
|
||||
widgets.cbMaxScaleValid->setToolTip(tr("Activate or deactivate this scale value"));
|
||||
widgets.pbMaxScale ->setToolTip(tr("Get current map scale of map view"));
|
||||
widgets.pbMaxScaleTo ->setToolTip(tr("Set this scale value to map view as current scale"));
|
||||
}
|
||||
} // void LayerAggregationWidget::retranslate()
|
||||
|
||||
|
||||
LayerAggregationWidget::~LayerAggregationWidget()
|
||||
{
|
||||
delete m_internal; m_internal = nullptr;
|
||||
} // LayerAggregationWidget::~LayerAggregationWidget()
|
||||
|
||||
|
||||
void LayerAggregationWidget::onZoomTo()
|
||||
{
|
||||
QPushButton *senderButton = qobject_cast<QPushButton *>(sender());
|
||||
if (nullptr == senderButton) return;
|
||||
|
||||
int row = senderButton->property("row").toInt();
|
||||
|
||||
if ((row < 0) || (row >= m_internal->m_aggregationList.size()))
|
||||
return;
|
||||
|
||||
const AggregationData &data = m_internal->m_aggregationList[row];
|
||||
const AggregationWidgets &widgets = m_internal->m_aggregationWidgets[data.layerName];
|
||||
double scale = 0.0;
|
||||
|
||||
if ((widgets.pbMinScaleTo == senderButton) && (data.minScaleValid))
|
||||
scale = data.minScale;
|
||||
|
||||
if ((widgets.pbMaxScaleTo == senderButton) && (data.maxScaleValid))
|
||||
scale = data.maxScale;
|
||||
|
||||
if (scale < 1)
|
||||
return;
|
||||
|
||||
m_internal->m_map->setScale(scale);
|
||||
|
||||
} // void LayerAggregationWidget::onZoomTo()
|
||||
|
||||
|
||||
void LayerAggregationWidget::onGetMinScale()
|
||||
{
|
||||
QPushButton *senderButton = qobject_cast<QPushButton *>(sender());
|
||||
if (nullptr == senderButton) return;
|
||||
|
||||
int row = senderButton->property("row").toInt();
|
||||
|
||||
if ((row < 0) || (row >= m_internal->m_aggregationList.size()))
|
||||
return;
|
||||
|
||||
double scale = m_internal->m_map->scale();
|
||||
|
||||
AggregationData &data = m_internal->m_aggregationList[row];
|
||||
|
||||
if (data.maxScaleValid && (data.maxScale >= scale))
|
||||
{
|
||||
const QString &msg = tr("Chosen scale is too small");
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this, msg, tr("Layer Aggregation"));
|
||||
return;
|
||||
}
|
||||
|
||||
data.minScale = scale;
|
||||
data.minScaleValid = true;
|
||||
|
||||
setMinScaleLabel(senderButton, data.minScale);
|
||||
|
||||
const AggregationWidgets &widgets = m_internal->m_aggregationWidgets[data.layerName];
|
||||
widgets.cbMinScaleValid->setChecked(true);
|
||||
widgets.cbMinScaleValid->setEnabled(true);
|
||||
|
||||
widgets.pbMinScaleTo->setEnabled(true);
|
||||
|
||||
widgets.pbReset->setEnabled(true);
|
||||
widgets.pbApply->setEnabled(true);
|
||||
|
||||
emit changesMade();
|
||||
} // void LayerAggregationWidget::onGetMinScale()
|
||||
|
||||
|
||||
void LayerAggregationWidget::onGetMaxScale()
|
||||
{
|
||||
QPushButton *senderButton = qobject_cast<QPushButton *>(sender());
|
||||
if (nullptr == senderButton) return;
|
||||
|
||||
int row = senderButton->property("row").toInt();
|
||||
|
||||
if ((row < 0) || (row >= m_internal->m_aggregationList.size()))
|
||||
return;
|
||||
|
||||
double scale = m_internal->m_map->scale();
|
||||
|
||||
AggregationData &data = m_internal->m_aggregationList[row];
|
||||
|
||||
if (data.minScaleValid && (data.minScale <= scale))
|
||||
{
|
||||
const QString &msg = tr("Chosen scale is too large");
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this, msg, tr("Layer Aggregation"));
|
||||
return;
|
||||
}
|
||||
|
||||
data.maxScale = scale;
|
||||
data.maxScaleValid = true;
|
||||
|
||||
setMaxScaleLabel(senderButton, data.maxScale);
|
||||
|
||||
const AggregationWidgets &widgets = m_internal->m_aggregationWidgets[data.layerName];
|
||||
widgets.cbMaxScaleValid->setChecked(true);
|
||||
widgets.cbMaxScaleValid->setEnabled(true);
|
||||
|
||||
widgets.pbMaxScaleTo->setEnabled(true);
|
||||
|
||||
widgets.pbReset->setEnabled(true);
|
||||
widgets.pbApply->setEnabled(true);
|
||||
|
||||
emit changesMade();
|
||||
|
||||
} // void LayerAggregationWidget::onGetMaxScale()
|
||||
|
||||
|
||||
void LayerAggregationWidget::onSetValid(bool value)
|
||||
{
|
||||
QCheckBox *senderButton = qobject_cast<QCheckBox *>(sender());
|
||||
if (nullptr == senderButton) return;
|
||||
|
||||
int row = senderButton->property("row").toInt();
|
||||
|
||||
if ((row < 0) || (row >= m_internal->m_aggregationList.size()))
|
||||
return;
|
||||
|
||||
AggregationData &data = m_internal->m_aggregationList[row];
|
||||
const AggregationWidgets &widgets = m_internal->m_aggregationWidgets[data.layerName];
|
||||
|
||||
if (senderButton == widgets.cbMinScaleValid)
|
||||
{
|
||||
if (data.maxScaleValid && value && (data.maxScale >= data.minScale))
|
||||
{
|
||||
senderButton->setChecked(false);
|
||||
const QString &msg = tr("Minimum scale is too small");
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this, msg, tr("Layer Aggregation"));
|
||||
return;
|
||||
}
|
||||
data.minScaleValid = value;
|
||||
}
|
||||
|
||||
if (senderButton == widgets.cbMaxScaleValid)
|
||||
{
|
||||
if (data.minScaleValid && value && (data.minScale <= data.maxScale))
|
||||
{
|
||||
senderButton->setChecked(false);
|
||||
const QString &msg = tr("Maximum scale is too large");
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this, msg, tr("Layer Aggregation"));
|
||||
return;
|
||||
}
|
||||
data.maxScaleValid = value;
|
||||
}
|
||||
|
||||
widgets.pbMinScaleTo->setEnabled(data.minScaleValid);
|
||||
widgets.pbMaxScaleTo->setEnabled(data.maxScaleValid);
|
||||
|
||||
widgets.pbReset->setEnabled(true);
|
||||
widgets.pbApply->setEnabled(true);
|
||||
|
||||
emit changesMade();
|
||||
|
||||
} // void LayerAggregationWidget::onSetValid(bool value)
|
||||
|
||||
|
||||
void LayerAggregationWidget::doReset(int row)
|
||||
{
|
||||
if ((row < 0) || (row >= m_internal->m_aggregationList.size()))
|
||||
return;
|
||||
|
||||
AggregationData &data = m_internal->m_aggregationList[row];
|
||||
data = m_internal->m_aggregationReset[data.layerName];
|
||||
|
||||
const AggregationWidgets &widgets = m_internal->m_aggregationWidgets[data.layerName];
|
||||
|
||||
setMinScaleLabel(widgets.pbMinScale, data.minScale);
|
||||
setMaxScaleLabel(widgets.pbMaxScale, data.maxScale);
|
||||
|
||||
widgets.cbMinScaleValid->setChecked(data.minScaleValid);
|
||||
widgets.cbMinScaleValid->setEnabled(data.minScaleValid);
|
||||
|
||||
widgets.cbMaxScaleValid->setChecked(data.maxScaleValid);
|
||||
widgets.cbMaxScaleValid->setEnabled(data.maxScaleValid);
|
||||
|
||||
widgets.pbMinScaleTo->setEnabled(data.minScaleValid);
|
||||
widgets.pbMaxScaleTo->setEnabled(data.maxScaleValid);
|
||||
|
||||
widgets.pbReset->setEnabled(false);
|
||||
widgets.pbApply->setEnabled(!widgets.pbApply->isEnabled());
|
||||
|
||||
} // void doReset(SituationMap::Map * map, const AggregationData & data)
|
||||
|
||||
|
||||
void LayerAggregationWidget::onReset()
|
||||
{
|
||||
QObject *senderObj = sender();
|
||||
if (nullptr == senderObj) return;
|
||||
|
||||
int row = senderObj->property("row").toInt();
|
||||
|
||||
if ((row < 0) || (row >= m_internal->m_aggregationList.size()))
|
||||
return;
|
||||
|
||||
doReset(row);
|
||||
|
||||
} // void LayerAggregationWidget::onReset()
|
||||
|
||||
|
||||
static void doApply(SituationMap::Map *map, const AggregationData &data)
|
||||
{
|
||||
LayerFactory &layerFactory = map->layerFactory();
|
||||
LayerParameter layerParamter = layerFactory.layerParameter(data.layerName);
|
||||
|
||||
layerParamter.minScale = data.minScaleValid ? data.minScale : LayerParameter::UNDEFINED_SCALE; // 0;
|
||||
layerParamter.maxScale = data.maxScaleValid ? data.maxScale : LayerParameter::UNDEFINED_SCALE; // 0;
|
||||
|
||||
layerFactory.setLayerParameter(data.layerName, layerParamter);
|
||||
} // void doApply(SituationMap::Map * map, const AggregationData & data)
|
||||
|
||||
|
||||
void LayerAggregationWidget::onApply()
|
||||
{
|
||||
QObject *senderObj = sender();
|
||||
if (!senderObj)
|
||||
return;
|
||||
|
||||
int row = senderObj->property("row").toInt();
|
||||
|
||||
if ((row < 0) || (row >= m_internal->m_aggregationList.size()))
|
||||
return;
|
||||
|
||||
const AggregationData &data = m_internal->m_aggregationList[row];
|
||||
doApply(m_internal->m_map, data);
|
||||
|
||||
const AggregationWidgets &widgets = m_internal->m_aggregationWidgets[data.layerName];
|
||||
widgets.pbApply->setEnabled(false);
|
||||
|
||||
} // void LayerAggregationWidget::onApply()
|
||||
|
||||
|
||||
void LayerAggregationWidget::onApplyAll()
|
||||
{
|
||||
for (const AggregationData &data : qAsConst(m_internal->m_aggregationList))
|
||||
{
|
||||
const AggregationWidgets &widgets = m_internal->m_aggregationWidgets[data.layerName];
|
||||
if (widgets.pbApply->isEnabled())
|
||||
{
|
||||
doApply(m_internal->m_map, data);
|
||||
widgets.pbApply->setEnabled(false);
|
||||
}
|
||||
}
|
||||
} // void LayerAggregationWidget::onApplyAll()
|
||||
|
||||
|
||||
void LayerAggregationWidget::onResetAll()
|
||||
{
|
||||
for (const auto &aggData : qAsConst(m_internal->m_aggregationList))
|
||||
{
|
||||
const AggregationWidgets &widgets = m_internal->m_aggregationWidgets[aggData.layerName];
|
||||
|
||||
doReset(widgets.pbApply->property("row").toInt());
|
||||
doApply(m_internal->m_map, aggData);
|
||||
widgets.pbApply->setEnabled(false);
|
||||
}
|
||||
} // void LayerAggregationWidget::onResetAll()
|
||||
|
||||
|
||||
void LayerAggregationWidget::onSetDefaultScales()
|
||||
{
|
||||
if (m_internal->m_aggregationList.isEmpty())
|
||||
return;
|
||||
|
||||
// Calculate scale defaults here ...
|
||||
|
||||
double mapMinScaleSQRT = sqrt(m_internal->m_map->minScale());
|
||||
double mapMaxScaleSQRT = sqrt(m_internal->m_map->maxScale());
|
||||
|
||||
const int aggregationListCount = m_internal->m_aggregationList.size();
|
||||
double stepScaleSQRT = (mapMinScaleSQRT - mapMaxScaleSQRT) / static_cast<double>(aggregationListCount);
|
||||
|
||||
unsigned int step = 0;
|
||||
|
||||
for (auto &aggData : m_internal->m_aggregationList)
|
||||
{
|
||||
double dScaleSQRT = mapMaxScaleSQRT + (step * stepScaleSQRT);
|
||||
aggData.maxScaleValid = true;
|
||||
aggData.maxScale = dScaleSQRT * dScaleSQRT;
|
||||
|
||||
dScaleSQRT = mapMaxScaleSQRT + ((step + 1) * stepScaleSQRT);
|
||||
aggData.minScaleValid = true;
|
||||
aggData.minScale = dScaleSQRT * dScaleSQRT;
|
||||
|
||||
} // for
|
||||
|
||||
// disable start and end
|
||||
if (aggregationListCount > 0)
|
||||
{
|
||||
// front -> max
|
||||
m_internal->m_aggregationList.front().maxScale = 0;
|
||||
m_internal->m_aggregationList.front().maxScaleValid = false;
|
||||
// back -> min
|
||||
m_internal->m_aggregationList.back().minScale = 0;
|
||||
m_internal->m_aggregationList.back().minScaleValid = false;
|
||||
} // if
|
||||
|
||||
// update ui to m_aggregationList:
|
||||
for (const auto &aggData : qAsConst(m_internal->m_aggregationList))
|
||||
{
|
||||
const AggregationWidgets &widgets = m_internal->m_aggregationWidgets[aggData.layerName];
|
||||
widgets.cbMinScaleValid->setEnabled(aggData.minScaleValid);
|
||||
widgets.cbMinScaleValid->setChecked(aggData.minScaleValid);
|
||||
widgets.pbMinScaleTo->setEnabled(aggData.minScaleValid);
|
||||
|
||||
widgets.cbMaxScaleValid->setEnabled(aggData.maxScaleValid);
|
||||
widgets.cbMaxScaleValid->setChecked(aggData.maxScaleValid);
|
||||
widgets.pbMaxScaleTo->setEnabled(aggData.maxScaleValid);
|
||||
|
||||
widgets.pbApply->setEnabled(true);
|
||||
widgets.pbReset->setEnabled(true);
|
||||
|
||||
setMinScaleLabel(widgets.pbMinScale, aggData.minScale);
|
||||
setMaxScaleLabel(widgets.pbMaxScale, aggData.maxScale);
|
||||
} // for
|
||||
|
||||
emit changesMade();
|
||||
|
||||
} // void LayerAggregationWidget::onSetDefaultScales()
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Handles aggregation of participant layer
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** 16.08.2017, JT : first edition
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Map/layer_factory.h>
|
||||
|
||||
#include <situation_map_export.h>
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
|
||||
class QPushButton;
|
||||
class QRegularExpression;
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
class Map;
|
||||
|
||||
/**
|
||||
@class LayerAggregationWidget layer_aggregation_widget.h
|
||||
@brief Class to handle aggregation of participant layer
|
||||
*/
|
||||
|
||||
class SITUATIONMAP_EXPORT LayerAggregationWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
Constructor to build gui widget for handling aggregation layers.
|
||||
|
||||
@param map Map the layer are part of
|
||||
@param layerType Type of layer in general this will be LayerType::Operational
|
||||
@param nameCondition If the nameCondition doesn't match with the layername the layer will be skipped and is not handled.
|
||||
Example of an expression "^Participant.+".
|
||||
@param parent Parent for Qt object hierarchy
|
||||
*/
|
||||
explicit LayerAggregationWidget(Map *map, LayerType layerType, const QRegularExpression &nameCondition, QWidget *parent);
|
||||
|
||||
/**
|
||||
Destructor to clean up memory.
|
||||
*/
|
||||
~LayerAggregationWidget();
|
||||
|
||||
void retranslate();
|
||||
|
||||
public slots:
|
||||
|
||||
void onApplyAll();
|
||||
void onResetAll();
|
||||
|
||||
void onSetDefaultScales();
|
||||
|
||||
signals:
|
||||
|
||||
void changesMade();
|
||||
|
||||
protected slots:
|
||||
|
||||
void onSetValid(bool value);
|
||||
|
||||
void onGetMinScale();
|
||||
void onGetMaxScale();
|
||||
void onZoomTo();
|
||||
void onReset();
|
||||
void onApply();
|
||||
|
||||
private:
|
||||
|
||||
void doReset(int row);
|
||||
|
||||
static QString scaleText(double scale);
|
||||
|
||||
static void setMinScaleLabel(QPushButton *btn, double scale);
|
||||
static void setMaxScaleLabel(QPushButton *btn, double scale);
|
||||
|
||||
class InternalData;
|
||||
|
||||
InternalData *m_internal;
|
||||
|
||||
}; // LayerAggregationWidget
|
||||
|
||||
} /* namespace SituationMap */
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Dialog of aggregation of participant layer
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** 18.08.2017, JT : first edition
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "participant_aggregation_dialog.h"
|
||||
#include "layer_aggregation_widget.h"
|
||||
|
||||
#include <Map/map.h>
|
||||
|
||||
#include <QtWidgets/QVBoxLayout>
|
||||
|
||||
|
||||
using namespace SituationMap;
|
||||
|
||||
|
||||
ParticipantAggregationDialog::ParticipantAggregationDialog(Map *map, QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
|
||||
{
|
||||
m_law = new LayerAggregationWidget(map, LayerType::Operational, QRegularExpression(QStringLiteral("^Participant.+"), QRegularExpression::CaseInsensitiveOption), this);
|
||||
|
||||
if (map)
|
||||
connect(map, &Map::beginDestroy, this, &ParticipantAggregationDialog::onMapDestroyed, Qt::UniqueConnection);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
|
||||
layout->addWidget(m_law);
|
||||
layout->addStretch(2);
|
||||
|
||||
LtsWidgets::DialogButton btnSetDefault = LtsWidgets::DialogButton::Print;
|
||||
|
||||
m_buttonBox->connectButton(btnSetDefault, m_law, &LayerAggregationWidget::onSetDefaultScales);
|
||||
|
||||
m_buttonBox->setButtonEnabled(btnSetDefault, true);
|
||||
m_buttonBox->setButtonVisible(btnSetDefault, true);
|
||||
|
||||
connect(this, &ParticipantAggregationDialog::canceled, m_law, &LayerAggregationWidget::onResetAll);
|
||||
connect(this, &ParticipantAggregationDialog::applied, m_law, &LayerAggregationWidget::onApplyAll);
|
||||
|
||||
connect(m_law, &LayerAggregationWidget::changesMade, this, &ParticipantAggregationDialog::slotChangesMade);
|
||||
|
||||
retranslate();
|
||||
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Participant_Aggregation"));
|
||||
|
||||
} // ParticipantAggregationDialog::ParticipantAggregationDialog( Map * map, QWidget * parent )
|
||||
|
||||
|
||||
void ParticipantAggregationDialog::retranslate()
|
||||
{
|
||||
// lupdate doesn't like translate(tr("foo")) ...
|
||||
const QString txt(tr("Participant Aggregation"));
|
||||
translate(txt);
|
||||
|
||||
LtsWidgets::DialogButton btnSetDefault = LtsWidgets::DialogButton::Print;
|
||||
|
||||
m_buttonBox->setText( btnSetDefault, tr("Set Scale Defaults"));
|
||||
m_buttonBox->setToolTip( btnSetDefault, tr("Calculate scale values for each aggregation from map scale range"));
|
||||
|
||||
m_law->retranslate();
|
||||
|
||||
} // void ParticipantAggregationDialog::retranslate()
|
||||
|
||||
|
||||
void ParticipantAggregationDialog::dialogCanceled()
|
||||
{
|
||||
emit canceled();
|
||||
} // void ParticipantAggregationDialog::dialogCanceled()
|
||||
|
||||
|
||||
bool ParticipantAggregationDialog::apply()
|
||||
{
|
||||
emit applied();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ParticipantAggregationDialog::onMapDestroyed()
|
||||
{
|
||||
// commit suicide
|
||||
delete this;
|
||||
} // bool ParticipantAggregationDialog::apply()
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Dialog of aggregation of participant layer
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** 18.08.2017, JT : first edition
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
|
||||
#include <situation_map_export.h>
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
class Map;
|
||||
class LayerAggregationWidget;
|
||||
|
||||
/**
|
||||
@class ParticpantAggregation particpant_aggregation.h
|
||||
@brief Class to handle aggregation of participant layer dialog
|
||||
*/
|
||||
|
||||
class SITUATIONMAP_EXPORT ParticipantAggregationDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit ParticipantAggregationDialog(SituationMap::Map *map, QWidget *parent);
|
||||
~ParticipantAggregationDialog() = default;
|
||||
|
||||
void retranslate() override;
|
||||
|
||||
void dialogCanceled() override;
|
||||
|
||||
protected:
|
||||
|
||||
bool apply() override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void canceled();
|
||||
void applied();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onMapDestroyed();
|
||||
|
||||
private:
|
||||
|
||||
LayerAggregationWidget *m_law;
|
||||
|
||||
}; // ParticipantAggregationDialog
|
||||
|
||||
} /* namespace SituationMap */
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
# LIBRARY
|
||||
|
||||
SET(LocalServer_SRCS
|
||||
local_server_export
|
||||
local_server.cpp
|
||||
local_server.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(LocalServer FILES ${LocalServer_SRCS})
|
||||
|
||||
NGL_ADD_LIBRARY(WS situationMapLocalServer SHARED ${LocalServer_SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(situationMapLocalServer
|
||||
PRIVATE
|
||||
ArcGIS::ArcGIS
|
||||
NGLLogger
|
||||
Qt5::Gui # can be removed once we get an official ESRI ArcGIS Qt version again
|
||||
PUBLIC
|
||||
Qt5::Core
|
||||
situationMapCommon
|
||||
)
|
||||
|
||||
# ESRI: /usr/include/arcgis/LocalServer/LocalServer.h: '#include "Object.h"'
|
||||
# so add required include path here as PRIVATE:
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(situationMapLocalServer
|
||||
PRIVATE
|
||||
${ARCGIS_INCLUDE_DIR}/arcgis
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(situationMapLocalServer)
|
||||
+519
@@ -0,0 +1,519 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* LocalServer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "local_server.h"
|
||||
#include <Common/resource_path.h>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/Error.h>
|
||||
|
||||
#include <arcgis/LocalServer/LocalServer.h>
|
||||
#include <arcgis/LocalServer/LocalGeoprocessingService.h>
|
||||
|
||||
|
||||
//Qt
|
||||
#include <QMap>
|
||||
|
||||
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
|
||||
QString toString(const Esri::ArcGISRuntime::Error &value)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << "Esri::ArcGISRuntime::Error: "
|
||||
<< " code=" << value.code()
|
||||
<< ", domain=" << (int)value.domain()
|
||||
<< ", extendedErrorType=" << (int)value.extendedErrorType()
|
||||
<< ", message='" << value.message() << "'"
|
||||
<< ", additionalMessage='" << value.additionalMessage() << "'";
|
||||
return QString::fromStdString(stream.str());
|
||||
}
|
||||
|
||||
std::ostream &operator<< (std::ostream &stream,
|
||||
const Esri::ArcGISRuntime::Error &value)
|
||||
{
|
||||
stream << toString(value);
|
||||
return stream;
|
||||
}
|
||||
|
||||
} // namespace ArcGISRuntime
|
||||
} // namespace Esri
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
bool LocalServiceData::isEmpty() const
|
||||
{
|
||||
return m_svcUrl.isEmpty();
|
||||
}
|
||||
|
||||
void LocalServiceData::setSvcUrl(const QUrl &svcUrl)
|
||||
{
|
||||
m_svcUrl = svcUrl;
|
||||
}
|
||||
|
||||
const QUrl &LocalServiceData::svcUrl() const
|
||||
{
|
||||
return m_svcUrl;
|
||||
}
|
||||
|
||||
void LocalServiceData::setSync(bool sync)
|
||||
{
|
||||
m_sync = sync;
|
||||
}
|
||||
|
||||
bool LocalServiceData::isSync() const
|
||||
{
|
||||
return m_sync;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
static QString toString(const Esri::ArcGISRuntime::LocalServerStatus &value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case Esri::ArcGISRuntime::LocalServerStatus::Stopped:
|
||||
return QLatin1String("Stopped");
|
||||
case Esri::ArcGISRuntime::LocalServerStatus::Starting:
|
||||
return QLatin1String("Starting");
|
||||
case Esri::ArcGISRuntime::LocalServerStatus::Started:
|
||||
return QLatin1String("Started");
|
||||
case Esri::ArcGISRuntime::LocalServerStatus::Stopping:
|
||||
return QLatin1String("Stopping");
|
||||
case Esri::ArcGISRuntime::LocalServerStatus::Failed:
|
||||
return QLatin1String("Failed");
|
||||
} // switch
|
||||
return QLatin1String("Esri-LocalServerStatusERROR");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class LocalServer::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
~Private() = default;
|
||||
|
||||
// ESRI data:
|
||||
Esri::ArcGISRuntime::LocalServer *m_localServer = nullptr;
|
||||
|
||||
// Own data:
|
||||
QMap<QString, Esri::ArcGISRuntime::LocalGeoprocessingService *> m_gpServiceMap;
|
||||
QMap<QString, QString> m_serviceSubLocationMap;
|
||||
|
||||
|
||||
QMap<QString, LocalServiceData> m_svcData;
|
||||
|
||||
|
||||
}; // class LocalServer::Private
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
LocalServer *LocalServer::instance()
|
||||
{
|
||||
static LocalServer *_instance = nullptr;
|
||||
if (_instance == nullptr)
|
||||
_instance = new LocalServer;
|
||||
return _instance;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
LocalServer::LocalServer()
|
||||
: BaseClass()
|
||||
, m_logger(getLogger("LocalServer"))
|
||||
, d(new Private)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " installPath = "
|
||||
<< " '" << Esri::ArcGISRuntime::LocalServer::installPath() << "'";
|
||||
|
||||
QString newInstallPath;
|
||||
|
||||
QString user = QString::fromLocal8Bit( qgetenv("USER") );
|
||||
if (user.compare(QLatin1Literal("ctc")) == 0)
|
||||
newInstallPath = SituationMap::getResourcePath() + QLatin1String("/localserver100.2_ctc/"); // USER ctc
|
||||
else
|
||||
newInstallPath = SituationMap::getResourcePath() + QLatin1String("/localserver100.2/"); // USER ctc_ws
|
||||
|
||||
Esri::ArcGISRuntime::LocalServer::setInstallPath(newInstallPath);
|
||||
|
||||
if (Esri::ArcGISRuntime::LocalServer::isInstallValid())
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " installPath ok = "
|
||||
<< " '" << Esri::ArcGISRuntime::LocalServer::installPath() << "'";
|
||||
else
|
||||
FATAL_LOG(m_logger) << LOGFUNCTION << " installPath failed = "
|
||||
<< " InstallPath = '" << Esri::ArcGISRuntime::LocalServer::installPath() << "'";
|
||||
|
||||
d->m_localServer = Esri::ArcGISRuntime::LocalServer::instance();
|
||||
|
||||
connect(d->m_localServer, &Esri::ArcGISRuntime::LocalServer::errorOccurred,
|
||||
this, &LocalServer::onLocalServerError);
|
||||
connect(d->m_localServer, &Esri::ArcGISRuntime::LocalServer::statusChanged,
|
||||
this, &LocalServer::onLocalServerStatusChanged);
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
LocalServer::~LocalServer()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
this->stop();
|
||||
delete d;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
void LocalServer::start()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
d->m_localServer->start();
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
void LocalServer::stop()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
stopAllLocalGeoprocessingServices();
|
||||
d->m_localServer->stop();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
bool LocalServer::isLocalServerStarted() const
|
||||
{
|
||||
return d->m_localServer->status() == Esri::ArcGISRuntime::LocalServerStatus::Started;
|
||||
}
|
||||
bool LocalServer::isLocalServerStopped() const
|
||||
{
|
||||
return d->m_localServer->status() == Esri::ArcGISRuntime::LocalServerStatus::Stopped;
|
||||
}
|
||||
|
||||
|
||||
bool LocalServer::setLocalGeoprocessingService(const QString &serviceName,
|
||||
const QString &packagePath,
|
||||
const QString &serviceSubLocation,
|
||||
bool sync)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||||
<< " serviceName: '" << serviceName << "'"
|
||||
<< " packagePath: '" << packagePath << "'"
|
||||
<< " serviceSubLocation: '" << serviceSubLocation << "'";
|
||||
if (d->m_gpServiceMap.contains(serviceName))
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName: '" << serviceName << "'" << " already provided";
|
||||
return false;
|
||||
}
|
||||
|
||||
QString localPackagePath = packagePath;
|
||||
|
||||
{
|
||||
QFileInfo fileinfo(packagePath);
|
||||
if (!fileinfo.isAbsolute())
|
||||
localPackagePath = SituationMap::getResourcePath() + QLatin1String("/gpk/") + packagePath;
|
||||
}
|
||||
QFileInfo fileinfo(localPackagePath);
|
||||
|
||||
if (!fileinfo.exists())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName: '" << serviceName << "'"
|
||||
<< " packagePath does not exist: "
|
||||
<< " localPackagePath: '" << localPackagePath << "'";
|
||||
return false;
|
||||
}
|
||||
if (!fileinfo.isReadable())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName: '" << serviceName << "'"
|
||||
<< " packagePath is not readable: "
|
||||
<< " localPackagePath: '" << localPackagePath << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " create LocalGeoprocessingService: "
|
||||
<< " localPackagePath: '" << localPackagePath << "'";
|
||||
|
||||
|
||||
Esri::ArcGISRuntime::LocalGeoprocessingService *lgps =
|
||||
new Esri::ArcGISRuntime::LocalGeoprocessingService(localPackagePath, this);
|
||||
lgps->setObjectName(QString(QLatin1Literal("LocalGeoprocessingService-%1")).arg(serviceName));
|
||||
|
||||
if (sync)
|
||||
lgps->setServiceType(Esri::ArcGISRuntime::GeoprocessingServiceType::SynchronousExecute); // SynchronousExecute | AsynchronousSubmit | ...
|
||||
else
|
||||
lgps->setServiceType(Esri::ArcGISRuntime::GeoprocessingServiceType::AsynchronousSubmit); // SynchronousExecute | AsynchronousSubmit | ...
|
||||
|
||||
connect(lgps, &Esri::ArcGISRuntime::LocalGeoprocessingService::errorOccurred,
|
||||
this, &LocalServer::onLGPSError);
|
||||
connect(lgps, &Esri::ArcGISRuntime::LocalGeoprocessingService::statusChanged,
|
||||
this, &LocalServer::onLGPSStatusChanged);
|
||||
|
||||
// add to own management:
|
||||
d->m_gpServiceMap[serviceName] = lgps;
|
||||
d->m_serviceSubLocationMap[serviceName] = serviceSubLocation;
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||||
<< " serviceName: '" << serviceName << "'"
|
||||
<< " localPackagePath: '" << localPackagePath << "'"
|
||||
<< " serviceSubLocation: '" << serviceSubLocation << "'";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LocalServer::startLocalGeoprocessingService(const QString &serviceName)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
if (!d->m_gpServiceMap.contains(serviceName))
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << " not found";
|
||||
return false;
|
||||
}
|
||||
Esri::ArcGISRuntime::LocalGeoprocessingService *lgps = d->m_gpServiceMap[serviceName];
|
||||
if (!lgps)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << ", no service";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isLocalServerStarted())
|
||||
lgps->start();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LocalServer::stopLocalGeoprocessingService(const QString &serviceName)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
if (!d->m_gpServiceMap.contains(serviceName))
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << " not found";
|
||||
return false;
|
||||
}
|
||||
Esri::ArcGISRuntime::LocalGeoprocessingService *lgps = d->m_gpServiceMap[serviceName];
|
||||
if (!lgps)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << ", no service";
|
||||
return false;
|
||||
}
|
||||
|
||||
lgps->stop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LocalServer::isLocalGeoprocessingServiceStarted(const QString &serviceName) const
|
||||
{
|
||||
if (!d->m_gpServiceMap.contains(serviceName))
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << " not found";
|
||||
return false;
|
||||
}
|
||||
Esri::ArcGISRuntime::LocalGeoprocessingService *lgps = d->m_gpServiceMap[serviceName];
|
||||
if (!lgps)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << ", no service";
|
||||
return false;
|
||||
}
|
||||
return lgps->status() == Esri::ArcGISRuntime::LocalServerStatus::Started;
|
||||
}
|
||||
bool LocalServer::isLocalGeoprocessingServiceStopped(const QString &serviceName) const
|
||||
{
|
||||
if (!d->m_gpServiceMap.contains(serviceName))
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << " not found";
|
||||
return false;
|
||||
}
|
||||
Esri::ArcGISRuntime::LocalGeoprocessingService *lgps = d->m_gpServiceMap[serviceName];
|
||||
if (!lgps)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << ", no service";
|
||||
return false;
|
||||
}
|
||||
return lgps->status() == Esri::ArcGISRuntime::LocalServerStatus::Stopped;
|
||||
}
|
||||
|
||||
bool LocalServer::isLocalGeoprocessingServiceSynchronousExecute(const QString &serviceName) const
|
||||
{
|
||||
if (!d->m_gpServiceMap.contains(serviceName))
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << " not found";
|
||||
return false;
|
||||
}
|
||||
Esri::ArcGISRuntime::LocalGeoprocessingService *lgps = d->m_gpServiceMap[serviceName];
|
||||
if (!lgps)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << ", no service";
|
||||
return false;
|
||||
}
|
||||
return lgps->serviceType() == Esri::ArcGISRuntime::GeoprocessingServiceType::SynchronousExecute;
|
||||
}
|
||||
|
||||
bool LocalServer::isLocalGeoprocessingServiceAsynchronousSubmit(const QString &serviceName) const
|
||||
{
|
||||
if (!d->m_gpServiceMap.contains(serviceName))
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << " not found";
|
||||
return false;
|
||||
}
|
||||
Esri::ArcGISRuntime::LocalGeoprocessingService *lgps = d->m_gpServiceMap[serviceName];
|
||||
if (!lgps)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << ", no service";
|
||||
return false;
|
||||
}
|
||||
return lgps->serviceType() == Esri::ArcGISRuntime::GeoprocessingServiceType::AsynchronousSubmit;
|
||||
}
|
||||
|
||||
bool LocalServer::localGeoprocessingServiceData(const QString &serviceName, LocalServiceData &localServiceDataOut) const
|
||||
{
|
||||
if (!d->m_svcData.contains(serviceName))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << " not found";
|
||||
return false;
|
||||
}
|
||||
localServiceDataOut = d->m_svcData[serviceName];
|
||||
return true;
|
||||
}
|
||||
|
||||
void LocalServer::startAllPendingLocalGeoprocessingServices()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
QMapIterator<QString, Esri::ArcGISRuntime::LocalGeoprocessingService *> mapIt(d->m_gpServiceMap);
|
||||
|
||||
while (mapIt.hasNext())
|
||||
{
|
||||
mapIt.next();
|
||||
const QString &serviceName = mapIt.key();
|
||||
Esri::ArcGISRuntime::LocalGeoprocessingService *lgps = mapIt.value();
|
||||
|
||||
if (!lgps)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << ", no service";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lgps->status() == Esri::ArcGISRuntime::LocalServerStatus::Started)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << ", already started, continue";
|
||||
continue;
|
||||
}
|
||||
else
|
||||
lgps->start();
|
||||
} // while
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
void LocalServer::stopAllLocalGeoprocessingServices()
|
||||
{
|
||||
QMapIterator<QString, Esri::ArcGISRuntime::LocalGeoprocessingService *> mapIt(d->m_gpServiceMap);
|
||||
|
||||
while (mapIt.hasNext())
|
||||
{
|
||||
mapIt.next();
|
||||
const QString &serviceName = mapIt.key();
|
||||
Esri::ArcGISRuntime::LocalGeoprocessingService *lgps = mapIt.value();
|
||||
|
||||
if (!lgps)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " serviceName '" << serviceName << "'" << ", no service";
|
||||
continue;
|
||||
}
|
||||
lgps->stop();
|
||||
} // while
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
|
||||
void LocalServer::onLocalServerError(const Esri::ArcGISRuntime::Error &error)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " EsriError occured: " << error;
|
||||
}
|
||||
|
||||
void LocalServer::onLocalServerStatusChanged()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " LocalServer: status changed to: " << toString(d->m_localServer->status());
|
||||
|
||||
emit localServerStatusChanged();
|
||||
|
||||
if (d->m_localServer->status() == Esri::ArcGISRuntime::LocalServerStatus::Started)
|
||||
{
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " LocalServer: STARTED"
|
||||
<< " (url= '" << d->m_localServer->url().toString() << "')"
|
||||
<< " (Esri::ArcGISRuntime::LocalServer->tempDataPath= '" << d->m_localServer->tempDataPath() << "')";
|
||||
startAllPendingLocalGeoprocessingServices();
|
||||
}
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
void LocalServer::onLGPSError(const Esri::ArcGISRuntime::Error &error)
|
||||
{
|
||||
QString senderName;
|
||||
Esri::ArcGISRuntime::LocalGeoprocessingService *lgs = qobject_cast<Esri::ArcGISRuntime::LocalGeoprocessingService *>(sender());
|
||||
if (lgs)
|
||||
senderName = lgs->objectName();
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " LocalGeoprocessingService -> EsriError occured: " << error;
|
||||
}
|
||||
|
||||
void LocalServer::onLGPSStatusChanged()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
Esri::ArcGISRuntime::LocalGeoprocessingService *lgsp = qobject_cast<Esri::ArcGISRuntime::LocalGeoprocessingService *>(sender());
|
||||
|
||||
if (!lgsp)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " qobject_cast failed to get sender!?";
|
||||
return;
|
||||
}
|
||||
|
||||
QString senderName = lgsp->objectName();
|
||||
const QString &serviceName = d->m_gpServiceMap.key(lgsp);
|
||||
|
||||
if (lgsp->status() == Esri::ArcGISRuntime::LocalServerStatus::Started)
|
||||
{
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " ***** LocalGeoprocessingService:"
|
||||
<< " sender= '" << senderName << "'"
|
||||
<< " status changed to: " << toString(lgsp->status())
|
||||
<< " url= '" << lgsp->url().toString() << "'";
|
||||
|
||||
LocalServiceData svcData;
|
||||
|
||||
const QString &serviceSubLocation = d->m_serviceSubLocationMap[serviceName];
|
||||
const QString &url = lgsp->url().toString() + QLatin1String("/") + serviceSubLocation;
|
||||
svcData.setSvcUrl(QUrl(url));
|
||||
svcData.setSync(lgsp->serviceType() == Esri::ArcGISRuntime::GeoprocessingServiceType::SynchronousExecute);
|
||||
|
||||
d->m_svcData[serviceName] = svcData; // store in own management
|
||||
|
||||
emit localGeoprocessingServiceStatusChanged(serviceName);
|
||||
emit localGeoprocessingServiceStarted(serviceName, svcData);
|
||||
}
|
||||
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " LocalGeoprocessingService:"
|
||||
<< " sender= '" << senderName << "'"
|
||||
<< " status changed to: " << toString(lgsp->status());
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* LocalServer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "local_server_export.h"
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
namespace Esri {
|
||||
namespace ArcGISRuntime {
|
||||
class Error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
#include <QString>
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
class LOCALSERVER_EXPORT LocalServiceData
|
||||
{
|
||||
private:
|
||||
QUrl m_svcUrl;
|
||||
bool m_sync = false;
|
||||
public:
|
||||
bool isEmpty() const;
|
||||
|
||||
void setSvcUrl(const QUrl &svcUrl);
|
||||
const QUrl &svcUrl() const;
|
||||
|
||||
void setSync(bool sync);
|
||||
bool isSync() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief The LocalServer class wrap ESRI`s LocalServer.
|
||||
* This is a container for geoprocessing services
|
||||
* The LocalServer has to be started as well as the seperate instances of LocalGeoprocessingService.
|
||||
* To ease the usage you should set the required number of LocalGeoprocessingService (with different serviceNames).
|
||||
* Then simply start the LocalServer (and if that is up all pending will be started.)
|
||||
*/
|
||||
class LOCALSERVER_EXPORT LocalServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
using BaseClass = QObject;
|
||||
|
||||
private:
|
||||
explicit LocalServer();
|
||||
~LocalServer();
|
||||
|
||||
public:
|
||||
/*! \name Check Installation ( no guarantee )*/
|
||||
static bool isInstallValid();
|
||||
|
||||
|
||||
/*! \name Singleton */
|
||||
static LocalServer *instance();
|
||||
|
||||
|
||||
/*! \name LocalServer */
|
||||
//@{
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
bool isLocalServerStarted() const;
|
||||
bool isLocalServerStopped() const;
|
||||
//@}
|
||||
|
||||
/*! \name LocalGeoprocessingService */
|
||||
//@{
|
||||
bool setLocalGeoprocessingService(const QString &serviceName, const QString &packagePath, const QString &serviceSubLocation, bool sync);
|
||||
bool startLocalGeoprocessingService(const QString &serviceName);
|
||||
bool stopLocalGeoprocessingService(const QString &serviceName);
|
||||
|
||||
bool isLocalGeoprocessingServiceStarted(const QString &serviceName) const;
|
||||
bool isLocalGeoprocessingServiceStopped(const QString &serviceName) const;
|
||||
|
||||
bool isLocalGeoprocessingServiceSynchronousExecute(const QString &serviceName) const;
|
||||
bool isLocalGeoprocessingServiceAsynchronousSubmit(const QString &serviceName) const;
|
||||
|
||||
bool localGeoprocessingServiceData(const QString &serviceName, LocalServiceData &localServiceDataOut) const;
|
||||
//@}
|
||||
|
||||
protected:
|
||||
void startAllPendingLocalGeoprocessingServices();
|
||||
void stopAllLocalGeoprocessingServices();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onLocalServerError(const Esri::ArcGISRuntime::Error &error);
|
||||
void onLocalServerStatusChanged();
|
||||
|
||||
void onLGPSError(const Esri::ArcGISRuntime::Error &error);
|
||||
void onLGPSStatusChanged();
|
||||
|
||||
Q_SIGNALS:
|
||||
void localServerStatusChanged();
|
||||
|
||||
void localGeoprocessingServiceStatusChanged(const QString &serviceName);
|
||||
void localGeoprocessingServiceStarted(const QString &serviceName, const LocalServiceData&localSvcData);
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
class Private;
|
||||
/**
|
||||
* The private d->pointer to not break BC when changing internals of this class
|
||||
*/
|
||||
Private *d = nullptr;
|
||||
};
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Export definitions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <qglobal.h>
|
||||
|
||||
#ifndef LOCALSERVER_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define LOCALSERVER_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SITUATIONMAPLOCALSERVER_LIB)
|
||||
# define LOCALSERVER_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define LOCALSERVER_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 524 KiB |
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Interface of AbstractEffectSimulation
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "abstract_map_object.h"
|
||||
#include "line_style.h"
|
||||
#include "fill_style.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The AesEffectState enum define the different states a EffectSimulation can have.
|
||||
*/
|
||||
enum class AesEffectState
|
||||
{
|
||||
Unknown = 0, ///< EffectSimulation is unknown.
|
||||
Error = -1, ///< EffectSimulation has an error.
|
||||
Expired = 1, ///< EffectSimulation has finished.
|
||||
Removed = 2, ///< EffectSimulation is deleted.
|
||||
Created = 4, ///< EffectSimulation is created.
|
||||
Prepared = 5, ///< EffectSimulation is created, but activation time is in future.
|
||||
Activated = 6, ///< EffectSimulation is created, and activation time is aimed.
|
||||
Paused = 7 ///< A triggered EffectSimulation is paused.
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief The AbstractEffectSimulation class contains some specific parameters.
|
||||
* Inherenting of this class ease the adding of this functionality.
|
||||
*/
|
||||
class SITUATIONMAP_EXPORT AbstractEffectSimulation
|
||||
{
|
||||
public:
|
||||
virtual ~AbstractEffectSimulation() = default;
|
||||
|
||||
virtual AesEffectState aesState() const = 0;
|
||||
virtual void setAesState(AesEffectState aesState) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
+424
@@ -0,0 +1,424 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Interface of AbstractMapObject
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "situation_map_types.h"
|
||||
#include "situation_map_utils.h"
|
||||
#include "text_style.h"
|
||||
#include <Common/referenced.h>
|
||||
#include <situation_map_export.h>
|
||||
|
||||
#include <MathUtils/geometry_engine.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QString>
|
||||
#include <QColor>
|
||||
#include <QList>
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
// forward:
|
||||
class BoundingBox;
|
||||
|
||||
/**
|
||||
* @brief The AbstractMapObject class is the baseclass of all MapObjects.
|
||||
* (The class 'Referenced' is for the RefPointer only)
|
||||
*
|
||||
* This class supports main parameters like uniqueMapId, debugInfo and identifier
|
||||
* to differentiate the objects.
|
||||
*
|
||||
* Second, the SymbolData can be set to use the TacticalAppearance of objects.
|
||||
*
|
||||
* Last but not least, visibility and drawOrder can be modified.
|
||||
*
|
||||
* An object has typically two Appearances:
|
||||
* The Technical and the Tactical Appearance.
|
||||
* Both can be switched on of off separatly,
|
||||
* see setVisibility(ObjectAppearance appearance, bool visibility).
|
||||
* @internal
|
||||
* The AbstractMapObjectImpl has to be initialized (set the Map, Layer and so on).
|
||||
* This call is done by the ObjectFactory.
|
||||
*/
|
||||
class SITUATIONMAP_EXPORT AbstractMapObject : virtual public Referenced
|
||||
{
|
||||
public:
|
||||
/*! \name Construction, Destruction */
|
||||
//@{
|
||||
/// Constructor
|
||||
AbstractMapObject() = default;
|
||||
|
||||
/// Destructor
|
||||
virtual ~AbstractMapObject() = default;
|
||||
|
||||
virtual void removeMySelf() = 0;
|
||||
//@}
|
||||
|
||||
|
||||
/*! \name Emulate QObject::property */
|
||||
//@{
|
||||
/**
|
||||
* @brief Set named property to value.
|
||||
* @param name name.
|
||||
* @param value value.
|
||||
* @return True on success, otherwise false.
|
||||
*/
|
||||
virtual bool setProperty(const char *name, const QVariant &value) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get named property to value.
|
||||
* @param name to retrieve
|
||||
* @return Requested value.
|
||||
*/
|
||||
virtual QVariant property(const char *name) const = 0;
|
||||
//@}
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \name Identification */
|
||||
//@{
|
||||
/**
|
||||
* @brief Get uniqueMapId.
|
||||
* @return uniqueMapId.
|
||||
*/
|
||||
virtual UniqueMapId uniqueMapId() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get debugInfo.
|
||||
* @return debugInfo.
|
||||
*/
|
||||
virtual QString debugInfo() const = 0;
|
||||
/**
|
||||
* @brief Set DebugInfo.
|
||||
* @param debugInfo new value.
|
||||
*/
|
||||
virtual void setDebugInfo(const QString &debugInfo) = 0;
|
||||
|
||||
/**
|
||||
* @brief toString delivers a string with some parameters.
|
||||
* @return String with some parameters.
|
||||
*/
|
||||
virtual QString toString() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get identifier.
|
||||
* @return identifier.
|
||||
*/
|
||||
virtual QString identifier() const = 0;
|
||||
/**
|
||||
* @brief Set identifier of object to be displayed on the Map.
|
||||
* @param identifier new value.
|
||||
*/
|
||||
virtual void setIdentifier(const QString &identifier) = 0;
|
||||
|
||||
virtual bool identifierVisible() const = 0;
|
||||
virtual void setIdentifierVisible(bool identifierVisible) = 0;
|
||||
//@}
|
||||
|
||||
|
||||
/*! \name Direct and indirect assignment
|
||||
* These values (partyId) has a high priority. Therefore it will overwrite
|
||||
* some other values.
|
||||
* \n An example is the line and fill color of an AreaFire.
|
||||
* \n You can specify AreaFire::rLineStyle.setLineColor(Qt::blue) (== direct).
|
||||
* \n But if a valid partyId is provided, this will overwrite the line and fill
|
||||
* \n Exeption:
|
||||
* \n If forcePartyColor is used, this has more priority than the partyId.
|
||||
* parameter, color (== indirect).
|
||||
*/
|
||||
//@{
|
||||
|
||||
/**
|
||||
* @brief Get partyId.
|
||||
* @return partyId.
|
||||
*/
|
||||
virtual int partyId() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Check partyId
|
||||
* @return True if partyId is valid, otherwise false.
|
||||
*/
|
||||
virtual bool isPartyIdValid() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Set PartyId
|
||||
* @param partyId new value.
|
||||
*/
|
||||
virtual void setPartyId(int partyId) = 0;
|
||||
|
||||
/**
|
||||
* @brief If the color of a party changes the partyId has to re-evaluated to the new color.
|
||||
* @param partyColorToForce the color to be forced.
|
||||
* This method set the internal flag, that the next updateView will take the new color.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief If the color of a party changes the partyId has to re-evaluated to the new color.
|
||||
* If relevant this method will set the internal flag, that the next updateView will take the new color.
|
||||
* @param partyId causing the change, If less then 0, setting the internal flag is forced.
|
||||
* @return true if relevant for this object, otherwise false
|
||||
*/
|
||||
virtual bool setPartyIdChanged(int partyId = -1) = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @brief forcePartyColor to fulfill the flashing (e.g. of a participant)
|
||||
* This forcedColor has more priority that than the partyId.
|
||||
* @param partyColorToForce the color to be forced.
|
||||
*/
|
||||
virtual void forcePartyColor(const QColor &partyColorToBeForced) = 0;
|
||||
//@}
|
||||
|
||||
/**
|
||||
* @brief useLightColor Use the light party color instead the normal one
|
||||
*/
|
||||
virtual bool useLightColor() const = 0; ///< Only for Participants
|
||||
virtual void setUseLightColor(bool useLightColor) = 0; ///< Only for Participants
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/**
|
||||
* @brief Get copy of textStyle.
|
||||
* @return textStyle.
|
||||
*/
|
||||
virtual TextStyle textStyle() const = 0;
|
||||
/**
|
||||
* @brief Get reference to TextStyle (to modify easily).
|
||||
* @return Reference to TextStyle.
|
||||
* @note: Use this with caution. This will set the internal changed flag.
|
||||
* Maybe you should prefer setTextStyle.
|
||||
*/
|
||||
virtual TextStyle &rTextStyle() = 0;
|
||||
/**
|
||||
* @brief Set TextStyle to be used for identifier.
|
||||
* @param textStyle new value.
|
||||
*/
|
||||
virtual void setTextStyle(const TextStyle &textStyle) = 0;
|
||||
//@}
|
||||
|
||||
/*! \name User scale */
|
||||
//@{
|
||||
/**
|
||||
* @brief Get scale.
|
||||
* @return scale
|
||||
*/
|
||||
virtual float scale() const = 0;
|
||||
/**
|
||||
* @brief Set scale of object.
|
||||
* @param newScale new value.
|
||||
*/
|
||||
virtual void setScale(float newScale) = 0;
|
||||
|
||||
virtual bool isScaleEnabled() const = 0;
|
||||
virtual void setScaleEnable(bool enabled) = 0;
|
||||
//@}
|
||||
|
||||
|
||||
/*! \name Layer and draworder */
|
||||
//@{
|
||||
/**
|
||||
* @brief Get logical layername.
|
||||
* @return logical layername.
|
||||
*/
|
||||
virtual QString layer() const = 0;
|
||||
/**
|
||||
* @brief Get drawOrder.
|
||||
* @return drawOrder.
|
||||
*/
|
||||
virtual int drawOrder() const = 0;
|
||||
/**
|
||||
* @brief Set drawOrder.
|
||||
* Caused by internal dependencies, the value MUST be within -3000...+3000. (INT_MAX=+32767 / 10 = 3276 -> ~3000).
|
||||
* \n Otherwise the internal graphics will be disordered.
|
||||
* \internal Background: Due to missing relative drawOrder an absolute drawOrder has to be used.\n
|
||||
* To create an absolute drawOrder the specified drawOrder is multiplied with 10.
|
||||
* The components (usually GraphicalObjects) receive that multiplied valued added by s small offset.
|
||||
* drawOrder() is not influenced by this and will return the value you set before.
|
||||
* @param drawOrder new value.
|
||||
*/
|
||||
virtual void setDrawOrder(int drawOrder) = 0;
|
||||
//@}
|
||||
|
||||
|
||||
/** \name Visibility
|
||||
* If the object has to be invisible setVisibility() should be used.
|
||||
*
|
||||
* If only a single part has to be modified, remember the Technical and the Tactical ObjectAppearance.
|
||||
* Both can be switch on or off separately.
|
||||
*
|
||||
* Attention: If the two ObjectAppearances are invisible setVisibility(true) will make them <B>NOT</B> visibile.
|
||||
**/
|
||||
//@{
|
||||
// Visibility :
|
||||
// Prio 1:
|
||||
/**
|
||||
* @brief Get visibility of the whole object (Prio 1).
|
||||
* @return visibility of the whole object.
|
||||
*/
|
||||
virtual bool visibility() const = 0;
|
||||
/**
|
||||
* @brief Set visibility of the whole object (Prio 1).
|
||||
* @param visibility new value.
|
||||
*/
|
||||
virtual void setVisibility(bool visibility) = 0;
|
||||
|
||||
// Prio 2
|
||||
/**
|
||||
* @brief Get visibility of a specific ObjectAppearance (Prio 2).
|
||||
* @param appearance to be retrieved.
|
||||
* @return Current value.
|
||||
*/
|
||||
virtual bool visibility(ObjectAppearance appearance) const = 0;
|
||||
/**
|
||||
* @brief Set Visibility of a specific ObjectAppearance (Prio 2).
|
||||
* @param appearance to be modified.
|
||||
* @param visibility new value.
|
||||
*/
|
||||
virtual void setVisibility(ObjectAppearance appearance, bool visibility) = 0;
|
||||
|
||||
/**
|
||||
Calculates the intersection of map object another geometry
|
||||
@param intersector_polyline Geometry to intersect with
|
||||
@note: The geometry must be closed like a polyline. (not really sure)
|
||||
*/
|
||||
virtual bool geometryIntersect(const MathUtils::GeometryEngine::Geometry &intersector_polyline) const = 0;
|
||||
|
||||
/**
|
||||
Calculates if the map object is inside another geometry.
|
||||
@param hull_polygon Geometry to check against.
|
||||
@note: The geometry must be closed like a polygon. (not really sure)
|
||||
*/
|
||||
virtual bool geometryIsInHull(const MathUtils::GeometryEngine::Geometry &hull_polygon) const = 0;
|
||||
|
||||
protected:
|
||||
static int s_scaleHasVisibilityValue;
|
||||
public:
|
||||
static void setScaleHasVisibility(int scaleHasVisibility)
|
||||
{
|
||||
s_scaleHasVisibilityValue = scaleHasVisibility;
|
||||
}
|
||||
|
||||
// : Visibility
|
||||
//@}
|
||||
|
||||
|
||||
/*! \name Selection, Picking */
|
||||
//@{
|
||||
/**
|
||||
* @brief Get selected state.
|
||||
* @return true if selected, otherwise false.
|
||||
*/
|
||||
virtual bool selected() const = 0;
|
||||
/**
|
||||
* @brief Set selected state.
|
||||
* @param selected new state.
|
||||
*/
|
||||
virtual void setSelected(bool selected) = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get pickable state.
|
||||
* @return true if pickable, otherwise false.
|
||||
*/
|
||||
virtual bool pickable() const = 0;
|
||||
/**
|
||||
* @brief Set pickable state.
|
||||
* @param pickable new state.
|
||||
*/
|
||||
virtual void setPickable(bool pickable) = 0;
|
||||
//@}
|
||||
|
||||
|
||||
|
||||
/*! \name Symbol */
|
||||
//@{
|
||||
/**
|
||||
* @brief Get current symbol.
|
||||
* @return Current symbol.
|
||||
*/
|
||||
virtual SymbolData symbol() const = 0;
|
||||
/**
|
||||
* @brief Set new Symbol
|
||||
* @param symbol new value.
|
||||
*/
|
||||
virtual void setSymbol(const SymbolData &symbol) = 0;
|
||||
|
||||
/**
|
||||
* @brief reRenderSymbol
|
||||
* Will set the changed flag to true, following updateView is required
|
||||
*/
|
||||
virtual void reRenderSymbol() = 0;
|
||||
|
||||
|
||||
virtual SymbolDataToRender symbolDataToRender() const = 0;
|
||||
|
||||
/**
|
||||
* @brief symbolImage returns an image, maybe to be used as preview icon.
|
||||
* @return image of this MapObject.
|
||||
*/
|
||||
virtual SymbolImage symbolImage() const = 0;
|
||||
|
||||
|
||||
virtual QImage previewImage() const = 0;
|
||||
virtual QImage previewImageTypical() const = 0;
|
||||
virtual QImage previewImageSpecific() const = 0;
|
||||
//@}
|
||||
|
||||
|
||||
|
||||
/*! \name Common convenience methode, e.g. for MapObjectIndicator */
|
||||
//@{
|
||||
virtual void boundingBox(BoundingBox &bbox) const = 0;
|
||||
virtual void setForceMajorColor(const QColor &majorColor) = 0;
|
||||
virtual QColor majorColor() const = 0;
|
||||
//@}
|
||||
|
||||
/*! \name Some methods regarding extrusion (renderer approach) */
|
||||
//@{
|
||||
virtual double extrusionHeight() const = 0;
|
||||
virtual void setExtrusionHeight(double height = std::nan("")) = 0;
|
||||
|
||||
virtual const QString extrusionColorName() const = 0;
|
||||
virtual void setExtrusionColorName(const QString &extrusionColorName) = 0;
|
||||
//@}
|
||||
|
||||
|
||||
|
||||
/*! \name updateView */
|
||||
//@{
|
||||
/**
|
||||
* @brief Transfer all values to view
|
||||
* @return true on success
|
||||
*/
|
||||
virtual bool updateView() = 0;
|
||||
//@}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief Output operator used fo all deriving classes.
|
||||
* @param stream used to stream into.
|
||||
* @param value to be streamed.
|
||||
* @return appended stream.
|
||||
*/
|
||||
SITUATIONMAP_EXPORT std::ostream &operator<< (std::ostream &stream,
|
||||
const AbstractMapObject &value);
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
Executable
+170
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Interface of AbstractMapObject
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "bounding_box.h"
|
||||
#include "situation_map_utils.h"
|
||||
#include <situation_map_export.h>
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
BoundingBox::BoundingBox(ExtentType extentType)
|
||||
{
|
||||
reset();
|
||||
m_extentType = extentType;
|
||||
}
|
||||
|
||||
BoundingBox::BoundingBox(ExtentType extentType, const Point3D ¢er, double width, double height)
|
||||
: m_extentType(extentType),
|
||||
m_center(center),
|
||||
m_width(width),
|
||||
m_height(height)
|
||||
{
|
||||
}
|
||||
|
||||
void BoundingBox::reset()
|
||||
{
|
||||
m_extentType = ExtentType::Undefined;
|
||||
|
||||
m_center = Point3D();
|
||||
m_width = m_height = std::numeric_limits<double>::lowest();
|
||||
}
|
||||
|
||||
BoundingBox::ExtentType BoundingBox::extentType() const
|
||||
{
|
||||
return m_extentType;
|
||||
}
|
||||
|
||||
void BoundingBox::setExtentType(BoundingBox::ExtentType extentType)
|
||||
{
|
||||
m_extentType = extentType;
|
||||
}
|
||||
|
||||
bool BoundingBox::isValid() const
|
||||
{
|
||||
return
|
||||
m_extentType != ExtentType::Undefined &&
|
||||
!m_center.isNull() &&
|
||||
m_width != std::numeric_limits<double>::lowest() &&
|
||||
m_height != std::numeric_limits<double>::lowest();
|
||||
}
|
||||
|
||||
Point3D BoundingBox::center() const
|
||||
{
|
||||
return m_center;
|
||||
}
|
||||
|
||||
double BoundingBox::width() const
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
double BoundingBox::height() const
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
|
||||
Point3D BoundingBox::topLeft() const
|
||||
{
|
||||
return Point3D(m_center.x() - width() / 2.0,
|
||||
m_center.y() + height() / 2.0,
|
||||
m_center.z());
|
||||
}
|
||||
|
||||
Point3D BoundingBox::topRight() const
|
||||
{
|
||||
return Point3D(m_center.x() + width() / 2.0,
|
||||
m_center.y() + height() / 2.0,
|
||||
m_center.z());
|
||||
}
|
||||
|
||||
Point3D BoundingBox::bottomLeft() const
|
||||
{
|
||||
return Point3D(m_center.x() - width() / 2.0,
|
||||
m_center.y() - height() / 2.0,
|
||||
m_center.z());
|
||||
}
|
||||
|
||||
Point3D BoundingBox::bottomRight() const
|
||||
{
|
||||
return Point3D(m_center.x() + width() / 2.0,
|
||||
m_center.y() - height() / 2.0,
|
||||
m_center.z());
|
||||
}
|
||||
|
||||
Point3D BoundingBox::centerRight() const
|
||||
{
|
||||
return Point3D(m_center.x() + width() / 2.0,
|
||||
m_center.y(),
|
||||
m_center.z());
|
||||
}
|
||||
|
||||
|
||||
PositionCont BoundingBox::positions() const
|
||||
{
|
||||
PositionCont posCont;
|
||||
posCont.reserve(4);
|
||||
|
||||
posCont.append(topLeft());
|
||||
posCont.append(topRight());
|
||||
posCont.append(bottomRight());
|
||||
posCont.append(bottomLeft());
|
||||
|
||||
return posCont;
|
||||
}
|
||||
|
||||
|
||||
QString BoundingBox::toString() const
|
||||
{
|
||||
QString asString = toString(m_extentType);
|
||||
asString += QStringLiteral(" center=(%1;%2;%3), width=%4, height=%5")
|
||||
.arg(m_center.x()).arg(m_center.y()).arg(m_center.z()).arg(m_width).arg(m_height);
|
||||
return asString;
|
||||
}
|
||||
|
||||
|
||||
QString BoundingBox::toString(BoundingBox::ExtentType value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case BoundingBox::ExtentType::Undefined:
|
||||
return QLatin1String("Undefined");
|
||||
case BoundingBox::ExtentType::Sim:
|
||||
return QLatin1String("Sim");
|
||||
case BoundingBox::ExtentType::Pixel:
|
||||
return QLatin1String("Pixel");
|
||||
} // switch
|
||||
return QLatin1String("BoundingBox::ExtentTypeERROR");
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<< (std::ostream &stream,
|
||||
const BoundingBox &value)
|
||||
{
|
||||
stream << value.toString();
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::ostream &operator<< (std::ostream &stream,
|
||||
const BoundingBox::ExtentType &value)
|
||||
{
|
||||
stream << BoundingBox::toString(value);
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
Executable
+85
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Interface of AbstractMapObject
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "situation_map_types.h"
|
||||
#include "situation_map_utils.h"
|
||||
#include <situation_map_export.h>
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
class SITUATIONMAP_EXPORT BoundingBox
|
||||
{
|
||||
public:
|
||||
enum class ExtentType {Undefined, Sim, Pixel};
|
||||
static QString toString(BoundingBox::ExtentType value);
|
||||
|
||||
public:
|
||||
explicit BoundingBox(ExtentType extentType = ExtentType::Undefined);
|
||||
explicit BoundingBox(ExtentType extentType, const Point3D ¢er, double width = 0, double height = 0); ///< relative to BasePoint
|
||||
|
||||
void reset();
|
||||
|
||||
ExtentType extentType() const;
|
||||
void setExtentType(ExtentType extentType);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
Point3D center() const;
|
||||
|
||||
double width() const; ///< interpret values depending on type
|
||||
double height() const; ///< interpret values depending on type
|
||||
|
||||
Point3D topLeft() const; ///< use quadrant 1
|
||||
Point3D topRight() const; ///< use quadrant 1
|
||||
Point3D bottomLeft() const; ///< use quadrant 1
|
||||
Point3D bottomRight() const; ///< use quadrant 1
|
||||
|
||||
Point3D centerRight() const; ///< use quadrant 1
|
||||
|
||||
PositionCont positions() const;
|
||||
|
||||
|
||||
QString toString() const;
|
||||
|
||||
protected:
|
||||
ExtentType m_extentType = ExtentType::Undefined; ///< relevant for width and height
|
||||
|
||||
Point3D m_center; ///< simCoordinates
|
||||
|
||||
double m_width; ///< simCoordinates or pixel
|
||||
double m_height; ///< simCoordinates or pixel
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief Output operator
|
||||
* @param stream used to stream into.
|
||||
* @param value to be streamed.
|
||||
* @return appended stream.
|
||||
*/
|
||||
SITUATIONMAP_EXPORT std::ostream &operator<< (std::ostream &stream,
|
||||
const BoundingBox &value);
|
||||
SITUATIONMAP_EXPORT std::ostream &operator<< (std::ostream &stream,
|
||||
const BoundingBox::ExtentType &value);
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
Executable
+99
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Class Camera
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "camera.h"
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QJsonObject>
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
Camera::Camera()
|
||||
{
|
||||
resetCamera();
|
||||
}
|
||||
|
||||
void Camera::resetCamera()
|
||||
{
|
||||
loc_x_lon = 0;
|
||||
loc_y_lat = 0;
|
||||
loc_z = 0;
|
||||
heading = 0;
|
||||
pitch = 0;
|
||||
roll = 0;
|
||||
}
|
||||
|
||||
bool Camera::isNull() const
|
||||
{
|
||||
return qFuzzyIsNull(loc_x_lon) && qFuzzyIsNull(loc_y_lat) && qFuzzyIsNull(loc_z) &&
|
||||
qFuzzyIsNull(heading) && qFuzzyIsNull(pitch) && qFuzzyIsNull(roll);
|
||||
|
||||
}
|
||||
|
||||
Camera Camera::read(const QJsonObject &json)
|
||||
{
|
||||
Camera cam;
|
||||
if (json.contains(QLatin1String("loc_x_lon")))
|
||||
cam.loc_x_lon = json[QLatin1String("loc_x_lon")].toDouble();
|
||||
if (json.contains(QLatin1String("loc_y_lat")))
|
||||
cam.loc_y_lat = json[QLatin1String("loc_y_lat")].toDouble();
|
||||
if (json.contains(QLatin1String("loc_z")))
|
||||
cam.loc_z = json[QLatin1String("loc_z")].toDouble();
|
||||
|
||||
if (json.contains(QLatin1String("heading")))
|
||||
cam.heading = json[QLatin1String("heading")].toDouble();
|
||||
if (json.contains(QLatin1String("loc_x_lon")))
|
||||
cam.pitch = json[QLatin1String("pitch")].toDouble();
|
||||
if (json.contains(QLatin1String("roll")))
|
||||
cam.roll = json[QLatin1String("roll")].toDouble();
|
||||
|
||||
return cam;
|
||||
}
|
||||
QJsonObject Camera::toJsonObject() const
|
||||
{
|
||||
QJsonObject json;
|
||||
json[QLatin1String("loc_x_lon")] = loc_x_lon;
|
||||
json[QLatin1String("loc_y_lat")] = loc_y_lat;
|
||||
json[QLatin1String("loc_z")] = loc_z;
|
||||
json[QLatin1String("heading")] = heading;
|
||||
json[QLatin1String("pitch")] = pitch;
|
||||
json[QLatin1String("roll")] = roll;
|
||||
return json;
|
||||
}
|
||||
|
||||
|
||||
QString Camera::toString() const
|
||||
{
|
||||
QString str;
|
||||
str.append(QStringLiteral("xLon;yLat=%1;%2[rad").arg(loc_x_lon).arg(loc_y_lat) );
|
||||
str.append(QStringLiteral("xLon;yLat=%1;%2[deg").arg(loc_x_lon*180.0/M_PI).arg(loc_y_lat*180.0/M_PI) );
|
||||
str.append(QStringLiteral(" z=%1").arg(loc_z));
|
||||
|
||||
str.append(QStringLiteral(" heading=%1").arg(heading));
|
||||
str.append(QStringLiteral(" pitch=%1").arg(pitch));
|
||||
str.append(QStringLiteral(" roll=%1").arg(roll));
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
std::ostream &operator<< (std::ostream &stream,
|
||||
const Camera &value)
|
||||
{
|
||||
stream << "Camera(" << value.toString() << "): ";
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Class Camera
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "situation_map_types.h"
|
||||
#include <Common/situation_map_logging.h>
|
||||
#include <situation_map_export.h>
|
||||
|
||||
// Qt
|
||||
#include <QString>
|
||||
|
||||
class QJsonObject;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// for 3D:
|
||||
/**
|
||||
* @brief A Camera contains the spatial parameters to set a 3D view on a Scene (3D):
|
||||
* A virtual camera's location, orientation and field of view.
|
||||
*
|
||||
*/
|
||||
class SITUATIONMAP_EXPORT Camera
|
||||
{
|
||||
public:
|
||||
Camera();
|
||||
~Camera() = default;
|
||||
|
||||
void resetCamera();
|
||||
bool isNull() const;
|
||||
|
||||
static Camera read(const QJsonObject &json);
|
||||
QJsonObject toJsonObject() const;
|
||||
|
||||
QString toString() const;
|
||||
|
||||
|
||||
double loc_x_lon; ///< location x (longitude)
|
||||
double loc_y_lat; ///< location y (latitude)
|
||||
double loc_z; ///< location z
|
||||
|
||||
double heading;
|
||||
double pitch;
|
||||
double roll;
|
||||
};
|
||||
|
||||
SITUATIONMAP_EXPORT std::ostream &operator<< (std::ostream &stream,
|
||||
const SituationMap::Camera &value);
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Interface-Implementation of Map
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "situation_map_types.h"
|
||||
|
||||
|
||||
// ESRI
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QString>
|
||||
|
||||
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class Point;
|
||||
}
|
||||
}
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The CoordTranslationFunctor is a base class translating between
|
||||
* the GeographicCoordinats (WGS84 - EPSG:4326) and the
|
||||
* EsriMap working on map coordinates.
|
||||
*
|
||||
* Forward (geographicToMap):
|
||||
* Geo (lon, lat) to map.
|
||||
*
|
||||
* Backward (mapToGeographic):
|
||||
* Map to Geo (lon, lat).
|
||||
*/
|
||||
class CoordTranslationFunctor
|
||||
{
|
||||
public:
|
||||
/*! \name Construction, Destruction */
|
||||
//@{
|
||||
explicit CoordTranslationFunctor() = default; ///< Contructor
|
||||
virtual ~CoordTranslationFunctor() = default; ///< Destructor
|
||||
//@}
|
||||
|
||||
/*! \name Complete translation */
|
||||
//@{
|
||||
Q_REQUIRED_RESULT virtual QPointF geographicToMap(const double lon, const double lat) const = 0; ///< Forward: geographic coord to mapCoord, in radian
|
||||
Q_REQUIRED_RESULT virtual QPointF mapToGeographic(const double x, const double y) const = 0; ///< Backward: mapCoord to geographic Coord
|
||||
|
||||
Q_REQUIRED_RESULT virtual QPointF geographicToMap(const QPointF &coord) const = 0; ///< Forward: geographic coord to mapCoord
|
||||
Q_REQUIRED_RESULT virtual QPointF mapToGeographic(const QPointF &coord) const = 0; ///< Backward: mapCoord to geographic Coord
|
||||
|
||||
Q_REQUIRED_RESULT virtual QPointF geographicToMap(const Esri::ArcGISRuntime::Point &coord) const = 0; ///< Forward: geographic coord to mapCoord
|
||||
Q_REQUIRED_RESULT virtual QPointF mapToGeographic(const Esri::ArcGISRuntime::Point &coord) const = 0; ///< Backward: mapCoord to geographic Coord
|
||||
|
||||
Q_REQUIRED_RESULT virtual Point3D geographicToMap(const Point3D &point3D) const = 0; ///< Forward: geographic coord to mapCoord
|
||||
Q_REQUIRED_RESULT virtual Point3D mapToGeographic(const Point3D &point3D) const = 0; ///< Backward: mapCoord to geographic Coord
|
||||
|
||||
Q_REQUIRED_RESULT virtual bool mapIsGeographic() const = 0;
|
||||
|
||||
virtual void geographicToUtm(const double referenceLon, QList<QPointF> &points) const = 0; ///< tanslate to proper utm coordinate system
|
||||
virtual void utmToGeographic(const double referenceLon, QList<QPointF> &points) const = 0; ///< translate back to goegraphic coordiante system
|
||||
|
||||
//@}
|
||||
|
||||
/*! \name For statistic or tests */
|
||||
//@{
|
||||
virtual int projectionCounter() const = 0;
|
||||
virtual void resetProjectionCounter() = 0;
|
||||
//@}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Simple DropEventManager to manage drop events in SituationMap Map Widget
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Windows 7, Linux, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** 18.12.2015, JT : First edition for use with Qt5
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Common/referenced.h>
|
||||
|
||||
#include <QtCore/QPoint>
|
||||
|
||||
class QMimeData;
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
/**
|
||||
@class DropEventManager drop_event_manager.h
|
||||
@brief Drop event manager interface class.
|
||||
@see SituationMap::Map, PBase::PDropHandler
|
||||
|
||||
To process drop events the map window has to decide accepting a drop when it gets a drag enter event or not, depending on the type of mime data. Later
|
||||
when receiving a drop event the dropped data has to be processed. The DropEventManager class provides information of mime data type to decide handling
|
||||
the type of drop event or not. The function mimeFormatString() should return a uniquely defined string. To handle a special drop event the map will call
|
||||
the manageDrop function. Both functions have to be implemented in the derived class.
|
||||
|
||||
Following example shows how to implement a drop event mamager.
|
||||
|
||||
@code
|
||||
|
||||
#include <Map/drop_event_manager.h>
|
||||
|
||||
class DropEventManager : public SituationMap::DropEventManager
|
||||
{
|
||||
public:
|
||||
|
||||
DropEventManager() = default;
|
||||
|
||||
virtual ~DropEventManager()
|
||||
{
|
||||
// delete all dropHandler
|
||||
for (auto key : m_dropHandlerMap.keys())
|
||||
{
|
||||
delete m_dropHandlerMap[key];
|
||||
m_dropHandlerMap[key] = nullptr;
|
||||
}
|
||||
} // ~DropEventManager()
|
||||
|
||||
QString mimeFormatString() const { return QLatin1String("DropHandlerPtr"); }
|
||||
|
||||
void manageDrop( QPoint windowPos, const QMimeData * mimeData ) override
|
||||
{
|
||||
bool ok = false;
|
||||
qulonglong dropHandlerKey = mimeData->data(mimeFormatString()).toULongLong(&ok);
|
||||
if (ok)
|
||||
{
|
||||
QMap<qulonglong,PBase::PDropHandler*>::iterator dropHandler;
|
||||
dropHandler = m_dropHandlerMap.find( dropHandlerKey );
|
||||
if (dropHandler != m_dropHandlerMap.end())
|
||||
{
|
||||
(*dropHandler)->doDrop( windowPos.x(), windowPos.y(), mimeData );
|
||||
}
|
||||
}
|
||||
} // manageDrop( const QMimeData * mimeData )
|
||||
|
||||
qulonglong add( PBase::PDropHandler * dropHandler )
|
||||
{
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// DropEvewntManager get ownership of dropHandler and delete them in dtor.
|
||||
// See dtor above.
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
qulonglong key = qulonglong(dropHandler);
|
||||
if (dropHandler)
|
||||
{
|
||||
m_dropHandlerMap[key] = dropHandler;
|
||||
}
|
||||
return key;
|
||||
} // add(PBase::PDropHandler * dropHandler)
|
||||
|
||||
protected:
|
||||
|
||||
QMap<qulonglong,PBase::PDropHandler*> m_dropHandlerMap;
|
||||
|
||||
}; // DropEventManager
|
||||
|
||||
|
||||
void installDropEventManager()
|
||||
{
|
||||
m_dropEventManager = new DropEventManager();
|
||||
m_map -> installDropEventManager( m_dropEventManager );
|
||||
}
|
||||
|
||||
@endcode
|
||||
|
||||
*/
|
||||
|
||||
|
||||
class DropEventManager : public Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
DropEventManager() = default;
|
||||
~DropEventManager() = default;
|
||||
|
||||
DropEventManager(const DropEventManager *) = delete;
|
||||
|
||||
/*
|
||||
The function \c mimeFormatString() returns a uniquely defined string to identify type of mime data. The string will be used to call \c QMimeData::hasFormat()
|
||||
@see QMimeData
|
||||
*/
|
||||
virtual QString mimeFormatString() const = 0;
|
||||
|
||||
/*
|
||||
The function \c manageDrop() will be called to process drop events
|
||||
@param windowPos Mouse cursor from drop event
|
||||
@param mimeData Data of drop event to process.
|
||||
*/
|
||||
virtual void manageDrop(QPoint windowPos, const QMimeData *mimeData) = 0;
|
||||
|
||||
}; // DropEventManager
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
Loaded 100 of 16245 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user